Skip to content

feat(auth): encrypted keystore v3 files with passphrase prompt #681

Description

@SgtPooki

Part of #457.

Description

Add geth-style V3 keystore JSON (scrypt + AES-128-CTR) as the recommended CLI auth mode, replacing PRIVATE_KEY as the documented default. The key sits encrypted on disk; the user is prompted for a passphrase at use time, or supplies KEYSTORE_PASSWORD for non-interactive runs.

synapse-sdk #554 already ships this pattern in its example CLI (examples/cli/src/{client,commands/init,config}.ts); port it into src/core/keystore/.

Scope is ordinary CLI commands only. The pinning server, upload action, and session owner commands are covered by the unify-auth-surfaces child of #457. Beneficiary note: this serves the human at the terminal, not agent runtimes; it is also the prerequisite for the OS-keychain child, which local assistant-spawned MCP tools need for headless unlock.

Scope

  • CLI: keystore create|import|list|remove, --keystore <name> flag, KEYSTORE_PASSWORD env. The named-account UX follows Foundry's cast wallet import pattern: enroll once, reference by name forever, never type hex again.
    • import accepts a hex private key or an existing V3 JSON file. Mnemonics out of scope.
    • Files written 0600 under the platform data dir at keystores/<name>.json (same default dirs as the pinning server).
  • Implementation: use ox's Keystore module (viem's authors; viem itself has no keystore support) rather than pulling in ethers for fromEncryptedJson. scrypt at standard params takes seconds in JS; wire a progress indicator so keystore create does not look hung.
  • Ethereum-standard scrypt parameters (N=262144, r=8, p=1) so files round-trip with geth, MetaMask, and other web3 tooling. Do not use Node's crypto.scrypt defaults.
  • Non-interactive behavior: detect via stdin.isTTY && stdout.isTTY && !CI; when a passphrase prompt would be needed and the session is non-interactive, fail fast naming KEYSTORE_PASSWORD, never hang. Never fall back to reading key material from a plaintext file silently.
  • Precedence: extend the source-aware resolution in src/utils/cli-auth.ts (and its tests) with a full table covering keystore vs PRIVATE_KEY, session key, OWS, and read-only mode. Required behaviors: explicit --keystore beats env; PRIVATE_KEY in env beats an implicit default keystore; conflicting explicit sources error rather than silently pick.
  • Default selection: with no flag and no PRIVATE_KEY, auto-select a keystore only when exactly one exists; otherwise fail with a hint listing names.
  • Docs: mark this the recommended interactive mode; PRIVATE_KEY stays supported but demoted in examples.

Notes

The key still enters process memory at decrypt time; accepted tradeoff for this tier. What it eliminates: raw private keys in env vars, shell history, and CI logs. It is not secretless in CI: KEYSTORE_PASSWORD plus the keystore file is signing authority, so CI should prefer session keys (see #457) over keystore-plus-env-passphrase. Works in Node on all platforms with zero native dependencies.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestteam/filecoin-pin"Filecoin Pin" project is a stakeholder for this work.team/fs-wgFOC working group is a stakeholder for this work, and thus wants to track it on their project board.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions