Skip to content

Commit 9db7bdf

Browse files
Kevin Wallacetsileo
Kevin Wallace
authored andcommitted
remote follow: use HTML redirect to work around CSP issue
In Chrome, I get the following when trying to use the remote follow form: Refused to send form data to 'https://example.com/remote_follow' because it violates the following Content Security Policy directive: "form-action 'self'". It seems some browsers (but notably not Firefox) apply the form-action policy to the redirect target in addition to the initial form submission endpoint. See: w3c/webappsec-csp#8 In that thread, this workaround is suggested.
1 parent 793a939 commit 9db7bdf

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

app/main.py

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import base64
2+
import html
23
import os
34
import sys
45
import time
@@ -38,6 +39,7 @@
3839
from starlette.datastructures import Headers
3940
from starlette.datastructures import MutableHeaders
4041
from starlette.exceptions import HTTPException as StarletteHTTPException
42+
from starlette.responses import HTMLResponse
4143
from starlette.responses import JSONResponse
4244
from starlette.types import Message
4345
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware # type: ignore
@@ -254,6 +256,25 @@ class ActivityPubResponse(JSONResponse):
254256
media_type = "application/activity+json"
255257

256258

259+
class HTMLRedirectResponse(HTMLResponse):
260+
"""
261+
Similar to RedirectResponse, but uses a 200 response with HTML.
262+
263+
Needed for remote redirects on form submission endpoints,
264+
since our CSP policy disallows remote form submission.
265+
https://github.com/w3c/webappsec-csp/issues/8#issuecomment-810108984
266+
"""
267+
268+
def __init__(
269+
self,
270+
url: str,
271+
) -> None:
272+
super().__init__(
273+
content=f'<a href="{html.escape(url)}">Continue to remote resource</a>',
274+
headers={"Refresh": "0;url=" + url},
275+
)
276+
277+
257278
@app.get(config.NavBarItems.NOTES_PATH)
258279
async def index(
259280
request: Request,
@@ -961,7 +982,7 @@ async def post_remote_follow(
961982
request: Request,
962983
csrf_check: None = Depends(verify_csrf_token),
963984
profile: str = Form(),
964-
) -> RedirectResponse:
985+
) -> HTMLRedirectResponse:
965986
if not profile.startswith("@"):
966987
profile = f"@{profile}"
967988

@@ -970,9 +991,8 @@ async def post_remote_follow(
970991
# TODO(ts): error message to user
971992
raise HTTPException(status_code=404)
972993

973-
return RedirectResponse(
994+
return HTMLRedirectResponse(
974995
remote_follow_template.format(uri=ID),
975-
status_code=302,
976996
)
977997

978998

0 commit comments

Comments
 (0)