befb31137ebb

feat: UI-8 homograph warning — non-blocking row in Entry URL editor + save.ts offer banner when page domain is non-ASCII/punycode

time
2026-06-10 03:37 UTC · 4 months ago
machine
koh2
agent
claude-opus-4-8
session
audit fix integration
parent
41ef91e27e40
3 files src/content/save.ts+17 −1src/popup/styles/popup.css+11 −0src/popup/views/Entry.tsx+13 −1
src/content/save.ts+17 −1
@@ -1,4 +1,4 @@1-import { extractDomain } from "../shared/domain";1+import { detectHomograph, extractDomain } from "../shared/domain";22 import { ACCENT_COLORS } from "../shared/types";33 import type { VaultEntry } from "../shared/types";44 @@ -110,6 +110,13 @@110110       color: rgba(240,232,216,0.42);111111       margin: 0 0 12px;112112     }113+    .banner-warn {114+      font-family: "IBM Plex Mono", "SFMono-Regular", monospace;115+      font-size: 10px;116+      line-height: 1.4;117+      color: #C8A840;118+      margin: 0 0 12px;119+    }113120     .banner-actions {114121       display: flex;115122       gap: 8px;@@ -155,6 +162,15 @@155162   const subEl = banner.appendChild(document.createElement("p"));156163   subEl.className = "banner-sub";157164   subEl.textContent = subtitle;165+166+  // UI-8 / LV-2: non-blocking homograph warning when the page's own address167+  // is non-ASCII or punycode — never blocks saving.168+  if (detectHomograph(location.hostname)) {169+    const warnEl = banner.appendChild(document.createElement("p"));170+    warnEl.className = "banner-warn";171+    warnEl.textContent =172+      "⚠ This site's address contains non-ASCII or punycode characters. Verify it's the site you intend.";173+  }158174 159175   const actionsEl = banner.appendChild(document.createElement("div"));160176   actionsEl.className = "banner-actions";

view file

src/popup/styles/popup.css+11 −0
@@ -648,6 +648,17 @@648648   color: var(--peach-t2);649649   margin-bottom: 2px;650650 }651+/* UI-8 / LV-2: non-blocking homograph warning under the URL editor. */652+.peach-homograph-warning {653+  margin: 4px 0 2px;654+  padding: 6px 8px;655+  border-radius: 6px;656+  background: color-mix(in srgb, var(--peach-breach) 12%, transparent);657+  border: 1px solid color-mix(in srgb, var(--peach-breach) 36%, transparent);658+  color: var(--peach-t1);659+  font-size: 0.6875rem;660+  line-height: 1.4;661+}651662 .peach-additional-url-row {652663   display: flex;653664   align-items: center;

view file

src/popup/views/Entry.tsx+13 −1
@@ -2,7 +2,7 @@22 import type { ProFeature, VaultEntry } from "../../shared/types";33 import { isPasskeyOnly } from "../../shared/types";44 import { detectBrowser } from "../../shared/browser";5-import { getDisplayDomain } from "../../shared/domain";5+import { detectHomograph, getDisplayDomain } from "../../shared/domain";66 import { faviconUrl, faviconImgSig, globeFaviconSig, titleInitials, titleBackground } from "../../shared/favicon";77 import { generateTOTP, parseOtpauthURI } from "../../crypto/totp";88 import { sendMessage, triggerPipPulse, triggerRing } from "../App";@@ -723,6 +723,18 @@723723                         />724724                         <InlineSaveCancelRow onSave={saveField} onCancel={cancelEdit} saving={saving()} />725725                       </div>726+                      <Show727+                        when={728+                          detectHomograph(draft()) ||729+                          additionalUrlsDraft().some((u) => detectHomograph(u))730+                        }731+                      >732+                        {/* UI-8 / LV-2: non-blocking homograph warning. */}733+                        <p class="peach-homograph-warning">734+                          ⚠ This URL contains non-ASCII or punycode characters.735+                          Verify it&apos;s the site you intend.736+                        </p>737+                      </Show>726738                       <div class="peach-additional-urls">727739                         <Show when={additionalUrlsDraft().length > 0}>728740                           <span class="peach-label peach-additional-urls-label">also matches</span>

view file