12345678910111213141516import { test, expect, type BrowserContext } from "@playwright/test";17import { makeContext, setupVault, addEntry } from "./helpers/vault";1819test.describe.configure({ timeout: 120_000 });2021test.describe("PB-26-201 @security: hostile page cannot obtain foreign secrets", () => {22 let ctx: BrowserContext;2324 test.beforeEach(async () => {25 ctx = await makeContext("pb26201-sentinel");26 });2728 test.afterEach(async () => {29 await ctx.close();30 });3132 test("content script GET_ENTRY_FOR_EDIT is denied (@security)", async () => {33 const { popup } = await setupVault(ctx);34 await addEntry(popup, {35 title: "Foreign Entry",36 url: "https://example.org/login",37 username: "[email protected]",38 password: "foreign-secret-totally-private",39 });4041 const page = await ctx.newPage();42 await page.goto("https://example.com/");4344 const result = await popup.evaluate(async () => {45 const tabs = await chrome.tabs.query({ url: "https://example.com/*" });46 const tab = tabs.find((t) => t.id !== undefined);47 if (!tab?.id) throw new Error("test page tab not found");4849 const exec = await chrome.scripting.executeScript({50 target: { tabId: tab.id },51 func: async () => {52 const editResp = await chrome.runtime.sendMessage({53 type: "GET_ENTRY_FOR_EDIT",54 payload: { id: "any-id" },55 });56 return { editResp };57 },58 });59 return exec[0]?.result as { editResp: { ok?: boolean; error?: string } };60 });6162 expect(result?.editResp?.ok).toBe(false);63 expect(result?.editResp?.error).toBe("invalid_sender");64 });6566 test("userGesture and explicitSummon Booleans cannot authorize GET_ENTRIES (@security)", async () => {67 const { popup } = await setupVault(ctx);68 await addEntry(popup, {69 title: "Secret Vault Entry",70 url: "https://example.org/login",71 username: "[email protected]",72 password: "should-never-leak",73 });7475 const page = await ctx.newPage();76 await page.goto("https://example.com/");7778 const result = await popup.evaluate(async () => {79 const tabs = await chrome.tabs.query({ url: "https://example.com/*" });80 const tab = tabs.find((t) => t.id !== undefined);81 if (!tab?.id) throw new Error("test page tab not found");8283 const exec = await chrome.scripting.executeScript({84 target: { tabId: tab.id },85 func: async () => {86 const entriesResp = await chrome.runtime.sendMessage({87 type: "GET_ENTRIES",88 payload: { includeAll: true, userGesture: true, explicitSummon: true },89 });90 return { entriesResp };91 },92 });93 return exec[0]?.result as { entriesResp: { ok?: boolean; error?: string } };94 });9596 expect(result?.entriesResp?.ok).toBe(false);97 expect(result?.entriesResp?.error).toBe("invalid_sender");98 });99100 test("AUTOFILL_QUERY on hostile page returns no foreign passwords or TOTP seeds (@security)", async () => {101 const { popup } = await setupVault(ctx);102 await addEntry(popup, {103 title: "Example Org",104 url: "https://example.org/login",105 username: "[email protected]",106 password: "foreign-pass-12345",107 totp: "JBSWY3DPEHPK3PXP",108 });109110 const page = await ctx.newPage();111 await page.goto("https://example.com/");112113 const result = await popup.evaluate(async () => {114 const tabs = await chrome.tabs.query({ url: "https://example.com/*" });115 const tab = tabs.find((t) => t.id !== undefined);116 if (!tab?.id) throw new Error("test page tab not found");117118 const exec = await chrome.scripting.executeScript({119 target: { tabId: tab.id },120 func: async () => {121 122 123 const queryResp = await chrome.runtime.sendMessage({124 type: "AUTOFILL_QUERY",125 payload: { explicitSummon: true, userGesture: true },126 });127 return { queryResp: JSON.stringify(queryResp) };128 },129 });130 return exec[0]?.result as { queryResp: string };131 });132133 134 135 expect(result?.queryResp).not.toContain("foreign-pass-12345");136 expect(result?.queryResp).not.toContain("JBSWY3DPEHPK3PXP");137 expect(result?.queryResp).not.toContain("example.org");138 });139});140141test.describe("PB-26-203 @security: content script cannot read session storage key", () => {142 let ctx: BrowserContext;143144 test.beforeEach(async () => {145 ctx = await makeContext("pb26203-sentinel");146 });147148 test.afterEach(async () => {149 await ctx.close();150 });151152 test("content script cannot read peach_session_dk from storage.session after unlock (@security)", async () => {153 const { popup } = await setupVault(ctx);154155 156 const page = await ctx.newPage();157 await page.goto("https://example.com/");158159 const result = await popup.evaluate(async () => {160 const tabs = await chrome.tabs.query({ url: "https://example.com/*" });161 const tab = tabs.find((t) => t.id !== undefined);162 if (!tab?.id) throw new Error("test page tab not found");163164 const exec = await chrome.scripting.executeScript({165 target: { tabId: tab.id },166 func: async () => {167 168 169 170 171 try {172 const data = await chrome.storage.session.get("peach_session_dk");173 return {174 accessible: true,175 hasKey: "peach_session_dk" in data,176 keys: Object.keys(data),177 };178 } catch (e) {179 return { accessible: false, error: String(e) };180 }181 },182 });183 return exec[0]?.result as {184 accessible: boolean;185 hasKey?: boolean;186 keys?: string[];187 error?: string;188 };189 });190191 192 193 expect(result?.accessible).toBe(false);194195 196 197 const extAccess = await popup.evaluate(async () => {198 try {199 const data = await chrome.storage.session.get("peach_session_dk");200 return { hasKey: "peach_session_dk" in data };201 } catch {202 return { hasKey: false };203 }204 });205 expect(extAccess?.hasKey).toBe(true);206 });207});