|
1 | 1 | import os
|
2 | 2 | from urllib.parse import parse_qs
|
3 | 3 |
|
| 4 | +from django.contrib.auth.models import AnonymousUser |
4 | 5 | from django.core.exceptions import SuspiciousOperation
|
5 | 6 | from django.http import FileResponse, HttpRequest, HttpResponse, HttpResponseNotFound
|
6 | 7 | from reactpy.config import REACTPY_WEB_MODULES_DIR
|
7 | 8 |
|
8 |
| -from reactpy_django.utils import FileAsyncIterator, render_view |
| 9 | +from reactpy_django.utils import FileAsyncIterator, ensure_async, render_view |
9 | 10 |
|
10 | 11 |
|
11 | 12 | def web_modules_file(request: HttpRequest, file: str) -> FileResponse:
|
@@ -42,3 +43,40 @@ async def view_to_iframe(request: HttpRequest, dotted_path: str) -> HttpResponse
|
42 | 43 | # Ensure page can be rendered as an iframe
|
43 | 44 | response["X-Frame-Options"] = "SAMEORIGIN"
|
44 | 45 | return response
|
| 46 | + |
| 47 | + |
| 48 | +async def switch_user_session(request: HttpRequest, uuid: str) -> HttpResponse: |
| 49 | + """Switches the client's active session. |
| 50 | +
|
| 51 | + Django's authentication design requires HTTP cookies to persist login via cookies. |
| 52 | +
|
| 53 | + This is problematic since ReactPy is rendered via WebSockets, and browsers do not |
| 54 | + allow active WebSocket connections to modify HTTP cookies, which necessitates this |
| 55 | + view to exist.""" |
| 56 | + from reactpy_django.models import AuthSession |
| 57 | + |
| 58 | + # TODO: Maybe just relogin the user instead of switching sessions? |
| 59 | + |
| 60 | + # Find out what session we're switching to |
| 61 | + auth_session = await AuthSession.objects.aget(uuid=uuid) |
| 62 | + |
| 63 | + # Validate the session |
| 64 | + if auth_session.expired: |
| 65 | + msg = "Session expired." |
| 66 | + raise SuspiciousOperation(msg) |
| 67 | + if not request.session.exists(auth_session.session_key): |
| 68 | + msg = "Session does not exist." |
| 69 | + raise SuspiciousOperation(msg) |
| 70 | + |
| 71 | + # Delete the existing session |
| 72 | + flush_method = getattr(request.session, "aflush", request.session.flush) |
| 73 | + await ensure_async(flush_method)() |
| 74 | + request.user = AnonymousUser() |
| 75 | + |
| 76 | + # Switch the client's session |
| 77 | + request.session = type(request.session)(auth_session.session_key) |
| 78 | + load_method = getattr(request.session, "aload", request.session.load) |
| 79 | + await ensure_async(load_method)() |
| 80 | + await auth_session.adelete() |
| 81 | + |
| 82 | + return HttpResponse(status=204) |
0 commit comments