fix: audit fix pass #1 — all 19 verified HIGH findings + critical dep cleanup
Fixes every CRITICAL/HIGH finding from the 2026-06-09 full-codebase audit
(REVIEW_FINDINGS.md); each fix went through independent spec + code-quality
review. Plan and per-task log: docs/superpowers/plans/2026-06-10-audit-high-fix-pass.md
- attendance: schemas accept the combined local datetimes the forms/service
use (new dateTimeString helpers in schemas/common.ts), breaks persist on
create, AttendanceCreate submit rebuilt — every submit 400'd since 519edce
- 2fa: backup codes wired to /totp/backup-verify (+ remember-me parity),
enrollment QR generated locally via qrcode (CSP-blocked external service
also leaked the secret), dashboard shows per-user enrollment, not policy
- invoices/orders: per-line VAT survives re-saves (numberOr 0-respecting
coercion in formatters.ts), billing_text persists on update, issued-order
status transitions update UI gates
- trips: real pagination on all 3 pages, GET /trips/stats server aggregate
(shared buildTripsWhere + legacy distance coalesce), vehicle_id applies on
PUT with both-vehicle odometer recompute, print rebuilt (sync window.open,
escaped template, server totals)
- orders api: attachment_data PDF blob excluded from all non-binary reads
- warehouse: unit field is a Select over UnitEnum, receipt attachments
downloadable via new authenticated GET route
- downloads: shared RFC 5987 contentDisposition helper — Czech filenames no
longer 500 (warehouse, received-invoices, orders endpoints)
- misc: block-env hook actually blocks (exit 2 + stderr), project create
works with empty dates, NaN filter guards on trips endpoints
- deps: remove unused concurrently (clears both critical advisories), pin
@hono/node-server >=1.19.13 via overrides (clears the 3 moderates without
the Prisma 6 downgrade), drop deprecated @types stubs
Gates: tsc -b clean - vitest 30 files / 342 tests (31 new) - eslint 0 errors
- build OK
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import { useAuth } from "../context/AuthContext";
|
||||
import { useAlert } from "../context/AlertContext";
|
||||
import apiFetch from "../utils/api";
|
||||
import { dashboardOptions } from "../lib/queries/dashboard";
|
||||
import { require2FAOptions } from "../lib/queries/settings";
|
||||
import { totpStatusOptions } from "../lib/queries/settings";
|
||||
import { getCzechDate } from "../utils/dashboardHelpers";
|
||||
import { useApiMutation } from "../lib/queries/mutations";
|
||||
import { Card, Button, StatusChip, PageEnter } from "../ui";
|
||||
@@ -86,9 +86,11 @@ export default function Dashboard() {
|
||||
const { data: dashDataRaw, isPending: dashLoading } =
|
||||
useQuery(dashboardOptions());
|
||||
const dashData = dashDataRaw as DashData | undefined;
|
||||
// Personal 2FA enrollment (users.totp_enabled) — NOT the company-wide
|
||||
// require_2fa policy flag (the banner below uses user.require2FA for that).
|
||||
const { data: totpData, isPending: totpLoading } =
|
||||
useQuery(require2FAOptions());
|
||||
const totpEnabled = totpData?.require_2fa ?? !!user?.totpEnabled;
|
||||
useQuery(totpStatusOptions());
|
||||
const totpEnabled = totpData?.totp_enabled ?? !!user?.totpEnabled;
|
||||
|
||||
const punchMutation = useApiMutation<
|
||||
Record<string, unknown>,
|
||||
@@ -176,6 +178,7 @@ export default function Dashboard() {
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
queryClient.invalidateQueries({ queryKey: ["totp"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["settings"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["dashboard"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
@@ -206,6 +209,7 @@ export default function Dashboard() {
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
queryClient.invalidateQueries({ queryKey: ["totp"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["settings"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["dashboard"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
|
||||
Reference in New Issue
Block a user