#!/usr/bin/env python import base64 import io import cgi import collections from collections.abc import Mapping import hmac import mimetypes import os import secrets from typing import Any, Optional, overload import itsdangerous import requests def fail(status: str, reason: str) -> None: print(f"Status: {status}") print("Content-Type: text/html") print(f"X-Reason: {reason}") print(f"X-Sendfile: {SITE_DIRECTORY}/kontakt/fehler/index.html") print("") exit(0) HONEYPOT_FIELD_NAME = "addressline1" SITE_DIRECTORY = os.environ.get("SITE_DIRECTORY", "") request_uri = os.environ.get("REQUEST_URI", "").lower().rstrip("/") serializer = itsdangerous.URLSafeSerializer("secret key", "salt") session = requests.Session() cookies = dict[str, str]() for entry in os.environ.get("HTTP_COOKIE", "").split(";"): name, *value = entry.lstrip(" ").split("=", 1) cookies[name] = value[0] if len(value) == 1 else "" # Get the CSRF token. This is pass along according to the double-submit # technique[1]. First as a hidden form input. Second as a cookie, which is # signed on the server, so we can verify its authenticity. The latter is also # used for subsequent requests so every session only gets one token. # 1: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie if "__Host-csrftoken" in cookies: # We already have a token for this client - try and extract it. signed_csrf_token = cookies["__Host-csrftoken"] try: csrf_token = serializer.loads(signed_csrf_token) except: # The token wasn't valid, so we need to generate a new one. csrf_token = secrets.token_urlsafe(32) else: csrf_token = secrets.token_urlsafe(32) # Re-sign the token, so it's fresh and the timeout doesn't waive. signed_csrf_token = serializer.dumps(csrf_token) match os.environ.get("REQUEST_METHOD", "").upper(): case "GET": # For GET requests, serve the form that the user requested. The CSRF # token will be added here as well. print("Status: 200") print("Content-Type: text/html") print(f"Set-Cookie: __Host-csrftoken={signed_csrf_token}; path=/; Secure; SameSite=Strict; HttpOnly") print("") with open(f"{SITE_DIRECTORY}/{request_uri.strip('/')}/index.html", "r") as template: for line in template.readlines(): # This is a very rudimentary check to ensure that we actually # place the token *inside* the form. It assumes that there is # a) only one form on the site and # b) the