docs(ext/sw): tighten slice-3 comments per code review
Non-functional tightening flagged in the slice-3 code review: - session.ts: document future multi-vault refactor (β+) so the module- scope singleton is explicitly "deliberately simple," not an oversight. - vault.ts: move findByHostname doc comment above the function; note α's intentionally-coarse hostname match (no www-stripping, no public-suffix matching) and that tighter matching is a β/γ concern. - index.ts: expand the passphrase scope-clearing comment to make the theatre explicit rather than leaving it looking like real defense. - index.ts: TODO(slice-4) marker on delete_item's non-atomic two-write path — consider manifest-first ordering or retry/rollback at router- split time. - index.ts: cross-reference comment on itemToManifestEntry pointing at the Rust-side ManifestEntry::from_item derivation it must mirror. No behavior change; build still compiles with 2 bundle-size warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -122,8 +122,12 @@ async function handleMessage(req: Request): Promise<Response> {
|
|||||||
|
|
||||||
const handle = w.unlock(req.passphrase, imageBytes, meta.salt, meta.paramsJson);
|
const handle = w.unlock(req.passphrase, imageBytes, meta.salt, meta.paramsJson);
|
||||||
session.setCurrent(handle);
|
session.setCurrent(handle);
|
||||||
// Clear passphrase from scope best-effort.
|
// Best-effort scope clearing. JS strings are immutable so this only
|
||||||
// (JS strings are immutable; the message object goes out of scope after return.)
|
// nulls the one reference on `req`; wasm-bindgen already copied the
|
||||||
|
// string into WASM linear memory before `unlock` returned. Left in
|
||||||
|
// as a marker — future work may consider a direct-stream KDF that
|
||||||
|
// never materializes the string, or a `Zeroizing` wrapper on the
|
||||||
|
// WASM-side incoming buffer.
|
||||||
(req as { passphrase: string }).passphrase = '';
|
(req as { passphrase: string }).passphrase = '';
|
||||||
|
|
||||||
manifest = await vault.fetchAndDecryptManifest(git, handle);
|
manifest = await vault.fetchAndDecryptManifest(git, handle);
|
||||||
@@ -178,6 +182,10 @@ async function handleMessage(req: Request): Promise<Response> {
|
|||||||
const entry = manifest.items[req.id];
|
const entry = manifest.items[req.id];
|
||||||
if (!entry) return { ok: false, error: 'item_not_found' };
|
if (!entry) return { ok: false, error: 'item_not_found' };
|
||||||
// Soft-delete: fetch the item, set trashed_at, write it back.
|
// Soft-delete: fetch the item, set trashed_at, write it back.
|
||||||
|
// TODO(slice-4): not atomic across the two git writes. If the manifest
|
||||||
|
// write fails after the item write, next sync restores the live manifest
|
||||||
|
// and the trashed item re-appears. Consider manifest-first write order
|
||||||
|
// or a retry/rollback pass when router-splitting this handler.
|
||||||
const item = await vault.fetchAndDecryptItem(gitHost, handle, req.id);
|
const item = await vault.fetchAndDecryptItem(gitHost, handle, req.id);
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
const updated: Item = { ...item, trashed_at: now, modified: now };
|
const updated: Item = { ...item, trashed_at: now, modified: now };
|
||||||
@@ -253,6 +261,12 @@ async function handleMessage(req: Request): Promise<Response> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TS mirror of the Rust core's `ManifestEntry::from_item`
|
||||||
|
/// (see crates/relicario-core/src/manifest.rs). These two derivations must
|
||||||
|
/// stay in sync — if the Rust side learns to handle e.g. trailing-whitespace
|
||||||
|
/// URL parsing differently, this function drifts and the manifest diverges
|
||||||
|
/// between CLI-written and extension-written items. A future WASM helper
|
||||||
|
/// `item_to_manifest_entry(handle, item_json)` would eliminate the duplication.
|
||||||
function itemToManifestEntry(item: Item) {
|
function itemToManifestEntry(item: Item) {
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
/// α assumes one vault per extension install. The master key lives only
|
/// α assumes one vault per extension install. The master key lives only
|
||||||
/// inside WASM linear memory (wrapped in Zeroizing<[u8;32]>); this module
|
/// inside WASM linear memory (wrapped in Zeroizing<[u8;32]>); this module
|
||||||
/// just holds the opaque handle that names it.
|
/// just holds the opaque handle that names it.
|
||||||
|
///
|
||||||
|
/// Future multi-vault (β+) would replace `current` with
|
||||||
|
/// `Map<vaultId, SessionHandle>` and thread `vaultId` through every
|
||||||
|
/// handler. Deliberate α simplicity — not an oversight.
|
||||||
|
|
||||||
import type { SessionHandle } from '../../wasm/relicario_wasm';
|
import type { SessionHandle } from '../../wasm/relicario_wasm';
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,13 @@ export function searchItems(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Match manifest entries against a page hostname.
|
||||||
|
///
|
||||||
|
/// icon_hint is derived by the Rust core (crates/relicario-core/src/manifest.rs)
|
||||||
|
/// from LoginCore.url's hostname, so equality on icon_hint is the cheapest match.
|
||||||
|
/// α is intentionally coarse: no www.-stripping, no public-suffix matching
|
||||||
|
/// (`www.github.com` saved items will not match `github.com`, and vice versa).
|
||||||
|
/// Tighter matching is a 1C-β/γ concern.
|
||||||
export function findByHostname(
|
export function findByHostname(
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
hostname: string,
|
hostname: string,
|
||||||
@@ -132,6 +139,4 @@ export function findByHostname(
|
|||||||
return (Object.entries(manifest.items) as Array<[ItemId, ManifestEntry]>)
|
return (Object.entries(manifest.items) as Array<[ItemId, ManifestEntry]>)
|
||||||
.filter(([, e]) => e.trashed_at === undefined)
|
.filter(([, e]) => e.trashed_at === undefined)
|
||||||
.filter(([, e]) => (e.icon_hint ?? '').toLowerCase() === h);
|
.filter(([, e]) => (e.icon_hint ?? '').toLowerCase() === h);
|
||||||
// icon_hint is derived by Rust core from LoginCore.url's hostname,
|
|
||||||
// so hostname equality on icon_hint is the cheapest match.
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user