mirror of
https://github.com/sotashimozono/obsidian-remote-ssh.git
synced 2026-07-22 06:52:07 +00:00
Review of the write-through found two real defects it had introduced. 1. SYMLINK CLOBBER (the #455 bug class, reintroduced). writeThroughConfig mirrored every `<configDir>/**` write, and `fs.writeFileSync` FOLLOWS symlinks. `ShadowVaultBootstrap.installPlugin` symlinks remote-ssh's own main.js / manifest.json / styles.css in the shadow vault back to the SOURCE vault's real files, so any adapter write to those paths (e.g. updating the plugin from inside the shadow window) would have written straight through the link and overwritten the source vault's install — bricking it, exactly as #455 described. Now: lstat the target and refuse to mirror a symlink, and realpath the parent so a symlinked ANCESTOR (a stale whole-dir plugin symlink) cannot redirect the write out of the shadow root either. Skipping costs nothing — the remote write already succeeded, and for plugin CODE the local copy is owned by the pull/push binary round-trip, not by this cache. Pinned by a regression test that fails loudly without the guard: with it disabled the source vault's real file is observably overwritten ('SOURCE-REAL-FILE' -> 'NEW-BUNDLE-BYTES'). 2. PATH TRAVERSAL. The containment guard was a `startsWith(configDir + '/')` on the RAW string, applied before `..` was resolved — so `.obsidian/../evil.txt` passed the check and `path.join` then resolved it out of the shadow root (on win32, backslash separators were a second way through). The vault path reaches the adapter from Obsidian and from other plugins; it is not trusted input. Now: resolve first, then verify the resolved path is the shadow root or inside it. Pinned by a test that asserts nothing lands outside the root. Full suite green: 80 files, 1225 passed. |
||
|---|---|---|
| .. | ||
| e2e | ||
| scripts | ||
| src | ||
| tests | ||
| esbuild.config.mjs | ||
| eslint.config.mjs | ||
| manifest.json | ||
| package-lock.json | ||
| package.json | ||
| styles.css | ||
| tsconfig.json | ||
| versions.json | ||
| vitest.config.ts | ||
| vitest.integration.config.ts | ||
| vitest.replay.config.ts | ||
| vitest.setup.ts | ||