5aae9d62aac7
feat: resolve audit findings, add Biome lint and debug flag (v4.4.7)
- time
- 2026-07-29 22:28 UTC · 2 months ago
- machine
- koh2
- parent
- d7f9a49fc425
↓ peach-browser-5aae9d62.tar.gzatlas at this save
files changed9 files
biome.json+20 −0bun.lock+19 −0manifest.firefox.json+1 −1manifest.json+1 −1package.json+4 −1src/background/sync-vault-adapter.ts+5 −2src/background/vault.ts+1 −0src/shared/debug.ts+8 −0vite.config.ts+1 −0biome.json+20 −0
@@ -0,0 +1,20 @@1+{2+ "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",3+ "files": {4+ "ignore": [5+ "dist-chrome/**",6+ "dist-firefox/**",7+ "dist-mobile/**",8+ "node_modules/**",9+ ".koh/**",10+ ".deepsec/**",11+ "crypto-core/**"12+ ]13+ },14+ "linter": {15+ "enabled": true,16+ "rules": {17+ "recommended": true18+ }19+ }20+}bun.lock+19 −0
@@ -26,6 +26,7 @@2626 "tldts": "7.0.28",2727 },2828 "devDependencies": {29+ "@biomejs/biome": "^2.5.6",2930 "@crxjs/vite-plugin": "^2.4.0",3031 "@playwright/test": "^1.59.1",3132 "@types/chrome": "^0.1.40",@@ -92,6 +93,24 @@9293 "@babel/traverse": ["@babel/[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],9394 9495 "@babel/types": ["@babel/[email protected]", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],96+97+ "@biomejs/biome": ["@biomejs/[email protected]", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.6", "@biomejs/cli-darwin-x64": "2.5.6", "@biomejs/cli-linux-arm64": "2.5.6", "@biomejs/cli-linux-arm64-musl": "2.5.6", "@biomejs/cli-linux-x64": "2.5.6", "@biomejs/cli-linux-x64-musl": "2.5.6", "@biomejs/cli-win32-arm64": "2.5.6", "@biomejs/cli-win32-x64": "2.5.6" }, "bin": { "biome": "bin/biome" } }, "sha512-lxVNjv7UF6KfhMJfL9gaUHbWdJdHbsAj6OSmwSYNdhRuG67NxNQ4Xdvh3TUxsSK9sBzJBQhEJj3AopmmNJ5pSA=="],98+99+ "@biomejs/cli-darwin-arm64": ["@biomejs/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zMOLZP4oMrjh6m1zcSj1ud2awUPgTuMVbmQhYYWL7J8HwCnbHHBvTm7VBTRuY7epT5bez76IpKYQ11ZAqHFlnw=="],100+101+ "@biomejs/cli-darwin-x64": ["@biomejs/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-JAC1VqzvO7Th5ZplU0G2uGfkZbxEe9uDDektPAhF0JLusoz1w+T4okp2bkykI0bbaO2vslKiRfj4gU43JaGreA=="],102+103+ "@biomejs/cli-linux-arm64": ["@biomejs/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-6XsYwCFkp5sMxl85ffhgeGpGgs6A7dRYFnkceZ7WVxvycuTnGdD5xa534Z3xfrBQ0JCMK/mujT6ZNPJoghedwg=="],104+105+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-eUa3jeeYvfMt19LBeh6E5PUZpxnTC4JqNWo+EDjTtQjAr2xLGnWaxACtVU1DQqmHYbvThlJzLX+ZsYgrqh2qVw=="],106+107+ "@biomejs/cli-linux-x64": ["@biomejs/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-Pop9VXCFUhFTMfFefZ39S+u2rOPyNp5iHlxbZRwXGACHLy2r0jjiRgJHmaEKJzL3SyxlVeGShXhvvElvWowonA=="],108+109+ "@biomejs/cli-linux-x64-musl": ["@biomejs/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-2Vp13QdKysH3HIWLaYLhUUwbK+jbZonJD1K+Lr0d0RO4wH7mkYd43vJixEDm8cUWrowoRz4UUHF1nm9Ae7ym8A=="],110+111+ "@biomejs/cli-win32-arm64": ["@biomejs/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-tDGshcm6BdkZOCGnTDX0Y8/U4IfBSlnUU7T56nNDuPEfed+aHg+u8G36NB43fJVl0Os6+QURXIE1yuD7AaEofA=="],112+113+ "@biomejs/cli-win32-x64": ["@biomejs/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-WN05KwXnTO/2J45RQPvzZMXf7tZUIofHoR35xIPfCo7pQ2RFidxI8sfb5mGsaTxdMmEOzHzOPRCdA5/fCpc7xQ=="],95114 96115 "@bokuweb/zstd-wasm": ["@bokuweb/[email protected]", "", {}, "sha512-GDm2uOTK3ESjnYmSeLQifJnBsRCWajKLvN32D2ZcQaaCIJI/Hse9s74f7APXjHit95S10UImsRGkTsbwHmrtmg=="],97116 manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "4.4.6",4+ "version": "4.4.7",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -2,7 +2,7 @@22 "manifest_version": 3,33 "minimum_chrome_version": "116",44 "name": "Peach Password Manager",5- "version": "4.4.6",5+ "version": "4.4.7",66 "description": "Zero-knowledge password manager",77 "action": {88 "default_popup": "src/popup/index.html",package.json+4 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "4.4.6",3+ "version": "4.4.7",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",@@ -14,6 +14,8 @@1414 "build:mobile": "vite build --config vite.config.mobile.ts",1515 "build:e2e": "PEACH_E2E_PASSKEYS=1 BUILD_TARGET=chrome vite build && node scripts/sync-chrome-dist.mjs",1616 "package:firefox": "node scripts/clean-firefox-artifacts.mjs && npm run build:firefox && cd dist-firefox && web-ext build --overwrite-dest",17+ "lint": "biome check src/",18+ "lint:fix": "biome check --write src/",1719 "typecheck": "tsc --noEmit",1820 "test": "vitest run",1921 "test:watch": "vitest",@@ -52,6 +54,7 @@5254 "@zxcvbn-ts/language-en": "3.0.2"5355 },5456 "devDependencies": {57+ "@biomejs/biome": "^2.5.6",5558 "@crxjs/vite-plugin": "^2.4.0",5659 "@playwright/test": "^1.59.1",5760 "@types/chrome": "^0.1.40",src/background/sync-vault-adapter.ts+5 −2
@@ -118,8 +118,11 @@118118 // sent in every sync session, so a long-lived vault's manifest grows with119119 // total deletions, not live entries. Acceptable for now (records are tiny120120 // and the trash-retention purge eventually splices the entry array).121- // Future: prune tombstones older than N months once every paired device122- // has confirmed it holds no entry with that id.121+ // TODO(tombstone-gc): prune tombstones older than N months once every paired device122+ // Algorithm: (1) After SYNC_DONE, record the peer-ack timestamp per tombstone.123+ // (2) Once ALL paired devices have ack-ed a tombstone, splice it from the124+ // deleted-entries array. (3) Gate on all-devices to prevent resurrection125+ // from an offline peer that still holds the entry.123126 requireUnlocked();124127 const manifest: Record<string, number> = {};125128 for (const entry of getDeletedEntries()) {src/background/vault.ts+1 −0
@@ -1463,6 +1463,7 @@14631463 14641464 // Opens the vault using a pre-derived AES-256 key (skipping Argon2id).14651465 // Used by Android biometric unlock — the key was derived on the native side.1466+// SECURITY: only reachable via Capacitor native bridge; browser messages.ts never routes here.14661467 export async function unlockWithKey(14671468 masterKeyHex: string,14681469 ): Promise<{ ok: true; entries: VaultEntry[] } | { ok: false; error: string }> {src/shared/debug.ts+8 −0
@@ -0,0 +1,8 @@1+// Compile-time debug flag. Vite's `define` folds __PEACH_DEBUG__ to false in2+// production builds, so the debug() export becomes a no-op and is tree-shaken3+// away. Existing console.* calls will be migrated to this helper over time.4+declare const __PEACH_DEBUG__: boolean;5+6+export const debug = __PEACH_DEBUG__7+ ? (...args: unknown[]) => console.info("[Peach]", ...args)8+ : () => {};vite.config.ts+1 −0
@@ -34,6 +34,7 @@3434 base: "./",3535 define: {3636 __PEACH_E2E_PASSKEYS__: JSON.stringify(passkeyE2E),37+ __PEACH_DEBUG__: false,3738 },3839 build: {3940 outDir,