diff --git a/auth-gate.py b/auth-gate.py new file mode 100644 index 0000000..7a8f22b --- /dev/null +++ b/auth-gate.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""Tiny auth gate for nginx auth_request. Sets a cookie after successful basic auth.""" +import hashlib, hmac, http.server, time, base64, os + +SECRET = "sovereign-timmy-gate-2026" +USER = "Rockachopa" +PASS = "Iamrockachopathegend" +COOKIE_NAME = "sovereign_gate" +COOKIE_MAX_AGE = 86400 * 7 # 7 days + +def make_token(ts): + msg = f"{USER}:{ts}".encode() + return hmac.new(SECRET.encode(), msg, hashlib.sha256).hexdigest()[:32] + +def verify_token(token): + try: + # Token format: timestamp.signature + parts = token.split(".") + if len(parts) != 2: + return False + ts, sig = int(parts[0]), parts[1] + if time.time() - ts > COOKIE_MAX_AGE: + return False + return sig == make_token(ts) + except: + return False + +class Handler(http.server.BaseHTTPRequestHandler): + def log_message(self, *a): pass + + def do_GET(self): + # Check cookie first + cookies = self.headers.get("Cookie", "") + for c in cookies.split(";"): + c = c.strip() + if c.startswith(f"{COOKIE_NAME}="): + token = c[len(COOKIE_NAME)+1:] + if verify_token(token): + self.send_response(200) + self.end_headers() + return + + # Check basic auth header (forwarded by nginx) + auth = self.headers.get("Authorization", "") + if auth.startswith("Basic "): + try: + decoded = base64.b64decode(auth[6:]).decode() + u, p = decoded.split(":", 1) + if u == USER and p == PASS: + ts = int(time.time()) + token = f"{ts}.{make_token(ts)}" + self.send_response(200) + self.send_header("Set-Cookie", + f"{COOKIE_NAME}={token}; Path=/; Max-Age={COOKIE_MAX_AGE}; HttpOnly; SameSite=Lax") + self.end_headers() + return + except: + pass + + # Deny + self.send_response(401) + self.send_header("WWW-Authenticate", 'Basic realm="Sovereign Stack"') + self.end_headers() + +if __name__ == "__main__": + s = http.server.HTTPServer(("127.0.0.1", 9876), Handler) + print("Auth gate listening on 127.0.0.1:9876") + s.serve_forever() diff --git a/nginx-paperclip.conf b/nginx-paperclip.conf new file mode 100644 index 0000000..94ceaaf --- /dev/null +++ b/nginx-paperclip.conf @@ -0,0 +1,42 @@ +server { + listen 80; + server_name alexanderwhitestone.com 45.55.221.244; + + # Cookie-based auth gate — login once, cookie lasts 7 days + location = /_auth { + internal; + proxy_pass http://127.0.0.1:9876; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header Cookie $http_cookie; + proxy_set_header Authorization $http_authorization; + } + + location / { + auth_request /_auth; + # Forward the Set-Cookie from auth gate to the client + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + proxy_pass http://127.0.0.1:3100; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host localhost; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_cache_bypass $http_upgrade; + proxy_read_timeout 86400; + } + + # Return 401 with WWW-Authenticate when auth fails + error_page 401 = @login; + location @login { + proxy_pass http://127.0.0.1:9876; + proxy_set_header Authorization $http_authorization; + proxy_set_header Cookie $http_cookie; + } +}