3e34a4a87aa1
add browser + transports fields to PasskeyEntry, export detectBrowser, tag chrome creates
- time
- 2026-04-28 18:25 UTC · 6 months ago
- machine
- koh2
- parent
- 6b53ab782017
↓ peach-browser-3e34a4a8.tar.gzatlas at this save
files changed4 files
src/background/passkey.ts+13 −0src/popup/styles/popup.css+232 −0src/popup/views/Settings.tsx+13 −0src/shared/types.ts+8 −0src/background/passkey.ts+13 −0
@@ -36,6 +36,17 @@3636 return typeof chrome.webAuthenticationProxy?.attach === "function";3737 }3838 39+export function detectBrowser(): "chrome" | "firefox" | "unknown" {40+ if (typeof chrome !== "undefined" && chrome.webAuthenticationProxy) {41+ return "chrome";42+ }43+ try {44+ const url = chrome.runtime?.getURL?.("") ?? "";45+ if (url.startsWith("moz-extension://")) return "firefox";46+ } catch { /* extension context unavailable */ }47+ return "unknown";48+}49+3950 function getBrowserLabel(): string {4051 const ua = navigator.userAgent;4152 if (/Firefox\/(\d+)/.test(ua)) {@@ -305,6 +316,8 @@305316 aaguid: base64urlEncode(new Uint8Array(16)),306317 backupEligible: true,307318 backupState: false,319+ browser: "chrome",320+ transports: ["internal"],308321 createdAt: Date.now(),309322 modifiedAt: Date.now(),310323 };src/popup/styles/popup.css+232 −0
@@ -6049,3 +6049,235 @@60496049 transparent 60%60506050 );60516051 }6052+6053+/* ── Danger zone (Settings home → Panic flow) ──────────────────────────── */6054+.peach-danger-zone {6055+ border-top: 1px solid rgba(220, 38, 38, 0.3);6056+ margin: 24px 16px 0;6057+ padding-top: 20px;6058+}6059+6060+.peach-danger-zone-label {6061+ margin: 0 0 12px;6062+ font-family: "IBM Plex Mono", monospace;6063+ font-size: 10px;6064+ letter-spacing: 0.1em;6065+ color: rgba(220, 38, 38, 0.7);6066+}6067+6068+.peach-destroy-button {6069+ width: 100%;6070+ padding: 10px;6071+ background: transparent;6072+ border: 1px solid rgba(220, 38, 38, 0.4);6073+ border-radius: 8px;6074+ color: rgba(220, 38, 38, 0.7);6075+ font-size: 13px;6076+ cursor: pointer;6077+ transition: background 150ms ease, border-color 150ms ease, color 150ms ease;6078+}6079+6080+.peach-destroy-button:hover {6081+ background: rgba(220, 38, 38, 0.08);6082+ border-color: rgba(220, 38, 38, 0.7);6083+ color: rgb(220, 38, 38);6084+}6085+6086+/* ── Panic flow (three-step destruction) ───────────────────────────────── */6087+.peach-panic {6088+ display: flex;6089+ flex-direction: column;6090+ height: 100%;6091+ padding: 28px 20px 20px;6092+ gap: 18px;6093+ overflow-y: auto;6094+}6095+6096+.peach-panic-step2 {6097+ background: rgba(220, 38, 38, 0.04);6098+}6099+6100+.peach-panic-step3 {6101+ background: #0f0505;6102+ color: #ffffff;6103+}6104+6105+.peach-panic-icon {6106+ font-size: 32px;6107+ color: rgb(220, 38, 38);6108+ line-height: 1;6109+}6110+6111+.peach-panic-title {6112+ margin: 0;6113+ font-size: 18px;6114+ font-weight: 500;6115+ color: var(--peach-t1);6116+}6117+6118+.peach-panic-title--severe {6119+ font-size: 20px;6120+ font-weight: 700;6121+ color: rgb(220, 38, 38);6122+}6123+6124+.peach-panic-body {6125+ margin: 0;6126+ font-size: 13px;6127+ line-height: 1.55;6128+ color: var(--peach-t2);6129+}6130+6131+.peach-panic-body--severe {6132+ color: rgba(220, 38, 38, 0.85);6133+}6134+6135+.peach-panic-body--final {6136+ font-size: 16px;6137+ font-weight: 700;6138+ color: rgb(255, 80, 80);6139+ line-height: 1.4;6140+}6141+6142+.peach-panic-body--final-intro {6143+ font-size: 16px;6144+ color: #ffffff;6145+ font-weight: 400;6146+}6147+6148+.peach-panic-divider {6149+ height: 1px;6150+ background: rgba(255, 255, 255, 0.08);6151+ margin: 4px 0;6152+}6153+6154+.peach-panic-confirm-input {6155+ width: 100%;6156+ padding: 10px 12px;6157+ background: rgba(255, 255, 255, 0.02);6158+ border: 1px solid rgba(220, 38, 38, 0.4);6159+ border-radius: 8px;6160+ color: var(--peach-t1);6161+ font-family: "IBM Plex Mono", monospace;6162+ font-size: 14px;6163+ letter-spacing: 0.12em;6164+ text-transform: uppercase;6165+}6166+6167+.peach-panic-confirm-input:focus {6168+ outline: none;6169+ border-color: rgb(220, 38, 38);6170+}6171+6172+.peach-panic-confirm-input--match {6173+ border-color: rgb(220, 38, 38);6174+ color: rgb(220, 38, 38);6175+}6176+6177+.peach-panic-confirm-label {6178+ font-size: 11px;6179+ color: var(--peach-t2);6180+ margin: 0 0 -8px;6181+ letter-spacing: 0.06em;6182+}6183+6184+.peach-panic-actions {6185+ display: flex;6186+ flex-direction: column;6187+ gap: 10px;6188+ margin-top: auto;6189+}6190+6191+.peach-panic-button {6192+ width: 100%;6193+ padding: 12px;6194+ border-radius: 8px;6195+ font-size: 13px;6196+ cursor: pointer;6197+ transition: background 150ms ease, border-color 150ms ease, color 150ms ease;6198+}6199+6200+.peach-panic-button--primary {6201+ background: var(--peach-accent);6202+ border: 1px solid var(--peach-accent);6203+ color: #ffffff;6204+ font-weight: 600;6205+}6206+6207+.peach-panic-button--primary:hover {6208+ background: color-mix(in srgb, var(--peach-accent) 88%, white);6209+}6210+6211+.peach-panic-button--danger {6212+ background: rgb(220, 38, 38);6213+ border: 1px solid rgb(220, 38, 38);6214+ color: #ffffff;6215+ font-weight: 600;6216+}6217+6218+.peach-panic-button--danger:disabled {6219+ opacity: 0.35;6220+ cursor: not-allowed;6221+}6222+6223+.peach-panic-button--ghost {6224+ background: transparent;6225+ border: 1px solid rgba(255, 255, 255, 0.18);6226+ color: var(--peach-t2);6227+}6228+6229+.peach-panic-button--ghost:hover {6230+ border-color: rgba(255, 255, 255, 0.32);6231+ color: var(--peach-t1);6232+}6233+6234+.peach-panic-link {6235+ background: transparent;6236+ border: none;6237+ padding: 4px 0;6238+ color: rgba(220, 38, 38, 0.65);6239+ font-size: 12px;6240+ cursor: pointer;6241+ text-align: left;6242+ text-decoration: underline;6243+ text-underline-offset: 3px;6244+}6245+6246+.peach-panic-link:hover {6247+ color: rgb(220, 38, 38);6248+}6249+6250+.peach-panic-bar {6251+ background: rgb(220, 38, 38);6252+ padding: 16px 20px;6253+ margin: -28px -20px 0;6254+ text-align: center;6255+ font-size: 13px;6256+ font-weight: 700;6257+ letter-spacing: 0.12em;6258+ color: #ffffff;6259+}6260+6261+.peach-panic-final-button {6262+ width: 100%;6263+ padding: 14px;6264+ background: rgb(220, 38, 38);6265+ border: none;6266+ border-radius: 8px;6267+ color: #ffffff;6268+ font-size: 14px;6269+ font-weight: 700;6270+ letter-spacing: 0.08em;6271+ text-transform: uppercase;6272+ cursor: pointer;6273+ animation: peach-panic-pulse 2s ease-in-out infinite;6274+}6275+6276+@keyframes peach-panic-pulse {6277+ 0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.4); }6278+ 50% { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0); }6279+}6280+6281+[data-motion="reduce"] .peach-panic-final-button {6282+ animation: none;6283+}src/popup/views/Settings.tsx+13 −0
@@ -55,6 +55,7 @@5555 onOpenHealth?: () => void;5656 onOpenSyncPairing?: (mode: "initiate" | "accept") => void;5757 onOpenFileImport?: () => void;58+ onOpenPanic?: () => void;5859 }5960 6061 type SectionName =@@ -564,6 +565,18 @@564565 565566 <p class="peach-settings-nav-label">SUPPORT</p>566567 {renderCatRow({ section: "feedback", name: "Feedback", desc: "Report issues, suggest features", icon: iconBubble })}568+569+ <Show when={props.onOpenPanic}>570+ <div class="peach-danger-zone">571+ <p class="peach-danger-zone-label">⚠ DANGER ZONE</p>572+ <button573+ class="peach-destroy-button"574+ onClick={() => props.onOpenPanic?.()}575+ >576+ Destroy vault577+ </button>578+ </div>579+ </Show>567580 568581 <div class="peach-settings-footer">569582 <span>Peach {version}</span>src/shared/types.ts+8 −0
@@ -66,6 +66,11 @@6666 backupEligible?: boolean;6767 backupState?: boolean;6868 lastUsedAt?: number;69+ // Passkeys are not portable between browsers: a Chrome passkey holds its70+ // private key in Peach's vault, while a Firefox passkey delegates to the71+ // platform authenticator. Tag each entry so the UI can warn cross-browser.72+ browser?: "chrome" | "firefox";73+ transports?: string[];6974 // Card entry fields7075 cardholderName?: string;7176 cardNumber?: string; // full PAN, stored encrypted in vault@@ -116,6 +121,9 @@116121 backupEligible: boolean;117122 backupState: boolean;118123 lastUsedAt?: number;124+ // Optional on read for pre-v2.10.0 entries; new entries always set it.125+ browser?: "chrome" | "firefox";126+ transports?: string[];119127 }120128 121129 export interface PendingPasskeyRequest {