@fased/fased 0.1.62 → 0.1.64
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/CHANGELOG.md +32 -0
- package/README.md +38 -30
- package/config/dependency-ownership.json +1 -1
- package/config/signer-policies/README.md +49 -0
- package/config/signer-policies/agent.json.template +32 -0
- package/config/signer-policies/mining.json.template +69 -0
- package/config/signer-policies/network.json.template +5 -0
- package/config/signer-policies/vault.json.template +70 -0
- package/config/signer-protocol-v2.json +76 -0
- package/config/typescript-noemit-baseline.json +680 -0
- package/dist/agents/auth-profiles/store.js +267 -31
- package/dist/agents/bash-tools.exec.js +10 -4
- package/dist/agents/current-model-catalog.js +3 -3
- package/dist/agents/memory-search.js +7 -1
- package/dist/agents/model-catalog-access.js +1 -2
- package/dist/agents/model-catalog-snapshot.js +1 -1
- package/dist/agents/model-catalog-source.js +1 -1
- package/dist/agents/model-metadata.js +1 -1
- package/dist/agents/model-selection.js +2 -28
- package/dist/agents/models-config.providers.js +6 -6
- package/dist/agents/pi-embedded-runner/compact.js +15 -7
- package/dist/agents/pi-embedded-runner/model.js +1 -1
- package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
- package/dist/agents/pi-embedded-runner/run.js +2 -0
- package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
- package/dist/agents/pi-tool-definition-adapter.js +16 -1
- package/dist/agents/pi-tools.js +2 -1
- package/dist/agents/sandbox/config.js +1 -1
- package/dist/agents/sandbox/context.js +27 -2
- package/dist/agents/skills/env-overrides.js +38 -28
- package/dist/agents/skills/trust.js +93 -0
- package/dist/agents/skills/workspace.js +128 -0
- package/dist/agents/skills-clawhub.js +36 -11
- package/dist/agents/skills-marketplace-scan.js +49 -0
- package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
- package/dist/agents/tools/mining-tool.js +1 -1
- package/dist/agents/tools/session-status-tool.js +1 -1
- package/dist/agents/tools/wallet-action-tool.js +172 -36
- package/dist/agents/tools/wallet-skill-policy.js +65 -23
- package/dist/agents/tools/wallet-tool.js +7 -11
- package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
- package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
- package/dist/auto-reply/reply/directive-handling.model.js +2 -1
- package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
- package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
- package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
- package/dist/auto-reply/reply/model-selection.js +7 -4
- package/dist/auto-reply/reply/session-reset-model.js +4 -4
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/channel-web.js +2 -2
- package/dist/cli/gateway-cli/run.js +8 -0
- package/dist/cli/program/command-registry.js +1 -1
- package/dist/cli/program/register.onboard.js +2 -3
- package/dist/cli/program/register.wallet.js +16 -123
- package/dist/cli/providers-cli.js +1 -1
- package/dist/cli/sat-cli.js +129 -2
- package/dist/cli/update-cli/update-command.js +260 -11
- package/dist/commands/auth-choice.apply.api-providers.js +3 -3
- package/dist/commands/doctor-config-flow.js +1 -1
- package/dist/commands/doctor-legacy-config.js +2 -13
- package/dist/commands/model-picker.js +6 -6
- package/dist/commands/models/auth.js +1 -1
- package/dist/commands/onboard-auth.config-gateways.js +1 -1
- package/dist/commands/onboard-auth.credentials.js +32 -8
- package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
- package/dist/commands/onboard-non-interactive/local.js +5 -1
- package/dist/commands/wallet.js +568 -1911
- package/dist/config/config.js +2 -2
- package/dist/config/io.js +64 -2
- package/dist/config/schema.help.js +8 -7
- package/dist/config/schema.labels.js +5 -4
- package/dist/config/zod-schema.agent-runtime.js +1 -0
- package/dist/config/zod-schema.js +5 -0
- package/dist/control-ui/assets/{app-DLil9VO1.js → app-bR-fO5ty.js} +1511 -1555
- package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
- package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
- package/dist/control-ui/assets/{index-DdE_NIXo.js → index-ckCxHwjy.js} +3 -3
- package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
- package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
- package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
- package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
- package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/daemon/systemd-system.js +56 -50
- package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
- package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
- package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
- package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
- package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
- package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
- package/dist/federation/auto-connect.js +98 -8
- package/dist/federation/marketplace-capability-adapter.js +33 -7
- package/dist/federation/marketplace-delivery-outbox.js +196 -0
- package/dist/federation/marketplace-delivery.js +351 -215
- package/dist/federation/marketplace-direct-payment.js +272 -141
- package/dist/federation/marketplace-escrow.js +607 -249
- package/dist/federation/marketplace-settlement-ledger.js +352 -0
- package/dist/federation/offers.js +9 -7
- package/dist/federation/peer-auth-v2.js +529 -0
- package/dist/gateway/a2a-http.js +425 -96
- package/dist/gateway/a2a-settlement.js +259 -153
- package/dist/gateway/a2a-task-store.js +524 -0
- package/dist/gateway/auth.js +38 -2
- package/dist/gateway/config-reload.js +46 -33
- package/dist/gateway/durable-capacity.js +31 -0
- package/dist/gateway/federation-http.js +540 -135
- package/dist/gateway/federation-marketplace-run-store.js +397 -0
- package/dist/gateway/federation-marketplace.js +535 -230
- package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
- package/dist/gateway/security-path.js +1 -1
- package/dist/gateway/server-http.js +1084 -1205
- package/dist/gateway/server-methods/models.js +1 -1
- package/dist/gateway/server-methods/secrets.js +40 -0
- package/dist/gateway/server-methods.js +1 -2
- package/dist/gateway/server-reload-handlers.js +196 -66
- package/dist/gateway/server-runtime-config.js +1 -1
- package/dist/gateway/server-secrets-runtime.js +288 -0
- package/dist/gateway/server.impl.js +73 -42
- package/dist/gateway/sessions-patch.js +3 -5
- package/dist/index.js +4 -2
- package/dist/infra/fasedhub.js +64 -1
- package/dist/infra/local-source-paired-update.js +538 -0
- package/dist/infra/restart.js +41 -10
- package/dist/infra/update-runner.js +96 -0
- package/dist/light-update-status.js +11 -11
- package/dist/memory/backend-config.js +2 -1
- package/dist/memory/session-files.js +16 -2
- package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
- package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
- package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-BYxAt775.js} +27 -27
- package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
- package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
- package/dist/plugin-sdk/channel-plugin-common.js +4 -4
- package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DIRHG2gJ.js} +1 -1
- package/dist/plugin-sdk/command-status.d.ts +2 -2
- package/dist/plugin-sdk/command-status.js +27 -27
- package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
- package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
- package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
- package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-BOT7kHb6.js} +6779 -3696
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +6 -6
- package/dist/plugin-sdk/discord.js +19 -19
- package/dist/plugin-sdk/file-lock.js +35 -4
- package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
- package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
- package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
- package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
- package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +21 -39
- package/dist/plugin-sdk/index.js +29 -29
- package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
- package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
- package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
- package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
- package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
- package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-BCFDaqJ-.js} +31 -31
- package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.js} +27 -27
- package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
- package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
- package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
- package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
- package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
- package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
- package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
- package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
- package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
- package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
- package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
- package/dist/plugin-sdk/sat-runtime.js +29 -29
- package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
- package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
- package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
- package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
- package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
- package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
- package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BUTt8cxK.js} +39 -39
- package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
- package/dist/plugin-sdk/slack.d.ts +6 -6
- package/dist/plugin-sdk/slack.js +9 -9
- package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-D0wHVqjt.js} +3 -3
- package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
- package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-CC_qN4v0.js} +30 -30
- package/dist/plugin-sdk/telegram.d.ts +6 -6
- package/dist/plugin-sdk/telegram.js +8 -8
- package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
- package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
- package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
- package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
- package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -2
- package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
- package/dist/plugin-sdk/{web-CInY-lCv.js → web-BXsJ1vqe.js} +32 -32
- package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
- package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +13 -13
- package/dist/plugin-sdk/whatsapp.js +12 -12
- package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
- package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
- package/dist/providers/refresh.js +1 -1
- package/dist/providers/registry.js +1 -1
- package/dist/secrets/apply.js +1 -1
- package/dist/secrets/runtime.js +1 -1
- package/dist/wallet/external-submission-ledger.js +376 -0
- package/dist/wallet/legacy-embedded-keystore.js +40 -0
- package/dist/wallet/local-socket-signer-archive.js +30 -0
- package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
- package/dist/wallet/local-socket-signer-policy.js +166 -0
- package/dist/wallet/local-socket-signer-protocol.js +561 -118
- package/dist/wallet/native-signer-wallet-id.js +25 -0
- package/dist/wallet/providers/alchemy-adapter.js +3 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
- package/dist/wallet/providers/turnkey-adapter.js +292 -34
- package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
- package/dist/wallet/signer-network-admin.js +184 -0
- package/dist/wallet/signer-protocol-v2.generated.js +90 -0
- package/dist/wallet/solana-bond-signing.js +157 -69
- package/dist/wallet/solana-reviewed-transaction.js +375 -0
- package/dist/wallet/solana-swap.js +520 -64
- package/dist/wallet/solana-transaction-inspection.js +106 -4
- package/dist/wallet/solana-trigger.js +658 -320
- package/dist/wallet/turnkey-reviewed-state.js +370 -0
- package/dist/wallet/wallet-approval-auth.js +17 -28
- package/dist/wallet/wallet-atomic-state.js +53 -0
- package/dist/wallet/wallet-canary.js +0 -1
- package/dist/wallet/wallet-inbound-events.js +16 -11
- package/dist/wallet/wallet-policy-simulation.js +1 -1
- package/dist/wallet/wallet-policy.js +90 -36
- package/dist/wallet/wallet-provider-capabilities.js +28 -4
- package/dist/wallet/wallet-provider-registry.js +57 -44
- package/dist/wallet/wallet-provider-resolver.js +62 -63
- package/dist/wallet/wallet-runtime-config.js +28 -41
- package/dist/wallet/wallet-secrets-store.js +22 -0
- package/dist/wallet/wallet-send-approvals.js +1891 -589
- package/dist/wallet/wallet-send-execution-ledger.js +292 -0
- package/dist/wallet/wallet-settlement-links.js +14 -13
- package/dist/wallet/wallet-standard-review.js +353 -0
- package/dist/wallet/wallet-status.js +0 -9
- package/dist/wallet/wallet-task-ledger.js +16 -2
- package/dist/web/auto-reply/heartbeat-runner.js +1 -1
- package/dist/web/auto-reply/monitor.js +2 -2
- package/dist/wizard/host-security-capability.js +14 -23
- package/dist/wizard/onboarding.finalize.js +63 -184
- package/dist/wizard/onboarding.host-security.js +117 -1367
- package/dist/wizard/onboarding.js +172 -217
- package/dist/wizard/onboarding.wallet.js +232 -785
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/index.ts +498 -153
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
- package/extensions/sat-mining/src/audit-store.ts +50 -5
- package/extensions/sat-mining/src/claim-service.ts +85 -14
- package/extensions/sat-mining/src/config.ts +9 -0
- package/extensions/sat-mining/src/cycle-progress.ts +16 -8
- package/extensions/sat-mining/src/epoch-service.ts +9 -5
- package/extensions/sat-mining/src/gateway-runner.ts +21 -1
- package/extensions/sat-mining/src/protocol-contract.ts +45 -1
- package/extensions/sat-mining/src/recovery-service.ts +312 -0
- package/extensions/sat-mining/src/round-watcher.ts +391 -81
- package/extensions/sat-mining/src/rpc-read.ts +330 -89
- package/extensions/sat-mining/src/runtime.ts +14 -0
- package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
- package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
- package/extensions/sat-mining/src/solana-submit.ts +1199 -428
- package/extensions/sat-mining/src/submission-ledger.ts +433 -0
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4955 -0
- package/package.json +23 -5
- package/scripts/fased-host-updater.mjs +1421 -0
- package/scripts/fased-host-updaterctl.mjs +186 -0
- package/scripts/fased-managed-service.sh +36 -0
- package/scripts/fased-managed-updater.mjs +3065 -156
- package/scripts/fased-signer-enroll-hosting.sh +275 -0
- package/scripts/fased-signer-network-hosting.sh +143 -0
- package/scripts/fased-signer-owner-policy.mjs +1430 -0
- package/scripts/fased-signer-policy-hosting.sh +50 -0
- package/scripts/fased-signer-policy-local.sh +26 -0
- package/scripts/hosted-release-manifest.mjs +185 -0
- package/scripts/install-fased-signerd.sh +183 -108
- package/scripts/install-managed-runtime.mjs +212 -10
- package/scripts/managed-runtime-layout.mjs +75 -3
- package/scripts/migrate-hosted-signer-v2.mjs +58 -0
- package/scripts/start-managed.sh +169 -360
- package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
- package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
- package/dist/wallet/local-socket-signer-broker.js +0 -224
- package/dist/wallet/local-socket-signer-custody.js +0 -42
- package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
- package/dist/wallet/providers/privy-adapter.js +0 -80
- package/dist/wallet/wallet-custody.js +0 -1836
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
umask 077
|
|
5
|
+
|
|
6
|
+
if [[ "${EUID}" != "0" ]]; then
|
|
7
|
+
echo "Hosted signer enrollment must run as root from a root SSH or provider-console session." >&2
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
if [[ $# -gt 1 ]]; then
|
|
11
|
+
echo "usage: /usr/local/sbin/fased-signer-enroll [authenticator label]" >&2
|
|
12
|
+
exit 64
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
SIGNER_USER="fased-signer"
|
|
16
|
+
SIGNER_HOME="/var/lib/fased-signerd"
|
|
17
|
+
SIGNER_BIN="/opt/fased/signer/fased-signerd"
|
|
18
|
+
CONTROL_SOCKET="/run/fased-signerd/control.sock"
|
|
19
|
+
WEBAUTHN_ENV="/etc/fased/signerd-webauthn.env"
|
|
20
|
+
UPDATE_GATE="/var/lib/fased-signer-update-gate/active"
|
|
21
|
+
UPDATE_JOURNAL="/var/lib/fased-host-updater/active-signer-transaction.json"
|
|
22
|
+
ENROLLMENT_LOCK="/var/lib/fased-signerd/webauthn-enrollment.lock"
|
|
23
|
+
PROCESS_LOCK="/var/lib/fased-host-updater/signer-enrollment.lock"
|
|
24
|
+
UPDATER_STATE_DIR="/var/lib/fased-host-updater"
|
|
25
|
+
PUBLIC_PATH="/_fased/signer-enrollment"
|
|
26
|
+
LISTEN="127.0.0.1:18791"
|
|
27
|
+
LABEL="${1:-Wallet Operator}"
|
|
28
|
+
|
|
29
|
+
TAILSCALE_BIN="/usr/bin/tailscale"
|
|
30
|
+
RUNUSER_BIN="/usr/sbin/runuser"
|
|
31
|
+
ENV_BIN="/usr/bin/env"
|
|
32
|
+
FLOCK_BIN="/usr/bin/flock"
|
|
33
|
+
MKTEMP_BIN="/usr/bin/mktemp"
|
|
34
|
+
RM_BIN="/usr/bin/rm"
|
|
35
|
+
STAT_BIN="/usr/bin/stat"
|
|
36
|
+
GREP_BIN="/usr/bin/grep"
|
|
37
|
+
CHMOD_BIN="/usr/bin/chmod"
|
|
38
|
+
ID_BIN="/usr/bin/id"
|
|
39
|
+
SYSTEMCTL_BIN="/usr/bin/systemctl"
|
|
40
|
+
|
|
41
|
+
require_root_executable() {
|
|
42
|
+
local path="$1"
|
|
43
|
+
[[ -f "$path" && -x "$path" && ! -L "$path" ]] || {
|
|
44
|
+
echo "Required root-controlled executable is missing or unsafe: $path" >&2
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
local metadata
|
|
48
|
+
metadata="$($STAT_BIN -c '%u %a %h' "$path")"
|
|
49
|
+
local owner mode links
|
|
50
|
+
read -r owner mode links <<<"$metadata"
|
|
51
|
+
[[ "$owner" == "0" && "$links" -ge 1 && $((8#$mode & 8#22)) -eq 0 ]] || {
|
|
52
|
+
echo "Required executable is not root-owned and non-writable: $path" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for executable in \
|
|
58
|
+
"$TAILSCALE_BIN" "$RUNUSER_BIN" "$ENV_BIN" "$FLOCK_BIN" \
|
|
59
|
+
"$MKTEMP_BIN" "$RM_BIN" "$STAT_BIN" "$GREP_BIN"; do
|
|
60
|
+
require_root_executable "$executable"
|
|
61
|
+
done
|
|
62
|
+
require_root_executable "$CHMOD_BIN"
|
|
63
|
+
require_root_executable "$ID_BIN"
|
|
64
|
+
require_root_executable "$SYSTEMCTL_BIN"
|
|
65
|
+
require_root_executable "$SIGNER_BIN"
|
|
66
|
+
|
|
67
|
+
SIGNER_UID="$($ID_BIN -u "$SIGNER_USER")"
|
|
68
|
+
[[ "$SIGNER_UID" =~ ^[0-9]+$ && "$SIGNER_UID" != "0" ]] || {
|
|
69
|
+
echo "Dedicated fased-signer account is unavailable." >&2
|
|
70
|
+
exit 1
|
|
71
|
+
}
|
|
72
|
+
[[ -d "$SIGNER_HOME" && ! -L "$SIGNER_HOME" ]] || {
|
|
73
|
+
echo "Signer state directory is missing or unsafe: $SIGNER_HOME" >&2
|
|
74
|
+
exit 1
|
|
75
|
+
}
|
|
76
|
+
read -r state_owner state_mode <<<"$($STAT_BIN -c '%u %a' "$SIGNER_HOME")"
|
|
77
|
+
[[ "$state_owner" == "$SIGNER_UID" && "$state_mode" == "700" ]] || {
|
|
78
|
+
echo "Signer state directory must be signer-owned mode 0700." >&2
|
|
79
|
+
exit 1
|
|
80
|
+
}
|
|
81
|
+
[[ -S "$CONTROL_SOCKET" && ! -L "$CONTROL_SOCKET" ]] || {
|
|
82
|
+
echo "Root-managed signer control socket is unavailable: $CONTROL_SOCKET" >&2
|
|
83
|
+
exit 1
|
|
84
|
+
}
|
|
85
|
+
read -r socket_owner socket_mode <<<"$($STAT_BIN -c '%u %a' "$CONTROL_SOCKET")"
|
|
86
|
+
[[ "$socket_owner" == "$SIGNER_UID" && "$socket_mode" == "600" ]] || {
|
|
87
|
+
echo "Signer control socket ownership or mode is unsafe." >&2
|
|
88
|
+
exit 1
|
|
89
|
+
}
|
|
90
|
+
[[ -f "$WEBAUTHN_ENV" && ! -L "$WEBAUTHN_ENV" ]] || {
|
|
91
|
+
echo "Signer WebAuthn configuration is missing or unsafe: $WEBAUTHN_ENV" >&2
|
|
92
|
+
exit 1
|
|
93
|
+
}
|
|
94
|
+
read -r env_owner env_mode env_links <<<"$($STAT_BIN -c '%u %a %h' "$WEBAUTHN_ENV")"
|
|
95
|
+
[[ "$env_owner" == "0" && "$env_mode" == "644" && "$env_links" -eq 1 ]] || {
|
|
96
|
+
echo "Signer WebAuthn configuration must be root-owned mode 0644 with one link." >&2
|
|
97
|
+
exit 1
|
|
98
|
+
}
|
|
99
|
+
[[ -d "$UPDATER_STATE_DIR" && ! -L "$UPDATER_STATE_DIR" ]] || {
|
|
100
|
+
echo "Root updater state directory is missing or unsafe: $UPDATER_STATE_DIR" >&2
|
|
101
|
+
exit 1
|
|
102
|
+
}
|
|
103
|
+
read -r updater_owner updater_mode <<<"$($STAT_BIN -c '%u %a' "$UPDATER_STATE_DIR")"
|
|
104
|
+
[[ "$updater_owner" == "0" && "$updater_mode" == "700" ]] || {
|
|
105
|
+
echo "Root updater state directory must be root-owned mode 0700." >&2
|
|
106
|
+
exit 1
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
RP_ID=""
|
|
110
|
+
ORIGIN=""
|
|
111
|
+
while IFS='=' read -r name value; do
|
|
112
|
+
[[ -z "$name" ]] && continue
|
|
113
|
+
case "$name" in
|
|
114
|
+
FASED_WALLET_WEBAUTHN_RP_ID) RP_ID="$value" ;;
|
|
115
|
+
FASED_WALLET_WEBAUTHN_ORIGINS) ORIGIN="$value" ;;
|
|
116
|
+
*) echo "Signer WebAuthn environment contains an unsupported setting." >&2; exit 1 ;;
|
|
117
|
+
esac
|
|
118
|
+
done <"$WEBAUTHN_ENV"
|
|
119
|
+
[[ "$RP_ID" =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$ && "$ORIGIN" == "https://${RP_ID}" ]] || {
|
|
120
|
+
echo "Signer WebAuthn must use the exact configured Tailscale HTTPS origin." >&2
|
|
121
|
+
exit 1
|
|
122
|
+
}
|
|
123
|
+
if ! "$TAILSCALE_BIN" serve get-config --help >/dev/null 2>&1 || \
|
|
124
|
+
! "$TAILSCALE_BIN" serve set-config --help >/dev/null 2>&1; then
|
|
125
|
+
echo "This enrollment flow requires a current Tailscale CLI with serve get-config/set-config." >&2
|
|
126
|
+
echo "Update Tailscale, then retry; the existing Gateway route was not changed." >&2
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [[ -e "$UPDATE_GATE" || -e "$UPDATE_JOURNAL" ]]; then
|
|
131
|
+
echo "A signer update is active or awaiting a durable decision; finish it before enrollment." >&2
|
|
132
|
+
exit 1
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
if [[ -e "$PROCESS_LOCK" || -L "$PROCESS_LOCK" ]]; then
|
|
136
|
+
[[ -f "$PROCESS_LOCK" && ! -L "$PROCESS_LOCK" ]] || {
|
|
137
|
+
echo "Hosted enrollment process lock is not a safe regular file." >&2
|
|
138
|
+
exit 1
|
|
139
|
+
}
|
|
140
|
+
read -r process_lock_owner process_lock_mode process_lock_links <<<"$($STAT_BIN -c '%u %a %h' "$PROCESS_LOCK")"
|
|
141
|
+
[[ "$process_lock_owner" == "0" && "$process_lock_links" -eq 1 && $((8#$process_lock_mode & 8#77)) -eq 0 ]] || {
|
|
142
|
+
echo "Hosted enrollment process lock has unsafe ownership or permissions." >&2
|
|
143
|
+
exit 1
|
|
144
|
+
}
|
|
145
|
+
fi
|
|
146
|
+
exec 9>"$PROCESS_LOCK"
|
|
147
|
+
"$CHMOD_BIN" 0600 "$PROCESS_LOCK"
|
|
148
|
+
read -r process_lock_owner process_lock_mode process_lock_links <<<"$($STAT_BIN -c '%u %a %h' "$PROCESS_LOCK")"
|
|
149
|
+
[[ -f "$PROCESS_LOCK" && ! -L "$PROCESS_LOCK" && "$process_lock_owner" == "0" && "$process_lock_mode" == "600" && "$process_lock_links" -eq 1 ]] || {
|
|
150
|
+
echo "Hosted enrollment process lock could not be secured." >&2
|
|
151
|
+
exit 1
|
|
152
|
+
}
|
|
153
|
+
$FLOCK_BIN -n 9 || {
|
|
154
|
+
echo "Another hosted signer enrollment session is already active." >&2
|
|
155
|
+
exit 1
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
WORK_DIR=""
|
|
159
|
+
SNAPSHOT_PATH=""
|
|
160
|
+
STATUS_PATH=""
|
|
161
|
+
SERVER_PID=""
|
|
162
|
+
ROUTE_CHANGED=0
|
|
163
|
+
UPDATER_STOPPED=0
|
|
164
|
+
|
|
165
|
+
cleanup() {
|
|
166
|
+
local status=$?
|
|
167
|
+
local restore_failed=0
|
|
168
|
+
trap - EXIT INT TERM HUP
|
|
169
|
+
if [[ -n "$SERVER_PID" ]]; then
|
|
170
|
+
kill "$SERVER_PID" >/dev/null 2>&1 || true
|
|
171
|
+
wait "$SERVER_PID" >/dev/null 2>&1 || true
|
|
172
|
+
fi
|
|
173
|
+
if [[ "$ROUTE_CHANGED" == "1" && -f "$SNAPSHOT_PATH" ]]; then
|
|
174
|
+
if ! "$TAILSCALE_BIN" serve set-config "$SNAPSHOT_PATH" --all >/dev/null; then
|
|
175
|
+
echo "CRITICAL: could not restore the prior Tailscale Serve configuration." >&2
|
|
176
|
+
restore_failed=1
|
|
177
|
+
fi
|
|
178
|
+
fi
|
|
179
|
+
if [[ "$UPDATER_STOPPED" == "1" ]]; then
|
|
180
|
+
if ! "$SYSTEMCTL_BIN" start fased-host-updater.service; then
|
|
181
|
+
echo "CRITICAL: could not restart the root signer updater." >&2
|
|
182
|
+
restore_failed=1
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
if [[ -n "$WORK_DIR" ]]; then
|
|
186
|
+
"$RM_BIN" -rf -- "$WORK_DIR"
|
|
187
|
+
fi
|
|
188
|
+
if [[ "$restore_failed" == "1" ]]; then
|
|
189
|
+
exit 1
|
|
190
|
+
fi
|
|
191
|
+
exit "$status"
|
|
192
|
+
}
|
|
193
|
+
trap cleanup EXIT INT TERM HUP
|
|
194
|
+
|
|
195
|
+
"$SYSTEMCTL_BIN" is-active --quiet fased-host-updater.service || {
|
|
196
|
+
echo "The root signer updater must be active before enrollment can take its update lock." >&2
|
|
197
|
+
exit 1
|
|
198
|
+
}
|
|
199
|
+
UPDATER_STOPPED=1
|
|
200
|
+
"$SYSTEMCTL_BIN" stop fased-host-updater.service
|
|
201
|
+
if "$SYSTEMCTL_BIN" is-active --quiet fased-host-updater.service; then
|
|
202
|
+
echo "Could not quiesce the signer updater for enrollment." >&2
|
|
203
|
+
exit 1
|
|
204
|
+
fi
|
|
205
|
+
if [[ -e "$UPDATE_GATE" || -e "$UPDATE_JOURNAL" ]]; then
|
|
206
|
+
echo "A signer update raced with enrollment; the updater will recover before you retry." >&2
|
|
207
|
+
exit 1
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
WORK_DIR="$($MKTEMP_BIN -d /run/fased-signer-enrollment.XXXXXX)"
|
|
211
|
+
SNAPSHOT_PATH="${WORK_DIR}/tailscale-serve.json"
|
|
212
|
+
STATUS_PATH="${WORK_DIR}/tailscale-status.json"
|
|
213
|
+
|
|
214
|
+
"$TAILSCALE_BIN" status --json >"$STATUS_PATH"
|
|
215
|
+
if ! "$GREP_BIN" -Fq "\"DNSName\": \"${RP_ID}.\"" "$STATUS_PATH" && \
|
|
216
|
+
! "$GREP_BIN" -Fq "\"DNSName\":\"${RP_ID}.\"" "$STATUS_PATH"; then
|
|
217
|
+
echo "Configured signer RP ID does not match this Tailscale node." >&2
|
|
218
|
+
exit 1
|
|
219
|
+
fi
|
|
220
|
+
"$TAILSCALE_BIN" serve get-config "$SNAPSHOT_PATH" --all
|
|
221
|
+
"$CHMOD_BIN" 0600 "$SNAPSHOT_PATH" "$STATUS_PATH"
|
|
222
|
+
if "$GREP_BIN" -Fq '"AllowFunnel"' "$SNAPSHOT_PATH"; then
|
|
223
|
+
echo "Hosted signer enrollment refuses to run while any Tailscale Funnel route is active." >&2
|
|
224
|
+
echo "Temporarily disable Funnel on this host, enroll through tailnet-only Serve, then restore Funnel." >&2
|
|
225
|
+
exit 1
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
coproc SIGNER_ENROLLMENT_SERVER {
|
|
229
|
+
"$RUNUSER_BIN" -u "$SIGNER_USER" -- \
|
|
230
|
+
"$ENV_BIN" -i \
|
|
231
|
+
HOME="$SIGNER_HOME" \
|
|
232
|
+
PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
|
|
233
|
+
LANG="C.UTF-8" \
|
|
234
|
+
"$SIGNER_BIN" admin webauthn enrollment serve \
|
|
235
|
+
--control-socket "$CONTROL_SOCKET" \
|
|
236
|
+
--listen "$LISTEN" \
|
|
237
|
+
--origin "$ORIGIN" \
|
|
238
|
+
--base-path "${PUBLIC_PATH}/" \
|
|
239
|
+
--label "$LABEL" \
|
|
240
|
+
--update-gate "$UPDATE_GATE" \
|
|
241
|
+
--lock-file "$ENROLLMENT_LOCK" \
|
|
242
|
+
--timeout 5m
|
|
243
|
+
}
|
|
244
|
+
SERVER_PID="$SIGNER_ENROLLMENT_SERVER_PID"
|
|
245
|
+
if ! IFS= read -r ENROLLMENT_URL <&"${SIGNER_ENROLLMENT_SERVER[0]}"; then
|
|
246
|
+
wait "$SERVER_PID" || true
|
|
247
|
+
SERVER_PID=""
|
|
248
|
+
echo "Native signer enrollment server did not start." >&2
|
|
249
|
+
exit 1
|
|
250
|
+
fi
|
|
251
|
+
case "$ENROLLMENT_URL" in
|
|
252
|
+
"${ORIGIN}${PUBLIC_PATH}/#"?*) ;;
|
|
253
|
+
*) echo "Native signer returned an invalid enrollment URL." >&2; exit 1 ;;
|
|
254
|
+
esac
|
|
255
|
+
|
|
256
|
+
ROUTE_CHANGED=1
|
|
257
|
+
"$TAILSCALE_BIN" serve --yes --bg --set-path "$PUBLIC_PATH" "http://${LISTEN}" >/dev/null
|
|
258
|
+
"$TAILSCALE_BIN" serve status --json >"$STATUS_PATH"
|
|
259
|
+
if ! "$GREP_BIN" -Fq "$PUBLIC_PATH" "$STATUS_PATH" || ! "$GREP_BIN" -Fq "$LISTEN" "$STATUS_PATH"; then
|
|
260
|
+
echo "Tailscale did not acknowledge the temporary signer enrollment route." >&2
|
|
261
|
+
exit 1
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
echo "Open this one-time URL on your own Tailscale-connected computer:"
|
|
265
|
+
echo "$ENROLLMENT_URL"
|
|
266
|
+
echo "The URL expires in five minutes and becomes invalid after one successful enrollment."
|
|
267
|
+
unset ENROLLMENT_URL
|
|
268
|
+
|
|
269
|
+
if ! wait "$SERVER_PID"; then
|
|
270
|
+
SERVER_PID=""
|
|
271
|
+
echo "Signer-owned WebAuthn enrollment did not complete." >&2
|
|
272
|
+
exit 1
|
|
273
|
+
fi
|
|
274
|
+
SERVER_PID=""
|
|
275
|
+
echo "Signer-owned WebAuthn credential enrolled successfully."
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
umask 077
|
|
5
|
+
|
|
6
|
+
if [[ "${EUID}" != "0" ]]; then
|
|
7
|
+
echo "Hosted signer network activation must run as root from a root SSH or provider-console session." >&2
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
12
|
+
export PATH
|
|
13
|
+
SIGNER_USER="fased-signer"
|
|
14
|
+
SIGNER_HOME="/var/lib/fased-signerd"
|
|
15
|
+
SIGNER_BIN="/opt/fased/signer/fased-signerd"
|
|
16
|
+
CONTROL_SOCKET="/run/fased-signerd/control.sock"
|
|
17
|
+
RUNUSER_BIN="/usr/sbin/runuser"
|
|
18
|
+
ENV_BIN="/usr/bin/env"
|
|
19
|
+
NODE_BIN="$(command -v node || true)"
|
|
20
|
+
STAT_BIN="/usr/bin/stat"
|
|
21
|
+
|
|
22
|
+
usage() {
|
|
23
|
+
cat >&2 <<'EOF'
|
|
24
|
+
usage: /usr/local/sbin/fased-signer-network --wallet-id WALLET_ID --network-file /root/fased-network.json
|
|
25
|
+
|
|
26
|
+
The root-owned network file must be mode 0400 or 0600 and contain exactly:
|
|
27
|
+
{"schemaVersion":1,"primaryRpcUrl":"https://...","fallbackRpcUrl":"https://..."}
|
|
28
|
+
|
|
29
|
+
fallbackRpcUrl is optional. RPC credentials stay in the root-only file and signer-owned database.
|
|
30
|
+
EOF
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
wallet_id=""
|
|
34
|
+
network_file=""
|
|
35
|
+
while [[ $# -gt 0 ]]; do
|
|
36
|
+
case "$1" in
|
|
37
|
+
--wallet-id)
|
|
38
|
+
shift
|
|
39
|
+
wallet_id="${1:-}"
|
|
40
|
+
;;
|
|
41
|
+
--network-file)
|
|
42
|
+
shift
|
|
43
|
+
network_file="${1:-}"
|
|
44
|
+
;;
|
|
45
|
+
--help|-h)
|
|
46
|
+
usage
|
|
47
|
+
exit 0
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
usage
|
|
51
|
+
exit 64
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
shift
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
[[ "$wallet_id" =~ ^[a-z0-9_]{1,64}$ ]] || {
|
|
58
|
+
echo "wallet ID must be the canonical native signer ID." >&2
|
|
59
|
+
exit 64
|
|
60
|
+
}
|
|
61
|
+
[[ "$network_file" == /* && -f "$network_file" && ! -L "$network_file" ]] || {
|
|
62
|
+
echo "network file must be one absolute, non-symlink regular file." >&2
|
|
63
|
+
exit 1
|
|
64
|
+
}
|
|
65
|
+
read -r file_owner file_mode file_links <<<"$($STAT_BIN -c '%u %a %h' "$network_file")"
|
|
66
|
+
[[ "$file_owner" == "0" && "$file_links" == "1" && ( "$file_mode" == "400" || "$file_mode" == "600" ) ]] || {
|
|
67
|
+
echo "network file must be root-owned, single-link, and mode 0400 or 0600." >&2
|
|
68
|
+
exit 1
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for executable in "$SIGNER_BIN" "$RUNUSER_BIN" "$ENV_BIN" "$NODE_BIN" "$STAT_BIN"; do
|
|
72
|
+
[[ -f "$executable" && -x "$executable" && ! -L "$executable" ]] || {
|
|
73
|
+
echo "Required root-controlled executable is missing or unsafe: $executable" >&2
|
|
74
|
+
exit 1
|
|
75
|
+
}
|
|
76
|
+
read -r owner mode <<<"$($STAT_BIN -Lc '%u %a' "$executable")"
|
|
77
|
+
[[ "$owner" == "0" && $((8#$mode & 8#22)) -eq 0 ]] || {
|
|
78
|
+
echo "Required executable is not root-owned and non-writable: $executable" >&2
|
|
79
|
+
exit 1
|
|
80
|
+
}
|
|
81
|
+
done
|
|
82
|
+
[[ -S "$CONTROL_SOCKET" && ! -L "$CONTROL_SOCKET" ]] || {
|
|
83
|
+
echo "Root-managed signer control socket is unavailable." >&2
|
|
84
|
+
exit 1
|
|
85
|
+
}
|
|
86
|
+
SIGNER_UID="$(id -u "$SIGNER_USER")"
|
|
87
|
+
read -r socket_owner socket_mode <<<"$($STAT_BIN -c '%u %a' "$CONTROL_SOCKET")"
|
|
88
|
+
[[ "$SIGNER_UID" != "0" && "$socket_owner" == "$SIGNER_UID" && "$socket_mode" == "600" ]] || {
|
|
89
|
+
echo "Signer control socket ownership or mode is unsafe." >&2
|
|
90
|
+
exit 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
common=(
|
|
94
|
+
"$RUNUSER_BIN" -u "$SIGNER_USER" --
|
|
95
|
+
"$ENV_BIN" -i
|
|
96
|
+
HOME="$SIGNER_HOME"
|
|
97
|
+
PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
|
98
|
+
LANG="C.UTF-8"
|
|
99
|
+
"$SIGNER_BIN" admin network
|
|
100
|
+
)
|
|
101
|
+
current="$("${common[@]}" get --control-socket "$CONTROL_SOCKET" --wallet-id "$wallet_id")"
|
|
102
|
+
|
|
103
|
+
# Validate strict JSON and bind the update to the exact signer-owned current version. Secrets are
|
|
104
|
+
# transported only on stdin; they never appear in argv, environment variables, or app-owned files.
|
|
105
|
+
request="$($NODE_BIN - "$network_file" "$wallet_id" "$current" <<'NODE'
|
|
106
|
+
const fs = require("node:fs");
|
|
107
|
+
const [file, walletId, currentRaw] = process.argv.slice(2);
|
|
108
|
+
const raw = fs.readFileSync(file, "utf8");
|
|
109
|
+
if (!raw.trim() || Buffer.byteLength(raw) > 8192) throw new Error("network file is empty or too large");
|
|
110
|
+
const keyTokens = [...raw.matchAll(/"(?:\\.|[^"\\])*"\s*:/g)].map((match) =>
|
|
111
|
+
JSON.parse(match[0].slice(0, match[0].lastIndexOf(":")).trim()),
|
|
112
|
+
);
|
|
113
|
+
if (new Set(keyTokens).size !== keyTokens.length) throw new Error("network file has duplicate fields");
|
|
114
|
+
const value = JSON.parse(raw);
|
|
115
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("network file must be an object");
|
|
116
|
+
const keys = Object.keys(value).sort();
|
|
117
|
+
const expected = value.fallbackRpcUrl === undefined
|
|
118
|
+
? ["primaryRpcUrl", "schemaVersion"]
|
|
119
|
+
: ["fallbackRpcUrl", "primaryRpcUrl", "schemaVersion"];
|
|
120
|
+
if (keys.join(",") !== expected.join(",") || value.schemaVersion !== 1) {
|
|
121
|
+
throw new Error("network file contains unsupported fields or version");
|
|
122
|
+
}
|
|
123
|
+
function rpc(name, input) {
|
|
124
|
+
if (typeof input !== "string" || !input.trim() || input.length > 2048) throw new Error(`${name} is invalid`);
|
|
125
|
+
const parsed = new URL(input.trim());
|
|
126
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password) {
|
|
127
|
+
throw new Error(`${name} must be HTTPS and must not use URL userinfo`);
|
|
128
|
+
}
|
|
129
|
+
return parsed.toString();
|
|
130
|
+
}
|
|
131
|
+
const current = JSON.parse(currentRaw);
|
|
132
|
+
if (current.walletId !== walletId || !Number.isSafeInteger(current.version) || current.version < 0) {
|
|
133
|
+
throw new Error("signer returned invalid current network metadata");
|
|
134
|
+
}
|
|
135
|
+
process.stdout.write(JSON.stringify({
|
|
136
|
+
expectedVersion: current.version,
|
|
137
|
+
primaryRpcUrl: rpc("primaryRpcUrl", value.primaryRpcUrl),
|
|
138
|
+
...(value.fallbackRpcUrl ? { fallbackRpcUrl: rpc("fallbackRpcUrl", value.fallbackRpcUrl) } : {}),
|
|
139
|
+
}));
|
|
140
|
+
NODE
|
|
141
|
+
)"
|
|
142
|
+
printf '%s\n' "$request" | "${common[@]}" put --control-socket "$CONTROL_SOCKET" --wallet-id "$wallet_id"
|
|
143
|
+
unset request current
|