Skip to content

fix(privacy): keep private feed addresses out of generated notes - #454

Merged
chhoumann merged 8 commits into
masterfrom
fix/no-secret-in-notes
Oct 13, 2026
Merged

chhoumann merged 8 commits into
masterfrom
fix/no-secret-in-notes

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

Generated notes redact private feed addresses quoted in RSS metadata before Markdown conversion, filename formatting or URI encoding. Redaction also matches terminal-dot hosts and browser-valid slash aliases while preserving distinct episode and signed-media URLs.

An episode opened from an unsubscribed private feed keeps its live address for playback. Its generated note omits feedUrl, its resume output is empty, and captures, segments and published-transcript timestamps use plain time text. Existing notes are untouched. The feed cache stays device-local and is scrubbed when its metadata reaches a vault output.

Fixes #438. Fixes #441. Fixes #449.

Verification

Node 22.23.2. Real Obsidian 1.14.4 on Linux/Xvfb in this worktree's isolated vault. Synthetic Supercast-shaped feeds at http://priv3.supercast.com:44409/feeds/PRIV4_QUOTED_SENTINEL/feed.xml and /feeds/PRIV4_UNSUBSCRIBED_SENTINEL/feed.xml serve a 120-second WAV from http://podnotes.test:44409/audio.wav. Both hosts resolve to loopback in the isolated app.

Behavior Master 9b0eea8 PR head
Quoted addresses in cold and warm-cache notes Raw addresses and aliases Redacted; no sentinel
Terminal-dot and backslash aliases in data and export Sentinels present Redacted; signed media retained
Unsubscribed private episode note Raw frontmatter and encoded resume URL No feedUrl or resume URL; playback continues
Unsubscribed capture Encoded private feed URL Plain configured timestamp and segment
Existing raw subscribed note link Resolves to placeholder and plays Unchanged
Old raw v6 cache key before view opens Device-local key retained Unchanged

The final regression tests fail against current-master production sources (7bb28d3): 29 failed, 164 passed, including API capture and transcript timestamp regressions. The review fixes also had 11 failing regressions before their implementation.

The full runtime suite ran once: 122 passed, 1 failed. The failure is the mini-player status-bar overlap in #453; the focused test also fails with an independently built current-master bundle. All privacy and persistence runtime files passed. After the review fixes, the final privacy/persistence run passed all 17 tests.

Command Result
npm run lint 0 errors, 0 warnings
npm run format:check All matched files formatted
npm run typecheck Passed
npm run build Passed
npm run test 2,251 passed; Svelte checks clean
npm run test:tooling 13 passed
npm run docs:build 18 pages; internal links and 112 legacy fragments valid
npm run test:e2e 122 passed, 1 baseline UI failure (#453)
npm run test:e2e -- private-notes private-feeds sync-persistence 17 passed
npm run size 313,546 raw / 99,637 gzip bytes

Compared with current master, the bundle adds 596 raw / 225 gzip bytes and has 363 gzip bytes left under the gate. One independent review each from Claude Fable 5.1 and GPT-6 Astra informed the fixes.

Before | After: plain captures and no feed property | After: redacted subscribed note | Fixture, actual note bytes, screenshots and check logs

The initial focused run encountered an Obsidian IndexedDB error. A fresh isolated instance restored loading. The final replay reports no runtime errors.

API changes

Signatures are unchanged. buildEpisodeResumeLink(episode) returns "" when the episode's feed address carries credentials without a subscription placeholder, including when a downloaded copy exists. formatEpisodeTimestamp returns plain configured time text in that case, including when called through getPodcastTimeFormatted or getPodcastSegmentFormatted with linkify enabled. Captures, segment captures and published-transcript timestamps share that behavior. These outputs also omit links when the title or GUID quotes a known private feed address, since redacting the identity inside a link would make it unresolvable. One shared vaultSafeLinkTarget helper guards both link builders and frontmatter.

Release impact

No data schema or settings migration. No existing note rewrite. The URI handler and live episode retain their resolving identity. New vault output uses a subscription placeholder when available and omits an unsafe link otherwise.

Docs at release

  • notes.md and templates.md: explain private feed redaction in generated episode/feed notes, including metadata quoted in descriptions.
  • templates.md: document empty {{feedurl}} and {{episodelink}} output for unsubscribed credential-bearing feeds, and omitted feedUrl frontmatter.
  • api.md: document the unchanged signatures and changed output of the resume-link and linked timestamp APIs.
  • timestamps.md: explain that captures, segment captures and published-transcript timestamps become plain configured text when no safe feed target exists.
  • State that existing notes are not rewritten and the local cache is not synced with the vault.

Follow-ups

Note

Redact private feed addresses from generated notes and transcript output

Adds a private-feed redaction service in privateFeeds.ts and applies it across all template engines, note creation, timestamp/resume-link builders, and published transcript rendering. Private feed addresses are replaced with a saved-feed placeholder where one exists, and unsafe credential-bearing URLs are omitted entirely.

  • redactPrivateFeedAddresses in privateFeedUrl.ts now recognizes more URL aliases: slash and backslash protocol variants, trailing-dot hostnames, and HTML-encoded query separators
  • feedHtmlToMarkdown in TemplateEngine.ts redacts private addresses in feed HTML attributes and text before Markdown conversion
  • vaultSafeLinkTarget blocks links whose target or episode identity (title/GUID) would expose a private address; buildEpisodeResumeLink and formatEpisodeTimestamp return plain text or an empty link for unsafe feeds, even when a downloaded fallback exists
  • createPodcastNote.ts omits unsafe feed URL frontmatter; saved private feeds render their placeholder
  • Behavioral Change: episodes from credential-bearing feeds may now produce notes without feed frontmatter or deep links; check vaultSafeLinkTarget and the NoteTemplateEngine/FeedNoteTemplateEngine renderers if link or URL output changes unexpectedly

Macroscope summarized e19fd85.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Deploying podnotes with  Cloudflare Pages  Cloudflare Pages

Latest commit: e19fd85
Status: ✅  Deploy successful!
Preview URL: https://a249de52.podnotes.pages.dev
Branch Preview URL: https://fix-no-secret-in-notes.podnotes.pages.dev

View logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant