fix(ext): content-callable capture_save_login closes critical router gap
After Slice 4's router split, the capture prompt's Save button was silently failing on every site: content/capture.ts called four handlers (get_settings, get_item, update_item, add_item) that are all in POPUP_ONLY_TYPES, so the router rejected each with unauthorized_sender. Fix in two parts: Part A — get_settings: content scripts already have storage permission via the manifest, so read relicarioSettings directly from chrome.storage.local instead of round-tripping through the SW. Part B — new content-callable 'capture_save_login' message that consolidates what was previously three separate popup-only calls (get_item + update_item or add_item) into one SW-side operation. Content scripts no longer need to distinguish add vs update — the SW does that itself from the manifest. Security model (all enforced SW-side, never trusting content): - Origin is derived from sender.tab.url by the router. The payload contains only username + password; there is no way for content to influence which host the new/updated item binds to. - Update path re-verifies the existing item's core.url hostname matches senderHost before mutating. If the manifest icon_hint ever drifts from core.url, we return origin_mismatch rather than silently binding a password to the wrong origin. - Update mutates ONLY the password field + modified timestamp — never title, url, or any other core field. - Add path creates a new Login item whose title is senderHost and whose url is the sender's origin. Five new router tests cover: content-accept, popup-reject, update path rotates only the password, add path creates bound item, and origin_mismatch when the stored item's host disagrees with senderHost. Tests: 47 -> 52. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,8 @@ export type ContentMessage =
|
||||
| { type: 'get_autofill_candidates' }
|
||||
| { type: 'get_credentials'; id: ItemId }
|
||||
| { type: 'check_credential'; username: string; password: string }
|
||||
| { type: 'blacklist_site' };
|
||||
| { type: 'blacklist_site' }
|
||||
| { type: 'capture_save_login'; username: string; password: string };
|
||||
|
||||
// --- Union for chrome.runtime.sendMessage call sites ---
|
||||
|
||||
@@ -99,4 +100,5 @@ export const POPUP_ONLY_TYPES: ReadonlySet<PopupMessage['type']> = new Set([
|
||||
|
||||
export const CONTENT_CALLABLE_TYPES: ReadonlySet<ContentMessage['type']> = new Set([
|
||||
'get_autofill_candidates', 'get_credentials', 'check_credential', 'blacklist_site',
|
||||
'capture_save_login',
|
||||
] as ContentMessage['type'][]);
|
||||
|
||||
Reference in New Issue
Block a user