Remove client-side SHA-256 pre-hashing from setup and login

The sha256Hex helper used window.crypto.subtle.digest(), which is only
available in a secure context (HTTPS / localhost). In the HTTP Docker
environment crypto.subtle is undefined, causing a TypeError before any
request is sent — the setup and login forms both silently failed with
'An unexpected error occurred'.

Fix: pass raw passwords directly to the API. The backend already applies
bcrypt, which is sufficient. No stored hashes need migration because
setup never completed successfully in the HTTP environment.

* frontend/src/pages/SetupPage.tsx  — remove sha256Hex call
* frontend/src/api/auth.ts          — remove sha256Hex call
* frontend/src/pages/__tests__/SetupPage.test.tsx — drop crypto mock
* frontend/src/utils/crypto.ts      — deleted (no remaining callers)
This commit is contained in:
2026-03-15 21:29:23 +01:00
parent cdf73e2d65
commit c41165c294
4 changed files with 3 additions and 41 deletions

View File

@@ -22,7 +22,6 @@ import { useNavigate } from "react-router-dom";
import type { ChangeEvent, FormEvent } from "react";
import { ApiError } from "../api/client";
import { getSetupStatus, submitSetup } from "../api/setup";
import { sha256Hex } from "../utils/crypto";
// ---------------------------------------------------------------------------
// Styles
@@ -177,11 +176,8 @@ export function SetupPage(): React.JSX.Element {
setSubmitting(true);
try {
// Hash the password client-side before transmission — the plaintext
// never leaves the browser. The backend bcrypt-hashes the received hash.
const hashedPassword = await sha256Hex(values.masterPassword);
await submitSetup({
master_password: hashedPassword,
master_password: values.masterPassword,
database_path: values.databasePath,
fail2ban_socket: values.fail2banSocket,
timezone: values.timezone,

View File

@@ -10,11 +10,6 @@ vi.mock("../../api/setup", () => ({
submitSetup: vi.fn(),
}));
// Mock the crypto utility — we only need it to resolve without testing SHA256.
vi.mock("../../utils/crypto", () => ({
sha256Hex: vi.fn().mockResolvedValue("hashed-password"),
}));
import { getSetupStatus } from "../../api/setup";
const mockedGetSetupStatus = vi.mocked(getSetupStatus);