]>
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, and POST data. this makes debugging of api responses easier, as the request can be reconstructed and replayed.
21 from flask
import g
, request
22 from werkzeug
. exceptions
import InternalServerError
23 @app . errorhandler ( InternalServerError
)
25 if request
. method
== "POST" :
26 app
. logger
. error ( request
. data
)
27 if 'api_requests' in g
:
28 app
. logger
. error ( g
. api_requests
)
31 # TODO: build a proper flask extension
32 # Magic CSRF protection: This modifies outgoing HTML responses and injects a csrf token into all forms.
33 # All post requests are then checked if they contain the valid token.
35 # - don't use regex for injecting
36 # - inject a http header into all responses (that could be used by apis)
37 # - allow csrf token to be passed in http header, json, ...
38 # - a decorator on routes to opt out of verification or output munging
39 # https://stackoverflow.com/questions/19574694/flask-hit-decorator-before-before-request-signal-fires
40 # - allow specifying hmac message contents (currently request.remote_addr)
44 from flask
import request
46 def add_csrf_protection ( response
):
47 if response
. mimetype
== "text/html" :
48 token
= hmac
. new ( app
. secret_key
, request
. remote_addr
. encode ( 'ascii' ), hashlib
. sha256
). hexdigest () # TODO: will fail behind reverse proxy (remote_addr always localhost)
49 response
. set_data ( re
. sub (
50 rb
'''(<[Ff][Oo][Rr][Mm](\s+[a-zA-Z0-9-]+(=(\w*|'[^']*'|"[^"]*"))?)*>)''' , # match form tags with any number of attributes and any type of quotes
51 rb
'\1<input type="hidden" name="csrf" value="' + token
. encode ( 'ascii' )+ rb
'">' , # hackily append a hidden input with our csrf protection value
55 def verify_csrf_protection ():
56 token
= hmac
. new ( app
. secret_key
, request
. remote_addr
. encode ( 'ascii' ), hashlib
. sha256
). hexdigest () # TODO: will fail behind reverse proxy (remote_addr always localhost)
57 if request
. method
== "POST" and request
. form
. get ( 'csrf' ) != token
:
58 return "CSRF validation failed!" , 400
59 request
. form
= request
. form
. copy () # make it mutable
60 request
. form
. poplist ( 'csrf' ) # remove our csrf again