Flask launch CORS issue intermittently - python

I'm working on a personal project, where I scrap data from a store(article data, image, price, etc) with a self made Firefox extension, to have a pending to buy list, but Flask seems to be causing CORS errors randomly, like at one moment I make a request and get a CORS error, and then I make it again(Without changing anything) and works correctly. This is how I defined my Flask app:
db = SQLAlchemy()
migrate = Migrate()
cors = CORS()
def create_app(config_class=configc):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app=app)
migrate.init_app(app=app, db=db)
cors.init_app(app=app)
# A bunch of config lines...
return app
And all my Endpoints are just Namespace generic ones, with the API/Namespace flow
class ProductAPI(Resource):
def get(self, id=None):
#Things
#product_ns.expect(product_srl, validate=True)
def post(self, id=None):
#Things
def put(self, id):
#Things
def delete(self, id):
#Things
Now, something important to mention, in case this is where the problem could be: I divided the development of the project in 2 parts, the first where I only scrapped and sended the data of the article, which didn't gave me CORS problems during all the tests, and now when I added the part where I scrap the image, where I take the thumbnail and convert it to a Base64 string, and send it on a "thumb" string field, that is when I saw that my extension was reporting CORS problems, but the interesting part is what I mentioned, that it doesn't always happens, but is an intermitent problem, and I'm not sure if there is something about the base64 image field that could be causing it, and/or if there is a way to fix it.
For completeness, I also add the code of my request, in case there is something could be causing it there
var data = {url: base_url, token: token, price: price, name: name, thumb: thumb};
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => {
if (response.status) {
checkPage(token);
}
});

Related

Forbidden (CSRF cookie not set.) Django

I'm trying to do an endpoint API. And for that, i'm using django.
My url in urls.py is :
path('tutorials/', tutorial_list_test.as_view()),
and my views.py is like
class tutorial_list_test(GuestOnlyView, FormView):
print("test");
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
request = self.request;
if request.method == 'POST':
alldata=request.POST
username = alldata.get("username", "0")
print("POST name: " + username)
return Response('The tutorial does not exist', status=status.HTTP_404_NOT_FOUND)
But when i'm doing a request, i have everytime the same error "Forbidden (CSRF cookie not set.): /accounts/tutorials/"
So I did some research, and I could see several proposed solutions.
The first was to use csrf_exempt but it's not working for me:
path('tutorials/', csrf_exempt(tutorial_list_test.as_view())),
And it's the same for all the methods I used. Even if I remove this line from my settings.py, nothing changes
# django.middleware.csrf.CsrfViewMiddleware',
To test, I use Postman, but even using my angular front end, it does the same.
const formData = new FormData()
formData.append('username', this.username_signup);
this.http.post('http://127.0.0.1:8000/accounts/tutorials/', formData)
.map((data: Response) => {
if (data !== null) {
console.log(JSON.stringify(data));
};
}).subscribe(response => console.log(response))
I would like to know if you have any idea how I can do this.
Because I need to be able to access my Models, so not using a class and directly making a def is not an option, even if it works.
(I tried, effectively my requests pass, if I remove the class and my route is only linked to my def tutorial_list).
Thank you.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
#api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(self):
# code

Flask-Restx & Swagger Authorizations Sending Incorrect Token in Header

I have a Flask REST API that is using Flask-Restx, and JWT token authentication and is working making calls out of postman. However, when I am trying to use swagger, the token being sent is not the one I am inputting through the interface. My code looks like the following:
blueprint = Blueprint('api_bp', __name__, url_prefix='/api/1')
authorizations = {
'api_key' : {
'type' : 'apiKey',
'in' : 'header',
'name' : 'x-access-token'
}
}
api = Api(blueprint,
authorizations=authorizations,
title='My Title',
version='1.0',
security='api_key'
)
from timesheets.views.api_bp import api as ns1
np = api.namespace('index', description='Index API')
def token_required(f):
#wraps(f)
def decorated(*args, **kwargs):
...
#np.route('/users')
class Users(Resource):
#api.doc(security='api_key')
#token_required
def get(self, current_user):
...
return jsonify({'user' : output})
Then on the swagger page, I can enter my auth token:
and I can see that the correct x-access-token is placed in the curl call when I "Try it out."
But if I look into my request headers, every time I get the same x-access-token that is sent to my server:
So, where is this token being generated from? And how do I ensure I am only using the token I am passing through the interface?
After reviewing that it was the same key being returned, I found in the code that the value inputted was being overwritten by test data I had previously introduced

Cross-Origin Request Blocked with Flask when using BasicAuth

I have a Flask application containing various images displaying some clusters constructed by a K-Means algorithm.
The user should be able to select one or several images and afterwards get redirected to a web-page where the clusters can be further assessed.
The application worked as intended until I added basic access authentication.
Specifically, my (simplified) python script goes as follows:
from flask import Flask, render_template, request, redirect, url_for
from flask_cors import CORS
from flask_basicauth import BasicAuth
app=Flask(__name__)
app.config['BASIC_AUTH_USERNAME'] = os.environ['AUTH_USERNAME']
app.config['BASIC_AUTH_PASSWORD'] = os.environ['AUTH_PASSWORD']
app.config['BASIC_AUTH_FORCE']= True
basic_auth=BasicAuth(app)
CORS(app)
#app.route('/')
def show_index():
images=os.listdir(app.root_path+"/static/img/")
return render_template("cluster_images.html", cluster_images = images)
#app.route("/filter", methods=["POST", "GET"])
def filter():
if request.method=="POST":
sel=request.get_json()
#Do some operations with sel
The problem appears when I try to redirect to the /filter route from the main route which is done by "btn1".
The following shows the function from "cluster_images.html" taking care the http request when btn1 is fired
$("document").ready(function() {
$("#btn1").click(function(){
$.ajax({
type: 'POST',
beforeSend: function(){
$('.loader')},
contentType: 'application/json',
url: "http://localhost:5000/filter",
dataType : 'html',
data : JSON.stringify(images), success: function(){window.location.href = "http://localhost:5000/filter"}
})
})
})
When I press the button I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/filter. (Reason: CORS preflight channel did not succeed).[Learn More]

Flask-Login, Session Management and AJAX

I'm having trouble getting an AJAX call to work with the Flask-Login current_user object and the #login_required decorator. I believe it has something to do with the session not being passed.
The goal is for a user to click on a link that makes an AJAX call to a route URL that will provide a SSO session ID through a SOAP service. The SOAP service requires an emp_id to be passed which can be accessed through the current_user.emp_id attribute.
I initially attempted the AJAX call without the #login_required decorator and just passing a simple message as such which returned successfully:
app.js
const ssoLinks = document.querySelectorAll('.sso');
ssoLinks.forEach((ssoLink) => {
ssoLink.addEventListener('click', (e) => generateSSOLink(e, ssoLink.id));
});
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link")
.then(response => response.json())
.then(data => console.log(data))
}
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print('SUCCESS')
print('*'*75)
return jsonify(data)
My next attempt was to access the emp_id in current_user:
views.py
#app.route('/get_bpm_sso_link')
def get_bpm_sso_link():
data = {
'msg': 'success'
}
print('*'*75)
print(current_user.emp_id)
print('*'*75)
return jsonify(data)
Which gave me this error:
AttributeError: 'AnonymousUserMixin' object has no attribute 'emp_id'
Okay, so then I decided to try and access the same emp_id attribute on the initial index page(where the AJAX lives as well) and was able to do so. It sounds like during an AJAX request, the Flask-Login LoginManager doesn't recognize the session of the current_user. To further this claim, I added the #login_required decorator to the route and the JSON response returned a redirect to the login page.
What can I do to have Flask-Login recognize a user during an AJAX call? If not, what other libraries can handle user session management and AJAX requests seamlessly?
So I did some digging this week at Pycon 2018 in Cleveland and came across a noteworthy topic regarding the Fetch API. Seems by default that the API doesn't send any user credentials. To remedy this, it all came down to setting an option within the API:
app.js
function generateSSOLink(e, page) {
e.preventDefault();
fetch("/get_bpm_sso_link", {
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
}
Now my AJAX request hits my view even with the #login_required decorator.
What you need is to login using request loader as per this example on flask for each request
And probably disable setting the Flask Session cookie
Then Using fetch add headers with basic authentication
fetch('/get_bpm_sso_link', {
method: 'get',
//or whichever method you are using
headers: new Headers({
'Authorization': 'Basic '+btoa('username:password')
//btoa base64 encodes your credentials, the flask example above shows how to decode
})
});
Ideally because the credentials are not hashed, they should be passed over https in production

Flask "url_for" equivalent for Falcon

I'm new to Falcon, and I was wondering if there was a Flask-like "url_for" solution for the framework. I've scoured the docs and I can't seem to find anything relevant with a google/stack search.
To clarify for users of Falcon who haven't used Flask, I would like to dynamically fetch a defined resource's URL. I'm specifically trying to achieve resource expansion, by including a link to my resources within my payload so the frontend doesn't have to construct any URLs.
Code:
class PostResource(object):
def on_get(self, req, resp, post_id):
"""Fetch single post resource."""
resp.status = falcon.HTTP_200
post_dto = post_to_dto(get_post(post_id))
# TODO: find url_to alternative for falcon: specify post resource location
post_dto.href = ''
resp.body = to_json(PostDtoSerializer, post_dto)
class PostCollectionResource(object):
def on_get(self, req, resp):
"""
Fetch grid view for all post resources.
Note: This endpoint support pagination, pagination arguments must be provided via query args.
"""
resp.status = falcon.HTTP_200
# TODO: add hrefs for each post for end ui
post_collection_dto = PostCollectionDto(
posts=[post_to_dto(post, comments=False) for post in get_posts(
start=req.params.get('start', None), count=req.params.get('count', None)
)])
resp.body = to_json(PostCollectionDtoSerializer, post_collection_dto)
def on_post(self, req, resp):
"""Create a new post resource."""
resp.status = falcon.HTTP_201
payload = req.stream.read()
user = req.context.get('user')
create_post(user._id, from_json(PostFormDtoSerializer, payload))
# TODO: find url_to alternative for falcon: redirect to on_get
resp.set_header('Location', '')
Post collection example:
[
{
"href": ".../post/000000/",
"links": [
"rel": "like",
"href": ".../post/000000/like"
],
"title": "Foobar",
...
}
]
I would like to be able to generate a link to the PostResource.
For the sake of closing this thread, I'm now using the methodology detailed here https://github.com/neetjn/py-blog/issues/16.
Falcon does not support this as confirmed by the maintainers, my work around was to create a base resource with a static route and child method to construct a link to the given resource using the information from the request's req argument.
Example:
class BaseResource(object):
route = ''
#classmethod
def url_to(cls, host, **kwargs) -> str:
return f'{host}{cls.route.format(**kwargs)}'
...
class PostResource(BaseResource):
route = '/v1/post/{post_id}'
def on_get(self, req, res):
pass
class PostCollectionResource(BaseResource):
route = '/v1/posts/'
def on_get(self, req, res):
posts = get_posts()
for post in posts:
post.href = PostResource.url_to(req.netloc, post_id=post.id)

Categories

Resources