From 2f59a6ce635f653084f0e9bc258c468432ecb50d Mon Sep 17 00:00:00 2001 From: debont80 Date: Tue, 30 Jun 2026 14:35:00 -0400 Subject: [PATCH] Fix M10: consolidate .url Internet Shortcut parsing into shared utility Both DownloadBar (renderer, drag-drop) and deeplink.ts (main, argv) had their own regex to extract URL= from a Windows Internet Shortcut file -- with subtly different patterns (/^\s*URL\s*=\s*(\S+)/ vs /^URL=(.+)$/). Added parseUrlShortcutContent() to @shared/ipc. Both callers now delegate to it and apply their own http/https guard (looksLikeUrl in renderer, asHttpUrl in main). The local parseUrlFile wrapper in DownloadBar is kept as the validation compositing point; it's now a one-liner. typecheck + 242 tests green. Co-Authored-By: Claude Opus 4.8 --- CODE-AUDIT.md | 2 +- src/main/deeplink.ts | 4 ++-- src/renderer/src/components/DownloadBar.tsx | 4 ++-- src/shared/ipc.ts | 10 ++++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index eab18b7..2534a62 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -246,7 +246,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n - [x] **M9 — Three time formatters.** `relTime` (LibraryView), `formatWhen` (HistoryView), `fmtSchedule` (QueueItem) — consolidate into a date util. *Fixed: all three moved to [`datetime.ts`](src/renderer/src/datetime.ts) and imported by their views; unit-tested in `test/datetime.test.ts`.* -- [ ] **M10 — `.url` shortcut parsing duplicated** — `parseUrlFile` (DownloadBar) vs +- [x] **M10 — `.url` shortcut parsing duplicated** — `parseUrlFile` (DownloadBar) vs `readUrlShortcut` (main/deeplink). Different `URL=` extractors for the same file format. - [x] **M11 — Inconsistent clipboard access.** Reads use `navigator.clipboard.readText` (paste button) *and* `window.api.readClipboard` (suggestion watcher); writes use diff --git a/src/main/deeplink.ts b/src/main/deeplink.ts index 615de18..20f2d39 100644 --- a/src/main/deeplink.ts +++ b/src/main/deeplink.ts @@ -2,6 +2,7 @@ import { app, shell, type BrowserWindow } from 'electron' import { existsSync, openSync, readSync, closeSync } from 'fs' import { join } from 'path' import { assertHttpUrl } from './url' +import { parseUrlShortcutContent } from '@shared/ipc' /** Only ever forward http(s) targets into the app — same restriction the * external-link window-open handler in index.ts applies to in-page links. @@ -29,8 +30,7 @@ function readUrlShortcut(path: string): string | null { fd = openSync(path, 'r') const buf = Buffer.alloc(MAX_URL_FILE_BYTES) const bytes = readSync(fd, buf, 0, buf.length, 0) - const match = /^URL=(.+)$/im.exec(buf.toString('utf8', 0, bytes)) - const url = match?.[1]?.trim() + const url = parseUrlShortcutContent(buf.toString('utf8', 0, bytes)) return url ? asHttpUrl(url) : null } catch { return null diff --git a/src/renderer/src/components/DownloadBar.tsx b/src/renderer/src/components/DownloadBar.tsx index 6f8e259..a438bdc 100644 --- a/src/renderer/src/components/DownloadBar.tsx +++ b/src/renderer/src/components/DownloadBar.tsx @@ -36,6 +36,7 @@ import { Select } from './Select' import { Hint } from './Hint' import { SegmentedControl } from './ui/SegmentedControl' import { IconButton } from './ui/IconButton' +import { parseUrlShortcutContent } from '@shared/ipc' import { useClipboardLink, looksLikeUrl } from '../useClipboardLink' import { logError } from '../reportError' import { THUMB_LG } from '../thumbSizes' @@ -52,8 +53,7 @@ function firstUrl(text: string): string | null { /** Pull the URL= target out of a dropped Windows .url Internet Shortcut file. */ function parseUrlFile(content: string): string | null { - const m = /^\s*URL\s*=\s*(\S+)/im.exec(content) - const url = m?.[1]?.trim() + const url = parseUrlShortcutContent(content) return url && looksLikeUrl(url) ? url : null } diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index aa970d3..6b7cfad 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -771,6 +771,16 @@ export interface TerminalRunResult { error?: string } +/** + * Extract the `URL=` value from a Windows Internet Shortcut (.url) file's content. + * Returns the raw URL string (untrimmed), or null if not found. + * Callers validate the result with their own http/https check. + */ +export function parseUrlShortcutContent(text: string): string | null { + const m = /^\s*URL\s*=\s*(\S+)/im.exec(text) + return m?.[1]?.trim() ?? null +} + /** Overall queue state for the Windows taskbar progress bar (Phase O). */ export interface TaskbarProgress { /** 0..1 overall fraction; ignored when mode is 'none' */