Commit 5acc530
authored
Phase 2: enable IDP, seed me/me, localhost-only by default (#7)
* feat: enable IDP, seed me/me, localhost-only by default (#1 phase 2)
The welcome page is HEAD-adaptive: it reveals "Sign in" or "Sign up"
based on what the IDP advertises. With the IDP off (jspod's previous
default), neither button rendered and the only visible CTA was a
docs link going off-site. Turning the IDP on with single-user
seeding flips that page from "read the docs" to "sign in here."
- Flip default `--host` to 127.0.0.1 (was 0.0.0.0). Personal pods
almost always want localhost; making this the default also lets
us safely seed deliberately-weak rung-1 credentials.
- Replace `--no-multiuser`-only single-user behaviour with full
single-user mode: `--no-multiuser --single-user --idp
--single-user-password me`. JSS hardcodes the username on root
pods to 'me' (server.js:970), so credentials end up `me` / `me`
— symmetric, memorable, clearly a placeholder.
- Banner adds a "Sign In (rung 1 of the auth ladder)" section
showing username, password, and the climb hint. References the
ladder framing from issue #6.
- Loud red warning if user passes `--host 0.0.0.0` (or any
non-loopback host) telling them the well-known credentials are
now reachable beyond localhost.
- README: First Run Guide rewritten around the ladder. Rungs 0-4
table, climb instructions, and JSS_SINGLE_USER_PASSWORD escape
hatch for users who want a custom rung-1 password.
- Multi-user mode (`--multiuser`) still works: passes `--idp` so
the IDP is available for registration, but no `--single-user-*`
flags so registration stays open.
- Help text: --host default updated to 127.0.0.1.
- Bump jspod to 0.0.10.
This addresses issue #1 phase 2, executed through the lens of
issue #3 (single-user positioning) and issue #6 (auth ladder).
Refs #1 #3 #6
* fix: address Copilot review on PR #7
Four legitimate catches from the review:
1. `--no-auth` was a no-op against JSS. Now forwards JSS's `--public`
flag so the pod actually skips WAC and accepts unauthenticated
reads/writes (verified: JSS prints "PUBLIC MODE ENABLED").
2. `JSS_SINGLE_USER_PASSWORD` env override was documented in the
README but not honoured — the CLI always passed `--single-user-
password me`, drowning out the env. Now the env value is read in
jspod, passed to JSS via the CLI flag, AND surfaced in the
banner ("Sign In (password from JSS_SINGLE_USER_PASSWORD)") so
the displayed credentials match reality.
3. Loopback detection was too strict — only 127.0.0.1 / localhost /
::1 were treated as safe. Expanded to the full 127.0.0.0/8 IPv4
range (covers Ubuntu's default 127.0.1.1 in /etc/hosts) and the
bracketed `[::1]` form a user might paste in by accident.
4. README First Run Guide had duplicated Step 3 / Step 4 left over
from the previous version. Renumbered and removed the obsolete
"Register with a passkey" step (registration is disabled in
single-user mode anyway).
Refs #1 #3 #6
* fix: address Copilot review 2 on PR #7
Four follow-ups from the second pass:
1. Banner no longer prints the env-provided password verbatim. When
the credential comes from JSS_SINGLE_USER_PASSWORD, the banner
confirms "(hidden — set via JSS_SINGLE_USER_PASSWORD)" instead of
echoing the value to stdout. Default rung-1 'me' still prints
(the user doesn't know it yet, and it has no secrecy property).
Avoids leaking real passwords into terminal scrollback, shell
history capture, CI logs, and shared sessions.
2. `--host [::1]` (bracketed IPv6) now parses cleanly. Brackets are
stripped at CLI parse time, so options.host stays canonical
('::1'), and formatUrl re-adds brackets only where URLs need
them. Previously the bracketed form would round-trip through
formatUrl as http://[[::1]]:PORT (invalid).
3. LAN-exposure warning no longer references a `--single-user-
password` jspod flag that doesn't exist. It now points users to
JSS_SINGLE_USER_PASSWORD=... or binding to 127.0.0.1.
4. README's "Default Configuration" code block previously claimed
TOKEN_SECRET was "(auto)" / "auto-generated". The code actually
uses a static fallback ('jspod-default-secret-change-in-
production'). Documentation now matches reality. A real
per-data-dir secret-generator can land in a follow-up PR.
Refs #1 #3 #6
* fix: address Copilot review 3 on PR #7
Four follow-ups from the third pass:
1. Missing-value validation for flags that take an argument.
`jspod --host` (or --port, --root) used to read undefined off the
args array and crash with a cryptic TypeError on the next
operation. Now exits cleanly with "Missing value for --host" and a
pointer to --help.
2. IPv6 zone identifiers (e.g. fe80::1%lo0) are now rejected at CLI
parse time with a clear error. The previous %25-encoding attempt
was correct per RFC 6874 but Node's WHATWG URL parser doesn't
accept zone IDs regardless — any URL we built (banner, auto-open,
readiness probe) would be unparseable. Failing fast beats shipping
silently broken auto-open.
3. TOKEN_SECRET now auto-generates a 48-byte random secret on first
run and persists it at <root>/.token-secret with mode 0600.
Subsequent restarts read the same secret so sessions and refresh
tokens survive process bounces. Per-data-dir, so different pods on
the same machine get different secrets. The previous static
fallback ('jspod-default-secret-change-in-production') was
remotely exploitable on any non-loopback bind — anyone who knew
the string could forge JWTs. Env TOKEN_SECRET still wins when
set, for operator-managed deployments.
4. README: replaced the literal fallback secret string with accurate
docs about auto-generation, persistence path, file mode, and the
env override use-case (operator-managed deployments / rotation /
secret managers).
Refs #1 #3 #6
* fix: address Copilot review 4 on PR #7
Four follow-ups from the fourth pass:
1. Validate --port: reject non-numeric, out-of-range (<1, >65535),
and trailing-garbage values at parse time. parseInt('abc') was
silently producing NaN, which then propagated to JSS as
`--port NaN` and crashed the server with a confusing error.
2. Validate the persisted JWT secret on read. If <root>/.token-secret
exists but is empty / whitespace-only / too short (<32 chars), warn
and regenerate rather than silently weakening signing. Empty file
could happen via a botched edit, a failed `cp`, or a partial write.
3. Differentiate the LAN-exposure warning based on whether the
password is env-supplied. Previously the warning always claimed
the server was exposing "well-known me/me credentials," even when
the user had supplied a strong password via env — a false statement
and a confusing one. Now: default rung-1 keeps the original
well-known-credentials wording; env-supplied gets a more neutral
"exposes single-user sign-in" warning that suggests strong-password
discipline and HTTPS for production.
4. Stop re-exposing the env-supplied password on the JSS subprocess
argv. `ps`, service-manager logs, and other local users could read
what we'd carefully hidden from the banner. The fix: pass
`--single-user-password` on argv only when it's the literal
rung-1 placeholder ('me' has no secrecy property). For env-
supplied passwords, JSS picks up JSS_SINGLE_USER_PASSWORD from
process.env directly (already inherited from jspod's env spread).
Verified via `ps` — JSS argv now: `--port ... --host ... --root
... --notifications --conneg --no-multiuser --single-user --idp`,
no password.
Refs #1 #3 #6
* fix: address Copilot review 5 on PR #7
Three follow-ups from the fifth pass:
1. requireValue() now rejects values that look like another option.
`jspod --host --no-auth` previously consumed `--no-auth` as the
host string and silently dropped the intended flag, then bound
the server to a literal '--no-auth' hostname. Now exits cleanly
with "Got: --no-auth (looks like another option, not a value)."
`--port -1` is caught here too (slightly less specific than the
range-check error, but still rejected before propagating).
2. .token-secret file mode is now enforced on every write, not just
on creation. writeFileSync's `mode` option is silently ignored
when overwriting an existing file (regeneration path), so a
previously-too-loose secret file could survive a regeneration
with its old permissions. New ensureMode0600() helper stats the
file, warns if the mode differs, and chmod's it to 0600.
3. .token-secret mode is also tightened on every read, not just
on write. A file created (or touched) before jspod 0.0.10 — or
by a different process — could be group/world-readable; jspod
now stats it on each start, warns the operator about the
previous mode, and chmod's it. README claim of "persisted with
mode 0600" now matches reality without doc edits.
ensureMode0600 swallows errors so platforms without unix mode
semantics (Windows) or exotic filesystems don't crash startup.
Refs #1 #3 #61 parent daec447 commit 5acc530
3 files changed
Lines changed: 242 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
| 82 | + | |
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| |||
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
95 | | - | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
96 | 97 | | |
97 | 98 | | |
98 | 99 | | |
| |||
105 | 106 | | |
106 | 107 | | |
107 | 108 | | |
108 | | - | |
| 109 | + | |
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
| |||
198 | 199 | | |
199 | 200 | | |
200 | 201 | | |
201 | | - | |
| 202 | + | |
202 | 203 | | |
203 | 204 | | |
204 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
205 | 208 | | |
206 | 209 | | |
207 | 210 | | |
| |||
216 | 219 | | |
217 | 220 | | |
218 | 221 | | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
| 222 | + | |
223 | 223 | | |
224 | | - | |
225 | | - | |
226 | | - | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
227 | 253 | | |
| 254 | + | |
228 | 255 | | |
229 | 256 | | |
230 | 257 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
20 | 25 | | |
21 | 26 | | |
22 | 27 | | |
| |||
31 | 36 | | |
32 | 37 | | |
33 | 38 | | |
34 | | - | |
| 39 | + | |
35 | 40 | | |
36 | 41 | | |
37 | 42 | | |
38 | 43 | | |
39 | 44 | | |
40 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
41 | 79 | | |
42 | 80 | | |
43 | 81 | | |
44 | 82 | | |
45 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
46 | 94 | | |
47 | | - | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
48 | 110 | | |
49 | | - | |
| 111 | + | |
50 | 112 | | |
51 | 113 | | |
52 | 114 | | |
| |||
66 | 128 | | |
67 | 129 | | |
68 | 130 | | |
69 | | - | |
| 131 | + | |
70 | 132 | | |
71 | 133 | | |
72 | 134 | | |
| |||
99 | 161 | | |
100 | 162 | | |
101 | 163 | | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
102 | 219 | | |
103 | 220 | | |
104 | 221 | | |
| |||
125 | 242 | | |
126 | 243 | | |
127 | 244 | | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
128 | 294 | | |
129 | 295 | | |
130 | 296 | | |
| |||
150 | 316 | | |
151 | 317 | | |
152 | 318 | | |
153 | | - | |
154 | | - | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
155 | 347 | | |
156 | 348 | | |
157 | 349 | | |
| |||
160 | 352 | | |
161 | 353 | | |
162 | 354 | | |
163 | | - | |
| 355 | + | |
164 | 356 | | |
165 | 357 | | |
166 | 358 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
0 commit comments