From 5fc07aed7aded00a242836dd61f52b3b92614fd1 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sun, 5 Jul 2026 16:35:29 +0100 Subject: [PATCH] =?UTF-8?q?refactor(js):=20extract=20TOTP=20module=20+=20a?= =?UTF-8?q?dd=20RFC=206238=20tests=20(=C2=A73.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fourth slice of the app.js split. Moves TOTP (base32Decode, generateTOTP, parseOtpAuthUri) plus the TOTP-secret and custom-field AES-GCM wrappers to js/app.totp.js. Loads before app.js (pure declarations), after app.crypto.js (uses encryptPwd/decryptPwd). Also called by app.import.js and app.sync.js via shared global scope. - Byte-for-byte identical extraction; no duplicate const; syntax OK on all five app parts. - NEW: js/tests/totp.test.js — 13 tests including the 5 RFC 6238 Appendix B reference vectors (generateTOTP reads Date.now(), so each case stubs the sandbox clock to the vector's fixed time), base32 decode edge cases, and parseOtpAuthUri. Extraction AND new coverage in one slice. - Suite: 42 → 55 tests, all green. - Assets regenerated (manifest now embeds all 6 ordered JS files: argon2 → crypto → totp → import → app → sync); also fixes the previous import commit's not-yet-rebuilt manifest. - Delphi build artifacts (*.vrc, *.$manifest) gitignored. app.js: 11936 → 10138 lines (4 modules extracted, ~1800 lines). Co-Authored-By: Claude Opus 4.8 --- .gitignore | 4 + CLAUDE.md | 9 +- CODE_AUDIT.md | 8 +- delphi-backend/assets/BuildAssets.ps1 | 1 + delphi-backend/assets/assets.inc | 4 +- delphi-backend/assets/assets.rc | 2 + delphi-backend/assets/assets.res | Bin 706800 -> 708892 bytes index.html | 1 + js/app.js | 119 +---------------------- js/app.totp.js | 131 ++++++++++++++++++++++++++ js/tests/harness.js | 4 +- js/tests/totp.test.js | 94 ++++++++++++++++++ 12 files changed, 253 insertions(+), 124 deletions(-) create mode 100644 js/app.totp.js create mode 100644 js/tests/totp.test.js diff --git a/.gitignore b/.gitignore index 63d4101..cec3549 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,7 @@ delphi-backend/vault - Copie*.db *.png *.jpg *.jpeg + +# Delphi build artifacts +delphi-backend/*.vrc +delphi-backend/*.$manifest diff --git a/CLAUDE.md b/CLAUDE.md index 48fab6b..20ec08d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,7 @@ visibles des suivants exactement comme dans le monofichier. Ordre actuel : ``` js/argon2.js (IIFE, globalThis.NobleArgon2) js/app.crypto.js (KDF, verifier, encrypt/decrypt — extrait §3.1) +js/app.totp.js (TOTP RFC 6238 + TOTP/custom-field crypto — extrait §3.1) js/app.import.js (export container + import CSV/JSON — extrait §3.1) js/app.js (le reste : state, Bridge, api, UI…) js/app.sync.js (WebDAV + merge — extrait §3.1, APRÈS app.js car @@ -75,9 +76,10 @@ invariant crypto/merge cassé avorte le build comme une erreur de syntaxe. via `npm test`. Voir [js/tests/README.md](js/tests/README.md) — le harness concatène `APP_PARTS` (`app.crypto.js` + `app.js`) et les charge dans un `node:vm` avec les globals navigateur stubbés (`argon2.js` chargé à part, -c'est un IIFE), puis expose les internals via un épilogue d'export. Couvre : round-trip crypto + dérivation verifier (legacy vs -v2), -parsing CSV d'import, et l'arbitrage merge/tombstone de sync -(`applyRemoteSnapshot`, seule `api()` est stubbée). +c'est un IIFE), puis expose les internals via un épilogue d'export. Couvre : round-trip crypto + dérivation verifier (legacy vs -v2) ++ Argon2id (vecteur RFC 9106), TOTP (vecteurs RFC 6238), parsing CSV +d'import, et l'arbitrage merge/tombstone de sync (`applyRemoteSnapshot`, +seule `api()` est stubbée). ## Carte des fichiers @@ -99,6 +101,7 @@ parsing CSV d'import, et l'arbitrage merge/tombstone de sync | Handlers REST | `delphi-backend/Handlers/PM.Handler.*.pas` | | Frontend principal (en cours de découpage §3.1) | `js/app.js` | | Crypto frontend (KDF, verifier, AES-GCM) — extrait §3.1 | `js/app.crypto.js` | +| TOTP (RFC 6238) + TOTP/custom-field crypto — extrait §3.1 | `js/app.totp.js` | | Import/export frontend (CSV/JSON parse, export container) — extrait §3.1 | `js/app.import.js` | | Sync frontend (WebDAV, snapshot, merge) — extrait §3.1 | `js/app.sync.js` | | Argon2id vendé (bundle `@noble/hashes`, IIFE) | `js/argon2.js` | diff --git a/CODE_AUDIT.md b/CODE_AUDIT.md index 77242ed..f003f40 100644 --- a/CODE_AUDIT.md +++ b/CODE_AUDIT.md @@ -233,9 +233,13 @@ réécriture des call-sites, risque quasi nul vs conversion en modules ES). `doImport`/`doExport`) — byte-for-byte identique, couvert par les 14 tests CSV, chargé AVANT app.js (pures déclarations). Pattern + règles d'ordre documentés dans CLAUDE.md « Découpage frontend ». -- `app.js` : 11 936 → **10 253 lignes** (crypto + sync + import sortis). +- ✅ `js/app.totp.js` extrait (TOTP RFC 6238 + crypto TOTP/custom-fields) — + byte-for-byte identique, chargé AVANT app.js. **+13 tests TOTP (vecteurs + RFC 6238)** ajoutés en même temps → extraction *et* nouvelle couverture. +- `app.js` : 11 936 → **10 138 lignes** (crypto + totp + sync + import sortis). +- Suite de tests : 42 → **55 tests**. - Reste à extraire (grosses sections cohésives) : slideover, settings, - quicksearch, autofill, auto-backup… + quicksearch, autofill, auto-backup, favicons… - ✅ `node --check` en pré-étape de `BuildAssets.ps1` : **déjà fait** (cf. §3.2). ### 3.2 🟡 Aucun test automatisé — **partiellement adressé (2026-07-04)** diff --git a/delphi-backend/assets/BuildAssets.ps1 b/delphi-backend/assets/BuildAssets.ps1 index d947c5e..a1745d3 100644 --- a/delphi-backend/assets/BuildAssets.ps1 +++ b/delphi-backend/assets/BuildAssets.ps1 @@ -53,6 +53,7 @@ $patterns = @( 'index.html', 'js\argon2.js', 'js\app.crypto.js', + 'js\app.totp.js', 'js\app.import.js', 'js\app.js', 'js\app.sync.js', diff --git a/delphi-backend/assets/assets.inc b/delphi-backend/assets/assets.inc index 9875e95..f3742f6 100644 --- a/delphi-backend/assets/assets.inc +++ b/delphi-backend/assets/assets.inc @@ -1,10 +1,12 @@ // Auto-generated by BuildAssets.ps1 - do not edit by hand. const - EMBEDDED_ASSET_COUNT = 6; + EMBEDDED_ASSET_COUNT = 8; EMBEDDED_ASSETS: array[0..EMBEDDED_ASSET_COUNT-1] of TEmbeddedAsset = ( (UrlPath: '/index.html'; ResName: 'INDEX_HTML'), (UrlPath: '/js/argon2.js'; ResName: 'JS_ARGON2_JS'), (UrlPath: '/js/app.crypto.js'; ResName: 'JS_APP_CRYPTO_JS'), + (UrlPath: '/js/app.totp.js'; ResName: 'JS_APP_TOTP_JS'), + (UrlPath: '/js/app.import.js'; ResName: 'JS_APP_IMPORT_JS'), (UrlPath: '/js/app.js'; ResName: 'JS_APP_JS'), (UrlPath: '/js/app.sync.js'; ResName: 'JS_APP_SYNC_JS'), (UrlPath: '/css/style.css'; ResName: 'CSS_STYLE_CSS') diff --git a/delphi-backend/assets/assets.rc b/delphi-backend/assets/assets.rc index be440e3..a00d2ff 100644 --- a/delphi-backend/assets/assets.rc +++ b/delphi-backend/assets/assets.rc @@ -4,6 +4,8 @@ INDEX_HTML RCDATA "Z:\\password-manager\\index.html" JS_ARGON2_JS RCDATA "Z:\\password-manager\\js\\argon2.js" JS_APP_CRYPTO_JS RCDATA "Z:\\password-manager\\js\\app.crypto.js" +JS_APP_TOTP_JS RCDATA "Z:\\password-manager\\js\\app.totp.js" +JS_APP_IMPORT_JS RCDATA "Z:\\password-manager\\js\\app.import.js" JS_APP_JS RCDATA "Z:\\password-manager\\js\\app.js" JS_APP_SYNC_JS RCDATA "Z:\\password-manager\\js\\app.sync.js" CSS_STYLE_CSS RCDATA "Z:\\password-manager\\css\\style.css" diff --git a/delphi-backend/assets/assets.res b/delphi-backend/assets/assets.res index a04b0bcd153ac48e4a02bc840ee0ce08e925f5bc..81c32002de02a2ea356142b23468e16f442dd263 100644 GIT binary patch delta 1402 zcmai!?~5Bn7{_;Wz1WMwc|y7R3!k_CVzHMbmU6DO?kit@K@)+npqPo!wbx zCU?!NRD|9eU#JKR^$=01Z}g2Q5eg!{w&L5qY~KjJ@;_*wnawrVvmjx}vOCZBd7k-x zp85CF)%~wmKY_yH$q!HeeA@ngc}{Va{jqGX6r(uhLS^@s?K6`?5iIN#c`)mhqunHznx3E6caa7>qz+8KP@U0%ln6;%Dy zco>x`w1FKsu0cP&{2@bcZsnCZmu7?e%D&@c3?h28@qMDB*(FXmvcJxQ$`8 zhVONr)`#*?QhB%>tv4$P^VgW1kGr{_(>G7Y?nDISfC$XiXMBq=kO5C=6|2gYzL>i>*)A8Hm)?x;TGshzV%4-Z z5wDijvHTfYug^->a5XpEt&R^acvtm9_IGI^9(%bXn3&$s6hpuhMIyw;fqM4?_fofY z8FC#%NtE;*Viv& zlfftm+QY3<5ru4%G;*e+qJ;*OX<(<6`=l=)-n>)65Xsrn4h4PqhI3;;mhRcFj)5p0 z8ffxW6w@kPZu#EE0WnQ8@m`|D2w1d(C=Dp$swW`ALD1;vPy^3FFHe}jHrS{`W3Fg7 zA*md2RWZ}Q%f)qR%6WbYgQg(+@r8xTu_q{G&X@D0$u|#*@h?S0p}Ak2-2K-6>7!Tj zYvWn>MRwgj{_-2sdq$U2Hn&E_!GR$m7D=$?Y;mQqk}bVc@Up*F3g`FkZxnFN;W~zE zesX`K_}iVuqYP=~Q!~u|D{Q*g+GkEcIXyblmFl64-P_Miy0?$p=^Xa8=a&{HeyOzo F>th!!*=7I$ delta 98 zcmbQUNc+P??FkA@`^6iTwkk2M5#KH+!T73&IVY8UJ9`<^mgeocD;U* + diff --git a/js/app.js b/js/app.js index 90be4c1..be1d94a 100644 --- a/js/app.js +++ b/js/app.js @@ -713,124 +713,9 @@ async function api(path, opts) { } // ============================================================ -// TOTP (RFC 6238) — 6-digit time-based codes +// TOTP + TOTP/custom-field crypto — extracted to js/app.totp.js +// (§3.1), loaded as a separate