From 1f03f3ee144e864b112fba0e17647f2c6d07c207 Mon Sep 17 00:00:00 2001 From: Goffi Date: Wed, 31 Aug 2022 17:07:03 +0200 Subject: [PATCH] component AP gateway: work around encoding bug in Mastodon: Mastodon in wrongly unquoting URL path in `(request-target)`, and thus Libervia was doing the same to check signature. However that doesn't work with Pleroma which is using the path value used in the request (percent-encoded), and thus Pleroma signature were rejected. To work around that, signature is first checked without unquoting, and if this fails a new check is done with unquoting. Bug has been reported at https://github.com/mastodon/mastodon/issues/18871 rel 371 --- .../plugin_comp_ap_gateway/http_server.py | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/sat/plugins/plugin_comp_ap_gateway/http_server.py b/sat/plugins/plugin_comp_ap_gateway/http_server.py index e3fe9e90..0919b49b 100644 --- a/sat/plugins/plugin_comp_ap_gateway/http_server.py +++ b/sat/plugins/plugin_comp_ap_gateway/http_server.py @@ -980,7 +980,7 @@ class HTTPAPGServer(web_resource.Resource): for to_sign in signed_headers: if to_sign == "(request-target)": method = request.method.decode().lower() - uri = parse.unquote(request.uri.decode()) + uri = request.uri.decode() headers[to_sign] = f"{method} /{uri.lstrip('/')}" elif to_sign in ("(created)", "(expires)"): if algorithm != HS2019: @@ -1070,11 +1070,24 @@ class HTTPAPGServer(web_resource.Resource): if created > limit_ts: raise exceptions.EncryptionError("Signature has expired") - return await self.apg.checkSignature( - sign_data["signature"], - key_id, - headers - ) + try: + return await self.apg.checkSignature( + sign_data["signature"], + key_id, + headers + ) + except exceptions.EncryptionError: + method, url = headers["(request-target)"].rsplit(' ', 1) + headers["(request-target)"] = f"{method} {parse.unquote(url)}" + log.debug( + "Using workaround for (request-target) encoding bug in signature, " + "see https://github.com/mastodon/mastodon/issues/18871" + ) + return await self.apg.checkSignature( + sign_data["signature"], + key_id, + headers + ) def render(self, request): request.setHeader("server", VERSION)