# SPDX-License-Identifier: Apache-2.0 """A tiny local site for the examples: a login (with a 2FA step), a CSV download and a checkout form. python examples/fixture_site.py # http://0.0.0.0:8765 python examples/fixture_site.py 9000 # another port The browser runs inside the gateway, so it must reach this site: for a gateway in Docker on the same machine use http://host.docker.internal:8765 (on Linux start the container with --add-host=host.docker.internal:host-gateway). That is the default of WEBPILOT_FIXTURE in the examples. Pages: / links to everything below /login user "demo", password "demo-password" (store them in the vault as site "fixture") /account "Signed in as demo" once logged in (a cookie), else "Please log in" /verify asks for a 6-digit code: something only a person can do (see handoff.py) /files a link that downloads report.csv (Content-Disposition: attachment) /checkout email, name, country and a "Place order" button (see record_and_replay.py) Standard library only; nothing is stored. Not for real use: the password is in this file. """ from __future__ import annotations import html import sys from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from urllib.parse import parse_qs USER, PASSWORD = "demo", "demo-password" CSV = "city,country,population\nLjubljana,Slovenia,295504\nDublin,Ireland,592713\nMaribor,Slovenia,96211\n" PAGE = """
{'Signed in as demo' if signed_in else 'Please log in'}
")) elif path == "/verify": form = ( 'We sent a 6-digit code to your phone.
' ) self._send(200, page("Verify it's you", form)) elif path == "/files": self._send(200, page("Files", '')) elif path == "/files/report.csv": self._send(200, CSV.encode(), "text/csv", Content_Disposition='attachment; filename="report.csv"') elif path == "/checkout": form = ( '' ) self._send(200, page("Checkout", form)) else: self._send(404, page("Not found", "No such page.
")) def do_POST(self) -> None: path, f = self.path.split("?")[0], self._form() if path == "/login": if f.get("username") == USER and f.get("password") == PASSWORD: self._send(303, b"", Location="/account", Set_Cookie="sid=demo; Path=/; HttpOnly; SameSite=Lax") else: self._send( 401, page("Sign in", 'Wrong username or password.
Try again'), ) elif path == "/verify": ok = f.get("code", "").isdigit() and len(f.get("code", "")) == 6 self._send( 200, page( "Verified" if ok else "Verify it's you", "" + ("Verified." if ok else "That code is not valid.") + "
", ), ) elif path == "/checkout": who = html.escape(f"{f.get('name', '')} <{f.get('email', '')}>") self._send( 200, page("Order placed", f"Ordered for {who} to {html.escape(f.get('country', ''))}
") ) else: self._send(404, page("Not found", "")) def log_message(self, fmt: str, *args: object) -> None: sys.stderr.write("fixture: " + (fmt % args) + "\n") if __name__ == "__main__": port = int(sys.argv[1]) if len(sys.argv) > 1 else 8765 print(f"fixture site on http://0.0.0.0:{port} (from a gateway in Docker: http://host.docker.internal:{port})") ThreadingHTTPServer(("0.0.0.0", port), Handler).serve_forever()