mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
- Add BackupTestFlow.tsx: after downloading the Keycase, the step becomes an explicit "Test your backup" view — a large dropzone for the downloaded file, then a password prompt that succeeds the instant the password is typed completely, ending in a spring-in check badge with an emoji burst celebration (skipped under reduced motion) - Verification is instant and KDF-free: the dropped file's bytes are compared to the committed ncryptsec blob and the typed password to the in-memory passphrase, so no key material beyond what the creator already held enters the component - Wrong files get inline errors (Keycase-but-different vs not-a-Keycase); full-length wrong passwords get a mismatch hint; a "Re-download backup" button re-opens the native save dialog and "Use a different file" returns to the dropzone - EncryptedBackupCreator.tsx: swap the masked-ncryptsec result view (NsecMaskedDisplay + "Save a copy…") for BackupTestFlow - DownloadKeyStep.tsx: header/subtitle now conditional — "Backup your key with a password" while creating, "Test your backup" once created; remove the bracketed shell-box visual, the keep-this-file-private hints, and the "back up anytime in Settings" footer note - BackupStep.tsx / MachineOnboardingFlow.tsx: chooser footer "Next" now always leads into the download step (skip lives there as "Skip for now") - Update onboarding-backup.spec.ts happy path to drive the new flow (wrong file, right file, wrong password, success, Next) with screenshots; align docked-CTA spec and passThroughBackupStep helper with the new navigation; allowlist BackupTestFlow.tsx in the ncryptsec source scan Signed-off-by: Taylor Ho <taylorkmho@gmail.com> Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
69 lines
2.4 KiB
JavaScript
69 lines
2.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import test from "node:test";
|
|
|
|
// Structural tripwire (plan D4, defense-in-depth): NIP-49 backup material
|
|
// handling in the webview is confined to the identity/backup/import UI and
|
|
// its API wrappers. Anything else in `desktop/src` touching `ncryptsec` is
|
|
// structural drift toward an unguarded egress path and must be reviewed —
|
|
// the runtime guarantee lives in src-tauri's egress guard, this scan only
|
|
// keeps the blob from quietly spreading through the frontend.
|
|
//
|
|
// Mirror of the Rust-side scan in
|
|
// `src-tauri/src/egress_guard_tests.rs::ncryptsec_handling_is_confined_to_allowlisted_files`.
|
|
|
|
const SRC_ROOT = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
"../..",
|
|
);
|
|
|
|
const ALLOWLIST = [
|
|
"shared/api/tauriIdentity.ts",
|
|
"features/onboarding/lib/encryptedBackup.ts",
|
|
"features/onboarding/lib/encryptedBackup.test.mjs",
|
|
"features/onboarding/lib/keyImportInput.ts",
|
|
"features/onboarding/lib/keyImportInput.test.mjs",
|
|
"features/onboarding/ui/BackupStep.tsx",
|
|
"features/onboarding/ui/BackupTestFlow.tsx",
|
|
"features/onboarding/ui/EncryptedBackupCreator.tsx",
|
|
"features/onboarding/ui/NostrKeyImportForm.tsx",
|
|
"features/onboarding/ui/NsecMaskedDisplay.tsx",
|
|
"features/settings/ui/ProfileSettingsCard.tsx",
|
|
// e2e-only mock bridge (never in the production bundle):
|
|
"testing/e2eBridge.ts",
|
|
// this scan:
|
|
"shared/lib/ncryptsecSourceScan.test.mjs",
|
|
];
|
|
|
|
function* walk(dir) {
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
yield* walk(full);
|
|
} else if (/\.(ts|tsx|mjs|js|jsx)$/.test(entry.name)) {
|
|
yield full;
|
|
}
|
|
}
|
|
}
|
|
|
|
test("ncryptsec handling is confined to allowlisted frontend files", () => {
|
|
const violations = [];
|
|
for (const file of walk(SRC_ROOT)) {
|
|
const rel = path.relative(SRC_ROOT, file).replaceAll("\\", "/");
|
|
if (ALLOWLIST.includes(rel)) continue;
|
|
const content = fs.readFileSync(file, "utf8");
|
|
if (content.toLowerCase().includes("ncryptsec")) {
|
|
violations.push(rel);
|
|
}
|
|
}
|
|
assert.deepEqual(
|
|
violations,
|
|
[],
|
|
`NIP-49 material outside allowlisted files — wire it through the ` +
|
|
`identity layer (and its egress-guarded Rust commands) instead:\n` +
|
|
violations.join("\n"),
|
|
);
|
|
});
|