1import { describe, expect, it } from "vitest";23import {4 getMessageContext,5 isMessageSenderAllowed,6 MESSAGE_CONTEXT_POLICY,7} from "./message-policy";8import type { MessageType } from "../shared/types";910describe("message context policy", () => {11 it("classifies every declared message type", () => {12 const policy = MESSAGE_CONTEXT_POLICY as Record<string, string>;13 const declaredTypes: MessageType[] = [14 "GET_SYNC_ALERTS", "CLEAR_CLIPBOARD", "GET_PENDING_VOUCHED_DEVICES", "CONFIRM_VOUCHED_DEVICE",15 "REJECT_VOUCHED_DEVICE", "VOUCHED_DEVICE_PENDING", "ROTATE_SYNC_IDENTITY", "DEVICE_KEY_ROTATED",16 "UNLOCK", "UNLOCK_WITH_PIN", "GET_PIN_STATUS", "LOCK", "IS_UNLOCKED", "HAS_VAULT", "GET_ENTRIES", "EXPORT_ENTRIES", "ADD_ENTRY",17 "BATCH_ADD_ENTRIES", "RESTORE_ENTRIES", "CLEAR_VAULT_ENTRIES", "UPDATE_ENTRY", "ADD_ADDITIONAL_URL",18 "REQUEST_REMEMBER_SITE",19 "DELETE_ENTRY", "AUTOFILL_QUERY", "COPY", "CREATE_VAULT", "CREATE_VAULT_FROM_ROOT_KEY",20 "GET_ENTRY_FOR_FILL", "GET_ENTRY_FOR_EDIT", "CHECK_ALL_BREACHES", "GET_SETTINGS", "UPDATE_SETTINGS",21 "SETUP_PIN", "DISABLE_PIN", "FIRE_CANARY_PING", "ACTIVATE_LICENSE", "GET_LICENSE", "GET_LICENSE_KEY",22 "IS_DURESS_ENABLED", "SETUP_DURESS", "DISABLE_DURESS", "VERIFY_MAIN_PASSWORD", "CHANGE_PASSWORD",23 "GET_SITE_PASSWORD_POLICY", "GET_LOCAL_IDENTITY", "LIST_PAIRED_DEVICES", "RENAME_PAIRED_DEVICE",24 "UNPAIR_DEVICE", "RENAME_LOCAL_DEVICE", "LIST_PENDING_ADOPTION_HOLDERS", "REMOVE_PENDING_ADOPTION_HOLDER", "START_ADOPTION_SOURCE", "START_ADOPTION_RECEIVER",25 "CANCEL_ADOPTION_SOURCE", "SOURCE_SAS_DECISION", "RECEIVER_SAS_DECISION", "ADOPTION_SOURCE_SAS", "ADOPTION_SOURCE_RESULT",26 "TRIGGER_SYNC", "GET_SYNC_STATE", "GET_SYNC_GENERATION", "SECURE_RESET", "GET_SYNC_SETTINGS", "SET_SYNC_SETTINGS", "GET_PENDING_PASSKEY",27 "APPROVE_PASSKEY", "DENY_PASSKEY", "GET_PASSKEY_PROVIDER_STATE", "SET_PASSKEY_PROVIDER_ENABLED",28 "GET_DELETED_ENTRIES", "RESTORE_ENTRY", "PURGE_ENTRY", "PURGE_EXPIRED_TRASH", "GET_VAULT_HISTORY",29 "RESTORE_VAULT_SNAPSHOT", "COUNT_DUPLICATES", "DEDUPLICATE_ENTRIES", "RECORD_MANUAL_SUMMON",30 "DECLINE_CARD_SAVE", "IS_CARD_DECLINED", "GET_VAULT_STATUS", "GET_ADVANCED_HEALTH_REPORT",31 "DEACTIVATE_LICENSE", "GET_IDENTITIES", "DESTROY_VAULT", "INITIATE_FIREFOX_PASSKEY_CREATE",32 "COMPLETE_FIREFOX_PASSKEY_CREATE", "PASSKEY_OFFER_DECLINE", "GET_PASSKEY_OFFER_DECLINED",33 "GET_PASSKEY_FOR_DOMAIN", "PASSKEY_HAS_CREDENTIALS", "PASSKEY_CREATE", "PASSKEY_GET",34 "MARK_PASSKEY_BANNER_SHOWN",35 "PASSKEY_AUTH_RESPONSE", "VALIDATE_RECOVERY_WORDS", "RECOVER_WITH_WORDS", "GET_RECOVERY_WORDS",36 "GET_RECOVERY_CONFIRM_PENDING", "SET_RECOVERY_CONFIRM_PENDING", "CLEAR_RECOVERY_CONFIRM_PENDING",37 "GET_IDENTITY_SUGGESTIONS", "TOUCH_AUTO_LOCK", "SAVE_NOTE", "DELETE_NOTE", "GET_NOTES", "SEARCH_VAULT",38 "ML_INIT", "ML_PREDICT_BATCH", "PING", "SUMMON_AUTOFILL", "VAULT_LOCKED", "VAULT_UNLOCKED",39 "PRO_GATE_TRIGGERED", "PASSKEY_PRO_GATE", "OPEN_PRO_GATE", "OPEN_POPUP", "OPEN_DETACHED_POPUP",40 "SHOW_PASSKEY_TOAST", "DISMISS_PASSKEY_TOAST", "SHOULD_PLAY_CELEBRATION", "MARK_CELEBRATION_PLAYED",41 "GET_CODEX_VAULT_DATA", "ESTIMATE_CODEX_PAGES", "GENERATE_CODEX", "RESTORE_FROM_CODEX",42 ];4344 expect(Object.keys(policy).sort()).toEqual([...new Set(declaredTypes)].sort());45 for (const type of declaredTypes) expect(getMessageContext(type)).toBeDefined();46 });4748 it("fails closed for unknown runtime message types", () => {49 expect(getMessageContext("TOTALLY_UNKNOWN_MESSAGE")).toBeUndefined();50 expect(getMessageContext(undefined)).toBeUndefined();51 });5253 it("refuses URL-less senders for privileged extension-page messages", () => {54 expect(55 isMessageSenderAllowed(56 "GET_ENTRIES",57 { id: "peach-extension" },58 "peach-extension",59 "chrome-extension://peach-extension/",60 ),61 ).toBe(false);62 });6364 it("marks the bulk vault and device-authority handlers extension-page-only", () => {65 for (const type of [66 "GET_ENTRIES",67 "GET_RECOVERY_WORDS",68 "RESTORE_ENTRIES",69 "UNPAIR_DEVICE",70 "CONFIRM_VOUCHED_DEVICE",71 "ROTATE_SYNC_IDENTITY",72 ] as const) {73 expect(getMessageContext(type)).toBe("extension-page-only");74 }75 });7677 it("allows COPY from popup pages and from page frames", () => {78 const extensionOrigin = "chrome-extension://peach-extension/";79 80 81 82 expect(getMessageContext("COPY")).toBe("content-script-allowed");83 expect(84 isMessageSenderAllowed(85 "COPY",86 { id: "peach-extension", url: `${extensionOrigin}popup.html` },87 "peach-extension",88 extensionOrigin,89 ),90 ).toBe(true);91 expect(92 isMessageSenderAllowed(93 "COPY",94 { id: "peach-extension", url: "https://example.test/login" },95 "peach-extension",96 extensionOrigin,97 ),98 ).toBe(true);99 });100101 it("keeps the global identity inventory extension-page-only", () => {102 expect(getMessageContext("GET_IDENTITIES")).toBe("extension-page-only");103104 const extensionOrigin = "chrome-extension://peach-extension/";105 expect(106 isMessageSenderAllowed(107 "GET_IDENTITIES",108 { id: "peach-extension", url: `${extensionOrigin}popup.html` },109 "peach-extension",110 extensionOrigin,111 ),112 ).toBe(true);113114 for (const sender of [115 { id: "peach-extension", url: "https://example.test/signup" },116 { id: "peach-extension", url: "https://example.test/signup", tab: { id: 1 } },117 ]) {118 expect(119 isMessageSenderAllowed("GET_IDENTITIES", sender, "peach-extension", extensionOrigin),120 ).toBe(false);121 }122 });123124 it("covers every message type against popup, content-script, and foreign senders", () => {125 const popup = {126 id: "peach-extension",127 url: "chrome-extension://peach-extension/src/popup/index.html",128 };129 const contentScript = { id: "peach-extension", url: "https://evil.test/login" };130 const foreign = { id: "other-extension", url: "https://evil.test/login" };131132 for (const [type, context] of Object.entries(MESSAGE_CONTEXT_POLICY)) {133 expect(134 isMessageSenderAllowed(type, popup, "peach-extension", "chrome-extension://peach-extension/"),135 `popup ${type}`,136 ).toBe(context === "extension-page-only" || context === "content-script-allowed");137 expect(138 isMessageSenderAllowed(type, contentScript, "peach-extension", "chrome-extension://peach-extension/"),139 `content script ${type}`,140 ).toBe(context === "content-script-allowed" || context === "page-relay");141 expect(142 isMessageSenderAllowed(type, foreign, "peach-extension", "chrome-extension://peach-extension/"),143 `foreign sender ${type}`,144 ).toBe(false);145 }146147 expect(148 isMessageSenderAllowed(149 "TOTALLY_UNKNOWN_MESSAGE",150 contentScript,151 "peach-extension",152 "chrome-extension://peach-extension/",153 ),154 ).toBe(false);155 });156});