Fix passkey length and add reset action

Introduce a single PASSKEY_LENGTH constant (6) and enforce it across passkey config/load/save/update, removing the previous user-adjustable length/clamping. Add resetSequence() to clear stored hash/salt, reset length/attempts/lockout and persist the cleared state. Update settings UI: relabel "Change Passkey" to "Reset Passkey", show "6 digits" and "Fixed for testing", remove length adjustment controls/handlers, and call state.passkey.resetSequence() when resetting so setup will run on next lock.
This commit is contained in:
2026-02-16 11:50:07 +13:00
parent 3a2c3f9ff1
commit c890636f03
2 changed files with 20 additions and 22 deletions
+15 -4
View File
@@ -1,11 +1,12 @@
const PASSKEY_STORAGE_KEY = "nebula.passkey.v1";
const PASSKEY_VERSION = 1;
const PASSKEY_LENGTH = 6;
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
const FALLBACK_CONFIG = {
enabled: true,
length: 6,
length: PASSKEY_LENGTH,
requireConfirm: false,
keyboardSupport: true,
maxAttempts: 5,
@@ -49,7 +50,7 @@ export const loadPasskeyConfig = () => {
return {
...FALLBACK_CONFIG,
...parsed,
length: clamp(Number(parsed.length ?? FALLBACK_CONFIG.length), 4, 8),
length: PASSKEY_LENGTH,
maxAttempts: clamp(Number(parsed.maxAttempts ?? FALLBACK_CONFIG.maxAttempts), 1, 10),
cooldownSeconds: clamp(Number(parsed.cooldownSeconds ?? FALLBACK_CONFIG.cooldownSeconds), 5, 120),
requireConfirm: Boolean(parsed.requireConfirm ?? FALLBACK_CONFIG.requireConfirm),
@@ -76,7 +77,7 @@ export const savePasskeyConfig = (config) => {
...FALLBACK_CONFIG,
...config,
version: PASSKEY_VERSION,
length: clamp(Number(config.length ?? FALLBACK_CONFIG.length), 4, 8),
length: PASSKEY_LENGTH,
maxAttempts: clamp(Number(config.maxAttempts ?? FALLBACK_CONFIG.maxAttempts), 1, 10),
cooldownSeconds: clamp(Number(config.cooldownSeconds ?? FALLBACK_CONFIG.cooldownSeconds), 5, 120),
};
@@ -150,13 +151,22 @@ export const createPasskeyController = () => {
const updateConfig = (partial) => {
Object.assign(config, partial);
config.length = clamp(Number(config.length), 4, 8);
config.length = PASSKEY_LENGTH;
config.maxAttempts = clamp(Number(config.maxAttempts), 1, 10);
config.cooldownSeconds = clamp(Number(config.cooldownSeconds), 5, 120);
persist();
return { ...config };
};
const resetSequence = () => {
config.hash = "";
config.salt = "";
config.length = PASSKEY_LENGTH;
failedAttempts = 0;
lockoutUntil = 0;
persist();
};
const getConfig = () => ({ ...config });
return {
@@ -164,6 +174,7 @@ export const createPasskeyController = () => {
updateConfig,
verifySequence,
setSequence,
resetSequence,
inLockout,
getLockoutRemainingMs,
hasPasskey: () => Boolean(config.hash && config.salt),
+5 -18
View File
@@ -36,13 +36,13 @@ const SETTINGS_TEMPLATE = `
<p class="muted" data-passkey-enabled>Enabled</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="1" data-toggle="passkey-change" data-focus-key="passkey-change">
<p class="settings-card-title">Change Passkey</p>
<p class="muted" data-passkey-change>Open setup on next lock</p>
<p class="settings-card-title">Reset Passkey</p>
<p class="muted" data-passkey-change>Clear and set a new passkey</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="2" data-toggle="passkey-length" data-focus-key="passkey-length">
<p class="settings-card-title">Required Length</p>
<p class="muted" data-passkey-length>6 inputs</p>
<p class="muted">Use LB / RB to adjust</p>
<p class="muted" data-passkey-length>6 digits</p>
<p class="muted">Fixed for testing</p>
</button>
<button class="focusable settings-card" data-focusable="true" data-row="1" data-col="3" data-toggle="passkey-confirm" data-focus-key="passkey-confirm">
<p class="settings-card-title">Require Confirm</p>
@@ -185,6 +185,7 @@ export const createSettingsView = ({ state, renderView }) => {
}
if (toggle === "passkey-change") {
state.passkey.resetSequence();
state.passkeySetupRequired = true;
state.locked = true;
state.activeView = "lock";
@@ -193,8 +194,6 @@ export const createSettingsView = ({ state, renderView }) => {
}
if (toggle === "passkey-length") {
const current = state.passkey.getConfig().length;
updatePasskey({ length: current >= 8 ? 4 : current + 1 });
return;
}
@@ -221,18 +220,6 @@ export const createSettingsView = ({ state, renderView }) => {
return false;
}
if (action === "l1") {
const next = state.passkey.getConfig().length - 1;
updatePasskey({ length: next < 4 ? 8 : next });
return true;
}
if (action === "r1") {
const next = state.passkey.getConfig().length + 1;
updatePasskey({ length: next > 8 ? 4 : next });
return true;
}
return false;
},
};