refactor(js): extract crypto module from app.js monofile (§3.1 start)
First slice of the app.js split. Approach: ordered classic-script files loaded via separate <script> tags (argon2.js → app.crypto.js → app.js), NOT ES modules / a bundler. Classic scripts share one global lexical environment, so consts/functions cross-reference across files exactly as in the monofile — zero call-site rewrites, near-zero risk. Chosen over the audit's esbuild/ES-module suggestion because the code is written entirely in global scope (functions call each other by bare name everywhere). - js/app.crypto.js: KDF (PBKDF2 + Argon2id), verifier, AES-GCM encrypt/ decrypt, key persist/restore. Verified byte-for-byte identical to the original block before removal; no duplicate const across the two scripts. - index.html + BuildAssets whitelist + test harness updated for the load order. Harness CONCATENATES app.crypto.js + app.js (node:vm doesn't share top-level const across separate runInContext calls the way browsers share it across <script> tags); argon2.js stays a separate IIFE. - Runtime-validated: rebuilt exe unlocks via quick-unlock and loads/decrypts entries — the extracted crypto (restoreCryptoKey, verifierFromKeyHex, decryptPwd) works from the separate file. 42/42 tests green. - Docs: CLAUDE.md "Découpage frontend" (pattern + rules), file map, tests README, CODE_AUDIT §3.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+10
-2
@@ -25,7 +25,12 @@ const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
const { webcrypto } = require('node:crypto');
|
||||
|
||||
const APP_JS = path.join(__dirname, '..', 'app.js');
|
||||
// The frontend is split into ordered classic-script files (§3.1). In the
|
||||
// browser they share one global lexical environment; node:vm does NOT share
|
||||
// top-level const/let across separate runInContext calls, so we CONCATENATE
|
||||
// the app.* parts (in <script> load order) into one script. argon2.js is a
|
||||
// self-contained IIFE and loads separately (see below).
|
||||
const APP_PARTS = ['app.crypto.js', 'app.js'].map(f => path.join(__dirname, '..', f));
|
||||
|
||||
// In-memory Storage stub (Web Storage API surface used by app.js).
|
||||
function makeStorage() {
|
||||
@@ -119,7 +124,10 @@ function loadApp(overrides = {}) {
|
||||
const ARGON2_JS = path.join(__dirname, '..', 'argon2.js');
|
||||
vm.runInContext(fs.readFileSync(ARGON2_JS, 'utf8'), sandbox, { filename: 'argon2.js' });
|
||||
|
||||
let src = fs.readFileSync(APP_JS, 'utf8');
|
||||
// Concatenate the app.* parts in load order (see APP_PARTS). Newline
|
||||
// separators keep line-based errors legible; shared global scope is
|
||||
// preserved because it's a single script run.
|
||||
let src = APP_PARTS.map(p => fs.readFileSync(p, 'utf8')).join('\n;\n');
|
||||
|
||||
// Export epilogue — surface the lexical (const) symbols we test, plus a
|
||||
// couple of function-decl seams for convenience. Kept in one place so the
|
||||
|
||||
Reference in New Issue
Block a user