08f5e342b0
--tls generates a self-signed cert (SANs: localhost, 127.0.0.1, LAN IP) so a headless box is reachable directly over HTTPS, which browsers treat as a secure context (required for cross-origin isolation). make web now defaults to TLS.
74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import ipaddress
|
|
import socket
|
|
import ssl
|
|
import subprocess
|
|
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
|
from pathlib import Path
|
|
|
|
|
|
class IsolatedHandler(SimpleHTTPRequestHandler):
|
|
def end_headers(self):
|
|
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
|
|
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
|
|
self.send_header("Cross-Origin-Resource-Policy", "same-origin")
|
|
super().end_headers()
|
|
|
|
|
|
def local_ip():
|
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
|
try:
|
|
s.connect(("8.8.8.8", 80))
|
|
return s.getsockname()[0]
|
|
except OSError:
|
|
return "127.0.0.1"
|
|
|
|
|
|
def ensure_cert(cert: Path, key: Path):
|
|
"""Generate a self-signed cert covering localhost and the LAN IP, so a
|
|
headless box can be reached directly over HTTPS (secure context)."""
|
|
if cert.exists() and key.exists():
|
|
return
|
|
ip = local_ip()
|
|
san = f"subjectAltName=DNS:localhost,IP:127.0.0.1,IP:{ip}"
|
|
subprocess.run(
|
|
["openssl", "req", "-x509", "-newkey", "rsa:2048", "-sha256",
|
|
"-days", "3650", "-nodes", "-keyout", str(key), "-out", str(cert),
|
|
"-subj", "/CN=localhost", "-addext", san],
|
|
check=True,
|
|
)
|
|
print(f"Generated self-signed cert for localhost and {ip} at {cert}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--port", type=int, default=8000)
|
|
parser.add_argument("--host", default="0.0.0.0")
|
|
parser.add_argument("--tls", action="store_true", help="serve over HTTPS with a self-signed cert")
|
|
parser.add_argument("--cert", default=".serve-cert.pem")
|
|
parser.add_argument("--key", default=".serve-key.pem")
|
|
args = parser.parse_args()
|
|
|
|
server = ThreadingHTTPServer((args.host, args.port), IsolatedHandler)
|
|
scheme = "http"
|
|
if args.tls:
|
|
ensure_cert(Path(args.cert), Path(args.key))
|
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
context.load_cert_chain(args.cert, args.key)
|
|
server.socket = context.wrap_socket(server.socket, server_side=True)
|
|
scheme = "https"
|
|
|
|
print(f"Serving on {scheme}://{args.host}:{args.port}/web/")
|
|
if args.tls:
|
|
print(f"Reach it directly at {scheme}://{local_ip()}:{args.port}/web/ "
|
|
"(accept the self-signed cert warning once).")
|
|
else:
|
|
print("Note: WASM pthreads need a secure context — use localhost, an SSH "
|
|
"tunnel, or --tls; a bare LAN IP over HTTP is not cross-origin isolated.")
|
|
server.serve_forever()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|