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
4 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/views/Entry.tsx+97 −76
manifest.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": {

view file

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",

view file

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": {

view file

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 ─────────────────────────────────── */}

view file