Repository navigation
fix: keep private feed secrets and vault files out of settings and OPML transfers - #404
Merged
Merged
Conversation
Each test fails on master: - an imported data.json keeps a private feed URL in queue, favorites and playlist episode snapshots on disk - re-importing an OPML that lists a saved private feed fetches it again and saves it a second time - a settings export carries Local Files and local-file episodes, and an import brings another vault's local files into this one
…ML transfers - Importing a data.json with a private feed now replaces its URL in queue, favorites, playlist and history snapshots too, not only in the feed list. Interning and scrubbing are one function, protectPrivateFeeds, used by both the load-time migration and the import. - Re-importing an OPML that lists a saved private feed recognizes it by its real URL, so it is skipped instead of fetched and saved a second time. - Settings export and import leave this vault's local files behind: Local Files is not exported, and local-file episodes are dropped from the queue, favorites and playlists. Playback progress now travels; on import this vault's progress wins and the file adds the rest. - The import dialog names the queue and favorites it replaces. - The OPML failure notice no longer points to a console that production builds strip.
…ML, keep progress imported during playback - On load, a saved private feed's real URL is replaced in episode snapshots too, so data.json files that an earlier import already leaked into are repaired once; a load that changes nothing writes nothing. - OPML import gives a saved private feed whose URL is not on this device the listed URL instead of dropping it as a duplicate title, so settings import plus OPML import moves private feeds between vaults. - Progress imported while an episode plays is no longer lost when the player saves a position during the import; the live store wins and the file adds the rest. - Import re-hydration trusts the codec's normalization instead of repeating it, and stale or narrating comments are removed.
… this device can resolve An episode snapshot's feedUrl, and its url when it fell back to the feed URL, becomes its podcast's placeholder whenever it is credential-bearing. This needs no secret on this device, so importing a backup that an older build already leaked into no longer writes the URL, and snapshots of unsubscribed private feeds are cleaned too. The load notice now reads accurately when a load only repairs snapshots.
# Conflicts: # src/ui/settings/PodNotesSettingsTab.ts
A load that cleans episode snapshots while a feed's URL still could not move into SecretStorage showed both the move notice and the failure notice. It now shows only the failure notice. A test pins that such a feed keeps its raw URL while its snapshots get the placeholder.
…nsfers Each fails on 3d5f9b0: - an episode without feedUrl keeps a saved private feed's URL - a feed saved under a key other than its title gets episode placeholders named by the title, which links cannot resolve - an import whose private feed URL SecretStorage cannot keep reports success and persists the URL - a playlist's current episode and progress records carry vault paths out of an export and into an import - a private feed synced to disk while an import saves is written raw
…ransfer - A private feed's real URL maps to the placeholder that names its saved key, and that mapping applies to an episode's url and feedUrl, so an episode without feedUrl loses the URL too and links still resolve when the saved key differs from the title. A private URL no saved feed matches still becomes its podcast's placeholder. - An import whose private feed URL SecretStorage cannot keep is refused before anything is written, with one notice shared with the API-key failure. - Settings transfers drop a playlist's current episode, which no player reads, and keep only title, podcast, time, duration and finished in progress records, so neither carries a vault path. - The writer protects the data.json it reads before merging it, so a private feed another device synced is never written back raw. - Both export error handlers show the error itself instead of a reworded copy for a missing folder.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moving PodNotes between vaults through settings export/import, a raw
data.jsonimport, or OPML is now safe for private feeds and leaves vault files behind.data.json. Importing adata.jsonwhose podcasts include a private feed (a URL with?auth=...oruser:pass@) used to protect the feed itself but keep the secret URL in every queued, favorited and playlist episode, where it stayed for good. Protecting a private feed and cleaning episode snapshots are now one function,protectPrivateFeeds, which the load path, the import, and the writer's read ofdata.jsonall call. A private feed's real URL maps to the placeholder that names its saved key, in an episode'surlandfeedUrlalike, so links keep resolving. A private URL no saved feed matches still becomes its podcast's placeholder. Vaults and backups that an earlier import leaked into are repaired once, a private feed that another device syncs in is never written back raw, and a load that changes nothing writes nothing.Small changes in the same code: the OPML failure notice no longer points at a console that production builds strip, the settings tab drops a try/catch around
importOPMLthat could never fire, both export error handlers show the error itself instead of a reworded copy for a missing folder, and the import trusts the codec's normalization instead of repeating it. These deletions keep the bundle below master's size.The first row is the import of vault X's settings into vault Y. The second row shows X's local file in Y's queue on master, and on this branch a private feed that arrived through a settings import, revived by an OPML import.
Verification
Obsidian 1.13.7 on headless Linux (Xvfb), in this worktree's isolated vault. Every scenario ran on master
6421261first, through Settings > PodNotes with the real file picker or by seedingdata.jsonwith the plugin off. A local fixture served a private feed athttp://127.0.0.1.nip.io:<port>/private/feed.xml?auth=<secret>, and the verify skill's fixtures servedPodNotes FixtureandFixtures/Local Fixture.wav. Counts are plaintext occurrences of the test secret indata.jsonor in the export file.data.jsonwith a private feed in saved feeds, queue, favorites and a playlistdata.jsondata.jsoninto a fresh vaulturlis the private feed URL and that has nofeedUrldata.jsonand 4 in the exportdata.jsonunchanged, 0 in the exportdata.jsonwhile an import savesUnit tests: each bug has a test that fails on master (commit
b27a826), and each V-404 finding has a test that fails on the earlier head3d5f9b0(commit177c49e). The import tests drive the real confirm dialog, a realdata.jsonwriter and the realPlayerController. Every new test was checked by reverting its fix and watching it fail. Three review rounds by Claude Fable 5.1 and GPT 6.0 Astra and the independent V-404 verification shaped the later commits.Release impact
No
data.jsonschema change. Private feeds keep SecretStorage and placeholders.data.jsonimport left a private feed URL in episode snapshots is rewritten once without it, with the notice "Moved private feed URLs out of data.json." The load-time notice no longer counts URLs.data.jsonfiles import as before, minus those entries.data.json.Docs at release
import_export.md, "Settings & templates": playback progress is now included. On import, progress is added for episodes this vault has not played, and this vault's own progress is kept. Local Files, local-file episodes in the queue, favorites and playlists, and download bookkeeping stay in their vault.import_export.md, "Importing settings": the confirmation names the feeds, playlists, queue and favorites it replaces. An import that cannot store a private feed URL or API key in SecretStorage is refused and changes nothing.import_export.md, OPML: importing an OPML that lists a private feed already saved here skips it. In a vault where that feed arrived through a settings import without its private URL, the OPML import restores it.sync.md, private feeds: besides removing and re-adding a private feed whose URL is missing on a device, importing an OPML that lists it now restores it.Not in this PR
filePath,size) on downloaded feed episodes in the queue still travel, though the target vault ignores them.data.jsonand the next load shows the existing failure notice, as on master.Note
Keep private feed secrets and vault-local files out of settings and OPML transfers
migratePrivateFeedUrlsandscrubMigratedEpisodeUrlswith a singleprotectPrivateFeedsoperation in privateFeeds.ts. It moves credential-bearing feed URLs into SecretStorage and scrubs matching raw URLs from all episode snapshots (queue, favorites, playlists, downloads, current episode) in one pass.protectPrivateFeedsbefore the first settings write and aborts with a retry-safe notice when a secret cannot be stored, instead of persisting the leak.playedEpisodesprogress while excluding vault-local data (localFiles,downloadedEpisodes,podNotes,currentEpisode), and strips local-file episodes, playlist current episodes, and SecretStorage references from queue, favorites, and playlists on both export and import.playedEpisodesis now included in exports and imports (previously excluded); import confirmation now lists saved feeds, playlists, queue, and favorites that will be replaced; import merges progress additively with current vault values winning conflicts.Macroscope summarized 5c1b468.