From 95cf7dd36f219c152a8db47d5c1ab50fd9a6d942 Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Sun, 4 Oct 2026 09:29:55 -0400 Subject: [PATCH] Lower account password minimum to eight characters --- docs/authentication.md | 2 +- scripts/reset-admin.mjs | 2 +- src/lib/server/auth/passwords.js | 4 ++-- src/routes/account/+page.svelte | 6 +++--- src/routes/settings/users/+page.svelte | 6 +++--- src/routes/setup/+page.svelte | 6 +++--- tests/unit/auth-users.test.ts | 9 +++++---- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/authentication.md b/docs/authentication.md index b0c17ab..8f73d6b 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -48,7 +48,7 @@ Accounts are disabled rather than deleted so history retains their identity. ## Passwords, sessions and recovery -Passwords are 15–128 characters and stored using salted scrypt hashes. Temporary +Passwords are 8–128 characters and stored using salted scrypt hashes. Temporary passwords created or reset by administrators must be changed before any fleet access. Password changes require the current password. diff --git a/scripts/reset-admin.mjs b/scripts/reset-admin.mjs index db0340c..e346656 100644 --- a/scripts/reset-admin.mjs +++ b/scripts/reset-admin.mjs @@ -35,7 +35,7 @@ try { database.pragma('busy_timeout=5000'); const user = database.prepare("SELECT id FROM auth_users WHERE username=? AND role='admin' AND disabled=0").get(username); if (!user) throw new Error('An enabled administrator with that username was not found.'); - const password = await secret('New administrator password (15–128 characters): '); + const password = await secret('New administrator password (8–128 characters): '); const confirmation = await secret('Repeat password: '); if (password !== confirmation) throw new Error('Passwords did not match.'); const passwordHash = await hashPassword(password); diff --git a/src/lib/server/auth/passwords.js b/src/lib/server/auth/passwords.js index 16bffae..26152d9 100644 --- a/src/lib/server/auth/passwords.js +++ b/src/lib/server/auth/passwords.js @@ -7,8 +7,8 @@ let active = 0; /** @param {unknown} password */ export function validatePassword(password) { - if (typeof password !== 'string' || [...password].length < 15 || [...password].length > 128) { - throw new Error('Use a password or passphrase between 15 and 128 characters.'); + if (typeof password !== 'string' || [...password].length < 8 || [...password].length > 128) { + throw new Error('Use a password or passphrase between 8 and 128 characters.'); } return password; } diff --git a/src/routes/account/+page.svelte b/src/routes/account/+page.svelte index 6e774ff..5c91508 100644 --- a/src/routes/account/+page.svelte +++ b/src/routes/account/+page.svelte @@ -40,9 +40,9 @@
- -

Use 15–128 characters and a password you do not use elsewhere.

- + +

Use 8–128 characters and a password you do not use elsewhere.

+
diff --git a/src/routes/settings/users/+page.svelte b/src/routes/settings/users/+page.svelte index bb1afcb..8b49321 100644 --- a/src/routes/settings/users/+page.svelte +++ b/src/routes/settings/users/+page.svelte @@ -123,8 +123,8 @@

3–64 characters: letters, numbers, periods, underscores, and hyphens. Start with a letter or number.

{roleDescription}

- -

15–128 characters. Save it before adding the user; it will not be displayed again.

+ +

8–128 characters. Save it before adding the user; it will not be displayed again.

@@ -137,7 +137,7 @@

{roleDescription}

Disabled users cannot sign in. Running game servers continue operating.

{#if editing?.id === $page.data.user?.id}

Use My account to change your own password. Changes to your access can sign you out.

- {:else}

Leave blank to keep the current password. A reset requires the user to choose a new password at their next sign-in.

{/if} + {:else}

Leave blank to keep the current password. A reset requires the user to choose a new password at their next sign-in.

{/if}
diff --git a/src/routes/setup/+page.svelte b/src/routes/setup/+page.svelte index 297ac6f..a2accd4 100644 --- a/src/routes/setup/+page.svelte +++ b/src/routes/setup/+page.svelte @@ -27,9 +27,9 @@

3–64 characters. Start with a letter or number; periods, underscores, and hyphens are allowed.

- -

Use 15–128 characters. A long, unique passphrase works well.

- + +

Use 8–128 characters. A long, unique passphrase works well.

+ Already have an account? Sign in diff --git a/tests/unit/auth-users.test.ts b/tests/unit/auth-users.test.ts index e140464..21e90ae 100644 --- a/tests/unit/auth-users.test.ts +++ b/tests/unit/auth-users.test.ts @@ -7,7 +7,7 @@ vi.setConfig({ testTimeout: 20_000, hookTimeout: 20_000 }); import { newFixture, type Fixture } from '../helpers/fixture.js'; import type { UserRole } from '../../src/lib/auth.js'; -const password = 'correct horse battery staple'; +const password = 'testpass'; const replacement = 'another long secret passphrase'; const setupToken = 'ec_setup_test_0123456789abcdef0123456789abcdef'; let passwordHash: string; @@ -106,10 +106,11 @@ describe('password storage and verification', () => { it('bounds password length by Unicode characters and rejects invalid inputs before hashing', async () => { const { validatePassword, hashPassword, verifyPassword } = await import('../../src/lib/server/auth/passwords.js'); - for (const value of [undefined, null, 123, '', 'short password', 'a'.repeat(129)]) { - await expect(hashPassword(value)).rejects.toThrow('15 and 128'); + for (const value of [undefined, null, 123, '', 'a'.repeat(7), '🦊'.repeat(7), 'a'.repeat(129)]) { + await expect(hashPassword(value)).rejects.toThrow('8 and 128'); } - expect(validatePassword('🦊'.repeat(15))).toBe('🦊'.repeat(15)); + expect(validatePassword('a'.repeat(8))).toBe('a'.repeat(8)); + expect(validatePassword('🦊'.repeat(8))).toBe('🦊'.repeat(8)); expect(validatePassword('a'.repeat(128))).toHaveLength(128); expect(await verifyPassword('a'.repeat(129), passwordHash)).toBe(false); });