mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-11-06 21:02:04 +00:00
TS port slice 4: portable backup, CI, and the agent-blind CLI MVP
- Portable backup (format_version 1): TS imports Python exports, re-exports
byte-identically under pinned nonce/timestamp, verifies the canonical
checksum, rejects tampering and unknown versions.
- .github/workflows/ts-parity.yml: typecheck + Node/jsdom parity suite on
js/ changes, plus a fixture-drift job that regenerates fixtures from
Python and fails if the committed ones don't match (manifest commit field
excluded by construction).
- packages/cli — seedpass-js MVP implementing plan section 9.3:
* reference-first output: entry list/get/search emit sp://entry/<id> refs
and metadata; secret-bearing fields become has_* flags
* 'entry reveal' is the only plaintext egress command
* 'use --clipboard|--exec|--stdin-to' delivers secrets to sinks; --exec
injects SEEDPASS_SECRET into the child env, never argv or stdout
* vault export/import over portable backups; capabilities --format json
* mnemonic comes from SEEDPASS_MNEMONIC env, never the command line
- CLI tests prove the blindness properties: derived password matches the v2
fixture, TOTP at pinned time, secrets absent from all default output and
from sink-delivery confirmations.
- 125 core parity tests (Node + jsdom) + 11 CLI tests green.
Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
2345f61431
commit
ab569fe900
22 files changed
+1362
-14
No files matched your search
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Vault file access for the CLI: an encrypted index file (V3 payload, with
|
||||
* or without the JSON kdf/ct wrapper) unlocked by the parent seed mnemonic.
|
||||
*/
|
||||
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import {
|
||||
decryptPayload,
|
||||
parseEncryptedFile,
|
||||
deriveIndexKeyBytes,
|
||||
encryptV3,
|
||||
parseVaultIndex,
|
||||
utf8,
|
||||
type VaultIndex,
|
||||
} from "@seedpass/core";
|
||||
|
||||
export interface OpenedVault {
|
||||
index: VaultIndex;
|
||||
mnemonic: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export async function openVault(path: string, mnemonic: string): Promise<OpenedVault> {
|
||||
const blob = new Uint8Array(await readFile(path));
|
||||
const { ciphertext } = parseEncryptedFile(blob);
|
||||
const key = deriveIndexKeyBytes(mnemonic);
|
||||
const plaintext = await decryptPayload(key, ciphertext);
|
||||
const index = parseVaultIndex(JSON.parse(new TextDecoder().decode(plaintext)));
|
||||
return { index, mnemonic, path };
|
||||
}
|
||||
|
||||
export async function saveVault(vault: OpenedVault): Promise<void> {
|
||||
const key = deriveIndexKeyBytes(vault.mnemonic);
|
||||
const payload = await encryptV3(key, utf8(JSON.stringify(vault.index)));
|
||||
await writeFile(vault.path, payload, { mode: 0o600 });
|
||||
}
|
||||
Reference in new issue
Block a user