Skip to content

Commit 052bf0a

Browse files
Document --single-user-password and harden config persistence
- src/config.js: saveConfig() strips singleUserPassword so the secret is never written to .jss/config (it must come from CLI/env at runtime). Matches the existing pattern of stripping ssl/logger. - src/config.js: printConfig() shows the single-user state when active with the password's source (provided / will-prompt / missing) but never the value itself, so operators can verify configuration without leaking secrets to logs. - docs/configuration.md: documents --single-user-password and JSS_SINGLE_USER_PASSWORD with the priority order (CLI flag → env var → TTY prompt → warn-and-skip), and that the password is consulted only on first start and never persisted.
1 parent 5f1d7ea commit 052bf0a

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

docs/configuration.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ export JSS_ACTIVITYPUB=true
201201
export JSS_AP_USERNAME=alice
202202
export JSS_PUBLIC=true
203203
export JSS_READ_ONLY=true
204+
export JSS_SINGLE_USER=true
205+
export JSS_SINGLE_USER_NAME=me
206+
export JSS_SINGLE_USER_PASSWORD=choose-a-good-one # seeds IDP account on first start
204207
export JSS_LIVE_RELOAD=true
205208
export JSS_SOLIDOS_UI=true
206209
export JSS_PAY=true
@@ -256,8 +259,13 @@ For personal pod servers where only one user needs access:
256259

257260
```bash
258261
# Basic single-user mode (creates pod at /me/)
262+
# On first run JSS will prompt for an initial password (TTY only).
259263
jss start --single-user --idp
260264

265+
# Provide the initial IDP password non-interactively (systemd, containers, CI):
266+
jss start --single-user --idp --single-user-password 'choose-a-good-one'
267+
JSS_SINGLE_USER_PASSWORD='choose-a-good-one' jss start --single-user --idp
268+
261269
# Custom username
262270
jss start --single-user --single-user-name alice --idp
263271

@@ -270,10 +278,19 @@ JSS_SINGLE_USER=true jss start --idp
270278

271279
**Features:**
272280
- Pod auto-created on first startup with full structure (inbox, public, private, profile)
281+
- IDP account auto-seeded so the operator can log in immediately
273282
- Registration endpoint disabled (returns 403)
274-
- Login still works for the single user
283+
- Login works for the single user via password (`POST /idp/credentials`) or any other configured method
275284
- Proper ACLs generated automatically
276285

286+
**Initial password sources, in priority order:**
287+
1. `--single-user-password <pw>` CLI flag
288+
2. `JSS_SINGLE_USER_PASSWORD` env var
289+
3. Interactive no-echo prompt (TTY only)
290+
4. None — server starts and warns; the pod is created but isn't loggable until a password is set later via `jss passwd <user>`
291+
292+
The password is only consulted on the first start — once an account exists, subsequent restarts skip the seed step and never overwrite it. The password is never written to the saved config file (`.jss/config`).
293+
277294

278295
## Invite-Only Registration
279296

src/config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ export async function saveConfig(config, configFile) {
355355
// Remove derived/runtime values
356356
delete toSave.ssl;
357357
delete toSave.logger;
358+
// Never persist secrets to a static config file. The password is
359+
// expected to come from --single-user-password or
360+
// JSS_SINGLE_USER_PASSWORD at runtime, not be written into .jss/config.
361+
delete toSave.singleUserPassword;
358362

359363
await fs.ensureDir(path.dirname(configFile));
360364
await fs.writeFile(configFile, JSON.stringify(toSave, null, 2));
@@ -371,6 +375,12 @@ export function printConfig(config) {
371375
console.log(` Root: ${path.resolve(config.root)}`);
372376
console.log(` SSL: ${config.ssl ? 'enabled' : 'disabled'}`);
373377
console.log(` Multi-user: ${config.multiuser}`);
378+
if (config.singleUser) {
379+
const pwSource = config.singleUserPassword
380+
? 'provided'
381+
: (process.stdin.isTTY ? 'will prompt at startup' : 'missing — login disabled');
382+
console.log(` Single-user: ${config.singleUserName} (password: ${pwSource})`);
383+
}
374384
console.log(` Conneg: ${config.conneg}`);
375385
console.log(` Notifications: ${config.notifications}`);
376386
console.log(` IdP: ${config.idp ? (config.idpIssuer || 'enabled') : 'disabled'}`);

0 commit comments

Comments
 (0)