space-data-module-sdk 0.8.4 → 0.8.6
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/README.md +117 -20
- package/bin/space-data-module.js +263 -0
- package/docs/.nojekyll +1 -0
- package/docs/AGENTS.md +34 -0
- package/docs/architecture.svg +141 -0
- package/docs/browser-wasmedge-isomorphic.md +179 -0
- package/docs/flatsql-streaming-standard.md +341 -0
- package/docs/gpu-module-abi.md +193 -0
- package/docs/index.html +125 -0
- package/docs/isomorphic-pthreads.md +188 -0
- package/docs/isomorphic-sdn-runtime-plan.md +167 -0
- package/docs/language-runtime-matrix.md +82 -0
- package/docs/manifest-structure.svg +114 -0
- package/docs/module-bundle-runtime-plan.md +19 -0
- package/docs/module-lifecycle.svg +70 -0
- package/docs/module-publication-standard.md +540 -0
- package/docs/node-red-default-node-parity.md +88 -0
- package/docs/protocol-installation.md +196 -0
- package/docs/secrets-capability.md +152 -0
- package/docs/styles.css +288 -0
- package/docs/testing-harness.md +408 -0
- package/docs/tri-runtime-parity.md +132 -0
- package/docs/wallet-callback.html +2 -0
- package/package.json +25 -6
- package/schemas/HttpRequestAbi.fbs +41 -0
- package/schemas/HttpResponseAbi.fbs +36 -0
- package/schemas/PluginManifest.fbs +2 -1
- package/src/AGENTS.md +1 -1
- package/src/app/codec.js +548 -0
- package/src/app/index.js +6 -0
- package/src/browser.js +5 -0
- package/src/bundle/constants.js +1 -0
- package/src/bundle/index.js +15 -0
- package/src/bundle/sigdomain.js +179 -0
- package/src/bundle/signing.js +767 -0
- package/src/bundle/wasm.js +3 -2
- package/src/capabilities.js +3 -0
- package/src/compat/index.js +7 -0
- package/src/compat/sdnLegacy.js +449 -0
- package/src/compiler/compileModule.js +556 -55
- package/src/compiler/flatcSupport.js +41 -27
- package/src/compiler/index.d.ts +2 -0
- package/src/compiler/index.js +18 -0
- package/src/compiler/invokeGlue.js +1212 -183
- package/src/compiler/pthreadArtifactGuard.js +910 -0
- package/src/compiler/sdnShimGenerator.js +323 -0
- package/src/compiler/wasiThreadsToolchain.js +150 -0
- package/src/compliance/index.js +11 -1
- package/src/compliance/legacyWildcardPorts.js +228 -0
- package/src/compliance/pluginCompliance.js +1000 -96
- package/src/field-stream/index.d.ts +31 -0
- package/src/field-stream/index.js +119 -0
- package/src/flow/dependencyStreamBridge.js +234 -0
- package/src/flow/flatsqlLinkShim.js +304 -0
- package/src/flow/flowCodec.js +107 -0
- package/src/flow/flowCompiler.js +2900 -0
- package/src/flow/flowRuntimeHost.js +877 -0
- package/src/flow/index.d.ts +117 -0
- package/src/flow/index.js +31 -0
- package/src/flow/isomorphicFlowHost.js +384 -0
- package/src/flow/jsFlowRuntime.js +275 -0
- package/src/flow/normalize.js +294 -0
- package/src/flow/runtime-src/flow_runtime.cpp +1699 -0
- package/src/flow/vendor/sdn-flow/MethodRegistry.js +400 -0
- package/src/flow/vendor/sdn-flow/constants.js +39 -0
- package/src/flow/vendor/sdn-flow/index.js +29 -0
- package/src/flow/vendor/sdn-flow/normalize.js +506 -0
- package/src/flow/vendor/sdn-flow/wasmCompatibility.js +189 -0
- package/src/generated/http/cpp/HttpRequestAbi_generated.h +285 -0
- package/src/generated/http/cpp/HttpResponseAbi_generated.h +192 -0
- package/src/generated/http/sdn/http/http-header.js +53 -0
- package/src/generated/http/sdn/http/http-header.ts +67 -0
- package/src/generated/http/sdn/http/http-request.js +132 -0
- package/src/generated/http/sdn/http/http-request.ts +179 -0
- package/src/generated/http/sdn/http/http-response.js +144 -0
- package/src/generated/http/sdn/http/http-response.ts +168 -0
- package/src/generated/http/sdn/http.js +11 -0
- package/src/generated/http/sdn/http.ts +4 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts +12 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.js +17 -0
- package/src/generated/orbpro/flow/backpressure-policy.js.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.ts +15 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts +142 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js +304 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.ts +399 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts +113 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.js +221 -0
- package/src/generated/orbpro/flow/flow-edge.js.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.ts +292 -0
- package/src/generated/orbpro/flow/flow-node.d.ts +80 -0
- package/src/generated/orbpro/flow/flow-node.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-node.js +158 -0
- package/src/generated/orbpro/flow/flow-node.js.map +1 -0
- package/src/generated/orbpro/flow/flow-node.ts +202 -0
- package/src/generated/orbpro/flow/flow-program.d.ts +164 -0
- package/src/generated/orbpro/flow/flow-program.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-program.js +350 -0
- package/src/generated/orbpro/flow/flow-program.js.map +1 -0
- package/src/generated/orbpro/flow/flow-program.ts +477 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts +108 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.js +207 -0
- package/src/generated/orbpro/flow/flow-trigger.js.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.ts +276 -0
- package/src/generated/orbpro/flow/node-kind.d.ts +13 -0
- package/src/generated/orbpro/flow/node-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/node-kind.js +16 -0
- package/src/generated/orbpro/flow/node-kind.js.map +1 -0
- package/src/generated/orbpro/{invoke.ts → flow/node-kind.ts} +12 -2
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts +52 -0
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js +85 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.ts +121 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts +70 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js +143 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.ts +189 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts +71 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.js +142 -0
- package/src/generated/orbpro/flow/trigger-binding.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.ts +181 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts +14 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.js +17 -0
- package/src/generated/orbpro/flow/trigger-kind.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.ts +17 -0
- package/src/generated/orbpro/flow.d.ts +21 -0
- package/src/generated/orbpro/flow.d.ts.map +1 -0
- package/src/generated/orbpro/flow.js +23 -0
- package/src/generated/orbpro/flow.js.map +1 -0
- package/src/generated/orbpro/flow.ts +24 -0
- package/src/generated/orbpro/manifest/capability-kind.d.ts +2 -1
- package/src/generated/orbpro/manifest/capability-kind.js +1 -0
- package/src/generated/orbpro/manifest/capability-kind.ts +1 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.d.ts +93 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.js +160 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.ts +211 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.d.ts +99 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.js +175 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.ts +226 -0
- package/src/generated/orbpro/plugin.js +8 -0
- package/src/generated/orbpro/stream.d.ts +12 -0
- package/src/generated/orbpro/stream.js +14 -0
- package/src/generated/orbpro/stream.ts +15 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts +52 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.js +106 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.ts +162 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts +90 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.js +189 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.ts +270 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts +492 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLG.js +1139 -0
- package/src/generated/spacedatastandards/plg/PLG.ts +1600 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts +63 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.js +138 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.ts +189 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.js +104 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.ts +151 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts +68 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.js +124 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.ts +184 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts +58 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.js +126 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.ts +161 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.js +164 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.ts +244 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts +55 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.js +105 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.ts +162 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.js +83 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts +36 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.js +90 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts +53 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.js +153 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.ts +210 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts +70 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.js +149 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.ts +212 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts +73 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.js +199 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.ts +292 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts +40 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.js +103 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.ts +148 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.js +82 -0
- package/src/generated/spacedatastandards/plg/{plugin-capability.ts → PluginCapability.ts} +55 -18
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.js +80 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.ts +124 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts +85 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/TAB.js +173 -0
- package/src/generated/spacedatastandards/plg/TAB.ts +228 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.ts +23 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.ts +23 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts +20 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.js +22 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.ts +25 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts +10 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.js +12 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.ts +13 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts +51 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.js +53 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.ts +55 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts +15 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.js +17 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.ts +19 -0
- package/src/generated/spacedatastandards/plg/main.d.ts +29 -0
- package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/main.js +30 -0
- package/src/generated/spacedatastandards/plg/main.ts +32 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts +17 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.js +19 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.ts +21 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.js +84 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.ts +103 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/publicationState.js +20 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.js +20 -0
- package/src/host/AGENTS.md +2 -2
- package/src/host/abi.js +53 -66
- package/src/host/browserHost.js +355 -8
- package/src/host/cpp/keyslotClient.hpp +231 -0
- package/src/host/cpp/secretsClient.hpp +583 -0
- package/src/host/hostcallWire.js +183 -0
- package/src/host/index.js +2 -0
- package/src/host/isomorphicLoader.js +44 -7
- package/src/host/nodeHost.js +227 -8
- package/src/host/sabHostcallChannel.js +206 -0
- package/src/host/timerDriver.js +203 -0
- package/src/host/wasiShim.js +41 -1
- package/src/host/wasiThreadBrowserWorker.mjs +48 -0
- package/src/host/wasiThreadHost.js +393 -0
- package/src/host/wasiThreadWorker.mjs +32 -0
- package/src/host/wasiThreadWorkerRuntime.js +93 -0
- package/src/http/index.js +339 -0
- package/src/index.d.ts +725 -11
- package/src/index.js +4 -0
- package/src/invoke/codec.js +1202 -128
- package/src/invoke/index.js +5 -1
- package/src/licensing/index.d.ts +2 -0
- package/src/licensing/index.js +2 -0
- package/src/licensing/records.js +287 -8
- package/src/manifest/codec.js +62 -14
- package/src/manifest/index.js +2 -0
- package/src/manifest/legacyToPlg.js +164 -25
- package/src/manifest/normalize.js +1 -0
- package/src/manifest/plgCodec.js +1303 -62
- package/src/manifest/typeRefs.js +162 -24
- package/src/runtime/compiledRuntimeAbi.js +47 -0
- package/src/runtime/compiledRuntimeAbi.json +33 -0
- package/src/runtime/index.d.ts +32 -0
- package/src/runtime/index.js +1 -0
- package/src/runtime-host/index.js +3 -0
- package/src/runtime-host/methodRegistry.js +55 -0
- package/src/standards/index.js +200 -56
- package/src/standards/sharedCatalog.js +16 -0
- package/src/testing/browserModuleHarness.js +604 -31
- package/src/testing/docker/wasmedge-parity.Dockerfile +39 -0
- package/src/testing/index.d.ts +151 -0
- package/src/testing/index.js +21 -0
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +25 -1
- package/src/testing/parityBrowserRunner.js +138 -0
- package/src/testing/parityHarness.js +616 -0
- package/src/testing/parityLanes.js +537 -0
- package/src/testing/processInvoke.js +29 -21
- package/src/testing/streamInvokeCodec.js +10 -175
- package/src/testing/wasmedgePin.json +6 -0
- package/src/testing/workerModuleHarness.js +242 -0
- package/src/testing/workerModuleHarnessWorker.js +176 -0
- package/src/transport/index.js +3 -0
- package/src/transport/pki.js +352 -14
- package/src/transport/records.js +16 -7
- package/src/utils/ecdsaDer.js +106 -0
- package/src/utils/wasmCrypto.js +0 -43
- package/templates/gpu-module/README.md +48 -0
- package/templates/gpu-module/include/space_data_gpu_abi.h +122 -0
- package/templates/gpu-module/manifest.json +84 -0
- package/schemas/PluginInvokeRequest.fbs +0 -18
- package/schemas/PluginInvokeResponse.fbs +0 -30
- package/schemas/spacedatastandards/PLG.fbs +0 -191
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +0 -51
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +0 -131
- package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.ts +0 -173
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +0 -76
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +0 -184
- package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.ts +0 -243
- package/src/generated/orbpro/invoke.d.ts +0 -3
- package/src/generated/orbpro/invoke.js +0 -5
- package/src/generated/spacedatastandards/plg/entry-function.js +0 -86
- package/src/generated/spacedatastandards/plg/entry-function.ts +0 -119
- package/src/generated/spacedatastandards/plg/index.js +0 -16
- package/src/generated/spacedatastandards/plg/index.ts +0 -11
- package/src/generated/spacedatastandards/plg/plg.js +0 -657
- package/src/generated/spacedatastandards/plg/plg.ts +0 -924
- package/src/generated/spacedatastandards/plg/plugin-capability.js +0 -66
- package/src/generated/spacedatastandards/plg/plugin-category.js +0 -15
- package/src/generated/spacedatastandards/plg/plugin-category.ts +0 -53
- package/src/generated/spacedatastandards/plg/plugin-dependency.js +0 -63
- package/src/generated/spacedatastandards/plg/plugin-dependency.ts +0 -86
- package/src/generated/spacedatastandards/plg/publication-state.js +0 -9
- package/src/generated/spacedatastandards/plg/purchase-tier.js +0 -9
- /package/src/generated/spacedatastandards/plg/{publication-state.ts → publicationState.ts} +0 -0
- /package/src/generated/spacedatastandards/plg/{purchase-tier.ts → purchaseTier.ts} +0 -0
package/src/host/browserHost.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
* Browser host adapter for the SDN host contract.
|
|
3
3
|
*
|
|
4
4
|
* Mirrors the NodeHost public interface using browser-native Web APIs.
|
|
5
|
-
* Plugs into
|
|
5
|
+
* Plugs into createHostcallBridge() exactly like NodeHost does.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { RuntimeTarget } from "../runtime/constants.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
base64ToBytes,
|
|
11
|
+
bytesToBase64,
|
|
12
|
+
hexToBytes,
|
|
13
|
+
toUint8Array,
|
|
14
|
+
} from "../utils/encoding.js";
|
|
15
|
+
import { derSignatureToRaw, rawSignatureToDer } from "../utils/ecdsaDer.js";
|
|
10
16
|
import {
|
|
11
17
|
parseCronExpression,
|
|
12
18
|
matchesCronExpression,
|
|
@@ -36,6 +42,9 @@ export const BrowserHostSupportedCapabilities = Object.freeze([
|
|
|
36
42
|
"crypto_key_agreement",
|
|
37
43
|
"crypto_kdf",
|
|
38
44
|
"wallet_sign",
|
|
45
|
+
"pubsub",
|
|
46
|
+
"storage_query",
|
|
47
|
+
"storage_write",
|
|
39
48
|
"logging",
|
|
40
49
|
]);
|
|
41
50
|
|
|
@@ -72,7 +81,15 @@ export const BrowserHostSupportedOperations = Object.freeze([
|
|
|
72
81
|
"protocol_handle.unregister",
|
|
73
82
|
"protocol_dial.dial",
|
|
74
83
|
"protocol.request",
|
|
75
|
-
"keyslot.
|
|
84
|
+
"keyslot.sign",
|
|
85
|
+
"keyslot.unwrap",
|
|
86
|
+
"storage.write",
|
|
87
|
+
"storage.query",
|
|
88
|
+
"storage.delete",
|
|
89
|
+
"pubsub.publish",
|
|
90
|
+
"pubsub.subscribe",
|
|
91
|
+
"pubsub.unsubscribe",
|
|
92
|
+
"pubsub.list_topics",
|
|
76
93
|
"context.get",
|
|
77
94
|
"context.set",
|
|
78
95
|
"context.delete",
|
|
@@ -86,6 +103,9 @@ export const BrowserHostSupportedOperations = Object.freeze([
|
|
|
86
103
|
"crypto.x25519.generateKeypair",
|
|
87
104
|
"crypto.x25519.publicKey",
|
|
88
105
|
"crypto.x25519.sharedSecret",
|
|
106
|
+
"crypto.secp256k1.publicKeyFromPrivate",
|
|
107
|
+
"crypto.secp256k1.sign",
|
|
108
|
+
"crypto.secp256k1.verify",
|
|
89
109
|
"crypto.ed25519.publicKeyFromSeed",
|
|
90
110
|
"crypto.ed25519.sign",
|
|
91
111
|
"crypto.ed25519.verify",
|
|
@@ -150,6 +170,13 @@ function resolveCapabilityAdapters(options = {}) {
|
|
|
150
170
|
adapters.protocolDial ??
|
|
151
171
|
adapters.protocol_dial ??
|
|
152
172
|
null,
|
|
173
|
+
storage:
|
|
174
|
+
options.storage ??
|
|
175
|
+
adapters.storage ??
|
|
176
|
+
adapters.storage_write ??
|
|
177
|
+
adapters.storage_query ??
|
|
178
|
+
null,
|
|
179
|
+
pubsub: options.pubsub ?? adapters.pubsub ?? null,
|
|
153
180
|
};
|
|
154
181
|
}
|
|
155
182
|
|
|
@@ -175,6 +202,194 @@ async function invokeAdapterMethod(adapter, methodName, params, label) {
|
|
|
175
202
|
);
|
|
176
203
|
}
|
|
177
204
|
|
|
205
|
+
// keyslotUnwrapHKDFInfo domain-separates the HKDF step of keyslot.unwrap from
|
|
206
|
+
// every other HKDF use in this host (e.g. crypto.hkdf). Must match the Go
|
|
207
|
+
// reference implementation's keyslotUnwrapHKDFInfo constant
|
|
208
|
+
// (sdn-server/internal/modulert/caps/keyslot.go) exactly, or wrapped
|
|
209
|
+
// payloads produced against one host will fail to unwrap on the other.
|
|
210
|
+
const KEYSLOT_UNWRAP_HKDF_INFO = "sdn-server/keyslot.unwrap/v1";
|
|
211
|
+
const keyslotTextEncoder = new TextEncoder();
|
|
212
|
+
|
|
213
|
+
// normalizeKeySlotMaterial accepts the raw key-slot secret returned by a
|
|
214
|
+
// host-supplied walletSign adapter's internal "get" resolver and coerces it
|
|
215
|
+
// to a Uint8Array. This resolver is never exposed to the guest directly
|
|
216
|
+
// (there is no "keyslot.get" hostcall) — it only feeds the host-side
|
|
217
|
+
// keyslot.sign / keyslot.unwrap crypto oracle below, mirroring Go's
|
|
218
|
+
// resolveKeySlot() in keyslot.go. Callers MUST NOT return the result of this
|
|
219
|
+
// function, or any encoding of it, to the guest.
|
|
220
|
+
function normalizeKeySlotMaterial(raw) {
|
|
221
|
+
if (raw instanceof Uint8Array) {
|
|
222
|
+
return raw;
|
|
223
|
+
}
|
|
224
|
+
if (raw instanceof ArrayBuffer) {
|
|
225
|
+
return new Uint8Array(raw);
|
|
226
|
+
}
|
|
227
|
+
if (ArrayBuffer.isView(raw)) {
|
|
228
|
+
return toUint8Array(raw);
|
|
229
|
+
}
|
|
230
|
+
if (typeof raw === "string") {
|
|
231
|
+
return base64ToBytes(raw);
|
|
232
|
+
}
|
|
233
|
+
if (raw && typeof raw === "object") {
|
|
234
|
+
if (raw.base64 !== undefined) {
|
|
235
|
+
return base64ToBytes(raw.base64);
|
|
236
|
+
}
|
|
237
|
+
if (raw.hex !== undefined) {
|
|
238
|
+
return hexToBytes(raw.hex);
|
|
239
|
+
}
|
|
240
|
+
if (raw.value !== undefined) {
|
|
241
|
+
return normalizeKeySlotMaterial(raw.value);
|
|
242
|
+
}
|
|
243
|
+
if (raw.bytes !== undefined) {
|
|
244
|
+
return normalizeKeySlotMaterial(raw.bytes);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
throw new Error(
|
|
248
|
+
"wallet_sign adapter returned an unrecognized key-slot material shape.",
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function resolveKeySlotMaterial(walletSignAdapter, slotId) {
|
|
253
|
+
const normalizedSlotId = String(slotId ?? "").trim();
|
|
254
|
+
if (!normalizedSlotId) {
|
|
255
|
+
throw new Error("slotId is required.");
|
|
256
|
+
}
|
|
257
|
+
const record = await invokeAdapterMethod(
|
|
258
|
+
walletSignAdapter,
|
|
259
|
+
"get",
|
|
260
|
+
{ slotId: normalizedSlotId },
|
|
261
|
+
"wallet_sign",
|
|
262
|
+
);
|
|
263
|
+
const material = normalizeKeySlotMaterial(record);
|
|
264
|
+
if (material.length === 0) {
|
|
265
|
+
throw new Error(`keyslot "${normalizedSlotId}" not found`);
|
|
266
|
+
}
|
|
267
|
+
return material;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// keyslotSign performs a host-side signature over a guest-supplied payload
|
|
271
|
+
// using the named slot's private key. Request:
|
|
272
|
+
// {slotId, payload: base64, algorithm?: "ed25519" | "secp256k1"}
|
|
273
|
+
// algorithm defaults to "ed25519". Response: {signature: base64, algorithm}.
|
|
274
|
+
// The slot's key material never appears in the response. Mirrors
|
|
275
|
+
// handleKeyslotSign() in keyslot.go.
|
|
276
|
+
async function keyslotSign(walletSignAdapter, wasmWallet, params = {}) {
|
|
277
|
+
const slotId = String(params.slotId ?? "").trim();
|
|
278
|
+
if (!slotId) {
|
|
279
|
+
throw new Error("slotId is required.");
|
|
280
|
+
}
|
|
281
|
+
const keyMaterial = await resolveKeySlotMaterial(walletSignAdapter, slotId);
|
|
282
|
+
const payload =
|
|
283
|
+
params.payload === undefined || params.payload === null
|
|
284
|
+
? new Uint8Array()
|
|
285
|
+
: base64ToBytes(String(params.payload));
|
|
286
|
+
const algorithm = String(params.algorithm ?? "").trim() || "ed25519";
|
|
287
|
+
|
|
288
|
+
if (algorithm === "ed25519") {
|
|
289
|
+
if (!wasmWallet?.curves?.ed25519?.sign) {
|
|
290
|
+
throw new Error(
|
|
291
|
+
"Browser host keyslot.sign requires a preloaded wasmWallet.",
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (keyMaterial.length !== 32) {
|
|
295
|
+
throw new Error(`keyslot "${slotId}" is not a 32-byte ed25519 seed`);
|
|
296
|
+
}
|
|
297
|
+
const signature = new Uint8Array(
|
|
298
|
+
wasmWallet.curves.ed25519.sign(payload, keyMaterial),
|
|
299
|
+
);
|
|
300
|
+
return { signature: bytesToBase64(signature), algorithm: "ed25519" };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (algorithm === "secp256k1") {
|
|
304
|
+
if (!wasmWallet?.utils?.sha256 || !wasmWallet?.curves?.secp256k1?.sign) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"Browser host keyslot.sign requires a preloaded wasmWallet.",
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
if (keyMaterial.length !== 32) {
|
|
310
|
+
throw new Error(
|
|
311
|
+
`keyslot "${slotId}" is not a 32-byte secp256k1 private key`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
const digest = new Uint8Array(wasmWallet.utils.sha256(payload));
|
|
315
|
+
const rawSignature = new Uint8Array(
|
|
316
|
+
wasmWallet.curves.secp256k1.sign(digest, keyMaterial),
|
|
317
|
+
);
|
|
318
|
+
return {
|
|
319
|
+
signature: bytesToBase64(rawSignatureToDer(rawSignature)),
|
|
320
|
+
algorithm: "secp256k1",
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
throw new Error(`unsupported keyslot.sign algorithm: ${algorithm}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// keyslotUnwrap decrypts a payload that was sealed to a slot's X25519 public
|
|
328
|
+
// key, returning only the decrypted plaintext (e.g. a licensing content key)
|
|
329
|
+
// — never the slot's private key. Wrap scheme is ephemeral-sender ECIES:
|
|
330
|
+
// X25519(slotPrivateKey, ephemeralPublicKey) -> HKDF-SHA256 -> AES-256-GCM.
|
|
331
|
+
// Request:
|
|
332
|
+
// {slotId, ephemeralPublicKey: base64, nonce: base64, ciphertext: base64}
|
|
333
|
+
// Response: {plaintext: base64}. Mirrors handleKeyslotUnwrap() in
|
|
334
|
+
// keyslot.go, including the wire format where `ciphertext` is
|
|
335
|
+
// (ciphertext || 16-byte GCM tag), per Go's crypto/cipher.GCM convention.
|
|
336
|
+
async function keyslotUnwrap(walletSignAdapter, wasmWallet, params = {}) {
|
|
337
|
+
const slotId = String(params.slotId ?? "").trim();
|
|
338
|
+
if (!slotId) {
|
|
339
|
+
throw new Error("slotId is required.");
|
|
340
|
+
}
|
|
341
|
+
if (
|
|
342
|
+
!wasmWallet?.curves?.x25519?.ecdh ||
|
|
343
|
+
!wasmWallet?.utils?.hkdf ||
|
|
344
|
+
!wasmWallet?.utils?.aesGcm?.decrypt
|
|
345
|
+
) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
"Browser host keyslot.unwrap requires a preloaded wasmWallet.",
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
const keyMaterial = await resolveKeySlotMaterial(walletSignAdapter, slotId);
|
|
351
|
+
if (keyMaterial.length !== 32) {
|
|
352
|
+
throw new Error(
|
|
353
|
+
`keyslot "${slotId}" is not a 32-byte x25519 private key`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const ephemeralPublicKey = base64ToBytes(
|
|
358
|
+
String(params.ephemeralPublicKey ?? ""),
|
|
359
|
+
);
|
|
360
|
+
const nonce = base64ToBytes(String(params.nonce ?? ""));
|
|
361
|
+
const wireCiphertext = base64ToBytes(String(params.ciphertext ?? ""));
|
|
362
|
+
if (ephemeralPublicKey.length === 0 || wireCiphertext.length === 0) {
|
|
363
|
+
throw new Error(
|
|
364
|
+
"keyslot.unwrap requires ephemeralPublicKey and ciphertext",
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
if (wireCiphertext.length < 16) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
"keyslot.unwrap ciphertext is too short to contain a GCM tag",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
const tagStart = wireCiphertext.length - 16;
|
|
373
|
+
const ciphertext = wireCiphertext.subarray(0, tagStart);
|
|
374
|
+
const tag = wireCiphertext.subarray(tagStart);
|
|
375
|
+
|
|
376
|
+
const sharedSecret = new Uint8Array(
|
|
377
|
+
wasmWallet.curves.x25519.ecdh(keyMaterial, ephemeralPublicKey),
|
|
378
|
+
);
|
|
379
|
+
const aesKey = new Uint8Array(
|
|
380
|
+
wasmWallet.utils.hkdf(
|
|
381
|
+
sharedSecret,
|
|
382
|
+
new Uint8Array(),
|
|
383
|
+
keyslotTextEncoder.encode(KEYSLOT_UNWRAP_HKDF_INFO),
|
|
384
|
+
32,
|
|
385
|
+
),
|
|
386
|
+
);
|
|
387
|
+
const plaintext = new Uint8Array(
|
|
388
|
+
wasmWallet.utils.aesGcm.decrypt(aesKey, ciphertext, tag, nonce),
|
|
389
|
+
);
|
|
390
|
+
return { plaintext: bytesToBase64(plaintext) };
|
|
391
|
+
}
|
|
392
|
+
|
|
178
393
|
export class BrowserHost {
|
|
179
394
|
constructor(options = {}) {
|
|
180
395
|
this.runtimeTarget = RuntimeTarget.BROWSER;
|
|
@@ -214,6 +429,8 @@ export class BrowserHost {
|
|
|
214
429
|
const walletSignAdapter = capabilityAdapters.walletSign;
|
|
215
430
|
const protocolHandleAdapter = edgeShims.protocolHandle;
|
|
216
431
|
const protocolDialAdapter = edgeShims.protocolDial;
|
|
432
|
+
const storageAdapter = capabilityAdapters.storage;
|
|
433
|
+
const pubsubAdapter = capabilityAdapters.pubsub;
|
|
217
434
|
|
|
218
435
|
this._grantedCapabilities = granted;
|
|
219
436
|
this._contextStore = options.contextStore ?? new Map();
|
|
@@ -440,10 +657,60 @@ export class BrowserHost {
|
|
|
440
657
|
},
|
|
441
658
|
});
|
|
442
659
|
|
|
660
|
+
// keyslot is a host-side crypto oracle (parity with the Go node's
|
|
661
|
+
// internal/modulert/caps/keyslot.go): it never returns a slot's private
|
|
662
|
+
// key material to the guest. Guests get the *outputs* of private-key
|
|
663
|
+
// operations (a signature, or the plaintext that was wrapped to a
|
|
664
|
+
// slot's public key) — never the key itself. There is no "keyslot.get"
|
|
665
|
+
// raw-export operation; unknown keyslot operations fail closed via the
|
|
666
|
+
// default branch of invoke()'s switch below.
|
|
443
667
|
this.keyslot = Object.freeze({
|
|
444
|
-
|
|
445
|
-
this.#assertCapability("wallet_sign", "keyslot.
|
|
446
|
-
return
|
|
668
|
+
sign: async (params = {}) => {
|
|
669
|
+
this.#assertCapability("wallet_sign", "keyslot.sign");
|
|
670
|
+
return keyslotSign(walletSignAdapter, wasmWallet, params);
|
|
671
|
+
},
|
|
672
|
+
unwrap: async (params = {}) => {
|
|
673
|
+
this.#assertCapability("wallet_sign", "keyslot.unwrap");
|
|
674
|
+
return keyslotUnwrap(walletSignAdapter, wasmWallet, params);
|
|
675
|
+
},
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// Storage + pubsub mirror the Go node's module capability contract
|
|
679
|
+
// (sdn-server internal/modulert/caps): storage.write {schema, data:base64}
|
|
680
|
+
// -> {cid}; storage.query {schema, day, entity_id, norad_cat_id, limit};
|
|
681
|
+
// storage.delete {schema, cid}; pubsub.publish {topic, data:utf8};
|
|
682
|
+
// pubsub.subscribe/unsubscribe {topic}; pubsub.list_topics {} -> {topics}.
|
|
683
|
+
this.storage = Object.freeze({
|
|
684
|
+
write: async (params = {}) => {
|
|
685
|
+
this.#assertCapability("storage_write", "storage.write");
|
|
686
|
+
return invokeAdapterMethod(storageAdapter, "write", params, "storage");
|
|
687
|
+
},
|
|
688
|
+
query: async (params = {}) => {
|
|
689
|
+
this.#assertCapability("storage_query", "storage.query");
|
|
690
|
+
return invokeAdapterMethod(storageAdapter, "query", params, "storage");
|
|
691
|
+
},
|
|
692
|
+
delete: async (params = {}) => {
|
|
693
|
+
this.#assertCapability("storage_write", "storage.delete");
|
|
694
|
+
return invokeAdapterMethod(storageAdapter, "delete", params, "storage");
|
|
695
|
+
},
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
this.pubsub = Object.freeze({
|
|
699
|
+
publish: async (params = {}) => {
|
|
700
|
+
this.#assertCapability("pubsub", "pubsub.publish");
|
|
701
|
+
return invokeAdapterMethod(pubsubAdapter, "publish", params, "pubsub");
|
|
702
|
+
},
|
|
703
|
+
subscribe: async (params = {}) => {
|
|
704
|
+
this.#assertCapability("pubsub", "pubsub.subscribe");
|
|
705
|
+
return invokeAdapterMethod(pubsubAdapter, "subscribe", params, "pubsub");
|
|
706
|
+
},
|
|
707
|
+
unsubscribe: async (params = {}) => {
|
|
708
|
+
this.#assertCapability("pubsub", "pubsub.unsubscribe");
|
|
709
|
+
return invokeAdapterMethod(pubsubAdapter, "unsubscribe", params, "pubsub");
|
|
710
|
+
},
|
|
711
|
+
listTopics: async (params = {}) => {
|
|
712
|
+
this.#assertCapability("pubsub", "pubsub.list_topics");
|
|
713
|
+
return invokeAdapterMethod(pubsubAdapter, "list_topics", params, "pubsub");
|
|
447
714
|
},
|
|
448
715
|
});
|
|
449
716
|
|
|
@@ -590,6 +857,60 @@ export class BrowserHost {
|
|
|
590
857
|
),
|
|
591
858
|
);
|
|
592
859
|
},
|
|
860
|
+
secp256k1: Object.freeze({
|
|
861
|
+
publicKeyFromPrivate: (privateKey) => {
|
|
862
|
+
this.#assertCapability(
|
|
863
|
+
"crypto_sign",
|
|
864
|
+
"crypto.secp256k1.publicKeyFromPrivate",
|
|
865
|
+
);
|
|
866
|
+
if (!wasmWallet?.curves?.publicKeyFromPrivate) {
|
|
867
|
+
throw new Error(
|
|
868
|
+
"Browser host crypto.secp256k1.publicKeyFromPrivate requires a preloaded wasmWallet.",
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
return new Uint8Array(
|
|
872
|
+
wasmWallet.curves.publicKeyFromPrivate(toUint8Array(privateKey)),
|
|
873
|
+
);
|
|
874
|
+
},
|
|
875
|
+
sign: (message, privateKey) => {
|
|
876
|
+
this.#assertCapability("crypto_sign", "crypto.secp256k1.sign");
|
|
877
|
+
if (
|
|
878
|
+
!wasmWallet?.utils?.sha256 ||
|
|
879
|
+
!wasmWallet?.curves?.secp256k1?.sign
|
|
880
|
+
) {
|
|
881
|
+
throw new Error(
|
|
882
|
+
"Browser host crypto.secp256k1.sign requires a preloaded wasmWallet.",
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
const digest = new Uint8Array(
|
|
886
|
+
wasmWallet.utils.sha256(toUint8Array(message)),
|
|
887
|
+
);
|
|
888
|
+
const rawSignature = new Uint8Array(
|
|
889
|
+
wasmWallet.curves.secp256k1.sign(digest, toUint8Array(privateKey)),
|
|
890
|
+
);
|
|
891
|
+
return rawSignatureToDer(rawSignature);
|
|
892
|
+
},
|
|
893
|
+
verify: (message, signature, publicKey) => {
|
|
894
|
+
this.#assertCapability("crypto_verify", "crypto.secp256k1.verify");
|
|
895
|
+
if (
|
|
896
|
+
!wasmWallet?.utils?.sha256 ||
|
|
897
|
+
!wasmWallet?.curves?.secp256k1?.verify
|
|
898
|
+
) {
|
|
899
|
+
throw new Error(
|
|
900
|
+
"Browser host crypto.secp256k1.verify requires a preloaded wasmWallet.",
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
const digest = new Uint8Array(
|
|
904
|
+
wasmWallet.utils.sha256(toUint8Array(message)),
|
|
905
|
+
);
|
|
906
|
+
const result = wasmWallet.curves.secp256k1.verify(
|
|
907
|
+
digest,
|
|
908
|
+
derSignatureToRaw(signature),
|
|
909
|
+
toUint8Array(publicKey),
|
|
910
|
+
);
|
|
911
|
+
return { result: Boolean(result) };
|
|
912
|
+
},
|
|
913
|
+
}),
|
|
593
914
|
ed25519: Object.freeze({
|
|
594
915
|
publicKeyFromSeed: (seed) => {
|
|
595
916
|
this.#assertCapability("crypto_sign", "crypto.ed25519.publicKeyFromSeed");
|
|
@@ -774,8 +1095,24 @@ export class BrowserHost {
|
|
|
774
1095
|
return this.protocolDial.dial(params);
|
|
775
1096
|
case "protocol.request":
|
|
776
1097
|
return this.protocolDial.request(params);
|
|
777
|
-
case "keyslot.
|
|
778
|
-
return this.keyslot.
|
|
1098
|
+
case "keyslot.sign":
|
|
1099
|
+
return this.keyslot.sign(params);
|
|
1100
|
+
case "keyslot.unwrap":
|
|
1101
|
+
return this.keyslot.unwrap(params);
|
|
1102
|
+
case "storage.write":
|
|
1103
|
+
return this.storage.write(params);
|
|
1104
|
+
case "storage.query":
|
|
1105
|
+
return this.storage.query(params);
|
|
1106
|
+
case "storage.delete":
|
|
1107
|
+
return this.storage.delete(params);
|
|
1108
|
+
case "pubsub.publish":
|
|
1109
|
+
return this.pubsub.publish(params);
|
|
1110
|
+
case "pubsub.subscribe":
|
|
1111
|
+
return this.pubsub.subscribe(params);
|
|
1112
|
+
case "pubsub.unsubscribe":
|
|
1113
|
+
return this.pubsub.unsubscribe(params);
|
|
1114
|
+
case "pubsub.list_topics":
|
|
1115
|
+
return this.pubsub.listTopics(params);
|
|
779
1116
|
case "context.get":
|
|
780
1117
|
return this.context.get(params.scope, params.key);
|
|
781
1118
|
case "context.set":
|
|
@@ -805,6 +1142,16 @@ export class BrowserHost {
|
|
|
805
1142
|
params.privateKey,
|
|
806
1143
|
params.publicKey,
|
|
807
1144
|
);
|
|
1145
|
+
case "crypto.secp256k1.publicKeyFromPrivate":
|
|
1146
|
+
return this.crypto.secp256k1.publicKeyFromPrivate(params.privateKey);
|
|
1147
|
+
case "crypto.secp256k1.sign":
|
|
1148
|
+
return this.crypto.secp256k1.sign(params.message, params.privateKey);
|
|
1149
|
+
case "crypto.secp256k1.verify":
|
|
1150
|
+
return this.crypto.secp256k1.verify(
|
|
1151
|
+
params.message,
|
|
1152
|
+
params.signature,
|
|
1153
|
+
params.publicKey,
|
|
1154
|
+
);
|
|
808
1155
|
case "crypto.ed25519.publicKeyFromSeed":
|
|
809
1156
|
return this.crypto.ed25519.publicKeyFromSeed(params.seed);
|
|
810
1157
|
case "crypto.ed25519.sign":
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// C++ guest-side wrapper for the `keyslot` host capability.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors the intent of space-data-module-sdk/src/host/hostcallWire.js plus
|
|
4
|
+
// the server-side handlers in
|
|
5
|
+
// sdn-server/internal/modulert/caps/keyslot.go: `keyslot` is a host-side
|
|
6
|
+
// crypto oracle. A module never receives a slot's private key material —
|
|
7
|
+
// only the *outputs* of private-key operations cross the host/guest
|
|
8
|
+
// boundary (a signature; the plaintext of a payload wrapped to a slot's
|
|
9
|
+
// public key). The removed `keyslot.get` raw-export operation must never be
|
|
10
|
+
// reintroduced here.
|
|
11
|
+
//
|
|
12
|
+
// This header assumes the including translation unit has already pulled in
|
|
13
|
+
// the sdm_hostcall wire protocol (sdm_hostcall::call / Segment / Response —
|
|
14
|
+
// see space-data-network-modules/common/sdm_hostcall_wire.hpp) ahead of this
|
|
15
|
+
// file, since that protocol is what actually crosses the WASM import
|
|
16
|
+
// boundary. Keeping that as a precondition (rather than a relative
|
|
17
|
+
// #include reaching across repos) avoids a fragile cross-repo path that
|
|
18
|
+
// would break depending on checkout layout.
|
|
19
|
+
//
|
|
20
|
+
// keyslot.sign request/response wire shape (JSON meta document; the
|
|
21
|
+
// payload bytes travel as a binary segment referenced by "$bin", not
|
|
22
|
+
// inline base64 — the host bridge base64-encodes it for the capability
|
|
23
|
+
// handler on the way through):
|
|
24
|
+
//
|
|
25
|
+
// -> {"slotId":"...", "payload":{"$bin":0}, "algorithm":"ed25519"}
|
|
26
|
+
// <- {"signature":"<base64>", "algorithm":"ed25519"}
|
|
27
|
+
//
|
|
28
|
+
// See sdn-server/internal/modulert/caps/keyslot.go (handleKeyslotSign) for
|
|
29
|
+
// the authoritative host-side implementation.
|
|
30
|
+
|
|
31
|
+
#ifndef SDM_KEYSLOT_CLIENT_HPP
|
|
32
|
+
#define SDM_KEYSLOT_CLIENT_HPP
|
|
33
|
+
|
|
34
|
+
#ifndef SDM_HOSTCALL_WIRE_HPP
|
|
35
|
+
#error "include sdm_hostcall_wire.hpp (sdm_hostcall::call/Segment/Response) before keyslotClient.hpp"
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
#include <cstdint>
|
|
39
|
+
#include <string>
|
|
40
|
+
#include <string_view>
|
|
41
|
+
#include <vector>
|
|
42
|
+
|
|
43
|
+
namespace sdm_keyslot {
|
|
44
|
+
|
|
45
|
+
namespace detail {
|
|
46
|
+
|
|
47
|
+
inline std::string escape_json_string(std::string_view value) {
|
|
48
|
+
std::string escaped;
|
|
49
|
+
escaped.reserve(value.size());
|
|
50
|
+
for (const char c : value) {
|
|
51
|
+
switch (c) {
|
|
52
|
+
case '"':
|
|
53
|
+
escaped += "\\\"";
|
|
54
|
+
break;
|
|
55
|
+
case '\\':
|
|
56
|
+
escaped += "\\\\";
|
|
57
|
+
break;
|
|
58
|
+
case '\n':
|
|
59
|
+
escaped += "\\n";
|
|
60
|
+
break;
|
|
61
|
+
case '\r':
|
|
62
|
+
escaped += "\\r";
|
|
63
|
+
break;
|
|
64
|
+
case '\t':
|
|
65
|
+
escaped += "\\t";
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
escaped.push_back(c);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return escaped;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
inline int decode_base64_char(char c) {
|
|
76
|
+
if (c >= 'A' && c <= 'Z') return c - 'A';
|
|
77
|
+
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
|
78
|
+
if (c >= '0' && c <= '9') return c - '0' + 52;
|
|
79
|
+
if (c == '+') return 62;
|
|
80
|
+
if (c == '/') return 63;
|
|
81
|
+
if (c == '=') return -2;
|
|
82
|
+
return -1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
inline bool decode_base64_bytes(std::string_view text, std::vector<uint8_t>* bytes_out) {
|
|
86
|
+
if (!bytes_out) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
bytes_out->clear();
|
|
90
|
+
uint32_t accumulator = 0;
|
|
91
|
+
int bits_collected = 0;
|
|
92
|
+
bool padding_seen = false;
|
|
93
|
+
for (const char c : text) {
|
|
94
|
+
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const int decoded = decode_base64_char(c);
|
|
98
|
+
if (decoded == -1) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (decoded == -2) {
|
|
102
|
+
padding_seen = true;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (padding_seen) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
accumulator = (accumulator << 6) | static_cast<uint32_t>(decoded);
|
|
109
|
+
bits_collected += 6;
|
|
110
|
+
if (bits_collected >= 8) {
|
|
111
|
+
bits_collected -= 8;
|
|
112
|
+
bytes_out->push_back(static_cast<uint8_t>((accumulator >> bits_collected) & 0xffu));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
inline size_t skip_json_ws(std::string_view text, size_t cursor) {
|
|
119
|
+
while (cursor < text.size()) {
|
|
120
|
+
const char c = text[cursor];
|
|
121
|
+
if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
++cursor;
|
|
125
|
+
}
|
|
126
|
+
return cursor;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Minimal find-key-then-read-string-value JSON scan. Good enough for the
|
|
130
|
+
// small, flat `{"signature":"...","algorithm":"..."}` result documents this
|
|
131
|
+
// header parses; not a general JSON parser.
|
|
132
|
+
inline bool extract_json_string_field(
|
|
133
|
+
std::string_view text,
|
|
134
|
+
std::string_view field,
|
|
135
|
+
std::string* value_out) {
|
|
136
|
+
if (!value_out) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const std::string marker = "\"" + std::string(field) + "\"";
|
|
140
|
+
const size_t field_pos = text.find(marker);
|
|
141
|
+
if (field_pos == std::string_view::npos) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const size_t colon_pos = text.find(':', field_pos + marker.size());
|
|
145
|
+
if (colon_pos == std::string_view::npos) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
size_t cursor = skip_json_ws(text, colon_pos + 1);
|
|
149
|
+
if (cursor >= text.size() || text[cursor] != '"') {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
++cursor;
|
|
153
|
+
|
|
154
|
+
std::string out;
|
|
155
|
+
while (cursor < text.size()) {
|
|
156
|
+
const char c = text[cursor++];
|
|
157
|
+
if (c == '"') {
|
|
158
|
+
*value_out = out;
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (c == '\\') {
|
|
162
|
+
if (cursor >= text.size()) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
const char escaped = text[cursor++];
|
|
166
|
+
switch (escaped) {
|
|
167
|
+
case '"':
|
|
168
|
+
case '\\':
|
|
169
|
+
case '/':
|
|
170
|
+
out.push_back(escaped);
|
|
171
|
+
break;
|
|
172
|
+
case 'b':
|
|
173
|
+
out.push_back('\b');
|
|
174
|
+
break;
|
|
175
|
+
case 'f':
|
|
176
|
+
out.push_back('\f');
|
|
177
|
+
break;
|
|
178
|
+
case 'n':
|
|
179
|
+
out.push_back('\n');
|
|
180
|
+
break;
|
|
181
|
+
case 'r':
|
|
182
|
+
out.push_back('\r');
|
|
183
|
+
break;
|
|
184
|
+
case 't':
|
|
185
|
+
out.push_back('\t');
|
|
186
|
+
break;
|
|
187
|
+
default:
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
out.push_back(c);
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
} // namespace detail
|
|
198
|
+
|
|
199
|
+
// keyslot_sign asks the host to sign `data` (length `len`) using the
|
|
200
|
+
// private key material held in slot `slot_id`. `algorithm` is "ed25519" (the
|
|
201
|
+
// default) or "secp256k1" — it must match what the slot actually holds. The
|
|
202
|
+
// slot's private key never crosses into guest memory; only the resulting
|
|
203
|
+
// signature does. Returns false on any hostcall, transport, or decode
|
|
204
|
+
// failure and leaves `signature_out` untouched in that case.
|
|
205
|
+
inline bool keyslot_sign(
|
|
206
|
+
std::string_view slot_id,
|
|
207
|
+
const uint8_t* data,
|
|
208
|
+
size_t len,
|
|
209
|
+
std::vector<uint8_t>* signature_out,
|
|
210
|
+
std::string_view algorithm = "ed25519") {
|
|
211
|
+
if (!signature_out || slot_id.empty()) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
const std::string meta =
|
|
215
|
+
"{\"slotId\":\"" + detail::escape_json_string(slot_id) +
|
|
216
|
+
"\",\"payload\":{\"$bin\":0},\"algorithm\":\"" +
|
|
217
|
+
detail::escape_json_string(algorithm) + "\"}";
|
|
218
|
+
sdm_hostcall::Response response;
|
|
219
|
+
if (!sdm_hostcall::call("keyslot.sign", meta, {{data, len}}, &response)) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
std::string signature_base64;
|
|
223
|
+
if (!detail::extract_json_string_field(response.meta, "signature", &signature_base64)) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
return detail::decode_base64_bytes(signature_base64, signature_out);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
} // namespace sdm_keyslot
|
|
230
|
+
|
|
231
|
+
#endif // SDM_KEYSLOT_CLIENT_HPP
|