]> git.gir.st - subscriptionfeed.git/blob - app/__init__.py
move reddit to seperate blueprint
[subscriptionfeed.git] / app / __init__.py
1 import base64
2 import secrets
3 from flask import Flask
4
5 from .common.common import *
6
7 app = Flask(__name__)
8 app.secret_key = base64.b64decode(cf['frontend'].get('secret_key','')) or \
9 secrets.token_bytes(16) # development fallback; CSRF/cookies won't persist.
10
11 from .common.user import init_login
12 init_login(app)
13
14 from . import youtube
15 app.register_blueprint(youtube.frontend)
16
17 from . import reddit
18 app.register_blueprint(reddit.frontend)
19
20 # TODO: build a proper flask extension
21 # Magic CSRF protection: This modifies outgoing HTML responses and injects a csrf token into all forms.
22 # All post requests are then checked if they contain the valid token.
23 # TODO:
24 # - don't use regex for injecting
25 # - inject a http header into all responses (that could be used by apis)
26 # - allow csrf token to be passed in http header, json, ...
27 # - a decorator on routes to opt out of verification or output munging
28 # https://stackoverflow.com/questions/19574694/flask-hit-decorator-before-before-request-signal-fires
29 # - allow specifying hmac message contents (currently request.remote_addr)
30 import re
31 import hmac
32 import hashlib
33 from flask import request
34 @app.after_request
35 def add_csrf_protection(response):
36 if response.mimetype == "text/html":
37 token = hmac.new(app.secret_key, request.remote_addr.encode('ascii'), hashlib.sha256).hexdigest() # TODO: will fail behind reverse proxy (remote_addr always localhost)
38 response.set_data( re.sub(
39 rb'''(<[Ff][Oo][Rr][Mm](\s+[a-zA-Z0-9-]+(=(\w*|'[^']*'|"[^"]*"))?)*>)''', # match form tags with any number of attributes and any type of quotes
40 rb'\1<input type="hidden" name="csrf" value="'+token.encode('ascii')+rb'">', # hackily append a hidden input with our csrf protection value
41 response.get_data()))
42 return response
43 @app.before_request
44 def verify_csrf_protection():
45 token = hmac.new(app.secret_key, request.remote_addr.encode('ascii'), hashlib.sha256).hexdigest() # TODO: will fail behind reverse proxy (remote_addr always localhost)
46 if request.method == "POST" and request.form.get('csrf') != token:
47 return "CSRF validation failed!", 400
48 request.form = request.form.copy() # make it mutable
49 request.form.poplist('csrf') # remove our csrf again
Imprint / Impressum