ORION PERMIT PORTAL — LOGIN SETUP (for whoever runs the server) =============================================================== What this adds The whole site (dashboard + every /api route) now requires a login. People sign up themselves, but only emails on an approved list are accepted. Files to upload (same place as the rest of the site) server.py (updated — now loads the login) auth.py (new) auth_core.py (new) manage_users.py (new — admin tool) dashboard.html (updated — shows "Signed in as ... Sign out") dashboard_template.html, scraper_v2.py (only if the server regenerates dashboard.html) One-time setup 1. Make a PRIVATE folder for login data OUTSIDE the folder you upload, writable by the user that runs gunicorn, and NOT served by the web server. Example: mkdir -p /var/lib/orion-auth && chown /var/lib/orion-auth && chmod 700 /var/lib/orion-auth (Keeping it outside means re-uploading the site can never overwrite accounts.) 2. Tell the server where it is, wherever gunicorn's environment is set: ORION_AUTH_DIR=/var/lib/orion-auth 3. Copy approved_emails.example.txt to /var/lib/orion-auth/approved_emails.txt and put one email per line. (If this file is missing, NOBODY can sign up.) 4. Restart gunicorn. Check it worked - Open the site in a private window: you should land on a sign-in page. - https:///api/leads should say {"error":"login required"}, not data. Settings (environment variables, all optional) ORION_AUTH_DIR where login data lives (see above) ORION_COOKIE_SECURE default 1 = login cookie only over HTTPS. Use 0 only for plain-http testing. ORION_BEHIND_PROXY default 1 = trust X-Forwarded-* headers from the host's proxy. Use 0 if gunicorn is reachable directly from the internet. Day to day (run on the server; add ORION_AUTH_DIR=... in front if you set one) python3 manage_users.py list who is approved / who has signed up python3 manage_users.py approve a@co.com b@co.com let people sign up (no restart needed; use REAL addresses — the examples in this file are placeholders and are refused) python3 manage_users.py unapprove a@co.com remove access — they're signed out on their next click python3 manage_users.py set-password a@co.com reset a forgotten password python3 manage_users.py delete a@co.com delete an account Sign-ups, sign-ins, failures and lockouts are logged to /auth_events.log Good to know - Passwords are stored hashed. 5 wrong passwords locks that email for 15 minutes. - Sessions last 14 days. Sign-out is in the dashboard sidebar. - There is no email verification: whoever signs up first with an approved address owns that account. Have people sign up promptly; if an account is ever claimed wrongly, delete it and have the right person sign up again. (Adding email verification needs working outgoing email.) - There are no emailed password resets — use set-password above. - The login protects the live site only. A copy of dashboard.html opened from a computer's disk contains all the data and is NOT protected — keep copies private. - Needs Flask (already required). Nothing else new to install.