Commit graph

161 commits

Author SHA1 Message Date
liyachen
fc6aeb9f42 release: 0.4.3 — plugin review fixes 2026-07-18 21:31:16 -04:00
liyachen
d1ddf50f94 fix: address plugin review errors (await revealLeaf, replace inline styles with CSS class) 2026-07-18 21:31:16 -04:00
liyachen
5f98c8dcc3 fix: remove 'Obsidian' from manifest description per plugin guidelines 2026-07-18 19:10:41 -04:00
liyachen
ae46c553e9 docs: remove internal pre-release audit from public repo
Detailed the (now-fixed) SSRF/injection attack paths; no need to publish
it on a plugin heading for store review. Kept in git history and locally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:42:29 -04:00
liyachen
deaa5a29ab release: 0.4.2 — pre-submission audit fixes
Merges 12 audited fixes (5 data-integrity, 2 security, 6 robustness)
plus a final-review SSRF trailing-dot fix. No /clip contract change.
170/170 tests, tsc clean. Y1 verified end-to-end in Obsidian; F (SSRF)
verified end-to-end via localhost probes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:35:42 -04:00
liyachen
6abf716e96 release: 0.4.2 (pre-submission audit fixes)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:16:18 -04:00
liyachen
074ecf9bc9 fix: close trailing-dot bypass in private-host check
new URL() keeps the trailing dot on FQDN hostnames ('localhost.',
'printer.local.') while stripping it from IPv4, so those slipped past
the loopback/.local literal checks. Strip one trailing dot before the
compares. Found in final whole-branch review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:15:20 -04:00
liyachen
99f8435e41 fix: handle client aborts during request body read
A client disconnect mid-POST emits 'error' on the request stream; with
no listener Node rethrew it as an uncaught exception (renderer console
noise). Added a no-op error listener — the socket is already gone, so
there is nothing to respond to.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:09:47 -04:00
liyachen
fbcbbb0701 fix: survive server restart races and surface listen failures
restartServer now rebinds inside close()'s callback instead of the same
tick, closing the close->listen race that produced EADDRINUSE. A failed
listen (EADDRINUSE or otherwise) nulls the server reference and shows a
Notice, so /ping and clips stop silently pretending the server is up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:07:09 -04:00
liyachen
596c8f87c9 fix: restart server when port setting changes
The port onChange only saved the value; the server kept listening on the
old port until Obsidian restarted. It now restarts so a port change takes
effect immediately (no unit test — settings UI has none per convention;
verified by reading + tsc).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:05:46 -04:00
liyachen
bd47b6250a test: lock null title never renders '# undefined'
The coercion itself landed in the injection-hardening commit (inlineText
coerces null/undefined to ''); this pins the behavior as a regression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:05:27 -04:00
liyachen
1077a282e1 fix: recognize YouTube Shorts and Live URLs as the same video
/shorts/<id> and /live/<id> now extract the id (instead of falling back
to the full URL), so the same video clipped from a Shorts or Live URL
merges into one note and gets its gallery cover. Hook mode is exactly
the Shorts use case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:04:54 -04:00
liyachen
af8427dfa5 fix: harden frontmatter and body interpolation against injection
platform/published now go through yamlString (a crafted value could
inject frontmatter keys; a legit value with a colon broke parsing).
Untrusted titles are newline/backtick-stripped before body headings,
transcripts backtick-stripped (with Dataview JS enabled an injected
dataviewjs fence executes on render). Filenames also drop backticks.
clip-validate gains type-only checks for optional string fields —
verified against the extension contract tests, which pass unmodified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 18:03:23 -04:00
liyachen
6427fbafde fix: reject private/loopback thumbnail hosts
The CSRF-reachable /clip endpoint let a malicious page point
thumbnail_url at localhost, LAN, or cloud-metadata addresses and write
the response into the vault. assertDownloadable now blocks literal
loopback/private/link-local hosts (IPv4 incl. parser-normalized hex
forms, IPv6 incl. v4-mapped, localhost, .local). DNS-rebinding
protection deliberately out of scope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:58:31 -04:00
liyachen
99ed675a1a fix: serialize clip handling to prevent concurrent-clip races
Double-clicks and extension retries interleaved read-modify-write on the
same note (last writer dropped the other's section) and raced
vault.create for new videos. All clips now run through a serial queue;
a failed clip still answers its own request and never blocks the next.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:54:40 -04:00
liyachen
6f8c35e75e fix: match notes via metadataCache so Properties edits don't orphan them
Obsidian's Properties editor re-serializes frontmatter (drops quotes,
rewrites inline lists to block style), which broke the exact-substring
video_id match and the addDimension regex — every later clip created a
permanent duplicate note. Cache misses (just-created notes) fall back
to a quote-tolerant scan; cached non-matches skip the file read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:51:40 -04:00
liyachen
25b0f5b029 fix: slice Buffer pool view before writing image binaries
Buffers under ~4 KB are views into Node's shared 8 KB pool; passing
.buffer raw wrote the whole pool (with unrelated memory) as the image.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:47:34 -04:00
liyachen
362cddf39d fix: strip Obsidian-reserved chars [ ] # ^ from filenames
Titles like '[Official Video]' or 'C#' produced names Obsidian rejects
or that break the ![[...]] embed syntax.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:45:01 -04:00
liyachen
7f5d9f15cc fix: preserve user-added headings during clip merge
Unrecognized ## headings no longer fall back to kind='motion' (which
rewrote the heading text and re-sorted the section). Unknown sections
keep their exact text and sort after all known sections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:44:04 -04:00
liyachen
0a0eeaf066 docs: pre-release audit findings (18 issues, scoped fix plan)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 17:18:25 -04:00
liyachen
47ec3d5956 fix: replace hardcoded colors with Obsidian CSS variables for theme compatibility
Community plugin review requires theme-aware colors. Also document why
SOP loading uses Node fs instead of the Vault API (absolute paths may
point outside the vault).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 16:45:28 -04:00
liyachen
b42b5722e6 release: 0.4.1 (security hardening for the local /clip endpoint) 2026-07-18 14:49:29 -04:00
liyachen
235aff9358 docs: document the unauthenticated-by-design local endpoint and its worst case 2026-07-18 14:41:01 -04:00
liyachen
2d1719ef24 build: rebuild main.js with cross-review security fixes 2026-07-18 14:35:25 -04:00
liyachen
171aa6f7c9 test: lock the extension->backend /clip contract against drift 2026-07-18 14:34:42 -04:00
liyachen
e5da359fcb fix: save video frames with a .jpg extension matching their JPEG bytes 2026-07-18 14:31:09 -04:00
liyachen
d56e0a7307 fix(security): restrict outbound cover/thumbnail fetches to http(s) with a size cap 2026-07-18 14:29:36 -04:00
liyachen
14a72e9f8c feat(security): validate and normalize /clip payloads; stop leaking error internals 2026-07-18 14:28:21 -04:00
liyachen
06901b74c9 fix: clamp out-of-range persisted port to the default 2026-07-18 14:26:04 -04:00
liyachen
8118b43a64 fix(security): escape untrusted values written to note frontmatter 2026-07-18 14:24:55 -04:00
liyachen
f3b78d2bdf fix(security): sanitize thumbnail video_id before using it as a vault path 2026-07-18 14:23:40 -04:00
liyachen
6998b503c7 docs: extension repo renamed to visual-clipper 2026-07-17 23:00:13 -04:00
liyachen
dca3f72040 docs: fix extension repo links to echore/obsidian-visual-clipper 2026-07-17 22:54:23 -04:00
liyachen
f8bb01fbee release: 0.4.0 (publish dates in notes and gallery, Live Preview embed fix, SOP sync)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 21:45:08 -04:00
liyachen
a7fd3dab55 feat(sops): sync bundled SOPs with rewritten vault versions (2026-07-17)
All 3 SOPs (cover/hook/keyframe, zh+en) updated to the new point-at-things
analysis framework. Vault frontmatter stripped; en-dashes in EN copies
replaced with hyphens to satisfy the no-dash style test.
2026-07-17 21:35:32 -04:00
liyachen
bf55ad1d45 feat(gallery): show video publish date on cards, clip date as fallback
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:11:34 -04:00
liyachen
abd47cb079 feat(clip): carry published_at into note frontmatter with upsert backfill
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:03:36 -04:00
liyachen
9d0a8b9a28 fix(styles): 16:9 embed fix now applies in Live Preview too
The aspect-ratio rule only matched reading-view containers
(.markdown-preview-view / .markdown-rendered), so in Live Preview the
iframe fell back to its fixed height="315" and rendered squashed.
Add .markdown-source-view to cover CM6 html embeds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 17:32:19 -04:00
liyachen
e0c39433fa release: 0.3.0 (native video library gallery) 2026-07-16 23:05:27 -04:00
liyachen
f995b1b962 chore: rebuild main.js with gallery view 2026-07-16 22:31:20 -04:00
liyachen
b19e75a408 feat(gallery): ship styles.css (gallery styles + scoped 16:9 embed fix) 2026-07-16 22:31:01 -04:00
liyachen
76cb9d245f feat(gallery): native video library view with data-driven chips (bilingual) 2026-07-16 22:29:59 -04:00
liyachen
170dae98ab feat(gallery): pure model layer for the video library view 2026-07-16 22:27:23 -04:00
liyachen
6b8bcf1031 docs: community plugin market submission checklist and steps 2026-07-16 21:56:33 -04:00
liyachen
6a37801d89 release: 0.2.0 (base folder, built-in SOPs with customize fork) 2026-07-16 21:55:38 -04:00
liyachen
e34c2ada38 feat(sop): built-in SOPs on by default with per-mode customize fork
- Empty sopPath now falls back to the mode's bundled SOP (master switch
  useBuiltinSops, default on); a filled path always wins, and a broken
  path falls back to built-in instead of dropping the analysis block.
- Settings: Analysis SOPs section with per-row state line (built-in /
  custom / off) and a Customize button that forks the built-in into
  <base>/SOPs and points the path at the copy. Install-all button removed.
- sopPath accepts vault-relative paths (readFileSync resolves them).
- Bundled SOP files carry no personal vault frontmatter (regression test).
- All strings bilingual (en + zh).
2026-07-16 21:53:50 -04:00
liyachen
2843a5114a chore: rebuild main.js with base folder and bundled SOPs 2026-07-16 21:02:10 -04:00
liyachen
534435a4ae feat(settings): bundle bilingual SOPs with one-click install into <base>/SOPs 2026-07-16 21:01:18 -04:00
liyachen
415b200370 feat(settings): Base folder row drives the four storage paths; restore defaults button 2026-07-16 20:57:02 -04:00
liyachen
6019e606dd feat(settings): baseFolder with deriveFolders/applyBaseFolder derivation 2026-07-16 20:44:14 -04:00