diff --git a/frontends/etiquette_flask/backend/common.py b/frontends/etiquette_flask/backend/common.py index 8399e7d..f53d1c8 100644 --- a/frontends/etiquette_flask/backend/common.py +++ b/frontends/etiquette_flask/backend/common.py @@ -78,11 +78,14 @@ def before_request(): # In NGINX: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; request.is_localhost = (request.remote_addr == '127.0.0.1') if site.localhost_only and not request.is_localhost: - flask.abort(403) + return flask.abort(403) + + session_manager._before_request(request) @site.after_request def after_request(response): response = flasktools.gzip_response(request, response) + response = session_manager._after_request(response) return response site.route = flasktools.decorate_and_route( @@ -95,7 +98,6 @@ site.route = flasktools.decorate_and_route( default_theme='slate', ), catch_etiquette_exception, - session_manager.give_token ], ) @@ -173,13 +175,11 @@ def back_url(): return request.args.get('goto') or request.referrer or '/' def render_template(request, template_name, **kwargs): - session = session_manager.get(request) theme = request.cookies.get('etiquette_theme', None) response = flask.render_template( template_name, request=request, - session=session, theme=theme, **kwargs, ) diff --git a/frontends/etiquette_flask/backend/endpoints/user_endpoints.py b/frontends/etiquette_flask/backend/endpoints/user_endpoints.py index fb3af3b..7c5848c 100644 --- a/frontends/etiquette_flask/backend/endpoints/user_endpoints.py +++ b/frontends/etiquette_flask/backend/endpoints/user_endpoints.py @@ -37,12 +37,10 @@ def get_user_id_redirect(user_id): @site.route('/user//edit', methods=['POST']) def post_user_edit(username): - session = session_manager.get(request) - - if not session: + if not request.session: return flasktools.json_response(etiquette.exceptions.Unauthorized().jsonify(), status=403) user = common.P_user(username, response_type='json') - if session.user != user: + if request.session.user != user: return flasktools.json_response(etiquette.exceptions.Unauthorized().jsonify(), status=403) display_name = request.form.get('display_name') @@ -68,8 +66,7 @@ def get_login(): @site.route('/login', methods=['POST']) @flasktools.required_fields(['username', 'password']) def post_login(): - session = session_manager.get(request) - if session.user: + if request.session.user: exc = etiquette.exceptions.AlreadySignedIn() response = exc.jsonify() return flasktools.json_response(response, status=403) @@ -93,8 +90,8 @@ def post_login(): response = exc.jsonify() return flasktools.json_response(response, status=400) - session = sessions.Session(request, user) - session_manager.add(session) + request.session = sessions.Session(request, user) + session_manager.add(request.session) return flasktools.json_response({}) @site.route('/logout', methods=['POST']) @@ -112,8 +109,7 @@ def get_register(): @site.route('/register', methods=['POST']) @flasktools.required_fields(['username', 'password_1', 'password_2']) def post_register(): - session = session_manager.get(request) - if session.user: + if request.session.user: exc = etiquette.exceptions.AlreadySignedIn() response = exc.jsonify() return flasktools.json_response(response, status=403) @@ -133,6 +129,6 @@ def post_register(): with common.P.transaction: user = common.P.new_user(username, password_1, display_name=display_name) - session = sessions.Session(request, user) - session_manager.add(session) + request.session = sessions.Session(request, user) + session_manager.add(request.session) return flasktools.json_response({}) diff --git a/frontends/etiquette_flask/backend/sessions.py b/frontends/etiquette_flask/backend/sessions.py index e5b6f0c..a21730e 100644 --- a/frontends/etiquette_flask/backend/sessions.py +++ b/frontends/etiquette_flask/backend/sessions.py @@ -34,6 +34,45 @@ class SessionManager: def __init__(self, maxlen=None): self.sessions = cacheclass.Cache(maxlen=maxlen) + def _before_request(self, request): + # Inject new token so the function doesn't know the difference + token = request.cookies.get('etiquette_session', None) + if not token or token not in self.sessions: + token = _generate_token() + # cookies is currently an ImmutableMultiDict, but in order to + # trick the wrapped function I'm gonna have to mutate it. + # It is important to use a werkzeug MultiDict and not a plain + # Python dict, because werkzeug puts cookies into lists like + # {name: [value]} and then cookies.get pulls the first item out + # of that list. A plain dict wouldn't have this .get behavior. + request.cookies = werkzeug.datastructures.MultiDict(request.cookies) + request.cookies['etiquette_session'] = token + + try: + session = self.get(request) + except KeyError: + session = Session(request, user=None) + self.add(session) + else: + session.maintain() + + request.session = session + return session + + def _after_request(self, response): + # Send the token back to the client + # but only if the endpoint didn't manually set the cookie. + function_cookies = response.headers.get_all('Set-Cookie') + if not any('etiquette_session=' in cookie for cookie in function_cookies): + response.set_cookie( + 'etiquette_session', + value=request.session.token, + max_age=SESSION_MAX_AGE, + httponly=True, + ) + + return response + def add(self, session): self.sessions[session.token] = session @@ -61,41 +100,10 @@ class SessionManager: ''' @functools.wraps(function) def wrapped(*args, **kwargs): - # Inject new token so the function doesn't know the difference - token = request.cookies.get('etiquette_session', None) - if not token or token not in self.sessions: - token = _generate_token() - # cookies is currently an ImmutableMultiDict, but in order to - # trick the wrapped function I'm gonna have to mutate it. - # It is important to use a werkzeug MultiDict and not a plain - # Python dict, because werkzeug puts cookies into lists like - # {name: [value]} and then cookies.get pulls the first item out - # of that list. A plain dict wouldn't have this .get behavior. - request.cookies = werkzeug.datastructures.MultiDict(request.cookies) - request.cookies['etiquette_session'] = token - - try: - session = self.get(request) - except KeyError: - session = Session(request, user=None) - self.add(session) - else: - session.maintain() - + self._before_request(request) response = function(*args, **kwargs) + return self._after_request(response) - # Send the token back to the client - # but only if the endpoint didn't manually set the cookie. - function_cookies = response.headers.get_all('Set-Cookie') - if not any('etiquette_session=' in cookie for cookie in function_cookies): - response.set_cookie( - 'etiquette_session', - value=session.token, - max_age=SESSION_MAX_AGE, - httponly=True, - ) - - return response return wrapped def remove(self, token): diff --git a/frontends/etiquette_flask/templates/admin.html b/frontends/etiquette_flask/templates/admin.html index 1a2ee55..ac2e06b 100644 --- a/frontends/etiquette_flask/templates/admin.html +++ b/frontends/etiquette_flask/templates/admin.html @@ -28,7 +28,7 @@ th, td -{{header.make_header(session=session)}} +{{header.make_header(session=request.session)}}

Admin tools

diff --git a/frontends/etiquette_flask/templates/album.html b/frontends/etiquette_flask/templates/album.html index 7ec3cba..8cabc7a 100644 --- a/frontends/etiquette_flask/templates/album.html +++ b/frontends/etiquette_flask/templates/album.html @@ -99,7 +99,7 @@ -{{header.make_header(session=session)}} +{{header.make_header(session=request.session)}}
@@ -162,7 +162,7 @@ const ALBUM_ID = undefined; -{{header.make_header(session=session)}} +{{header.make_header(session=request.session)}}