a1ec5abcd016
canary and passkey collapsed under + Advanced toggle in entry view (v2.28.0)
- time
- 2026-05-03 13:34 UTC · 5 months ago
- machine
- koh2
- parent
- b3757502a1b3
↓ peach-browser-a1ec5abc.tar.gzatlas at this save
files changed4 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/views/Entry.tsx+97 −76manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.27.2",4+ "version": "2.28.0",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.27.2",4+ "version": "2.28.0",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "2.27.2",3+ "version": "2.28.0",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/views/Entry.tsx+97 −76
@@ -46,6 +46,8 @@4646 const [totpHot, setTotpHot] = createSignal(false);4747 const [faviconSrc, setFaviconSrc] = createSignal<string | null>(null);4848 const [noteEditorEl, setNoteEditorEl] = createSignal<HTMLDivElement | null>(null);49+ // Auto-open advanced when entry already has passkey or canary configured50+ const [showAdvanced, setShowAdvanced] = createSignal(false);4951 let lastSavedNote: string | null = null;5052 5153 function noteExec(cmd: string, val?: string) {@@ -87,13 +89,14 @@8789 setFaviconSrc(domain ? faviconUrl(domain) : null);8890 });8991 90- // Reset transient prompts (trash confirmation, inline edits) when the91- // selected entry changes so they don't carry over between entries.92+ // Reset transient prompts (trash confirmation, inline edits, advanced panel)93+ // when the selected entry changes so they don't carry over between entries.9294 createEffect(() => {9395 void props.entry?.id;9496 setConfirmDelete(false);9597 setEditingField(null);9698 setEditingTags(false);99+ setShowAdvanced(false);97100 });98101 99102 const totpState = createMemo(() => {@@ -1090,86 +1093,104 @@10901093 </Show>10911094 </Show>10921095 1093- {/* ── Passkey ──────────────────────────────────────── */}1094- <Show when={entry().passkey}>1095- {(passkey) => {1096- const currentBrowser = detectBrowser();1097- const crossBrowser =1098- passkey().browser &&1099- currentBrowser !== "unknown" &&1100- passkey().browser !== currentBrowser;1101- const algorithmLabel =1102- passkey().algorithm === -8 ? "EdDSA (Ed25519)" : "ES256 (P-256)";1103- const formatDate = (ts?: number) =>1104- ts ? new Date(ts).toLocaleDateString() : "Never";1105- return (1106- <section1107- class="peach-fields peach-passkey-section"1108- style="position:relative;z-index:1;margin-top:6px;"1096+ {/* ── Advanced (canary + passkey) ───────────────────── */}1097+ <Show when={entry().type === "login"}>1098+ <Show1099+ when={showAdvanced()}1100+ fallback={1101+ <button1102+ class="peach-add-field-link peach-entry-add-link"1103+ onClick={() => setShowAdvanced(true)}11091104 >1110- <div class="peach-field-card">1111- <span class="peach-label">passkey · {passkey().rpId}</span>1112- <div class="peach-field-value-row">1113- <span class="peach-field-value">{passkey().userName}</span>1114- <span class="peach-passkey-badge">passkey</span>1115- </div>1116- </div>1105+ + Advanced1106+ </button>1107+ }1108+ >1109+ <Show when={!isPasskeyOnly(entry())}>1110+ <CanarySection entry={entry()} onSaved={props.onFieldSaved} />1111+ </Show>11171112 1118- <div class="peach-field-card">1119- <span class="peach-label">algorithm</span>1120- <div class="peach-field-value-row">1121- <span class="peach-field-value">{algorithmLabel}</span>1122- </div>1123- </div>1113+ <Show when={entry().passkey}>1114+ {(passkey) => {1115+ const currentBrowser = detectBrowser();1116+ const crossBrowser =1117+ passkey().browser &&1118+ currentBrowser !== "unknown" &&1119+ passkey().browser !== currentBrowser;1120+ const algorithmLabel =1121+ passkey().algorithm === -8 ? "EdDSA (Ed25519)" : "ES256 (P-256)";1122+ const formatDate = (ts?: number) =>1123+ ts ? new Date(ts).toLocaleDateString() : "Never";1124+ return (1125+ <section1126+ class="peach-fields peach-passkey-section"1127+ style="position:relative;z-index:1;margin-top:6px;"1128+ >1129+ <div class="peach-field-card">1130+ <span class="peach-label">passkey · {passkey().rpId}</span>1131+ <div class="peach-field-value-row">1132+ <span class="peach-field-value">{passkey().userName}</span>1133+ <span class="peach-passkey-badge">passkey</span>1134+ </div>1135+ </div>11241136 1125- <div class="peach-field-card">1126- <span class="peach-label">activity</span>1127- <div class="peach-field-value-row peach-passkey-activity">1128- <span class="peach-field-value">1129- used {passkey().signCount} time{passkey().signCount === 1 ? "" : "s"}1130- </span>1131- <span class="peach-passkey-meta">1132- created {formatDate(passkey().createdAt)}1133- </span>1134- <span class="peach-passkey-meta">1135- last used {formatDate(passkey().lastUsedAt)}1136- </span>1137- </div>1138- </div>1137+ <div class="peach-field-card">1138+ <span class="peach-label">algorithm</span>1139+ <div class="peach-field-value-row">1140+ <span class="peach-field-value">{algorithmLabel}</span>1141+ </div>1142+ </div>11391143 1140- <Show when={crossBrowser}>1141- <div class="peach-info-notice peach-info-notice--warn">1142- {`This passkey was created on ${1143- passkey().browser === "chrome" ? "Chrome" : "Firefox"1144- }. To use it on ${1145- currentBrowser === "chrome" ? "Chrome" : "Firefox"1146- }, re-register it on this device.`}1147- </div>1148- </Show>1144+ <div class="peach-field-card">1145+ <span class="peach-label">activity</span>1146+ <div class="peach-field-value-row peach-passkey-activity">1147+ <span class="peach-field-value">1148+ used {passkey().signCount} time{passkey().signCount === 1 ? "" : "s"}1149+ </span>1150+ <span class="peach-passkey-meta">1151+ created {formatDate(passkey().createdAt)}1152+ </span>1153+ <span class="peach-passkey-meta">1154+ last used {formatDate(passkey().lastUsedAt)}1155+ </span>1156+ </div>1157+ </div>11491158 1150- <div class="peach-info-notice">1151- {passkey().browser === "firefox"1152- ? "This passkey is held by your platform authenticator. Peach stores only the metadata."1153- : "The private key is stored encrypted in your Peach vault and is never shown in the UI."}1154- </div>1159+ <Show when={crossBrowser}>1160+ <div class="peach-info-notice peach-info-notice--warn">1161+ {`This passkey was created on ${1162+ passkey().browser === "chrome" ? "Chrome" : "Firefox"1163+ }. To use it on ${1164+ currentBrowser === "chrome" ? "Chrome" : "Firefox"1165+ }, re-register it on this device.`}1166+ </div>1167+ </Show>11551168 1156- <button1157- class="peach-add-field-link peach-entry-add-link"1158- style="color:rgba(220,38,38,0.7);"1159- onClick={async () => {1160- const id = entry().id;1161- await sendMessage({1162- type: "UPDATE_ENTRY",1163- payload: { id, patch: { passkey: undefined } },1164- });1165- await props.onFieldSaved();1166- }}1167- >1168- − remove passkey1169- </button>1170- </section>1171- );1172- }}1169+ <div class="peach-info-notice">1170+ {passkey().browser === "firefox"1171+ ? "This passkey is held by your platform authenticator. Peach stores only the metadata."1172+ : "The private key is stored encrypted in your Peach vault and is never shown in the UI."}1173+ </div>1174+1175+ <button1176+ class="peach-add-field-link peach-entry-add-link"1177+ style="color:rgba(220,38,38,0.7);"1178+ onClick={async () => {1179+ const id = entry().id;1180+ await sendMessage({1181+ type: "UPDATE_ENTRY",1182+ payload: { id, patch: { passkey: undefined } },1183+ });1184+ await props.onFieldSaved();1185+ }}1186+ >1187+ − remove passkey1188+ </button>1189+ </section>1190+ );1191+ }}1192+ </Show>1193+ </Show>11731194 </Show>11741195 11751196 {/* ── Bottom spacer ─────────────────────────────────── */}