]>
git.gir.st - subscriptionfeed.git/blob - app/__init__.py
4 from flask
import Flask
6 from .common
.common
import *
7 from .common
.user
import init_login
10 app
.secret_key
= base64
.b64decode(cf
['frontend'].get('secret_key','')) or \
11 secrets
.token_bytes(16) # development fallback; CSRF/cookies won't persist.
14 for name
in cf
['frontend']['modules'].split(','):
15 blueprint
= importlib
.import_module('.'+name
, __name__
)
16 app
.register_blueprint(blueprint
.frontend
)
19 # TODO: should this go somewhere else?
20 # This error handler logs requests to external apis. this makes debugging of api responses easier, as the request can be reconstructed and replayed.
22 from werkzeug
.exceptions
import InternalServerError
23 @app.errorhandler(InternalServerError
)
25 if 'api_requests' in g
:
26 app
.logger
.error(g
.api_requests
)
29 # TODO: build a proper flask extension
30 # Magic CSRF protection: This modifies outgoing HTML responses and injects a csrf token into all forms.
31 # All post requests are then checked if they contain the valid token.
33 # - don't use regex for injecting
34 # - inject a http header into all responses (that could be used by apis)
35 # - allow csrf token to be passed in http header, json, ...
36 # - a decorator on routes to opt out of verification or output munging
37 # https://stackoverflow.com/questions/19574694/flask-hit-decorator-before-before-request-signal-fires
38 # - allow specifying hmac message contents (currently request.remote_addr)
42 from flask
import request
44 def add_csrf_protection(response
):
45 if response
.mimetype
== "text/html":
46 token
= hmac
.new(app
.secret_key
, request
.remote_addr
.encode('ascii'), hashlib
.sha256
).hexdigest() # TODO: will fail behind reverse proxy (remote_addr always localhost)
47 response
.set_data( re
.sub(
48 rb
'''(<[Ff][Oo][Rr][Mm](\s+[a-zA-Z0-9-]+(=(\w*|'[^']*'|"[^"]*"))?)*>)''', # match form tags with any number of attributes and any type of quotes
49 rb
'\1<input type="hidden" name="csrf" value="'+token
.encode('ascii')+rb
'">', # hackily append a hidden input with our csrf protection value
53 def verify_csrf_protection():
54 token
= hmac
.new(app
.secret_key
, request
.remote_addr
.encode('ascii'), hashlib
.sha256
).hexdigest() # TODO: will fail behind reverse proxy (remote_addr always localhost)
55 if request
.method
== "POST" and request
.form
.get('csrf') != token
:
56 return "CSRF validation failed!", 400
57 request
.form
= request
.form
.copy() # make it mutable
58 request
.form
.poplist('csrf') # remove our csrf again