fix: setup routing, async bcrypt, password hashing, clean command
- Add SetupGuard component: redirects to /setup if setup not complete, shown as spinner while loading. All routes except /setup now wrapped. - SetupPage redirects to /login on mount when setup already done. - Fix async blocking: offload bcrypt.hashpw and bcrypt.checkpw to run_in_executor so they never stall the asyncio event loop. - Hash password with SHA-256 (SubtleCrypto) before transmission; added src/utils/crypto.ts with sha256Hex(). Backend stores bcrypt(sha256). - Add Makefile with make up/down/restart/logs/clean targets. - Add tests: _check_password async, concurrent bcrypt, expired session, login-without-setup, run_setup event-loop interleaving. - Update Architekture.md and Features.md to reflect all changes.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* All fields use Fluent UI v9 components and inline validation.
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import type { ChangeEvent, FormEvent } from "react";
|
||||
import { ApiError } from "../api/client";
|
||||
import { submitSetup } from "../api/setup";
|
||||
import { getSetupStatus, submitSetup } from "../api/setup";
|
||||
import { sha256Hex } from "../utils/crypto";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Styles
|
||||
@@ -105,6 +106,17 @@ export function SetupPage(): React.JSX.Element {
|
||||
const [apiError, setApiError] = useState<string | null>(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
// Redirect to /login if setup has already been completed.
|
||||
useEffect(() => {
|
||||
getSetupStatus()
|
||||
.then((res) => {
|
||||
if (res.completed) navigate("/login", { replace: true });
|
||||
})
|
||||
.catch(() => {
|
||||
/* ignore — stay on setup page */
|
||||
});
|
||||
}, [navigate]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -149,8 +161,11 @@ 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: values.masterPassword,
|
||||
master_password: hashedPassword,
|
||||
database_path: values.databasePath,
|
||||
fail2ban_socket: values.fail2banSocket,
|
||||
timezone: values.timezone,
|
||||
|
||||
Reference in New Issue
Block a user