From 5fb0af99e2dd5aa76689c3c81f6f7a0ca10dbd53 Mon Sep 17 00:00:00 2001 From: CaffeineFueled Date: Wed, 2 Sep 2026 17:27:29 +0200 Subject: [PATCH] feat: ADD password protection via URL query #34 --- README.md | 8 ++++++++ app.py | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index bd3aee6..bd1d604 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ The goal is to keep it simple! For feature-rich solutions please check out [hedg **Editor:** - real-time WebSocket collaboration with cursor preservation across remote edits - per-pad password protection (PBKDF2-SHA256), with a built-in password generator in the UI +- `?pw=…` on a pad URL locks it with that password if it is not protected yet, and unlocks it if it is — + so `https://aukpad.com/{pad_id}/?pw=s3cret` is a one-step create-and-lock link - line numbers; Tab inserts 4 spaces - dark / light mode (auto-detects system preference, manual toggle) - copy-to-clipboard and "new pad" buttons, live peer count in the header @@ -30,6 +32,7 @@ The goal is to keep it simple! For feature-rich solutions please check out [hedg **Endpoints:** - custom pad path `{pad_id}` (1–64 chars, `[a-zA-Z0-9_-]`); auto-generated IDs are 8-char `[a-z0-9]` - `POST /` — create a pad from request body (curl-friendly, see *Usage*) +- `GET /{pad_id}/` — editor page (`?pw=…` sets the password on an unprotected pad, unlocks a protected one) - `GET /{pad_id}/raw` — raw text (auth via `?pw=…` for protected pads) - `GET /system/info` — instance configuration page - `GET /health` — JSON health check (200 `ok` / 503 `degraded`) @@ -163,6 +166,11 @@ The following environment variables can be configured: ## Security +A password passed as `?pw=…` is convenient but not confidential: it stays in the address bar, +lands in browser history, and shows up in reverse-proxy access logs. Use the lock button in the +editor instead when that matters. Note also that pads have no owner — anyone who can open an +unprotected pad can set or change its password. + For security concerns or reports, please contact via `hello a t uphillsecurity d o t com` [gpg](https://uphillsecurity.com/gpg). --- diff --git a/app.py b/app.py index 5f28c2b..83bbc77 100644 --- a/app.py +++ b/app.py @@ -448,6 +448,13 @@ function connect(){ isAuthed = true; hideOverlay(); ver = msg.ver; ta.value = msg.text; updateGutter(); + // ?pw= on an unprotected pad sets the password instead of unlocking. + // Guard on !isProtected: the server re-sends init after a successful + // auth, and that init lands here too — without the guard every unlock + // would re-hash the same password and re-broadcast protected_changed. + if (urlPw && !isProtected) { + ws.send(JSON.stringify({type: "set_password", password: urlPw})); + } } } else if (msg.type === "auth_ok") { isAuthed = true;