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 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -246,7 +246,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
|
|||||||
- [x] **M9 — Three time formatters.** `relTime` (LibraryView), `formatWhen` (HistoryView),
|
- [x] **M9 — Three time formatters.** `relTime` (LibraryView), `formatWhen` (HistoryView),
|
||||||
`fmtSchedule` (QueueItem) — consolidate into a date util. *Fixed: all three moved to
|
`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`.*
|
[`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.
|
`readUrlShortcut` (main/deeplink). Different `URL=` extractors for the same file format.
|
||||||
- [x] **M11 — Inconsistent clipboard access.** Reads use `navigator.clipboard.readText` (paste
|
- [x] **M11 — Inconsistent clipboard access.** Reads use `navigator.clipboard.readText` (paste
|
||||||
button) *and* `window.api.readClipboard` (suggestion watcher); writes use
|
button) *and* `window.api.readClipboard` (suggestion watcher); writes use
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { app, shell, type BrowserWindow } from 'electron'
|
|||||||
import { existsSync, openSync, readSync, closeSync } from 'fs'
|
import { existsSync, openSync, readSync, closeSync } from 'fs'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { assertHttpUrl } from './url'
|
import { assertHttpUrl } from './url'
|
||||||
|
import { parseUrlShortcutContent } from '@shared/ipc'
|
||||||
|
|
||||||
/** Only ever forward http(s) targets into the app — same restriction the
|
/** 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.
|
* 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')
|
fd = openSync(path, 'r')
|
||||||
const buf = Buffer.alloc(MAX_URL_FILE_BYTES)
|
const buf = Buffer.alloc(MAX_URL_FILE_BYTES)
|
||||||
const bytes = readSync(fd, buf, 0, buf.length, 0)
|
const bytes = readSync(fd, buf, 0, buf.length, 0)
|
||||||
const match = /^URL=(.+)$/im.exec(buf.toString('utf8', 0, bytes))
|
const url = parseUrlShortcutContent(buf.toString('utf8', 0, bytes))
|
||||||
const url = match?.[1]?.trim()
|
|
||||||
return url ? asHttpUrl(url) : null
|
return url ? asHttpUrl(url) : null
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { Select } from './Select'
|
|||||||
import { Hint } from './Hint'
|
import { Hint } from './Hint'
|
||||||
import { SegmentedControl } from './ui/SegmentedControl'
|
import { SegmentedControl } from './ui/SegmentedControl'
|
||||||
import { IconButton } from './ui/IconButton'
|
import { IconButton } from './ui/IconButton'
|
||||||
|
import { parseUrlShortcutContent } from '@shared/ipc'
|
||||||
import { useClipboardLink, looksLikeUrl } from '../useClipboardLink'
|
import { useClipboardLink, looksLikeUrl } from '../useClipboardLink'
|
||||||
import { logError } from '../reportError'
|
import { logError } from '../reportError'
|
||||||
import { THUMB_LG } from '../thumbSizes'
|
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. */
|
/** Pull the URL= target out of a dropped Windows .url Internet Shortcut file. */
|
||||||
function parseUrlFile(content: string): string | null {
|
function parseUrlFile(content: string): string | null {
|
||||||
const m = /^\s*URL\s*=\s*(\S+)/im.exec(content)
|
const url = parseUrlShortcutContent(content)
|
||||||
const url = m?.[1]?.trim()
|
|
||||||
return url && looksLikeUrl(url) ? url : null
|
return url && looksLikeUrl(url) ? url : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -771,6 +771,16 @@ export interface TerminalRunResult {
|
|||||||
error?: string
|
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). */
|
/** Overall queue state for the Windows taskbar progress bar (Phase O). */
|
||||||
export interface TaskbarProgress {
|
export interface TaskbarProgress {
|
||||||
/** 0..1 overall fraction; ignored when mode is 'none' */
|
/** 0..1 overall fraction; ignored when mode is 'none' */
|
||||||
|
|||||||
Reference in New Issue
Block a user