|
| 1 | +from contextlib import suppress |
| 2 | +from typing import Literal |
| 3 | + |
| 4 | +from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest |
| 5 | +from django.views.decorators.csrf import csrf_exempt |
| 6 | +from django.views.decorators.http import require_http_methods |
| 7 | + |
| 8 | +_BOOL_TRUE_VALUES = frozenset({"true", "1", "yes", "on"}) |
| 9 | +_SAME_SITE_VALUES = frozenset({"lax", "strict", "none"}) |
| 10 | +_RESPONSE_BODY = """\ |
| 11 | +<!doctype html> |
| 12 | +<html> |
| 13 | +<head> |
| 14 | + <meta charset=utf-8> |
| 15 | + <title>Synced</title> |
| 16 | +</head> |
| 17 | +<body> |
| 18 | + <h2>.pycon.kr scope cookie sync complete</h2> |
| 19 | + <p>You can close this tab and proceed with the social login.</p> |
| 20 | +</body> |
| 21 | +</html>""" |
| 22 | + |
| 23 | + |
| 24 | +def _parse_int(s: str | None) -> int | None: |
| 25 | + with suppress(ValueError): |
| 26 | + return int(s.strip()) |
| 27 | + return None |
| 28 | + |
| 29 | + |
| 30 | +def _parse_bool(s: str | None) -> bool: |
| 31 | + return s.strip().lower() in _BOOL_TRUE_VALUES if s else None |
| 32 | + |
| 33 | + |
| 34 | +def _parse_samesite(s: str | None) -> Literal["Lax", "Strict", "None"] | None: |
| 35 | + if not s: |
| 36 | + return None |
| 37 | + |
| 38 | + s = s.strip().lower() |
| 39 | + return s.capitalize() if s in _SAME_SITE_VALUES else None |
| 40 | + |
| 41 | + |
| 42 | +@csrf_exempt |
| 43 | +@require_http_methods(["POST"]) |
| 44 | +def dev_set_cookie(request: HttpRequest) -> HttpResponse: |
| 45 | + if not (name := request.POST.get("name", "").strip()): |
| 46 | + return HttpResponseBadRequest("name required") |
| 47 | + if not (value := request.POST.get("value", "").strip()): |
| 48 | + return HttpResponseBadRequest("value required") |
| 49 | + |
| 50 | + response = HttpResponse(_RESPONSE_BODY, content_type="text/html; charset=utf-8") |
| 51 | + response.set_cookie( |
| 52 | + name, |
| 53 | + value, |
| 54 | + max_age=_parse_int(request.POST.get("max_age")), |
| 55 | + domain=request.POST.get("domain", "").strip() or None, |
| 56 | + secure=_parse_bool(request.POST.get("secure")), |
| 57 | + httponly=_parse_bool(request.POST.get("httponly")), |
| 58 | + samesite=_parse_samesite(request.POST.get("samesite")), |
| 59 | + ) |
| 60 | + return response |
0 commit comments