@needmoretruth/nmts-cli 0.17.2 → 0.34.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +125 -517
- package/CHANGELOG.md +104 -0
- package/README.ko.md +377 -469
- package/README.md +394 -474
- package/dist/account-proof.d.ts +29 -0
- package/dist/account-proof.js +6 -6
- package/dist/account.d.ts +18 -0
- package/dist/account.js +5 -5
- package/dist/agent-host.d.ts +71 -0
- package/dist/agent-host.js +169 -0
- package/dist/api-advice.d.ts +2 -0
- package/dist/api-advice.js +210 -0
- package/dist/api-key.d.ts +79 -0
- package/dist/api-key.js +7 -7
- package/dist/api-refusal.d.ts +14 -0
- package/dist/api-refusal.js +8 -0
- package/dist/api.d.ts +114 -0
- package/dist/api.js +59 -162
- package/dist/args.d.ts +160 -0
- package/dist/args.js +118 -30
- package/dist/artifact-about.d.ts +49 -0
- package/dist/autonomy.d.ts +39 -0
- package/dist/autonomy.js +110 -32
- package/dist/code-access.d.ts +29 -0
- package/dist/code-access.js +3 -3
- package/dist/code-vault.d.ts +38 -0
- package/dist/code-vault.js +8 -8
- package/dist/collision.d.ts +67 -0
- package/dist/collision.js +1 -1
- package/dist/commands/accept-terms.d.ts +11 -0
- package/dist/commands/accept-terms.js +106 -0
- package/dist/commands/balance.d.ts +7 -0
- package/dist/commands/balance.js +54 -1
- package/dist/commands/create-code-file.d.ts +24 -0
- package/dist/commands/create-code-file.js +93 -0
- package/dist/commands/create-link.d.ts +10 -0
- package/dist/commands/create-link.js +232 -0
- package/dist/commands/create.d.ts +20 -0
- package/dist/commands/create.js +43 -102
- package/dist/commands/credits.d.ts +9 -0
- package/dist/commands/credits.js +110 -0
- package/dist/commands/delete-account.d.ts +11 -0
- package/dist/commands/delete-account.js +63 -0
- package/dist/commands/deposit.d.ts +7 -0
- package/dist/commands/deposit.js +85 -0
- package/dist/commands/devices.d.ts +12 -0
- package/dist/commands/devices.js +144 -0
- package/dist/commands/documents.d.ts +35 -0
- package/dist/commands/documents.js +212 -0
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.js +10 -2
- package/dist/commands/erase.d.ts +13 -0
- package/dist/commands/erase.js +193 -0
- package/dist/commands/expiring.d.ts +19 -0
- package/dist/commands/extend.d.ts +33 -0
- package/dist/commands/extend.js +54 -15
- package/dist/commands/get.d.ts +18 -0
- package/dist/commands/key-manage.d.ts +11 -0
- package/dist/commands/key-manage.js +162 -0
- package/dist/commands/key.d.ts +28 -0
- package/dist/commands/key.js +249 -0
- package/dist/commands/kit.d.ts +11 -0
- package/dist/commands/kit.js +7 -7
- package/dist/commands/listfile.d.ts +13 -0
- package/dist/commands/listfile.js +12 -5
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.js +19 -19
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +1 -1
- package/dist/commands/losses.d.ts +12 -0
- package/dist/commands/losses.js +180 -0
- package/dist/commands/ls.d.ts +23 -0
- package/dist/commands/marks-dispatch.d.ts +2 -0
- package/dist/commands/marks-dispatch.js +51 -0
- package/dist/commands/marks.d.ts +46 -0
- package/dist/commands/marks.js +80 -0
- package/dist/commands/mcp.d.ts +24 -0
- package/dist/commands/mcp.js +70 -5
- package/dist/commands/mode.d.ts +8 -0
- package/dist/commands/mode.js +60 -24
- package/dist/commands/on-collision.d.ts +6 -0
- package/dist/commands/organise.d.ts +46 -0
- package/dist/commands/padding.d.ts +7 -0
- package/dist/commands/padding.js +114 -0
- package/dist/commands/public-code.d.ts +9 -0
- package/dist/commands/public-code.js +8 -8
- package/dist/commands/pull.d.ts +27 -0
- package/dist/commands/push-wallet.d.ts +19 -0
- package/dist/commands/push-wallet.js +69 -0
- package/dist/commands/push.d.ts +47 -0
- package/dist/commands/push.js +37 -7
- package/dist/commands/put-wallet.d.ts +77 -0
- package/dist/commands/put-wallet.js +316 -0
- package/dist/commands/put.d.ts +56 -0
- package/dist/commands/put.js +53 -6
- package/dist/commands/rebuild.d.ts +18 -0
- package/dist/commands/rebuild.js +108 -10
- package/dist/commands/receive.d.ts +24 -0
- package/dist/commands/recovery-dispatch.d.ts +2 -0
- package/dist/commands/recovery-dispatch.js +34 -0
- package/dist/commands/recovery-list.d.ts +11 -0
- package/dist/commands/recovery-list.js +6 -6
- package/dist/commands/recovery.d.ts +25 -0
- package/dist/commands/recovery.js +2 -2
- package/dist/commands/rollback.d.ts +9 -0
- package/dist/commands/rollback.js +118 -0
- package/dist/commands/s3.d.ts +23 -0
- package/dist/commands/s3.js +6 -6
- package/dist/commands/settings.d.ts +5 -0
- package/dist/commands/settings.js +21 -6
- package/dist/commands/share-dispatch.d.ts +2 -0
- package/dist/commands/share-dispatch.js +46 -0
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +13 -3
- package/dist/commands/shares-sent.d.ts +18 -0
- package/dist/commands/shares-sent.js +95 -0
- package/dist/commands/support.d.ts +24 -0
- package/dist/commands/support.js +321 -0
- package/dist/commands/sweep.d.ts +11 -0
- package/dist/commands/tip.d.ts +11 -0
- package/dist/commands/tip.js +86 -0
- package/dist/commands/trash.d.ts +17 -0
- package/dist/commands/trash.js +1 -1
- package/dist/commands/trial.d.ts +7 -0
- package/dist/commands/trial.js +16 -18
- package/dist/commands/unlock.d.ts +16 -0
- package/dist/commands/unlock.js +159 -0
- package/dist/commands/update.d.ts +42 -0
- package/dist/commands/update.js +1 -1
- package/dist/commands/usage.d.ts +8 -0
- package/dist/commands/verify.d.ts +18 -0
- package/dist/commands/verify.js +10 -6
- package/dist/commands/wallet-activity.d.ts +26 -0
- package/dist/commands/wallet-activity.js +117 -0
- package/dist/commands/wallet-donate.d.ts +26 -0
- package/dist/commands/wallet-donate.js +163 -0
- package/dist/commands/wallet-hall.d.ts +35 -0
- package/dist/commands/wallet-hall.js +214 -0
- package/dist/commands/wallet-send.d.ts +22 -0
- package/dist/commands/wallet-send.js +153 -0
- package/dist/commands/wallet-storage-ops.d.ts +24 -0
- package/dist/commands/wallet-storage-ops.js +215 -0
- package/dist/commands/wallet-storage.d.ts +18 -0
- package/dist/commands/wallet-storage.js +95 -0
- package/dist/commands/wallet-swap.d.ts +32 -0
- package/dist/commands/wallet-swap.js +287 -0
- package/dist/commands/wallet.d.ts +36 -0
- package/dist/commands/wallet.js +57 -15
- package/dist/commands/whoami.d.ts +10 -0
- package/dist/commands/whoami.js +24 -6
- package/dist/consent.d.ts +140 -0
- package/dist/consent.js +89 -30
- package/dist/credentials.d.ts +146 -0
- package/dist/credentials.js +10 -10
- package/dist/crypto-surface.d.ts +197 -0
- package/dist/crypto.d.ts +81 -0
- package/dist/crypto.js +13 -0
- package/dist/deposit.d.ts +25 -0
- package/dist/deposit.js +78 -0
- package/dist/download-part.d.ts +40 -0
- package/dist/download-sink.d.ts +76 -0
- package/dist/download.d.ts +79 -0
- package/dist/download.js +3 -3
- package/dist/drive-paths.d.ts +73 -0
- package/dist/environment.d.ts +62 -0
- package/dist/environment.js +29 -9
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +3 -3
- package/dist/exit.d.ts +44 -0
- package/dist/expiry.d.ts +58 -0
- package/dist/extend-budget.d.ts +35 -0
- package/dist/extend-budget.js +81 -0
- package/dist/extend-chain.d.ts +43 -0
- package/dist/extend-chain.js +40 -3
- package/dist/extend-plan.d.ts +148 -0
- package/dist/extend-plan.js +1 -1
- package/dist/gate.d.ts +18 -0
- package/dist/gate.js +100 -0
- package/dist/guards.d.ts +2 -0
- package/dist/help.d.ts +20 -0
- package/dist/help.js +199 -33
- package/dist/human-check.d.ts +23 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +49 -0
- package/dist/item-trash.d.ts +1 -0
- package/dist/kit-file.d.ts +56 -0
- package/dist/kit-file.js +10 -10
- package/dist/list-file.d.ts +88 -0
- package/dist/list-file.js +90 -7
- package/dist/list-view-find.d.ts +15 -0
- package/dist/list-view-order.d.ts +32 -0
- package/dist/main.d.ts +12 -0
- package/dist/main.js +112 -113
- package/dist/manifest-chunk-cache.d.ts +14 -0
- package/dist/manifest-chunk-cache.js +103 -0
- package/dist/manifest-chunk-flow.d.ts +81 -0
- package/dist/manifest-chunk-flow.js +307 -0
- package/dist/manifest-create.d.ts +23 -0
- package/dist/manifest-create.js +26 -30
- package/dist/manifest-write.d.ts +161 -0
- package/dist/manifest-write.js +42 -33
- package/dist/manifest.d.ts +82 -0
- package/dist/manifest.js +69 -21
- package/dist/mark-render.d.ts +26 -0
- package/dist/mcp-args.d.ts +17 -0
- package/dist/mcp-ask.d.ts +43 -0
- package/dist/mcp-ask.js +100 -0
- package/dist/mcp-tools/context.d.ts +46 -0
- package/dist/mcp-tools/credits.d.ts +3 -0
- package/dist/mcp-tools/credits.js +61 -0
- package/dist/mcp-tools/files.d.ts +3 -0
- package/dist/mcp-tools/files.js +34 -0
- package/dist/mcp-tools/organise.d.ts +3 -0
- package/dist/mcp-tools/organise.js +82 -2
- package/dist/mcp-tools/reads.d.ts +3 -0
- package/dist/mcp-tools/reads.js +132 -4
- package/dist/mcp-tools/share.d.ts +3 -0
- package/dist/mcp-tools/share.js +26 -7
- package/dist/mcp-tools/support.d.ts +3 -0
- package/dist/mcp-tools/support.js +140 -0
- package/dist/mcp-tools/tiers.d.ts +31 -0
- package/dist/mcp-tools/tiers.js +147 -0
- package/dist/mcp.d.ts +80 -0
- package/dist/mcp.js +110 -9
- package/dist/net-retry.d.ts +38 -0
- package/dist/network.d.ts +10 -0
- package/dist/notice.d.ts +7 -0
- package/dist/notice.js +7 -7
- package/dist/product.d.ts +29 -0
- package/dist/product.js +1 -1
- package/dist/progress.d.ts +37 -0
- package/dist/prompt.d.ts +31 -0
- package/dist/prompt.js +1 -1
- package/dist/rebuild-key-check.d.ts +26 -0
- package/dist/rebuild-key-check.js +90 -0
- package/dist/rebuild.d.ts +87 -0
- package/dist/rebuild.js +26 -4
- package/dist/recovery-assemble.d.ts +40 -0
- package/dist/recovery-assemble.js +1 -1
- package/dist/recovery-build.d.ts +40 -0
- package/dist/recovery-map-file.d.ts +53 -0
- package/dist/recovery-map-file.js +4 -4
- package/dist/recovery-map.d.ts +197 -0
- package/dist/recovery-release.d.ts +104 -0
- package/dist/recovery-seq.d.ts +10 -0
- package/dist/recovery-source.d.ts +50 -0
- package/dist/redact.d.ts +70 -0
- package/dist/redact.js +212 -0
- package/dist/registration.d.ts +30 -0
- package/dist/registration.js +5 -5
- package/dist/risk.d.ts +380 -0
- package/dist/risk.js +206 -0
- package/dist/run-log.d.ts +78 -0
- package/dist/run-log.js +301 -0
- package/dist/s3/listing.d.ts +47 -0
- package/dist/s3/multipart.d.ts +21 -0
- package/dist/s3/response-sink.d.ts +8 -0
- package/dist/s3/same-file.d.ts +54 -0
- package/dist/s3/server.d.ts +58 -0
- package/dist/s3/server.js +2 -2
- package/dist/s3/sigv4.d.ts +46 -0
- package/dist/s3/sigv4.js +1 -1
- package/dist/s3/staging.d.ts +10 -0
- package/dist/s3/xml.d.ts +28 -0
- package/dist/safe-path.d.ts +41 -0
- package/dist/seal.d.ts +120 -0
- package/dist/secret-reader.d.ts +28 -0
- package/dist/server.d.ts +9 -0
- package/dist/session.d.ts +32 -0
- package/dist/session.js +1 -1
- package/dist/setup-questions.d.ts +7 -0
- package/dist/share.d.ts +108 -0
- package/dist/share.js +1 -1
- package/dist/shared/lib/crypto/size-padding.d.ts +55 -0
- package/dist/shared/lib/crypto/size-padding.js +5 -0
- package/dist/shared/lib/drive/manifest-chunks.d.ts +95 -0
- package/dist/shared/lib/drive/manifest-chunks.js +252 -0
- package/dist/shared/lib/drive/manifest-codec.d.ts +214 -0
- package/dist/shared/lib/drive/manifest-codec.js +7 -7
- package/dist/shared/lib/drive/manifest-index.d.ts +98 -0
- package/dist/shared/lib/drive/manifest-ops.d.ts +167 -0
- package/dist/shared/lib/drive/manifest-ops.js +9 -4
- package/dist/shared/lib/drive/manifest-pack.d.ts +65 -0
- package/dist/shared/lib/drive/manifest-pack.js +287 -0
- package/dist/shared/lib/drive/manifest-settings.d.ts +113 -0
- package/dist/shared/lib/drive/manifest-settings.js +87 -6
- package/dist/shared/lib/drive/name-conflict.d.ts +76 -0
- package/dist/shared/lib/drive/rebuild-verify.d.ts +73 -0
- package/dist/shared/lib/drive/rebuild-verify.js +112 -0
- package/dist/shared/lib/drive/unique-name.d.ts +9 -0
- package/dist/shared/lib/drive/zstd.d.ts +27 -0
- package/dist/shared/lib/drive/zstd.js +74 -0
- package/dist/shared/lib/extend/epochs.d.ts +205 -0
- package/dist/shared/lib/net/retry-budget.d.ts +79 -0
- package/dist/shared/lib/share/shared-file-info.d.ts +21 -0
- package/dist/shared/lib/storage-control/chain.d.ts +57 -0
- package/dist/shared/lib/storage-control/chain.js +82 -0
- package/dist/shared/lib/storage-control/plan.d.ts +40 -0
- package/dist/shared/lib/storage-control/plan.js +72 -0
- package/dist/shared/lib/storage-control/reuse.d.ts +72 -0
- package/dist/shared/lib/storage-control/reuse.js +95 -0
- package/dist/shared/lib/storage-network.d.ts +25 -0
- package/dist/shared/lib/upload/part-plan.d.ts +24 -0
- package/dist/shared/lib/wallet/activity.d.ts +138 -0
- package/dist/shared/lib/wallet/activity.js +208 -0
- package/dist/shared/lib/wallet/send-rules.d.ts +68 -0
- package/dist/shared/lib/wallet/send-rules.js +116 -0
- package/dist/shared/lib/wallet/swap-rules.d.ts +115 -0
- package/dist/shared/lib/wallet/swap-rules.js +199 -0
- package/dist/shared/lib/wallet/tip.d.ts +14 -0
- package/dist/shared/lib/wallet/tip.js +34 -0
- package/dist/shared/lib/wallet/venue-ids.d.ts +23 -0
- package/dist/shared/lib/wallet/venue-ids.js +53 -0
- package/dist/standing-tip.d.ts +24 -0
- package/dist/standing-tip.js +52 -0
- package/dist/stdout.d.ts +38 -0
- package/dist/storage-control-chain.d.ts +38 -0
- package/dist/storage-control-chain.js +78 -0
- package/dist/sui-rpc.d.ts +15 -0
- package/dist/sui-rpc.js +59 -0
- package/dist/support-attach.d.ts +24 -0
- package/dist/support-attach.js +72 -0
- package/dist/support-copy.d.ts +42 -0
- package/dist/support-copy.js +109 -0
- package/dist/support-wire.d.ts +49 -0
- package/dist/support-wire.js +194 -0
- package/dist/trash-sweep.d.ts +55 -0
- package/dist/units.d.ts +2 -0
- package/dist/update-check.d.ts +50 -0
- package/dist/update-source.d.ts +63 -0
- package/dist/upload-api.d.ts +3 -0
- package/dist/upload-file.d.ts +97 -0
- package/dist/upload-file.js +3 -2
- package/dist/upload-price.d.ts +50 -0
- package/dist/upload-steps.d.ts +26 -0
- package/dist/upload-steps.js +29 -9
- package/dist/upload-store.d.ts +182 -0
- package/dist/upload-wallet-chain.d.ts +54 -0
- package/dist/upload-wallet-chain.js +203 -0
- package/dist/upload-wallet-plan.d.ts +128 -0
- package/dist/upload-wallet-plan.js +184 -0
- package/dist/upload-wallet.d.ts +24 -0
- package/dist/upload-wallet.js +208 -0
- package/dist/upload-wire.d.ts +244 -0
- package/dist/upload.d.ts +18 -0
- package/dist/upload.js +10 -0
- package/dist/usage-report.d.ts +35 -0
- package/dist/wallet-activity-chain.d.ts +5 -0
- package/dist/wallet-activity-chain.js +31 -0
- package/dist/wallet-chain.d.ts +19 -0
- package/dist/wallet-chain.js +2 -2
- package/dist/wallet-grant.d.ts +50 -0
- package/dist/wallet-grant.js +218 -0
- package/dist/wallet-send-chain.d.ts +24 -0
- package/dist/wallet-send-chain.js +49 -0
- package/dist/wallet-sign.d.ts +133 -0
- package/dist/wallet-sign.js +317 -0
- package/dist/wallet-storage-chain.d.ts +3 -0
- package/dist/wallet-storage-chain.js +20 -0
- package/dist/wallet-swap-chain.d.ts +52 -0
- package/dist/wallet-swap-chain.js +186 -0
- package/dist/wallet-swap-quote.d.ts +22 -0
- package/dist/wallet-swap-quote.js +126 -0
- package/dist/wallet.d.ts +135 -0
- package/dist/wallet.js +5 -5
- package/dist/walrus-write.d.ts +56 -0
- package/dist/walrus-write.js +5 -4
- package/dist/walrus.d.ts +86 -0
- package/dist/walrus.js +48 -10
- package/dist/zstd-node.d.ts +11 -0
- package/dist/zstd-node.js +71 -0
- package/docs/commands/accept-terms.md +15 -0
- package/docs/commands/create.md +17 -0
- package/docs/commands/credits.md +34 -0
- package/docs/commands/delete-account.md +14 -0
- package/docs/commands/deposit.md +27 -0
- package/docs/commands/devices.md +9 -0
- package/docs/commands/documents.md +10 -0
- package/docs/commands/env.md +21 -0
- package/docs/commands/extend.md +27 -0
- package/docs/commands/folders.md +10 -0
- package/docs/commands/get.md +14 -0
- package/docs/commands/key.md +14 -0
- package/docs/commands/login.md +23 -0
- package/docs/commands/logout.md +11 -0
- package/docs/commands/losses.md +13 -0
- package/docs/commands/ls.md +16 -0
- package/docs/commands/marks.md +9 -0
- package/docs/commands/mcp.md +33 -0
- package/docs/commands/mode.md +29 -0
- package/docs/commands/on-collision.md +13 -0
- package/docs/commands/padding.md +13 -0
- package/docs/commands/public-code.md +9 -0
- package/docs/commands/pull.md +9 -0
- package/docs/commands/push.md +12 -0
- package/docs/commands/put.md +36 -0
- package/docs/commands/rebuild.md +13 -0
- package/docs/commands/recovery.md +18 -0
- package/docs/commands/s3.md +17 -0
- package/docs/commands/share.md +15 -0
- package/docs/commands/support.md +16 -0
- package/docs/commands/tip.md +21 -0
- package/docs/commands/trash.md +25 -0
- package/docs/commands/trial.md +12 -0
- package/docs/commands/unlock.md +25 -0
- package/docs/commands/update.md +14 -0
- package/docs/commands/usage.md +14 -0
- package/docs/commands/verify.md +18 -0
- package/docs/commands/wallet.md +67 -0
- package/docs/commands/whoami.md +12 -0
- package/package.json +67 -8
- package/server.json +28 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm.d.ts +23 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm.js +44 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm +0 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm.d.ts +1 -0
- package/vendor/nmts-crypto/package.json +1 -1
- package/dist/commands/consent.js +0 -77
- package/dist/extend-sign.js +0 -130
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// `nmts key new` — make this machine's API key from the NMTS key it already holds.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ WHY IT EXISTS. Setting this tool up took TWO secrets and two places: the NMTS key here,
|
|
4
|
+
// and a key made at a browser — because the only door that minted one wanted a signed-in
|
|
5
|
+
// session as well as the code, and signing in goes through a human check no terminal can pass.
|
|
6
|
+
// So every automated setup began with a person at a screen, and a container that had the code
|
|
7
|
+
// still could not talk to the server. The server now has a door that takes the code alone, and
|
|
8
|
+
// this is the command that knocks on it: one secret in, one working machine out.
|
|
9
|
+
//
|
|
10
|
+
// ⛔ THE NMTS KEY IS NEVER AN ARGUMENT, and there is no option here that could carry one. It
|
|
11
|
+
// comes from where every other command gets it (`code-access.ts`), so a sealed store is opened
|
|
12
|
+
// the same way and an environment variable asks for the same agreement. What travels is the
|
|
13
|
+
// derived proof, which is what a sign-in sends and what `account-proof.ts` says is safe to
|
|
14
|
+
// send — never the code.
|
|
15
|
+
//
|
|
16
|
+
// ⛔ AND THERE IS NO MCP TOOL FOR THIS, DELIBERATELY. A key that could mint keys makes revoking
|
|
17
|
+
// one meaningless — revoke it and the program has already made three — and the whole reason
|
|
18
|
+
// the server refuses a key at these doors is that the credential which mints credentials must
|
|
19
|
+
// be the one a person holds. A tool here would hand that back through the side of the surface
|
|
20
|
+
// the server closed. Making a key is a person's act, at a command line.
|
|
21
|
+
//
|
|
22
|
+
// ⚠ THE KEY STRING IS PRINTED IN EXACTLY ONE PLACE. By default it is written into this machine's
|
|
23
|
+
// credentials file and never shown; `--print` puts it on the screen once, for somebody who has
|
|
24
|
+
// to paste it into another machine. Nothing else here — no confirmation, no error, no --json
|
|
25
|
+
// without --print — carries it.
|
|
26
|
+
import { identityOf } from "../account.js";
|
|
27
|
+
import { accountProofFor } from "../account-proof.js";
|
|
28
|
+
import { request } from "../api.js";
|
|
29
|
+
import { requireAccountCode } from "../code-access.js";
|
|
30
|
+
import { API_KEY_ENV_VAR, credentialsPath, readCredentialsFile, writeCredentials, } from "../credentials.js";
|
|
31
|
+
import { NmtsError } from "../errors.js";
|
|
32
|
+
import { isRecord } from "../guards.js";
|
|
33
|
+
import { resolveNetwork } from "../network.js";
|
|
34
|
+
import { BINARY_NAME, HOME_URL } from "../product.js";
|
|
35
|
+
import { resolveServer } from "../server.js";
|
|
36
|
+
/**
|
|
37
|
+
* The three permissions a key can carry, by the names the account screen uses for them.
|
|
38
|
+
*
|
|
39
|
+
* ⛔ THE BITS ARE THE SERVER'S AND THEY ARE FROZEN. `api/src/domain/api_key.rs` defines 1, 2 and 4
|
|
40
|
+
* and the browser mirrors the same three numbers; a fourth would be a new scope, which is a
|
|
41
|
+
* decision rather than an addition here.
|
|
42
|
+
*/
|
|
43
|
+
const SCOPE_BITS = {
|
|
44
|
+
read: 1,
|
|
45
|
+
write: 2,
|
|
46
|
+
spend: 4,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* What a key gets when nobody says.
|
|
50
|
+
*
|
|
51
|
+
* ⛔ THE SAME DEFAULT THE ACCOUNT SCREEN OFFERS — read only. A default that could write or spend
|
|
52
|
+
* would mean the narrowest thing anybody types is wider than the narrowest thing they could
|
|
53
|
+
* have asked for, and the screen and this tool would hand out different credentials for the
|
|
54
|
+
* same words.
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_SCOPES = "read";
|
|
57
|
+
/**
|
|
58
|
+
* How long a key lasts when nobody says.
|
|
59
|
+
*
|
|
60
|
+
* ⚠ A SECOND COPY OF THE SERVER'S `API_KEY_DEFAULT_TTL_SECS` (30 days), and it is a copy because
|
|
61
|
+
* there is nowhere to read the real one from: the route that reports the account's limits needs
|
|
62
|
+
* a key, and this is the command that does not have one yet. The server still decides the
|
|
63
|
+
* ceiling — a longer request is clamped, not refused — so the worst a stale number here does is
|
|
64
|
+
* ask for the wrong lifetime, which the reply then states.
|
|
65
|
+
*/
|
|
66
|
+
const DEFAULT_DAYS = 30;
|
|
67
|
+
/**
|
|
68
|
+
* `nmts key <verb>`.
|
|
69
|
+
*
|
|
70
|
+
* ⛔ A VERB AND NOT A BARE COMMAND. Three verbs: `new` mints, `list` shows, `revoke` cuts
|
|
71
|
+
* (`key-manage.ts` for the last two). All three present the NMTS key's proof and none is
|
|
72
|
+
* reachable with a key — a key cannot cut another key off, and that is what makes revoking
|
|
73
|
+
* mean something. `key` with no verb says which ones exist rather than doing one of them, so
|
|
74
|
+
* `nmts key` never turns out to have made something.
|
|
75
|
+
*/
|
|
76
|
+
export async function key(verb, args) {
|
|
77
|
+
if (verb === "list") {
|
|
78
|
+
const { keyList } = await import("./key-manage.js");
|
|
79
|
+
return await keyList({ server: args.server, json: args.json });
|
|
80
|
+
}
|
|
81
|
+
if (verb === "revoke") {
|
|
82
|
+
const { keyRevoke } = await import("./key-manage.js");
|
|
83
|
+
return await keyRevoke(args.operands[1], args, { server: args.server, json: args.json });
|
|
84
|
+
}
|
|
85
|
+
if (verb !== "new") {
|
|
86
|
+
throw new NmtsError(verb === undefined ? `\`${BINARY_NAME} key\` needs a verb.` : `\`${verb}\` is not a key verb.`, {
|
|
87
|
+
exitCode: 2,
|
|
88
|
+
nextStep: `The verbs are \`${BINARY_NAME} key new\` (make an API key for this machine from the ` +
|
|
89
|
+
`NMTS key it already holds), \`${BINARY_NAME} key list\` and ` +
|
|
90
|
+
`\`${BINARY_NAME} key revoke <id|all>\`. Each needs the NMTS key on this machine; ` +
|
|
91
|
+
`a key alone cannot list or cut keys.`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return await keyNew({
|
|
95
|
+
server: args.server,
|
|
96
|
+
network: args.network,
|
|
97
|
+
scopes: args.scopes,
|
|
98
|
+
days: args.days,
|
|
99
|
+
print: args.print,
|
|
100
|
+
json: args.json,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/** Turn `read,write` into the bitmask the server takes, refusing anything it does not define. */
|
|
104
|
+
export function scopeMask(spelled) {
|
|
105
|
+
const names = spelled
|
|
106
|
+
.split(",")
|
|
107
|
+
.map((part) => part.trim().toLowerCase())
|
|
108
|
+
.filter((part) => part !== "");
|
|
109
|
+
if (names.length === 0) {
|
|
110
|
+
throw new NmtsError(`--scopes was given nothing to read.`, {
|
|
111
|
+
exitCode: 2,
|
|
112
|
+
nextStep: `Name one or more of: ${Object.keys(SCOPE_BITS).join(", ")}.`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
let mask = 0;
|
|
116
|
+
for (const name of names) {
|
|
117
|
+
const bit = SCOPE_BITS[name];
|
|
118
|
+
if (bit === undefined) {
|
|
119
|
+
// ⛔ REFUSED, NOT IGNORED. A misspelt permission that was quietly dropped would make a key
|
|
120
|
+
// narrower than the person believes, and they would find out from a refusal days later
|
|
121
|
+
// on a machine nobody is watching.
|
|
122
|
+
throw new NmtsError(`\`${name}\` is not a permission a key can carry.`, {
|
|
123
|
+
exitCode: 2,
|
|
124
|
+
nextStep: `The three are: read (see what is stored), write (add and remove files), spend ` +
|
|
125
|
+
`(spend credits on storage). A program that uploads needs all three.`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
mask |= bit;
|
|
129
|
+
}
|
|
130
|
+
return mask;
|
|
131
|
+
}
|
|
132
|
+
/** The permission names a bitmask stands for, in the order they are defined. */
|
|
133
|
+
export function scopeNames(mask) {
|
|
134
|
+
return Object.entries(SCOPE_BITS)
|
|
135
|
+
.filter(([, bit]) => (mask & bit) !== 0)
|
|
136
|
+
.map(([name]) => name);
|
|
137
|
+
}
|
|
138
|
+
function wholeDays(given) {
|
|
139
|
+
if (given === undefined)
|
|
140
|
+
return DEFAULT_DAYS;
|
|
141
|
+
if (!/^[0-9]+$/u.test(given.trim())) {
|
|
142
|
+
throw new NmtsError(`--days takes a whole number of days.`, { exitCode: 2 });
|
|
143
|
+
}
|
|
144
|
+
const days = Number(given.trim());
|
|
145
|
+
if (days < 1)
|
|
146
|
+
throw new NmtsError(`--days must be at least 1.`, { exitCode: 2 });
|
|
147
|
+
return days;
|
|
148
|
+
}
|
|
149
|
+
function asIssued(value) {
|
|
150
|
+
if (!isRecord(value))
|
|
151
|
+
throw new NmtsError("The server's answer was not an object.");
|
|
152
|
+
const key = value["key"];
|
|
153
|
+
const keyId = value["key_id"];
|
|
154
|
+
const scopes = value["scopes"];
|
|
155
|
+
const expiresAt = value["expires_at"];
|
|
156
|
+
if (typeof key !== "string" ||
|
|
157
|
+
typeof keyId !== "string" ||
|
|
158
|
+
typeof scopes !== "number" ||
|
|
159
|
+
typeof expiresAt !== "string") {
|
|
160
|
+
throw new NmtsError("The server described the new key in a shape this version cannot read.", {
|
|
161
|
+
// ⛔ IT NAMES NO PART OF THE ANSWER. Whatever came back may contain the key.
|
|
162
|
+
nextStep: `A key may have been made even though this could not read the reply. Check the account ` +
|
|
163
|
+
`screen at ${HOME_URL} and revoke anything you did not mean to keep, then update this ` +
|
|
164
|
+
`tool — \`npm install -g ${BINARY_NAME}\`.`,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return { key, keyId, scopes, expiresAt };
|
|
168
|
+
}
|
|
169
|
+
export async function keyNew(options = {}) {
|
|
170
|
+
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
171
|
+
const mask = scopeMask(options.scopes ?? DEFAULT_SCOPES);
|
|
172
|
+
const days = wholeDays(options.days);
|
|
173
|
+
const held = await requireAccountCode();
|
|
174
|
+
const stored = readCredentialsFile();
|
|
175
|
+
const server = resolveServer(options.server ?? stored?.server);
|
|
176
|
+
// ⛔ RESOLVED ONLY WHEN THERE IS SOMEWHERE TO WRITE IT. The network is a property of the stored
|
|
177
|
+
// credential and nothing in this request touches the storage network, so demanding to be
|
|
178
|
+
// told which one a development server uses — which `resolveNetwork` rightly does — would
|
|
179
|
+
// refuse a run that was never going to record the answer.
|
|
180
|
+
const network = stored === null ? null : resolveNetwork(server, options.network ?? stored.network);
|
|
181
|
+
const identity = await identityOf(held.code);
|
|
182
|
+
// ⛔ THE PROOF IS BUILT FOR THIS ONE REQUEST AND NOTHING KEEPS IT. `accountProofFor` also asks
|
|
183
|
+
// for the agreement that covers sending it when the code came from an environment variable.
|
|
184
|
+
const authSecret = await accountProofFor({ code: held.code, source: held.source });
|
|
185
|
+
const issued = asIssued(await request(server, "/v1/account/api-keys/by-code", {
|
|
186
|
+
method: "POST",
|
|
187
|
+
body: {
|
|
188
|
+
account_id: identity.accountId,
|
|
189
|
+
auth_secret: authSecret,
|
|
190
|
+
scopes: mask,
|
|
191
|
+
lifetime_days: days,
|
|
192
|
+
},
|
|
193
|
+
// ⛔ NOT REPEATED ON A TIMEOUT. A request that reached the server and died on the way back
|
|
194
|
+
// has already spent one of the two live keys this account may hold, and a retry would
|
|
195
|
+
// spend the other — leaving somebody at the cap with two keys they never received.
|
|
196
|
+
retryBudgetMs: 0,
|
|
197
|
+
}));
|
|
198
|
+
// ⛔ THE STORE IS THE ONE THIS TOOL ALREADY HAS, WRITTEN THE ONE WAY IT IS WRITTEN. Whatever
|
|
199
|
+
// shape the NMTS key is in — sealed or in the clear — is carried through untouched:
|
|
200
|
+
// this command is about the key, and re-deciding how somebody's code is stored on the way
|
|
201
|
+
// past is exactly what `login` refuses to do with a key.
|
|
202
|
+
const canStore = stored !== null;
|
|
203
|
+
if (stored !== null && network !== null) {
|
|
204
|
+
writeCredentials({ ...stored, server, network, apiKey: issued.key });
|
|
205
|
+
}
|
|
206
|
+
if (options.json === true) {
|
|
207
|
+
// ⛔ THE KEY IS IN THE JSON ONLY WHEN IT WAS ASKED FOR ON THE SCREEN. A machine-readable
|
|
208
|
+
// answer goes into logs and into whatever is driving this; the default must not put a
|
|
209
|
+
// credential there because a caller happened to want a parseable reply.
|
|
210
|
+
const showKey = options.print === true || !canStore;
|
|
211
|
+
say(JSON.stringify({
|
|
212
|
+
key_id: issued.keyId,
|
|
213
|
+
scopes: scopeNames(issued.scopes),
|
|
214
|
+
expires_at: issued.expiresAt,
|
|
215
|
+
stored: canStore,
|
|
216
|
+
...(showKey ? { key: issued.key } : {}),
|
|
217
|
+
}));
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
say(`Key ${issued.keyId} made for ${server}${network === null ? "" : ` (${network})`}.`);
|
|
221
|
+
say(` may ${scopeNames(issued.scopes).join(", ")}`);
|
|
222
|
+
say(` stops ${issued.expiresAt}`);
|
|
223
|
+
say(``);
|
|
224
|
+
if (canStore) {
|
|
225
|
+
say(` Stored in ${credentialsPath()}, so every command on this machine now uses it.`);
|
|
226
|
+
say(` Whatever key was there before is no longer used; revoke it at ${HOME_URL} if it is`);
|
|
227
|
+
say(` running somewhere else.`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
say(` ⛔ NOTHING WAS STORED. This machine keeps no NMTS key file — it came from`);
|
|
231
|
+
say(` the environment — so there is nowhere to put the key. It is printed below because`);
|
|
232
|
+
say(` this is the only time it exists outside the server's memory.`);
|
|
233
|
+
}
|
|
234
|
+
if (options.print === true || !canStore) {
|
|
235
|
+
say(``);
|
|
236
|
+
say(` ⚠ The key is the account's credential. Anyone who reads it can do what it may do,`);
|
|
237
|
+
say(` until it is revoked or it stops. It is about to be on this screen and in this`);
|
|
238
|
+
say(` terminal's scrollback.`);
|
|
239
|
+
say(``);
|
|
240
|
+
// ⛔ ALONE ON ITS OWN LINE, for the reason `whoami --reveal` says: a line with nothing else
|
|
241
|
+
// on it is one a person can select without dragging a label into their clipboard.
|
|
242
|
+
say(issued.key);
|
|
243
|
+
say(``);
|
|
244
|
+
say(` Put it in ${API_KEY_ENV_VAR}, or in a file named by ${API_KEY_ENV_VAR}_FILE — the`);
|
|
245
|
+
say(` shape a container cannot leak. NMTS keeps no copy: lose it and the way back is to`);
|
|
246
|
+
say(` revoke it and make another.`);
|
|
247
|
+
}
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface KitOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
/** Where to put it: a directory, or the file name to write. Default: this directory. */
|
|
5
|
+
out?: string | undefined;
|
|
6
|
+
/** Replace a file that is already there. */
|
|
7
|
+
force?: boolean;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
write?: (line: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function kit(options?: KitOptions): Promise<number>;
|
package/dist/commands/kit.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// `nmts kit` — the recovery kit: one file that is enough to get everything back.
|
|
2
2
|
//
|
|
3
|
-
// ⛔⛔ IT WRITES THE
|
|
3
|
+
// ⛔⛔ IT WRITES THE NMTS KEY IN THE CLEAR. That is the format, decided deliberately: the point
|
|
4
4
|
// of the kit is that a person needs ONE thing, not two. So whoever holds this file holds the
|
|
5
5
|
// account and the wallet, and this command says exactly that at the moment it writes — not in a
|
|
6
6
|
// manual, not on a website. The moment somebody makes this file is the moment that fact
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
//
|
|
9
9
|
// ⛔ IT WRITES NOWHERE BUT THE PATH THE CALLER NAMED. Nothing is copied into this tool's own
|
|
10
10
|
// directory, nothing is left in a temporary file, nothing is printed to the terminal. A command
|
|
11
|
-
// that quietly kept a second copy of an
|
|
11
|
+
// that quietly kept a second copy of an NMTS key would be the worst defect in this program.
|
|
12
12
|
//
|
|
13
13
|
// ⛔ AND IT NEVER REPLACES A FILE NOBODY ASKED IT TO REPLACE. A taken name is a refusal unless
|
|
14
14
|
// `--force` says otherwise — the same rule every other writing command here follows.
|
|
@@ -59,7 +59,7 @@ export async function kit(options = {}) {
|
|
|
59
59
|
if (options.force !== true && existsSync(destination))
|
|
60
60
|
throw alreadyThere(destination);
|
|
61
61
|
try {
|
|
62
|
-
// ⛔ 0600, AND IT IS NOT A FORMALITY HERE. This file is the
|
|
62
|
+
// ⛔ 0600, AND IT IS NOT A FORMALITY HERE. This file is the NMTS key. On a filesystem that
|
|
63
63
|
// cannot keep the mode, this is still the only protection there is to ask for.
|
|
64
64
|
writeFileSync(destination, file.content, {
|
|
65
65
|
flag: options.force === true ? "w" : "wx",
|
|
@@ -84,7 +84,7 @@ export async function kit(options = {}) {
|
|
|
84
84
|
// ⛔ THE SENTENCE REACHES A READER THAT ONLY PARSES JSON. An agent that hands this file to
|
|
85
85
|
// somebody has to be able to say what it is, in the same words.
|
|
86
86
|
carries: ["account-code", "recovery-list"],
|
|
87
|
-
warning: "This file contains the
|
|
87
|
+
warning: "This file contains the NMTS key in the clear. Anyone who holds it holds the " +
|
|
88
88
|
"account and the wallet.",
|
|
89
89
|
missingFromSource: built.missingFromSource,
|
|
90
90
|
}));
|
|
@@ -92,9 +92,9 @@ export async function kit(options = {}) {
|
|
|
92
92
|
}
|
|
93
93
|
say(`Wrote ${destination}`);
|
|
94
94
|
say(``);
|
|
95
|
-
say(` ⛔ This file contains your
|
|
95
|
+
say(` ⛔ This file contains your NMTS key in the clear, together with the recovery list`);
|
|
96
96
|
say(` for ${built.fileCount} file(s). Anyone who holds it holds this account: every file in`);
|
|
97
|
-
say(` it, and the wallet that pays for storage. One
|
|
97
|
+
say(` it, and the wallet that pays for storage. One NMTS key opens both.`);
|
|
98
98
|
say(``);
|
|
99
99
|
say(` It was written only where you see it, with permissions 0600, and nowhere else.`);
|
|
100
100
|
say(` Do not keep it in a folder that syncs or backs up on its own, and do not send it to`);
|
|
@@ -130,7 +130,7 @@ function destinationFor(out, filename) {
|
|
|
130
130
|
function alreadyThere(destination) {
|
|
131
131
|
return new NmtsError(`${destination} is already there.`, {
|
|
132
132
|
exitCode: 4,
|
|
133
|
-
nextStep: `Nothing was written, and no
|
|
133
|
+
nextStep: `Nothing was written, and no NMTS key was put anywhere. Pass --out to choose another ` +
|
|
134
134
|
`name, or --force to replace it.`,
|
|
135
135
|
});
|
|
136
136
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ListFileOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Where to write it: a directory, a file name, or `-` for standard output. Default: this
|
|
4
|
+
* directory, under the name the file describes itself with.
|
|
5
|
+
*/
|
|
6
|
+
out?: string | undefined;
|
|
7
|
+
/** Replace a file that is already there. */
|
|
8
|
+
force?: boolean;
|
|
9
|
+
write?: (line: string) => void;
|
|
10
|
+
/** Where the document goes when `--out -` asked for it. */
|
|
11
|
+
writeDocument?: (text: string) => void;
|
|
12
|
+
}
|
|
13
|
+
export declare function listfile(options?: ListFileOptions): Promise<number>;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// which is a fact it can state exactly rather than a promise about the account.
|
|
13
13
|
//
|
|
14
14
|
// ⛔ WHAT THE FILE IS NOT. It is not a recovery on its own. The storage network's addresses are not
|
|
15
|
-
// in it — those live in the recovery list a browser writes — and neither is the
|
|
15
|
+
// in it — those live in the recovery list a browser writes — and neither is the NMTS key,
|
|
16
16
|
// deliberately: this file plus the code IS the account, and keeping both together turns one
|
|
17
17
|
// theft into a total loss. Both facts are printed, and both are inside the file for whoever
|
|
18
18
|
// finds it later without this text.
|
|
@@ -22,6 +22,7 @@ import { identityOf } from "../account.js";
|
|
|
22
22
|
import { requireAccountCode } from "../code-access.js";
|
|
23
23
|
import { NmtsError } from "../errors.js";
|
|
24
24
|
import { buildFileListFile } from "../list-file.js";
|
|
25
|
+
import { keptChunks } from "../manifest-chunk-flow.js";
|
|
25
26
|
import { readKeptList } from "../manifest.js";
|
|
26
27
|
import { BINARY_NAME } from "../product.js";
|
|
27
28
|
export async function listfile(options = {}) {
|
|
@@ -40,15 +41,21 @@ export async function listfile(options = {}) {
|
|
|
40
41
|
exitCode: 4,
|
|
41
42
|
nextStep: `Nothing was written. Run \`${BINARY_NAME} ls\` once while this machine can reach the ` +
|
|
42
43
|
`server: every read of the list keeps its sealed bytes here, and this command writes that ` +
|
|
43
|
-
`copy out. A copy cannot be made from the
|
|
44
|
+
`copy out. A copy cannot be made from the NMTS key alone — the list itself is what is ` +
|
|
44
45
|
`being copied.`,
|
|
45
46
|
});
|
|
46
47
|
}
|
|
48
|
+
// ⛔ THE PARTS TRAVEL WITH THE INDEX. At format version 2 the kept bytes are an index that names
|
|
49
|
+
// chunks; this machine holds those chunks by name beside it, and a copy of the index without
|
|
50
|
+
// them is a copy of nothing anybody can use. Null means the kept bytes are a single-blob list,
|
|
51
|
+
// which carries its entries itself.
|
|
52
|
+
const chunks = await keptChunks(resolved.code, identity.accountId, kept.ct);
|
|
47
53
|
const file = buildFileListFile({
|
|
48
54
|
accountId: identity.accountId,
|
|
49
55
|
seq: kept.seq,
|
|
50
56
|
savedAt: kept.savedAt,
|
|
51
57
|
sealed: kept.ct,
|
|
58
|
+
...(chunks === null ? {} : { chunks }),
|
|
52
59
|
});
|
|
53
60
|
if (toStdout) {
|
|
54
61
|
emit(file.content);
|
|
@@ -95,11 +102,11 @@ function destinationFor(out, filename) {
|
|
|
95
102
|
function saidWhatItIs(say, seq, savedAt, filename) {
|
|
96
103
|
say(``);
|
|
97
104
|
say(` File list version ${seq}, as this machine last read it (${savedAt}).`);
|
|
98
|
-
say(` It holds the names, folders and file keys of this account, sealed with the
|
|
105
|
+
say(` It holds the names, folders and file keys of this account, sealed with the NMTS key.`);
|
|
99
106
|
say(``);
|
|
100
107
|
say(` ⛔ It is not a recovery on its own. It carries no storage-network addresses — those are in`);
|
|
101
|
-
say(` the recovery list saved from the account screen — and it does not contain the
|
|
102
|
-
say(`
|
|
108
|
+
say(` the recovery list saved from the account screen — and it does not contain the NMTS`);
|
|
109
|
+
say(` key. Keep it somewhere other than your NMTS key: together they are the whole account.`);
|
|
103
110
|
say(` ⚠ A copy goes stale. Run this again after uploading: of two copies, the one whose`);
|
|
104
111
|
say(` filename carries the higher number supersedes the other (this one is ${filename}).`);
|
|
105
112
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LoginOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
/** Store the code in the clear rather than sealed. Behind `unsafe-code-storage`. */
|
|
5
|
+
plain?: boolean | undefined;
|
|
6
|
+
/** Store nothing; print the environment variable to set. Behind `plain-env`. */
|
|
7
|
+
env?: boolean | undefined;
|
|
8
|
+
/** Injected in tests so the terminal is not involved. */
|
|
9
|
+
readCode?: (() => Promise<string>) | undefined;
|
|
10
|
+
/** Injected in tests. Called twice for a new passphrase — the second is the confirmation. */
|
|
11
|
+
readPassphrase?: ((prompt: string) => Promise<string>) | undefined;
|
|
12
|
+
/** Injected in tests so the terminal is not involved. An empty answer means "not now". */
|
|
13
|
+
readApiKey?: (() => Promise<string>) | undefined;
|
|
14
|
+
/** Injected in tests. Answers the question that replaces a key already on this machine. */
|
|
15
|
+
confirmKeyReplace?: (() => Promise<string>) | undefined;
|
|
16
|
+
write?: (line: string) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function login(options?: LoginOptions): Promise<number>;
|
package/dist/commands/login.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `nmts login` — keep an
|
|
1
|
+
// `nmts login` — keep an NMTS key on this machine, in one of three shapes.
|
|
2
2
|
//
|
|
3
3
|
// ⚠ IT DOES NOT CHECK THE CODE WITH THE SERVER, AND IT SAYS SO. The code never goes to the server
|
|
4
4
|
// at all — it is what opens the files, and nothing on the far end has ever seen it — so there
|
|
@@ -53,7 +53,7 @@ export async function login(options = {}) {
|
|
|
53
53
|
if (options.plain === true && options.env === true) {
|
|
54
54
|
throw new NmtsError("--plain and --env ask for two different things.", {
|
|
55
55
|
exitCode: 2,
|
|
56
|
-
nextStep: "--plain writes the
|
|
56
|
+
nextStep: "--plain writes the NMTS key to this machine; --env writes nothing and prints it.",
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
if (existing === null)
|
|
@@ -120,12 +120,12 @@ async function readTheCode(options) {
|
|
|
120
120
|
? fromFile
|
|
121
121
|
: fromEnv !== undefined && fromEnv.length > 0
|
|
122
122
|
? fromEnv
|
|
123
|
-
: await promptSecret(`
|
|
123
|
+
: await promptSecret(`NMTS key (not shown as you type): `, CODE_ENV_VAR);
|
|
124
124
|
if (code.length === 0) {
|
|
125
|
-
throw new NmtsError("No
|
|
125
|
+
throw new NmtsError("No NMTS key was given.", {
|
|
126
126
|
exitCode: 2,
|
|
127
127
|
nextStep: stdinIsATerminal()
|
|
128
|
-
? `Run \`${BINARY_NAME} login\` again and
|
|
128
|
+
? `Run \`${BINARY_NAME} login\` again and enter your NMTS key.`
|
|
129
129
|
: `Set ${CODE_ENV_VAR} in the environment.`,
|
|
130
130
|
});
|
|
131
131
|
}
|
|
@@ -138,14 +138,14 @@ async function storeSealed(code, server, network, apiKey, options, say) {
|
|
|
138
138
|
writeCredentials({ lockedCode, server, network, ...(apiKey ? { apiKey } : {}) });
|
|
139
139
|
say(`Sealed for ${server} (${network}) in ${credentialsPath()}`);
|
|
140
140
|
say(``);
|
|
141
|
-
say(` What is on disk is not the
|
|
141
|
+
say(` What is on disk is not the NMTS key. Opening it needs the passphrase, so a copy of`);
|
|
142
142
|
say(` this file — in a backup, a synced folder, a container image, a stolen disk — is worth`);
|
|
143
143
|
say(` nothing on its own.`);
|
|
144
144
|
say(``);
|
|
145
|
-
say(` ⚠ It does NOT protect
|
|
145
|
+
say(` ⚠ It does NOT protect your NMTS key from anything running as you on this machine while you`);
|
|
146
146
|
say(` are using the tool. Whatever supplies the passphrase can be read the same way.`);
|
|
147
147
|
say(``);
|
|
148
|
-
say(` Every command that needs
|
|
148
|
+
say(` Every command that needs your NMTS key will ask for the passphrase, or read it from`);
|
|
149
149
|
say(` ${PASSPHRASE_ENV_VAR}. Opening it costs a fraction of a second and 64 MiB of memory each`);
|
|
150
150
|
say(` time, on purpose: that is what makes guessing the passphrase expensive.`);
|
|
151
151
|
return 0;
|
|
@@ -173,7 +173,7 @@ function storePlain(code, server, network, apiKey, say) {
|
|
|
173
173
|
if (!private_) {
|
|
174
174
|
say(``);
|
|
175
175
|
say(` ⛔ This machine did not keep the mode that was asked for, so anybody who can reach that`);
|
|
176
|
-
say(` path can read
|
|
176
|
+
say(` path can read your NMTS key. \`${BINARY_NAME} login\` without --plain seals it instead,`);
|
|
177
177
|
say(` and ${CODE_ENV_VAR}_FILE names a file this tool never copies.`);
|
|
178
178
|
}
|
|
179
179
|
return 0;
|
|
@@ -181,7 +181,7 @@ function storePlain(code, server, network, apiKey, say) {
|
|
|
181
181
|
/**
|
|
182
182
|
* Write nothing; print what to set.
|
|
183
183
|
*
|
|
184
|
-
* ⛔ THIS PRINTS THE
|
|
184
|
+
* ⛔ THIS PRINTS THE NMTS KEY, which every other part of this tool refuses to do. It is the
|
|
185
185
|
* one command whose entire purpose is to hand it back, it says so, and it is behind an
|
|
186
186
|
* agreement that names how an environment variable leaks.
|
|
187
187
|
*/
|
|
@@ -200,11 +200,11 @@ function printEnvForm(code, say) {
|
|
|
200
200
|
say(``);
|
|
201
201
|
say(` Nothing was written to this machine. Paste that where your program's environment is set.`);
|
|
202
202
|
say(``);
|
|
203
|
-
say(` ⚠
|
|
203
|
+
say(` ⚠ Your NMTS key is now on this screen, and probably in this terminal's scrollback. An`);
|
|
204
204
|
say(` environment variable is readable by anything running as you, by every child process,`);
|
|
205
205
|
say(` and — inside a container — by anybody who can run \`docker inspect\`.`);
|
|
206
206
|
say(``);
|
|
207
|
-
say(` ${CODE_ENV_VAR}_FILE names a FILE holding the
|
|
207
|
+
say(` ${CODE_ENV_VAR}_FILE names a FILE holding the NMTS key instead, and has none of those.`);
|
|
208
208
|
return 0;
|
|
209
209
|
}
|
|
210
210
|
/**
|
|
@@ -219,14 +219,14 @@ function printEnvForm(code, say) {
|
|
|
219
219
|
*/
|
|
220
220
|
function sayCheckSymbol(say, keyWasAccepted) {
|
|
221
221
|
say(``);
|
|
222
|
-
say(` The
|
|
222
|
+
say(` The NMTS key is well-formed — its own check symbol matches. That was verified here, offline.`);
|
|
223
223
|
if (!keyWasAccepted) {
|
|
224
224
|
say(` Whether the account EXISTS has not been checked: signing in goes through a human check`);
|
|
225
225
|
say(` this tool cannot pass yet, so that will first show up on a command that needs the server.`);
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
say(` ⚠ Whether it is the
|
|
229
|
-
say(` cannot be:
|
|
228
|
+
say(` ⚠ Whether it is the NMTS key for the account the API KEY belongs to has not been checked, and`);
|
|
229
|
+
say(` cannot be: an NMTS key never goes to the server, so nothing can compare the two. One`);
|
|
230
230
|
say(` from a different account looks like an account with nothing in it.`);
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
@@ -248,7 +248,7 @@ function sayAboutTheKey(outcome, server, say) {
|
|
|
248
248
|
say(`No API key is stored, and every command that talks to the server needs one.`);
|
|
249
249
|
say(``);
|
|
250
250
|
say(` Make one on the account screen at ${HOME_URL}, then run \`${BINARY_NAME} login\` again`);
|
|
251
|
-
say(` with it in ${API_KEY_ENV_VAR} — or
|
|
251
|
+
say(` with it in ${API_KEY_ENV_VAR} — or enter it when this asks. It is checked with the`);
|
|
252
252
|
say(` server before it is written down.`);
|
|
253
253
|
say(``);
|
|
254
254
|
say(` ${API_KEY_FILE_ENV_VAR} names a FILE holding the key instead, which is the shape a`);
|
|
@@ -277,7 +277,7 @@ function sayAboutTheKey(outcome, server, say) {
|
|
|
277
277
|
say(`⚠ A different API key is in ${keySourceName(outcome.from)}. It was NOT stored.`);
|
|
278
278
|
say(``);
|
|
279
279
|
say(` The key already on this machine is left as it is. Replacing one is something to say`);
|
|
280
|
-
say(` out loud, not something a run about the
|
|
280
|
+
say(` out loud, not something a run about the NMTS key does on the way past — every`);
|
|
281
281
|
say(` agent using the old one would stop working at a moment nobody would connect to this.`);
|
|
282
282
|
say(``);
|
|
283
283
|
say(` While that variable is set, every command uses what it holds anyway: the environment`);
|
|
@@ -303,7 +303,7 @@ async function newPassphrase(options) {
|
|
|
303
303
|
return fromEnv;
|
|
304
304
|
}
|
|
305
305
|
if (ask === undefined && !stdinIsATerminal()) {
|
|
306
|
-
throw new NmtsError("Sealing the
|
|
306
|
+
throw new NmtsError("Sealing the NMTS key needs a passphrase, and there is no terminal.", {
|
|
307
307
|
exitCode: 2,
|
|
308
308
|
nextStep: [
|
|
309
309
|
`One of these:`,
|
|
@@ -314,7 +314,7 @@ async function newPassphrase(options) {
|
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
316
|
const prompt = ask ?? ((q) => promptSecret(q, PASSPHRASE_ENV_VAR));
|
|
317
|
-
const first = await prompt(`New passphrase for the stored
|
|
317
|
+
const first = await prompt(`New passphrase for the stored NMTS key (not shown as you type): `);
|
|
318
318
|
if (first.length < MIN_PASSPHRASE)
|
|
319
319
|
throw tooShort();
|
|
320
320
|
const again = await prompt(`Type it again: `);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function logout(write?: (line: string) => void): number;
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `nmts logout` — remove the stored
|
|
1
|
+
// `nmts logout` — remove the stored NMTS key from this machine.
|
|
2
2
|
//
|
|
3
3
|
// ⚠ WHAT IT DOES NOT DO. It removes a file. It does not end any session on the server, and it
|
|
4
4
|
// cannot reach a copy of the code that has already been read by something else on this machine.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LossesOptions {
|
|
2
|
+
server?: string | undefined;
|
|
3
|
+
network?: string | undefined;
|
|
4
|
+
/** Machine-readable output. The list arm prints the server's own object, unchanged. */
|
|
5
|
+
json?: boolean;
|
|
6
|
+
write?: (line: string) => void;
|
|
7
|
+
/** Ask the chain about ONE listed object now, instead of listing. */
|
|
8
|
+
recheck?: string | undefined;
|
|
9
|
+
/** Take ONE line off this account's own drive, instead of listing. */
|
|
10
|
+
dismiss?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export declare function losses(options?: LossesOptions): Promise<number>;
|