Flask doesn't print to console (route) - flask

There is already another post with the same question that has an answer, but it doesn't work for me. There is also no explanation given what causes the problem.
Flask version: 1.0.2., running locally.
Route:
#bp.route("/mailbox/get_mail_attachment", methods = ["GET"])
#token_auth.login_required
def get_mail_attachment():
print("it should print")
return error_response(400)
I'm getting back a response with status code 400, but the route doesn't print to the console (all other routes of my application do). It is the right route though, because if I change the url of the route I get back 404.
I guess it doesn't matter where the request comes from, but maybe I'm wrong: In my case it comes from an Angular application (version 5).
The request looks like this:
getAttachment(data) {
const url: string = `${this.BASE_URL}` + '/mailbox/get_mail_attachment';
const headers = new Headers({'Authorization': 'Bearer ' + localStorage.getItem('token')})
return this.http.get(url, {headers: headers, params: data, responseType: ResponseContentType.Blob})
}
I simplified code of the flask route, that's why it doesn't make any use of the request.args.

Related

Why am I getting a CORS error depsite using flask_cors?

I'm getting the error
Access to fetch at 'http://hpap-dev.pmacs.upenn.edu:5801/get-categories' from origin 'http://hpap-dev.pmacs.upenn.edu:5802' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
despite using flask_cors. My flask app and route look like this
#Start flask app
app = Flask(__name__)
#Open flask for querying from domains outside of the app
CORS(app)
<snip>
#app.route('/get-categories')
#cross_origin()
def get_categories():
frame_dict = file_cat_wrangle.get_wrangle_dict()
# orig
# return jsonify(response=frame_dict)
# stauffer - try this to resolve CORS problem
response = jsonify(response=frame_dict)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
As you can see, the code's calling CORS(app) as well as #cross_origin() under the route. And I also tried adding the Access-Control-Allow-Origin header explicitly to the response, per another stackoverflow post.
I've rebuilt and restarted the flask server. AFAIK this used to work on this server (I've taken over this project at work and am pretty new to web dev). Other API calls that go between the front-end (node server) and back-end (the flask app) are working. I also checked that the route path and the call to it are identical.
Here's the call from the front end:
export const fetchCategories = () => {
return fetch(`${flask_url}/get-categories`)
.then(response => {
if (response.status >= 400) {
throw new Error(`${response.status}: ${response.statusText}`);
}
return response.json();
}).then(categories => categories);
}
Any suggestions??
Check if the header is really present in the network tab in your browser.
You can use hooks to enable cors as below:
#app.after_request
def after_request(response):
response.headers['Access-Control-Allow-Origin'] = '*'
return response
Turns out it was not actually a CORS-related error but some kind of odd error response. See my comment to the original question.

Axios Authorization not working - VueJS + Django

I am trying to build an application using VueJS and Django. I am also using Graphene-Django library, as the project utilize GraphQL.
Now, The authentication works fine and i get a JWT Token back.
But when i use the token for other queries that need authentication, i got this error in Vue:
"Error decoding signature"
and the Django Log also returns this:
graphql.error.located_error.GraphQLLocatedError: Error decoding signature
jwt.exceptions.DecodeError: Not enough segments
ValueError: not enough values to unpack (expected 2, got 1)
the bizarre thing is that the same query when executed in Postman just works fine.
As i mentioned in the title is use Axios for my requests, here's an example of a request:
axios({
method: "POST",
headers: { Authorization: "JWT " + localStorage.getItem("token") },
data: {
query: `{
dailyAppoint (today: "${today}") {
id
dateTime
}
}`
}
});
Note: It uses 'JWT' not 'Bearer' because somehow 'Bearer' didn't work for me.
Ok, couple of questions, does you API work without Vue.js from curl. Generate token, check API from curl.
If it does, then check the Headers sent from the request, from Network Inspector, mozilla dev tools/chrome devtools. And update your Post with those RAW Headers.
This particular error arises when your public key is unable to decode the string[token] signed by your private key. Which ultimately means the access token has been tampered with. It could also mean you're sending values like 'unkown'-- JS state initialization error.
Check the RAW headers of the request. It'll help.
Use a request interceptor to set the Authorization header:
axios.interceptors.request.use(config => {
if (localStorage.getItem("token") != null)
config.headers["Authorization"] = "JWT " + localStorage.getItem("token");
return config;
});

Ajax, CSRF and DELETE

I use the getCookie function from the django documentation to get the csrfmiddlewaretoken value.
I have the following ajax call:
var url = reverse_removeprofile.replace(/deadbeef/, key);
$.ajax({
type: "DELETE",
url: url,
data: "csrfmiddlewaretoken=" + getCookie("csrftoken"),
success: function() { ... },
});
When this code gets executed then django raises a 403 exception telling me that the CSRF verification failed. However, if I change the type from DELETE to POST then django is happy about it and doesn't complain at all.
I was not really able to find something useful in Google about this, but I've found this (now closed and fixed) ticket: https://code.djangoproject.com/ticket/15258
If I understand it correctly then this issue has been fixed in the 1.4 milestone. I use django 1.4 but still I cannot verify the CSRF token with a DELETE request.
Am I missing something here?
This appears to be a jQuery bug, caused by some confusion as to whether DELETE data should be attached to the URL (like a GET request) or the request body (like a POST)
See this bug report.
You can probably get around this by using the alternative CSRF method for AJAX calls, setting an X-CSRFToken header on the request. Try changing your AJAX call to look like this:
$.ajax({
type: "DELETE",
url: url,
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function() { ... },
});
Please note, when it comes to DELETE requests DJango does not check for csrfmiddlewaretoken in the request body. Rather it looks for X-CSRFToken header
Coming to working of DJango CSRFMiddleware you can see the source code of django > middleware > csrf.py > CsrfViewMiddleware in which it is very clear that DJango does not scan for csrfmiddlewaretoken in request body if the request is of DELETE type:
# Check non-cookie token for match.
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except OSError:
# Handle a broken connection before we've completed reading
# the POST data. process_view shouldn't raise any
# exceptions, so we'll ignore and serve the user a 403
# (assuming they're still listening, which they probably
# aren't because of the error).
pass
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

How to create a POST request (including CSRF token) using Django and AngularJS

I'm trying to create a POST request using angular.js to this Django view.
class PostJSON4SlickGrid(View):
"""
REST POST Interface for SlickGrid to update workpackages
"""
def post(self, request, root_id, wp_id, **kwargs):
print "in PostJSON4SlickGrid"
print request.POST
return HttpResponse(status=200)
Therefore I created this resource.
myModule.factory('gridData', function($resource) {
//define resource class
var root = {{ root.pk }};
return $resource('{% url getJSON4SlickGrid root.pk %}:wpID/', {wpID:'#id'},{
get: {method:'GET', params:{}, isArray:true},
update:{method:'POST'}
});
});
Calling the get method in a controller works fine. The url gets translated to http://127.0.0.1:8000/pm/rest/tree/1/.
function gridController($scope, gridData){
gridData.get(function(result) {
console.log(result);
$scope.treeData = result;
//broadcast that asynchronous xhr call finished
$scope.$broadcast('mySignal', {fake: 'Hello!'});
});
}
While I m facing issues executing the update/POST method.
item.$update();
The URL gets translated to http://127.0.0.1:8000/pm/rest/tree/1/345, which is missing a trailing slash. This can be easily circumvented when not using a trailing slash in your URL definition.
url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),
instead of
url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)/$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),
Using the workaround without the trailing slash I get now a 403 (Forbidden) status code, which is probably due to that I do not pass a CSRF token in the POST request. Therefore my question boils down to how I can pass the CSRF token into the POST request created by angular?
I know about this approach to pass the csrf token via the headers, but I m looking for a possibility to add the token to the body of the post request, as suggested here. Is it possible in angular to add data to the post request body?
As additional readings one can look at these discussions regarding resources, removed trailing slashes, and the limitations resources currently have: disc1 and disc2.
In one of the discussions one of the authors recommended to currently not use resources, but use this approach instead.
I know this is more than 1 year old, but if someone stumbles upon the same issue, angular JS already has a CSRF cookie fetching mechanism (versions of AngularJS starting at 1.1.5), and you just have to tell angular what is the name of the cookie that django uses, and also the HTTP header that it should use to communicate with the server.
Use module configuration for that:
var app = angular.module('yourApp');
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
Now every request will have the correct django CSRF token. In my opinion this is much more correct than manually placing the token on every request, because it uses built-in systems from both frameworks (django and angularJS).
Can't you make a call like this:
$http({
method: 'POST',
url: url,
data: xsrf,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
The data can be whatever you wish to pass and then just append &{{csrf_token}} to that.
In your resource params:{}, try adding csrfmiddlewaretoken:{{csrf_token}} inside the params
Edit:
You can pass data to the request body as
item.$update({csrfmiddlewaretoken:{{csrf_token}}})
and to headers as
var csrf = '{{ csrf_token }}';
update:{method:'POST', headers: {'X-CSRFToken' : csrf }}
It is an undocumented issue
In recent angularjs version giving solution is not working . So i tried the following
First add django tag {% csrf_token %} in the markup.
Add a $http inspector in your app config file
angular.module('myApp').config(function ( $httpProvider) {
$httpProvider.interceptors.push('myHttpRequestInterceptor');
});
Then define that myHttpRequestInterceptor
angular.module("myApp").factory('myHttpRequestInterceptor', function ( ) {
return {
config.headers = {
'X-CSRFToken': $('input[name=csrfmiddlewaretoken]').val() }
}
return config;
}};
});
it'll add the X-CSRFToken in all angular request
And lastly you need to add the Django middleware " django.middleware.csrf.CsrfViewMiddleware'"
It'll solve the CSRF issue
var app = angular.module('angularFoo', ....
app.config(["$httpProvider", function(provider) {
provider.defaults.headers.common['X-CSRFToken'] = '<<csrftoken value from template or cookie>>';
}])
I use this:
In Django view:
#csrf_protect
def index(request):
#Set cstf-token cookie for rendered template
return render_to_response('index.html', RequestContext(request))
In App.js:
(function(A) {
"use strict";
A.module('DesktopApplication', 'ngCookies' ]).config(function($interpolateProvider, $resourceProvider) {
//I use {$ and $} as Angular directives
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
//Without this Django not processed urls without trailing slash
$resourceProvider.defaults.stripTrailingSlashes = false;
}).run(function($http, $cookies) {
//Set csrf-kookie for every request
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
});
}(this.angular));
For sending correct request you must convert object to param-form:
$http.post('/items/add/', $.param({name: 'Foo'}));//Here $ is jQuery

Do all 404 pages share something in common?/Are 404 page distinguishable from regular pages?

Say I am running stumbleupon.com and users can submit sites to be added into the db of sites. Is there a way that I can write a program to see whether or not the site that was added by the user is actually a real website? Or if it bring me to a 404 that I can say "welp, that was some bugus" or maybe that the user made an error when submitting the url? Or do i need to put people on my payroll to see if the user submitted website bring me to a 404?
The response code from the request is a 404 not found, instead of a 200 success message that you get on a good response from the server. You can easily automate the check.
Since I don't know much about python, I offer a client side solution.
You could check if the URL is legit as soon as the user submits the page. Maybe throw up a 'verifying url' message or something.
Using this method you could make a cross domain call to see if that site is really there. Then you could pop up a message that asks them to fix their mistake or allow the URL to be submitted. This solution uses Yahoo as a proxy, but as you can see by my super simple function below it does work.
function doAjaxCheck(url){
// if the URL starts with http
if(url.match('^http')){
//add a 'loading message here, or something'
// assemble the YQL call
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+
"q=select%20*%20from%20html%20where%20url%3D%22"+
encodeURIComponent(url)+
"%22&format=xml'&callback=?",
function(data){
if(data.results[0]){
alert('it is OK');
} else {
alert('not OK');
}
}
);
} else {
$.ajax({
url: url,
timeout:5000,
success: function(data){
alert('it is OK');
},
error: function(req,error){
if(error === 'error'){error = req.statusText;}
alert('not OK : ' + error );
}
});
}
}
However, all this being said, I would go with a server-side check for reliability-sake.