37b22166bab5
scope auto-lock refresh to extension pages and secret-touching fill
- time
- 2026-09-03 22:14 UTC · 1 month ago
- machine
- koh2
- agent
- claude-sonnet-4-6
- session
- PB-26-304 passive auto-lock refresh
- parent
- af7feb6fddaf
↓ peach-browser-37b22166.tar.gzatlas at this save
files changed6 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/background/message-policy.ts+1 −1src/background/messages.autolock-refresh.test.ts+26 −5src/background/messages.ts+7 −2manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "5.0.71",4+ "version": "5.0.72",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": "5.0.71",5+ "version": "5.0.72",66 "description": "Zero-knowledge password manager",77 "action": {88 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "5.0.71",3+ "version": "5.0.72",44 "description": "Zero-knowledge password manager",55 "license": "GPL-3.0-only",66 "type": "module",src/background/message-policy.ts+1 −1
@@ -118,7 +118,7 @@118118 ML_PREDICT_BATCH: "content-script-allowed",119119 OPEN_PRO_GATE: "content-script-allowed",120120 OPEN_POPUP: "content-script-allowed",121- TOUCH_AUTO_LOCK: "content-script-allowed",121+ TOUCH_AUTO_LOCK: "extension-page-only",122122 MARK_PASSKEY_BANNER_SHOWN: "content-script-allowed",123123 124124 // These seven are the explicit Firefox MAIN-world passkey relay surface.src/background/messages.autolock-refresh.test.ts+26 −5
@@ -68,6 +68,14 @@6868 return (chrome.alarms.create as unknown as ReturnType<typeof vi.fn>).mock.calls.length;6969 }7070 71+ it("content-script GET_SETTINGS does not reschedule the lock alarm", async () => {72+ (chrome.alarms.create as unknown as ReturnType<typeof vi.fn>).mockClear();73+74+ await messages.handleMessage({ type: "GET_SETTINGS" }, pageSender);75+76+ expect(alarmCreations()).toBe(0);77+ });78+7179 it("repeated AUTOFILL_QUERY does not reschedule the lock alarm", async () => {7280 (chrome.alarms.create as unknown as ReturnType<typeof vi.fn>).mockClear();7381 @@ -94,13 +102,23 @@94102 expect(alarmCreations()).toBe(0);95103 });96104 97- // The control: this is not a blanket stop-refreshing. A user-initiated98- // message still pushes the deadline out.99- it("a user-initiated message still reschedules the lock alarm", async () => {105+ it("page TOUCH_AUTO_LOCK is rejected without rescheduling the lock alarm", async () => {100106 (chrome.alarms.create as unknown as ReturnType<typeof vi.fn>).mockClear();101107 102- await messages.handleMessage({ type: "TOUCH_AUTO_LOCK", payload: {} }, pageSender);108+ await expect(109+ messages.handleMessage({ type: "TOUCH_AUTO_LOCK", payload: {} }, pageSender),110+ ).resolves.toMatchObject({ ok: false, error: "invalid_sender" });111+ expect(alarmCreations()).toBe(0);112+ });103113 114+ it("an extension-page TOUCH_AUTO_LOCK reschedules the lock alarm", async () => {115+ (chrome.alarms.create as unknown as ReturnType<typeof vi.fn>).mockClear();116+117+ await messages.handleMessage(118+ { type: "TOUCH_AUTO_LOCK", payload: {} },119+ { url: "chrome-extension://test-extension-id/popup.html" },120+ );121+104122 expect(alarmCreations()).toBe(1);105123 });106124 @@ -115,7 +133,10 @@115133 pageSender,116134 );117135 }118- await messages.handleMessage({ type: "TOUCH_AUTO_LOCK", payload: {} }, pageSender);136+ await messages.handleMessage(137+ { type: "TOUCH_AUTO_LOCK", payload: {} },138+ { url: "chrome-extension://test-extension-id/popup.html" },139+ );119140 for (let i = 0; i < 20; i += 1) {120141 await messages.handleMessage(121142 { type: "AUTOFILL_QUERY", payload: { domain: "example.com", kind: "login" } },src/background/messages.ts+7 −2
@@ -380,7 +380,7 @@380380 return { ok: false, error: "invalid_sender" };381381 }382382 383- if (shouldRefreshAutoLock(msg.type) && vault.isUnlocked()) {383+ if (shouldRefreshAutoLock(msg.type, sender) && vault.isUnlocked()) {384384 touchAutoLock();385385 }386386 @@ -954,6 +954,7 @@954954 totpCode = undefined;955955 }956956 }957+ if (isPageSender(sender) && vault.isUnlocked()) touchAutoLock();957958 return { ok: true, data: { ...safeEntry, totpCode, totpRemaining } };958959 }959960 // Trusted full-entry fetch for extension-owned edit surfaces. Content@@ -1818,7 +1819,11 @@18181819 });18191820 }18201821 1821-function shouldRefreshAutoLock(type: MessageType): boolean {1822+function shouldRefreshAutoLock(1823+ type: MessageType,1824+ sender: Partial<chrome.runtime.MessageSender>,1825+): boolean {1826+ if (!isExtensionPageSender(sender)) return false;18221827 return (18231828 type !== "HAS_VAULT" &&18241829 type !== "IS_UNLOCKED" &&