I need to post some data to a django server using popup's js.because of the csrf, I should post data with csrftoken in cookie, how can i get the the value in the cookie. I have tried the following ways which do not work:
document.cookie
chrome.cookies.get({url: "chrome-extension://igmgfjnbghncmhbobdpjblokohejackc", name: "csrftoken"}, function(cookie){})
request infomation:
Request Method:POST
Status Code:403 FORBIDDEN
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
Content-Length:3
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:csrftoken=V6OTh2NdwnomqLbkfh24qRwT8C0kESIV
Host:127.0.0.1:8000
Origin:chrome-extension://igmgfjnbghncmhbobdpjblokohejackc
User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4
X-CSRFToken:null
You cannot access the csrftoken cookie from any domain but the one that generated it. So, you have to read the csrftoken when it's generated and save it if you want to use it from your extension.
In my case, when the token was not present, it didn't cause any error, but as soon as I logged in the server, the csrftoken was set, and couldn't retrieve it from any other domain, getting the 403 error on any request that was not generated in the same domain.
To fix it, first, I had to read the cookie from the domain when I logged in and save it to chrome storage. First, I need proper permissions (Note that, where I use background/background.js you could switch to popup/popup.js if needed)
manifest.json
...,
"background": {
"scripts": ["jquery-1.11.1.min.js","background.js"],
"persistent": false
},
"permissions": ["tabs", "<all_urls>", "storage", "webNavigation"],
"content_scripts":[
{
"matches":["yourDomain"],
"js": ["jquery-1.11.1.min.js", "readCSRFToken.js"]
}],...
Now, this small script will read the cookie we need if it's present and send it to our extension. You could check the host name before sending the cookie if you want to be sure that you take the correct CSRF token.
readCSRFToken.js
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
csrftoken = getCookie("csrftoken");
if ( csrftoken ){
chrome.runtime.sendMessage({action:"setCsrfToken", csrftoken:csrftoken}, function(){});
}
In the extension code, we add a listener that will save the csrf token in chrome storage when it's sent by the injected code.
There is also a webNavigation.onComplete that will read the token from storage every time we load a page.
background.js
csrftoken = null;
chrome.webNavigation.onCompleted.addListener(function(details) {
if ( details.frameId == 0 ){
chrome.storage.sync.get(["csrftoken"], function(storage){
csrftoken = storage.csrftoken;
});}
}
);
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
switch ( request.action ){
case "setCsrfToken":{
chrome.storage.sync.set({'csrftoken': request.csrftoken}, function() {});
}
break;
}
});
Finally, we have a csrftoken variable stored that we should be able to use to set the "X-CSRFToken" header to allow our AJAX request to work properly when used from the extension.
...
var headers = {}
if ( csrftoken ) headers["X-CSRFToken"] = csrftoken;
$.ajax({
dataType: 'json',
headers: headers,
...
});
I assume you already followed these steps: https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#how-to-use-it
I'm not familiar with popup.js but since it's a jquery plugin, this should work for you. An ajax request which puts the csrftoken into the request header:
$.ajax({
dataType: 'json',
headers: {"X-CSRFToken": $.cookie('csrftoken') },
...
}
Related
I have a index.html file .
That file for a html and Ajax call . If i run file through localhost that time api working Perfect..
But if i index.html file direct run on Google chrome, Mozilla firefox that time API given cors access control allow origin block error ..
<script type="text/javascript">
$( document ).ready(function() {
var channel_fid = $(this).attr("data-channel_fid");
var channel_id = $(this).attr("data-channel_id");
var userId = $('#uuid').val();
$.ajax({
url: 'https://3genrib1y0.execute-api.us-east-1.amazonaws.com/public/users/5ebc3ba8-37e6-4188-b52e-2e18d4a80034/channels',
type: "GET",
dataType:'json',
})
.done(function(res) {
if(res.success==true){
var val = res.galleries;
var options = new Array();
$.each(res.galleries, function(index, values) {
options.push('<li class="channels-list__item hover'+index+'" data-channel_fid="'+values.gallery_fid+'"><img src="https://www.cincopa.com/media-platform/api/thumb.aspx?size=large&fid='+values.gallery_fid+'"><div class="channels-list__info"><div class="channels-list__itemname"><h3>'+values.name+'</h3></div><div class="channels-list__itemdescr"><p>'+values.description+'</p></div></div></li>');
});
$('.dropdownItemContainer').html(options);
}
else
{
$('.dropdownItemContainer').html('');
}
});
var active = document.querySelector(".hover0") || document.querySelector(".dropdownItemContainer li");
document.addEventListener("keydown",handler);
function handler(e){
// console.log(active.classList);
active.classList.remove("hover0");
if (e.which == 40){
active = active.nextElementSibling || active;
}else if (e.which == 38){
active = active.previousElementSibling || active;
}else{
active = e.target;
}
active.classList.add("hover0");
}
});
</script>
It is not a matter of which tech stack you are using but of how you are trying to achieve your API consumption. You are requesting a remote resource (https://3genrib1y0.execute-api.....) from a probably totally different domain like example.com. Now chrome and firefox are smart enough to protect the user against a site that is trying to extract data from a foreign location - unless this site explicitly states via CORS Headers that it is allowed to be contacted e.g. from example.com.
So CORS is a security feature that happens on the level of your browser. The fact that it works locally is most likely due to calling the API from the same domain, like 127.0.0.1 which calls 127.0.0.1/api and is therefore considered a non-cross-origin ressource.
With this code, before an year about i could get the file via XMLHttpsRequest.
Now this do not more work, because of the error:
Access to XMLHttpRequest at 'https://drive.google.com/uc?id=1zGxNBh-YTAXu74v855l2b_LPmLUaomqZ&export=download' from origin 'https://encrypt.pdfzorro.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Is there a way at now, to get the file via javascript. I can not use any server solution, the file should go direct from googleDrive to the browser from the user.. without go on a server (with php e.g.) first.
function downloadFileContent(fileId){
gapi.client.request({
'path': '/drive/v2/files/' + fileId,
'method': 'GET',
callback: function ( theResponseJS, theResponseTXT ) {
var myToken = gapi.auth.getToken();
var myXHR = new XMLHttpRequest();
myXHR.open('GET', theResponseJS.downloadUrl, true );
myXHR.responseType = 'arraybuffer';
myXHR.setRequestHeader('Authorization', 'Bearer ' + myToken.access_token );
myXHR.onreadystatechange = function( theProgressEvent ) {
if (myXHR.readyState == 4) {
// 1=connection ok, 2=Request received, 3=running, 4=terminated
if ( myXHR.status == 200 ) {
// 200=OK
cossole.log(myXHR.response);
}
}
}
myXHR.send();
}
});
}
Im trying to help a friend out with a program but my coding experience is somewhat dated (10 years give or take). Where trying to pull data from a database via their API. Im making this request via a XMLhttpRequest but im having issues even getting to the Server.
The error that occurs:
Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost/jasper/api.shiftbase.com/api/rosters?min_date=2020-07-13&max_date=2020-12-31&department_id=24477
Its trying to search for the url on my own domain. But I need it to search cross domain.
The entire function:
function getRequest(){
var _request = new XMLHttpRequest();
var key = myKeyHere;
var url = "api.shiftbase.com/api/rosters?min_date=2020-07-13&max_date=2020-12-31&department_id=24477";
_request.onreadystatechange = function(event){
console.log(_request.readyState + " + " + _request.status);
if (_request.readyState == 4){
if ((_request.status >= 200 && _request.status < 300) || _request.status == 304){
alert(_request.responseText);
} else {
alert('Request was unsucceful: ' + _request.status);
}
}
};
_request.open("get", url, true);
_request.setRequestHeader("Accept", "application/JSON", false);
_request.setRequestHeader("Content-Type", "application/JSON", false);
_request.setRequestHeader("Authorization", key, false);
_request.send(null);
};
I've also read a lot about CORS and how this affects these kinds of requests cross domain, but i don't quite understand how it works and how i can work arround it.
Any help is appreciated.
First of all you need to prefix your URL with https://. This way you make a request to the external server instead of localhost. The second thing is that in your headers the application/JSON should be application/json.
Also dont forget that your key needs to be prefixed with "API". Example API [some_random_key]
I've tested the following code and it worked. You just have to add your own API KEY.
function getRequest(){
var _request = new XMLHttpRequest();
var key = "API [replace_this_with_your_key]"; // Example: "API a1b2c3d4e5f6g7h8i9"
var url = "https://api.shiftbase.com/api/rosters?min_date=2020-07-13&max_date=2020-12-31&department_id=24477";
_request.onreadystatechange = function(event){
console.log(_request.readyState + " + " + _request.status);
if (_request.readyState == 4){
if ((_request.status >= 200 && _request.status < 300) || _request.status == 304){
alert(_request.responseText);
} else {
alert('Request was unsucceful: ' + _request.status);
}
}
};
_request.open("get", url, true);
_request.setRequestHeader("Accept", "application/json", false);
_request.setRequestHeader("Content-Type", "application/json", false);
_request.setRequestHeader("Authorization", key, false);
_request.send(null);
};
Try to add // at the start of the line in url variable declaration (line 4), if you want to make a request to the external server.
Your request was made to the local webserver http://localhost/jasper/... and you've received a 404 (not found) error.
I am trying to sign a huge video upload, because I want to upload it directly to S3. It works on localhost, but on my live site it fails to sign the request because of:
Mixed Content: The page at 'https://www.example.com/profile' was loaded
over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://www.example.com/sign_s3/?file_name=17mbvid.mp4&file_type=video/mp4'.
This request has been blocked; the content must be served over HTTPS.
I am hosting everything on heroku, every page is already using HTTPS and its not possible to open it in HTTP, because I redirect all traffic to HTTPS. I am using the letsencrypt SSL certificate.
So far I have no idea where to look, the only information I found, is that I need a valid SSL certificate, which I have.
Here is the JS function:
function getSignedRequest(file) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/sign_s3?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('got signed request');
var response = JSON.parse(xhr.responseText);
console.log(response);
console.log('uploadFile', response.url)
uploadFile(file, response.data, response.url);
} else {
console.log("Could not get signed URL.");
}
}
};
//console.log('send');
xhr.send();
}
Right after the error in the console I see this console log:
Could not get signed URL.
which means it fails here:
if (xhr.status === 200)
On the server:
#app.route('/sign_s3/', methods=["GET", "POST"])
#login_required
#check_confirmed
def sign_s3():
if "localhost" in request.url_root:
file_name = str(current_user.id) + "local-profil-video." + request.args.get('file_name').split(".")[-1]
else:
file_name = str(current_user.id) + "-profil-video." + request.args.get('file_name').split(".")[-1]
file_type = request.args.get('file_type')
session = boto3.Session(
aws_access_key_id=app.config['MY_AWS_ID'],
aws_secret_access_key=app.config['MY_AWS_SECRET'],
region_name='eu-central-1'
)
s3 = session.client('s3')
presigned_post = s3.generate_presigned_post(
Bucket = 'adultpatreon',
Key = 'videos/' + file_name,
Fields = {"acl": "public-read", "Content-Type": file_type},
Conditions = [
{"acl": "public-read"},
{"Content-Type": file_type}
],
ExpiresIn = 3600
)
if current_user.profile_video != None:
delete_file_from_aws("videos/", current_user.profile_video)
setattr(current_user, "profile_video", file_name)
db_session.commit()
return json.dumps({'data': presigned_post, 'url': 'https://s3.eu-central-1.amazonaws.com/mybucket/' + 'videos/' + file_name})
After many hours of researching I decided to rebuild this function and use AJAX get, which I am more familiar with. I also changed the way I pass/recieve the query string arguments to the best way, which is actually used in flask/python.
function getSignedRequest(file) {
$.ajax({
url : "/sign_s3/" + file.name + "/" + file.type,
type : "get",
success : function(response) {
console.log("success file up, follow", response);
var json_response = JSON.parse(response);
console.log(json_response);
uploadFile(file, json_response.data, json_response.url);
},
error : function(xhr) {
console.log("file up failed", xhr);
}
});
}
And on server side I changed how file.name and file.type are recieved:
# Sign request for direct file upload through client for video
#app.route('/sign_s3/<path:file_name_data>/<path:file_type_data>', methods=["GET", "POST"])
#login_required
#check_confirmed
def sign_s3(file_name_data, file_type_data):
#etc...
Now it works perfectly. I think they way I was recieving the query string arguments on the server was not correct, probably it would also work with the old getSignedRequest function (untested).
I'm having a slight issue with a cross site origin request. I'm sure it is a simple fix.
Console error:
XMLHttpRequest cannot load https://subdomain.example.com/social/disqus. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.example.com' is therefore not allowed access.
js script causing the issue:
window.onload = function(){
//jQuery AJAX GET Method on Disqus Threads
$.ajax({
type: 'GET',
url: 'https://subdomain.example.com/social/disqus',
contentType: 'application/json; charset=utf-8',
success: function(threads) {
var len = Object.keys(threads.response).length
for (i = 0; i < len; i++){
if (threads.response[i].posts == 0 || threads.response[i].posts != 1) {
$('#' + threads.response[i].identifiers).html(threads.response[i].posts + " Comments ");
} else {
$('#' + threads.response[i].identifiers).html(threads.response[i].posts + " Comment ");
}
}
},
error: function() {
console.log("Aw, snap!");
}
});
};
I'm forcing redirects in Apache for both - this may be an issue, but it looks like the CORS request is being fired from a https:// valid site to another https:// valid site... url in the ajax request is definitely https.
I'm wondering if I am missing something from $.ajax ?