From 71733adc90ceabb813874d17d8aec9704ec9ec4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?= Date: Sat, 7 Mar 2020 13:10:49 +0100 Subject: [PATCH] Fix various edge cases around stale sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a session cookie is set, but prosody doesn’t know about the session anymore, we could get into fun states. This patch fixes them by requiring the session to be tested with a ping request on each HTTP request. --- snikket_web/__init__.py | 2 +- snikket_web/prosodyclient.py | 20 +++++++++++++++++--- snikket_web/user/__init__.py | 4 ++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/snikket_web/__init__.py b/snikket_web/__init__.py index 24567ca..c890f43 100644 --- a/snikket_web/__init__.py +++ b/snikket_web/__init__.py @@ -19,7 +19,7 @@ client.default_login_redirect = "login" @app.route("/login", methods=["GET", "POST"]) async def login(): - if client.has_session: + if client.has_session and (await client.test_session()): return redirect(url_for('user.index')) if request.method == "POST": diff --git a/snikket_web/prosodyclient.py b/snikket_web/prosodyclient.py index 3844a54..2d60f59 100644 --- a/snikket_web/prosodyclient.py +++ b/snikket_web/prosodyclient.py @@ -186,7 +186,7 @@ class ProsodyClient: def decorator(f): @functools.wraps(f) async def wrapped(*args, **kwargs): - if not self.has_session: + if not self.has_session or not (await self.test_session()): nonlocal redirect_to if redirect_to is not False: redirect_to = \ @@ -204,10 +204,12 @@ class ProsodyClient: headers.update({ "Content-Type": "application/xmpp+xml" }) + print(payload) async with session.post(self._rest_endpoint, headers=headers, data=payload) as resp: - print(payload) + if resp.status != 200: + abort(resp.status) reply_payload = await resp.read() print(reply_payload) return ET.fromstring(reply_payload) @@ -224,7 +226,7 @@ class ProsodyClient: session=session, ) avatar_hash = avatar_info["sha1"] - except quart.exceptions.BaseException: + except quart.exceptions.HTTPException: avatar_hash = None return { @@ -235,6 +237,18 @@ class ProsodyClient: "avatar_hash": avatar_hash, } + @autosession + async def test_session(self, session): + req = { + "kind": "iq", + "type": "get", + "ping": True, + "to": self.session_address, + } + + async with session.post(self._rest_endpoint, data=req) as resp: + return resp.status == 200 + @autosession async def get_user_nickname(self, session): iq_resp = await self._xml_iq_call( diff --git a/snikket_web/user/__init__.py b/snikket_web/user/__init__.py index 89ca3ee..88d80aa 100644 --- a/snikket_web/user/__init__.py +++ b/snikket_web/user/__init__.py @@ -55,12 +55,14 @@ class ProfileForm(FlaskForm): @user_bp.route("/") +@client.require_session() async def index(): user_info = await client.get_user_info() return await render_template("user_home.html", user_info=user_info) @user_bp.route('/passwd', methods=["GET", "POST"]) +@client.require_session() async def change_pw(): form = ChangePasswordForm() if form.validate_on_submit(): @@ -82,6 +84,7 @@ async def change_pw(): @user_bp.route("/profile", methods=["GET", "POST"]) +@client.require_session() async def profile(): form = ProfileForm() if request.method != "POST": @@ -106,6 +109,7 @@ async def profile(): @user_bp.route("/logout", methods=["GET", "POST"]) +@client.require_session() async def logout(): form = LogoutForm() if form.validate_on_submit():