@calimero-network/mero-js 26.10.0 → 27.0.0
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 +73 -288
- package/dist/cloud-v2/attestation.d.ts +91 -0
- package/dist/cloud-v2/attestation.js +135 -0
- package/dist/cloud-v2/capabilities.d.ts +30 -0
- package/dist/cloud-v2/capabilities.js +31 -0
- package/dist/cloud-v2/client.d.ts +426 -0
- package/dist/cloud-v2/client.js +646 -0
- package/dist/cloud-v2/errors.d.ts +98 -0
- package/dist/cloud-v2/errors.js +165 -0
- package/dist/cloud-v2/index.d.ts +10 -0
- package/dist/cloud-v2/index.js +5 -0
- package/dist/cloud-v2/passkey.d.ts +27 -0
- package/dist/cloud-v2/passkey.js +73 -0
- package/dist/crypto/internal.d.ts +3 -37
- package/dist/crypto/internal.js +3 -72
- package/dist/index.browser.mjs +4 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +1750 -12767
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -56
- package/dist/index.js +14 -75
- package/dist/index.mjs +1750 -12767
- package/dist/index.mjs.map +4 -4
- package/dist/sealed/index.d.ts +4 -4
- package/dist/sealed/index.js +2 -2
- package/dist/sealed/release.d.ts +21 -76
- package/dist/sealed/release.js +24 -108
- package/dist/sealed/sealed.d.ts +8 -56
- package/dist/sealed/sealed.js +11 -89
- package/dist/sealed/verify.d.ts +7 -13
- package/dist/sealed/verify.js +3 -7
- package/package.json +8 -13
- package/dist/account/account-admin.d.ts +0 -80
- package/dist/account/account-admin.js +0 -346
- package/dist/account/account.d.ts +0 -196
- package/dist/account/account.js +0 -269
- package/dist/account/application-id.d.ts +0 -50
- package/dist/account/application-id.js +0 -83
- package/dist/account/bootstrap-from-invitation.d.ts +0 -110
- package/dist/account/bootstrap-from-invitation.js +0 -80
- package/dist/account/create-context.d.ts +0 -103
- package/dist/account/create-context.js +0 -267
- package/dist/account/govern.d.ts +0 -24
- package/dist/account/govern.js +0 -50
- package/dist/account/index.d.ts +0 -26
- package/dist/account/index.js +0 -15
- package/dist/account/join-as-account.d.ts +0 -23
- package/dist/account/join-as-account.js +0 -34
- package/dist/account/join-with-node.d.ts +0 -115
- package/dist/account/join-with-node.js +0 -161
- package/dist/account/node-admin.d.ts +0 -20
- package/dist/account/node-admin.js +0 -33
- package/dist/account/relay-from-invitation.d.ts +0 -137
- package/dist/account/relay-from-invitation.js +0 -180
- package/dist/account/relay-login-error.d.ts +0 -32
- package/dist/account/relay-login-error.js +0 -34
- package/dist/account/session.d.ts +0 -266
- package/dist/account/session.js +0 -915
- package/dist/account/wordlist.d.ts +0 -16
- package/dist/account/wordlist.js +0 -273
- package/dist/admin-api/admin-client.d.ts +0 -686
- package/dist/admin-api/admin-client.js +0 -1225
- package/dist/admin-api/admin-factory.d.ts +0 -14
- package/dist/admin-api/admin-factory.js +0 -22
- package/dist/admin-api/admin-types.d.ts +0 -2041
- package/dist/admin-api/admin-types.js +0 -12
- package/dist/admin-api/index.d.ts +0 -4
- package/dist/admin-api/index.js +0 -5
- package/dist/admin-api/redeem-invitation.d.ts +0 -101
- package/dist/admin-api/redeem-invitation.js +0 -200
- package/dist/auth/index.d.ts +0 -34
- package/dist/auth/index.js +0 -67
- package/dist/auth-api/auth-client.d.ts +0 -31
- package/dist/auth-api/auth-client.js +0 -117
- package/dist/auth-api/auth-factory.d.ts +0 -7
- package/dist/auth-api/auth-factory.js +0 -41
- package/dist/auth-api/auth-types.d.ts +0 -130
- package/dist/auth-api/auth-types.js +0 -2
- package/dist/auth-api/index.d.ts +0 -3
- package/dist/auth-api/index.js +0 -4
- package/dist/capabilities.d.ts +0 -84
- package/dist/capabilities.js +0 -117
- package/dist/cloud/account-ownership.d.ts +0 -63
- package/dist/cloud/account-ownership.js +0 -87
- package/dist/cloud/cloud-client.d.ts +0 -949
- package/dist/cloud/cloud-client.js +0 -1068
- package/dist/cloud/connect.d.ts +0 -213
- package/dist/cloud/connect.js +0 -260
- package/dist/cloud/enrol-redirect.d.ts +0 -181
- package/dist/cloud/enrol-redirect.js +0 -244
- package/dist/cloud/index.d.ts +0 -12
- package/dist/cloud/index.js +0 -10
- package/dist/cloud/link-redirect.d.ts +0 -95
- package/dist/cloud/link-redirect.js +0 -121
- package/dist/cloud/link-state.d.ts +0 -36
- package/dist/cloud/link-state.js +0 -104
- package/dist/cloud/routing-proof.d.ts +0 -113
- package/dist/cloud/routing-proof.js +0 -96
- package/dist/device-cert/device-cert.d.ts +0 -189
- package/dist/device-cert/device-cert.js +0 -239
- package/dist/device-cert/device-scope.d.ts +0 -58
- package/dist/device-cert/device-scope.js +0 -76
- package/dist/device-cert/index.d.ts +0 -4
- package/dist/device-cert/index.js +0 -3
- package/dist/ephemeral/codec.d.ts +0 -4
- package/dist/ephemeral/codec.js +0 -12
- package/dist/ephemeral/index.d.ts +0 -57
- package/dist/ephemeral/index.js +0 -101
- package/dist/ephemeral/types.d.ts +0 -27
- package/dist/ephemeral/types.js +0 -1
- package/dist/errors/classify.d.ts +0 -65
- package/dist/errors/classify.js +0 -117
- package/dist/errors/index.d.ts +0 -2
- package/dist/errors/index.js +0 -1
- package/dist/events/group.d.ts +0 -95
- package/dist/events/group.js +0 -10
- package/dist/events/index.d.ts +0 -5
- package/dist/events/index.js +0 -2
- package/dist/events/sse.d.ts +0 -127
- package/dist/events/sse.js +0 -469
- package/dist/events/ws.d.ts +0 -57
- package/dist/events/ws.js +0 -212
- package/dist/http-client/api-response.d.ts +0 -15
- package/dist/http-client/api-response.js +0 -1
- package/dist/http-client/http-factory.d.ts +0 -71
- package/dist/http-client/http-factory.js +0 -68
- package/dist/http-client/http-types.d.ts +0 -87
- package/dist/http-client/http-types.js +0 -1
- package/dist/http-client/index.d.ts +0 -7
- package/dist/http-client/index.js +0 -11
- package/dist/http-client/path-segment.d.ts +0 -1
- package/dist/http-client/path-segment.js +0 -8
- package/dist/http-client/retry.d.ts +0 -5
- package/dist/http-client/retry.js +0 -82
- package/dist/http-client/signal-utils.d.ts +0 -2
- package/dist/http-client/signal-utils.js +0 -41
- package/dist/http-client/web-client.d.ts +0 -80
- package/dist/http-client/web-client.js +0 -557
- package/dist/invitation/index.d.ts +0 -2
- package/dist/invitation/index.js +0 -2
- package/dist/invitation/invitation.d.ts +0 -106
- package/dist/invitation/invitation.js +0 -104
- package/dist/login/index.d.ts +0 -4
- package/dist/login/index.js +0 -3
- package/dist/login/login.d.ts +0 -111
- package/dist/login/login.js +0 -110
- package/dist/login/session.d.ts +0 -124
- package/dist/login/session.js +0 -141
- package/dist/mero-js.d.ts +0 -231
- package/dist/mero-js.js +0 -469
- package/dist/namespace-op/index.d.ts +0 -2
- package/dist/namespace-op/index.js +0 -3
- package/dist/namespace-op/namespace-op.d.ts +0 -150
- package/dist/namespace-op/namespace-op.js +0 -191
- package/dist/nodeDiscovery.d.ts +0 -47
- package/dist/nodeDiscovery.js +0 -101
- package/dist/owner-op/index.d.ts +0 -2
- package/dist/owner-op/index.js +0 -3
- package/dist/owner-op/owner-op.d.ts +0 -119
- package/dist/owner-op/owner-op.js +0 -214
- package/dist/presence/relay-presence.d.ts +0 -56
- package/dist/presence/relay-presence.js +0 -107
- package/dist/presence/statement.d.ts +0 -12
- package/dist/presence/statement.js +0 -17
- package/dist/relay/index.d.ts +0 -4
- package/dist/relay/index.js +0 -2
- package/dist/relay/nonce-source.d.ts +0 -72
- package/dist/relay/nonce-source.js +0 -111
- package/dist/relay/relay-client.d.ts +0 -472
- package/dist/relay/relay-client.js +0 -518
- package/dist/relay-attestation/attest-node-key.d.ts +0 -66
- package/dist/relay-attestation/attest-node-key.js +0 -110
- package/dist/relay-attestation/index.d.ts +0 -1
- package/dist/relay-attestation/index.js +0 -1
- package/dist/request/caller-proof.d.ts +0 -43
- package/dist/request/caller-proof.js +0 -36
- package/dist/request/index.d.ts +0 -3
- package/dist/request/index.js +0 -3
- package/dist/request/proof-signer.d.ts +0 -49
- package/dist/request/proof-signer.js +0 -59
- package/dist/request/request-sig.d.ts +0 -99
- package/dist/request/request-sig.js +0 -95
- package/dist/request-proof/authorizer.d.ts +0 -41
- package/dist/request-proof/authorizer.js +0 -60
- package/dist/request-proof/index.d.ts +0 -4
- package/dist/request-proof/index.js +0 -2
- package/dist/request-proof/request-proof.d.ts +0 -53
- package/dist/request-proof/request-proof.js +0 -95
- package/dist/rpc/index.d.ts +0 -64
- package/dist/rpc/index.js +0 -78
- package/dist/signer/index.d.ts +0 -2
- package/dist/signer/index.js +0 -3
- package/dist/signer/signer.d.ts +0 -92
- package/dist/signer/signer.js +0 -147
- package/dist/token-store/index.d.ts +0 -27
- package/dist/token-store/index.js +0 -62
- package/dist/transport/index.d.ts +0 -6
- package/dist/transport/index.js +0 -3
- package/dist/transport/mero-client.d.ts +0 -294
- package/dist/transport/mero-client.js +0 -386
- package/dist/transport/relay-observer.d.ts +0 -152
- package/dist/transport/relay-observer.js +0 -173
- package/dist/transport/relay-transport.d.ts +0 -73
- package/dist/transport/relay-transport.js +0 -94
- package/dist/transport/types.d.ts +0 -100
- package/dist/transport/types.js +0 -32
- package/dist/types/api-response.d.ts +0 -15
- package/dist/types/api-response.js +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/warrant/creation-warrant.d.ts +0 -163
- package/dist/warrant/creation-warrant.js +0 -194
- package/dist/warrant/governance-op.d.ts +0 -202
- package/dist/warrant/governance-op.js +0 -355
- package/dist/warrant/governance-warrant.d.ts +0 -124
- package/dist/warrant/governance-warrant.js +0 -164
- package/dist/warrant/index.d.ts +0 -8
- package/dist/warrant/index.js +0 -5
- package/dist/warrant/warrant.d.ts +0 -188
- package/dist/warrant/warrant.js +0 -202
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { encodeGroupInvitation } from '../invitation/invitation.js';
|
|
2
|
-
import { concat, fromHex, hex, u32le, u64le } from '../crypto/internal.js';
|
|
3
|
-
import { resolveSigner } from '../signer/signer.js';
|
|
4
|
-
/**
|
|
5
|
-
* Core's `SIGNED_NAMESPACE_OP_SCHEMA_VERSION`. A node refuses any other value.
|
|
6
|
-
*
|
|
7
|
-
* 15: core went to 13 (TEE rows locked to the TEE roles, a TEE's relay role
|
|
8
|
-
* read at its namespace root row, inherited read-only roles read-only in Open
|
|
9
|
-
* subgroups), then 14 (`GroupOp::ContextRegisteredOnBehalf`) and 15
|
|
10
|
-
* (`GroupOp::OnBehalf` / `RootOp::OnBehalf`) for delegated context creation and
|
|
11
|
-
* governance through a relay. None of these changes a layout this module
|
|
12
|
-
* signs; the version moves with core's so nodes on different versions never
|
|
13
|
-
* share a namespace.
|
|
14
|
-
*
|
|
15
|
-
* 16: a namespace can be founded through a relay (a delegated
|
|
16
|
-
* `NamespaceCreatedV2`), and `GroupOp::FoundingRelayAttested` lets that relay
|
|
17
|
-
* admit itself as the namespace's first TEE. Again no layout this module signs.
|
|
18
|
-
*
|
|
19
|
-
* 17: `RootOp::GroupCreated` carries a `salt`, and its `group_id` must be the
|
|
20
|
-
* one `createdSubgroupId(admin, parentId, restricted, salt)` derives
|
|
21
|
-
* (calimero-network/core#4244), so two concurrent creates for one id can never
|
|
22
|
-
* name different creators. The layout of that variant changed.
|
|
23
|
-
*
|
|
24
|
-
* 18: owner-level ops need the account ROOT, not only a device of it
|
|
25
|
-
* (calimero-network/core, root-guarded owner ops). `GroupOp::RootGuarded` and
|
|
26
|
-
* `RootOp::RootGuarded` are appended and carry a root-signed proof, and the bare
|
|
27
|
-
* `TransferOwnership`, `AdminChanged`, `GroupDelete` and TEE policy ops are
|
|
28
|
-
* refused. No layout this module signs changes; see `../owner-op` for the proof.
|
|
29
|
-
*
|
|
30
|
-
* 19 is reserved for calimero-network/core#4269.
|
|
31
|
-
*
|
|
32
|
-
* 20: no layout change. A delegated `GroupCreated` whose executor is a TEE at
|
|
33
|
-
* the namespace root now seats that TEE in the new subgroup
|
|
34
|
-
* (calimero-network/core#4276), an apply-time rule older peers disagree on.
|
|
35
|
-
* Core signs and checks at 20, so every op this module signs must too.
|
|
36
|
-
*
|
|
37
|
-
* 21: no layout change. An op concurrent with its signer's removal is void
|
|
38
|
-
* (calimero-network/core#4275), an apply-time rule older peers disagree on.
|
|
39
|
-
* Core signs and checks at 21 from 0.11.0-rc.75. 23.4.0 and 23.4.1 still sign
|
|
40
|
-
* at 20, so against rc.75 every namespace op an account signs with them (a
|
|
41
|
-
* join, a create, any governance op) is refused "schema version mismatch:
|
|
42
|
-
* expected 21, got 20".
|
|
43
|
-
*
|
|
44
|
-
* 22: `GroupOp::SharedWritersRotated` is appended, a `SharedStorage` cell's
|
|
45
|
-
* writer-set step (calimero-network/core#4263), and a capability revoke voids
|
|
46
|
-
* the member's concurrent ops that needed a removed bit
|
|
47
|
-
* (calimero-network/core#4453). No layout this module signs changes.
|
|
48
|
-
*
|
|
49
|
-
* 23: a TEE admission op carries the quote it was admitted on and a TEE
|
|
50
|
-
* authority evidence op the credential it was made for
|
|
51
|
-
* (calimero-network/core#4265). Neither is an op this module signs, so only
|
|
52
|
-
* the version byte moves. Core signs and checks at 23 from 0.11.0-rc.81, the
|
|
53
|
-
* first release with both 22 and 23.
|
|
54
|
-
*
|
|
55
|
-
* 24: no layout change. Only a subgroup's creator may open it - flip it to
|
|
56
|
-
* `Open` (calimero-network/core#4522) - an apply-time rule older peers
|
|
57
|
-
* disagree on, since they let any of its admins open it. A UI that offers
|
|
58
|
-
* "make public" should offer it to the creator alone.
|
|
59
|
-
*
|
|
60
|
-
* 25: no layout change; refused device link/unlink/descope ops are never logged.
|
|
61
|
-
*
|
|
62
|
-
* 26: no layout change. A device link's scope is judged against every
|
|
63
|
-
* application the group may have targeted at the link's cut, not its live
|
|
64
|
-
* target (calimero-network/core#4603), so replicas agree on a link that races
|
|
65
|
-
* a target change; older peers judge it by fold order.
|
|
66
|
-
*
|
|
67
|
-
* 27: no layout change. The namespace founder is seated as an admin by the
|
|
68
|
-
* genesis op itself, so a founder who transfers ownership stays a member
|
|
69
|
-
* (calimero-network/core#4625); older peers seat her from the root's current
|
|
70
|
-
* owner and drop her.
|
|
71
|
-
*/
|
|
72
|
-
export const SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 27;
|
|
73
|
-
/** Domain prefixed to the signable bytes; core's `NAMESPACE_GOVERNANCE_SIGN_DOMAIN`. */
|
|
74
|
-
const NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode('calimero.namespace.v1');
|
|
75
|
-
/** `NamespaceOp::Root` is the first variant. */
|
|
76
|
-
const NAMESPACE_OP_ROOT = 0;
|
|
77
|
-
/**
|
|
78
|
-
* `RootOp` discriminants, in declaration order. Only the two join variants are
|
|
79
|
-
* emitted here; the rest are listed so the numbering is checkable against core
|
|
80
|
-
* rather than inferred from the two in use.
|
|
81
|
-
*/
|
|
82
|
-
const ROOT_OP = {
|
|
83
|
-
GroupCreated: 0,
|
|
84
|
-
GroupReparented: 1,
|
|
85
|
-
GroupDeleted: 2,
|
|
86
|
-
AdminChanged: 3,
|
|
87
|
-
PolicyUpdated: 4,
|
|
88
|
-
MemberJoined: 5,
|
|
89
|
-
KeyDelivery: 6,
|
|
90
|
-
MemberJoinedOpen: 7,
|
|
91
|
-
MemberJoinedAt: 8,
|
|
92
|
-
NamespaceCreatedV2: 9,
|
|
93
|
-
MemberJoinedViaTeeAttestation: 10,
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* Borsh `Option<[u8; 32]>` from the byte array JSON carries it as.
|
|
97
|
-
*
|
|
98
|
-
* `[u8; 32]` crosses JSON as 32 numbers, not as hex — the hex spelling belongs to
|
|
99
|
-
* `AccountId`, which has its own representation. Encoding one of these from a hex
|
|
100
|
-
* string would silently produce the wrong 32 bytes.
|
|
101
|
-
*/
|
|
102
|
-
function optionalBytes32(value, label) {
|
|
103
|
-
if (value === null || value === undefined) {
|
|
104
|
-
return new Uint8Array([0]);
|
|
105
|
-
}
|
|
106
|
-
if (value.length !== 32) {
|
|
107
|
-
throw new Error(`${label} must be 32 bytes, got ${value.length}`);
|
|
108
|
-
}
|
|
109
|
-
return concat(new Uint8Array([1]), new Uint8Array(value));
|
|
110
|
-
}
|
|
111
|
-
/** Borsh `String`: u32 length then UTF-8 bytes. */
|
|
112
|
-
function borshString(value) {
|
|
113
|
-
const bytes = new TextEncoder().encode(value);
|
|
114
|
-
return concat(u32le(bytes.length), bytes);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Borsh-encode a `SignedGroupOpenInvitation`.
|
|
118
|
-
*
|
|
119
|
-
* Re-encoded rather than passed through, because it has to go inside the op that
|
|
120
|
-
* gets signed. That makes this function version-locked to core: a field added to
|
|
121
|
-
* the invitation and omitted here produces an op whose inner invitation no longer
|
|
122
|
-
* matches the inviter's signature over it. That exact drift, in client-py, broke
|
|
123
|
-
* 93 scenarios — the failure surfaces as `invalid invitation signature` and points
|
|
124
|
-
* nowhere near the encoder.
|
|
125
|
-
*/
|
|
126
|
-
export function encodeSignedInvitation(signed) {
|
|
127
|
-
const body = signed.invitation;
|
|
128
|
-
const admitterAddrs = signed.admitter_addrs ?? [];
|
|
129
|
-
return concat(
|
|
130
|
-
// GroupInvitationFromAdmin, from the one encoder the SDK's own invitation
|
|
131
|
-
// signer uses: the bytes signed and the bytes carried must not drift.
|
|
132
|
-
encodeGroupInvitation(body),
|
|
133
|
-
// ...then the enclosing SignedGroupOpenInvitation, in declaration order.
|
|
134
|
-
// `inviter_account` sits between the signature and the addresses; putting it
|
|
135
|
-
// anywhere else still encodes 32 bytes and still verifies as nothing.
|
|
136
|
-
borshString(signed.inviter_signature), signed.inviter_account
|
|
137
|
-
? concat(new Uint8Array([1]), fromHex(signed.inviter_account, 'inviter_account', 32))
|
|
138
|
-
: new Uint8Array([0]),
|
|
139
|
-
// A `Vec<String>`, so each entry is a bare borsh string. This carried an
|
|
140
|
-
// enum until core dropped the URL variant, and an enum writes a
|
|
141
|
-
// discriminant byte ahead of each entry — encoding one here now would shift
|
|
142
|
-
// every following byte and fail as `invalid invitation signature`, pointing
|
|
143
|
-
// nowhere near this line.
|
|
144
|
-
u32le(admitterAddrs.length), ...admitterAddrs.map(borshString), optionalBytes32(signed.application_id, 'application_id'),
|
|
145
|
-
// Borsh order follows core's field order, where this is `bytecode_id`; the
|
|
146
|
-
// JSON key is `app_key`, a rename covering both directions that core pins in
|
|
147
|
-
// a test. Encoding by the Rust name would read `undefined` and emit a None
|
|
148
|
-
// where the inviter signed a Some.
|
|
149
|
-
optionalBytes32(signed.app_key, 'app_key'));
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Sign a `MemberJoined` (or `MemberJoinedAt`) namespace op and return it
|
|
153
|
-
* borsh-encoded and hex — the `signedOp` that `admitJoin` takes.
|
|
154
|
-
*/
|
|
155
|
-
export async function signMemberJoinOp(input) {
|
|
156
|
-
const parents = input.parentOpHashes ?? [];
|
|
157
|
-
const credential = fromHex(input.credential, 'credential', input.credential.length / 2);
|
|
158
|
-
// An invitation that expires must be claimed with `MemberJoinedAt`, which
|
|
159
|
-
// carries `joined_at` between the invitation and the credential. Choosing the
|
|
160
|
-
// variant from the invitation keeps the two in step: the discriminant and the
|
|
161
|
-
// presence of that field are one decision, and splitting them produces bytes
|
|
162
|
-
// that decode into the wrong shape rather than failing to decode.
|
|
163
|
-
const expires = BigInt(input.invitation.invitation.expiration_timestamp ?? 0) !== 0n;
|
|
164
|
-
const joinedAt = input.joinedAt ?? BigInt(Math.floor(Date.now() / 1000));
|
|
165
|
-
const rootOp = expires
|
|
166
|
-
? concat(new Uint8Array([ROOT_OP.MemberJoinedAt]), fromHex(input.member, 'member', 32), encodeSignedInvitation(input.invitation), u64le(joinedAt), credential)
|
|
167
|
-
: concat(new Uint8Array([ROOT_OP.MemberJoined]), fromHex(input.member, 'member', 32), encodeSignedInvitation(input.invitation), credential);
|
|
168
|
-
const op = concat(new Uint8Array([NAMESPACE_OP_ROOT]), rootOp);
|
|
169
|
-
const signingKey = await resolveSigner(input.deviceSecret, input.signer, 'deviceSecret');
|
|
170
|
-
// Named apart from the signer itself: this is the public half the op carries
|
|
171
|
-
// as its `signer` field, which every peer compares with the credential's
|
|
172
|
-
// `sign_pk` before applying the join.
|
|
173
|
-
const signerPublicKey = fromHex(signingKey.publicKey, 'signer.publicKey', 32);
|
|
174
|
-
const signable = concat(new Uint8Array([SIGNED_NAMESPACE_OP_SCHEMA_VERSION]), fromHex(input.namespaceId, 'namespaceId', 32), u32le(parents.length), ...parents.map((p, i) => fromHex(p, `parentOpHashes[${i}]`, 32)), signerPublicKey, u64le(input.nonce), op);
|
|
175
|
-
const signature = await signingKey.sign(concat(NAMESPACE_SIGN_DOMAIN, signable));
|
|
176
|
-
// The signed struct repeats the signable fields, then the signature, then the
|
|
177
|
-
// admitter endorsement. The domain is a signing prefix only and is never part
|
|
178
|
-
// of the encoded op.
|
|
179
|
-
//
|
|
180
|
-
// The endorsement is written as borsh `None` — a single `0x00` — and that is
|
|
181
|
-
// the correct value from here, not a placeholder. It authorises the membership
|
|
182
|
-
// and can only be signed by an account the invitation named as an admitter,
|
|
183
|
-
// which a keyholder is not. The admitter attaches its own as it relays the op
|
|
184
|
-
// through `admitJoin`.
|
|
185
|
-
//
|
|
186
|
-
// It sits outside `signable`, so it is outside this signature and outside the
|
|
187
|
-
// op's id. That is what makes attaching it possible: the admitter changes
|
|
188
|
-
// neither what was signed here nor which op this is.
|
|
189
|
-
const unendorsed = new Uint8Array([0]);
|
|
190
|
-
return hex(concat(signable, signature, unendorsed));
|
|
191
|
-
}
|
package/dist/nodeDiscovery.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local-node discovery.
|
|
3
|
-
*
|
|
4
|
-
* Calimero dev/desktop nodes expose a public, unauthenticated health endpoint
|
|
5
|
-
* at `GET {nodeUrl}/admin-api/health` that returns `{ "data": { "status":
|
|
6
|
-
* "alive" } }`. The most common local layouts run on a small, well-known set of
|
|
7
|
-
* ports, so instead of forcing the user to type a URL we probe those ports and
|
|
8
|
-
* offer whatever is actually running.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Default ports probed when discovering local nodes. Covers the two-node dev
|
|
12
|
-
* stacks used across the Calimero apps (RPC + alt ports for node1 / node2).
|
|
13
|
-
*/
|
|
14
|
-
export declare const DEFAULT_LOCAL_NODE_PORTS: readonly [2428, 2429, 2528, 2529];
|
|
15
|
-
export interface DiscoverLocalNodesOptions {
|
|
16
|
-
/** Ports to probe. Defaults to {@link DEFAULT_LOCAL_NODE_PORTS}. */
|
|
17
|
-
ports?: readonly number[];
|
|
18
|
-
/** Per-probe timeout in ms. Defaults to 2000. */
|
|
19
|
-
timeoutMs?: number;
|
|
20
|
-
/** Abort the whole discovery (e.g. when the modal closes). */
|
|
21
|
-
signal?: AbortSignal;
|
|
22
|
-
}
|
|
23
|
-
/** Build the canonical base URL for a local node on the given port. */
|
|
24
|
-
export declare function localNodeUrl(port: number): string;
|
|
25
|
-
/**
|
|
26
|
-
* Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a
|
|
27
|
-
* slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`
|
|
28
|
-
* deployment like `http://host/node1`) keeps that segment instead of having it
|
|
29
|
-
* stripped by relative URL resolution.
|
|
30
|
-
*/
|
|
31
|
-
export declare function nodeEndpoint(baseUrl: string, path: string): string;
|
|
32
|
-
/**
|
|
33
|
-
* Probe a single node's health endpoint. Resolves `true` only when the node
|
|
34
|
-
* answers with a 2xx and (when the body is JSON) reports a non-dead status.
|
|
35
|
-
* Any network error, timeout, or non-ok response resolves `false` — never
|
|
36
|
-
* throws (except on an external abort, which is swallowed as `false`).
|
|
37
|
-
*/
|
|
38
|
-
export declare function probeNodeHealth(baseUrl: string, options?: {
|
|
39
|
-
timeoutMs?: number;
|
|
40
|
-
signal?: AbortSignal;
|
|
41
|
-
}): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* Probe the configured local ports in parallel and return the base URLs that
|
|
44
|
-
* responded as healthy, in the same order as the `ports` argument (which
|
|
45
|
-
* defaults to ascending). Returns an empty array when nothing local is running.
|
|
46
|
-
*/
|
|
47
|
-
export declare function discoverLocalNodes(options?: DiscoverLocalNodesOptions): Promise<string[]>;
|
package/dist/nodeDiscovery.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local-node discovery.
|
|
3
|
-
*
|
|
4
|
-
* Calimero dev/desktop nodes expose a public, unauthenticated health endpoint
|
|
5
|
-
* at `GET {nodeUrl}/admin-api/health` that returns `{ "data": { "status":
|
|
6
|
-
* "alive" } }`. The most common local layouts run on a small, well-known set of
|
|
7
|
-
* ports, so instead of forcing the user to type a URL we probe those ports and
|
|
8
|
-
* offer whatever is actually running.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Default ports probed when discovering local nodes. Covers the two-node dev
|
|
12
|
-
* stacks used across the Calimero apps (RPC + alt ports for node1 / node2).
|
|
13
|
-
*/
|
|
14
|
-
export const DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529];
|
|
15
|
-
/** Host used to build local candidate URLs. */
|
|
16
|
-
const LOCAL_HOST = 'localhost';
|
|
17
|
-
/** Per-probe timeout. A reachable local node answers almost instantly; a
|
|
18
|
-
* closed port rejects fast, but a firewalled/black-holed one can hang, so we
|
|
19
|
-
* cap each probe. */
|
|
20
|
-
const DEFAULT_PROBE_TIMEOUT_MS = 2000;
|
|
21
|
-
/** Build the canonical base URL for a local node on the given port. */
|
|
22
|
-
export function localNodeUrl(port) {
|
|
23
|
-
return `http://${LOCAL_HOST}:${port}`;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a
|
|
27
|
-
* slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`
|
|
28
|
-
* deployment like `http://host/node1`) keeps that segment instead of having it
|
|
29
|
-
* stripped by relative URL resolution.
|
|
30
|
-
*/
|
|
31
|
-
export function nodeEndpoint(baseUrl, path) {
|
|
32
|
-
const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
33
|
-
return new URL(path, base).toString();
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Probe a single node's health endpoint. Resolves `true` only when the node
|
|
37
|
-
* answers with a 2xx and (when the body is JSON) reports a non-dead status.
|
|
38
|
-
* Any network error, timeout, or non-ok response resolves `false` — never
|
|
39
|
-
* throws (except on an external abort, which is swallowed as `false`).
|
|
40
|
-
*/
|
|
41
|
-
export async function probeNodeHealth(baseUrl, options = {}) {
|
|
42
|
-
const { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal } = options;
|
|
43
|
-
// Already cancelled before we start — don't fetch, and don't register a
|
|
44
|
-
// timer or listener that would then need cleanup.
|
|
45
|
-
if (signal?.aborted)
|
|
46
|
-
return false;
|
|
47
|
-
// Per-probe timeout, also linked to the caller's abort signal so closing the
|
|
48
|
-
// modal cancels every in-flight probe. Bind the signal to a local so the
|
|
49
|
-
// cleanup below stays symmetric with registration without re-narrowing.
|
|
50
|
-
const controller = new AbortController();
|
|
51
|
-
const onAbort = () => controller.abort();
|
|
52
|
-
const abortSignal = signal;
|
|
53
|
-
if (abortSignal)
|
|
54
|
-
abortSignal.addEventListener('abort', onAbort, { once: true });
|
|
55
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
56
|
-
try {
|
|
57
|
-
const url = nodeEndpoint(baseUrl, 'admin-api/health');
|
|
58
|
-
const res = await fetch(url, {
|
|
59
|
-
method: 'GET',
|
|
60
|
-
signal: controller.signal,
|
|
61
|
-
});
|
|
62
|
-
if (!res.ok)
|
|
63
|
-
return false;
|
|
64
|
-
// Health body is `{ data: { status: "alive" } }`, but tolerate plain
|
|
65
|
-
// `{ status }` and non-JSON 2xx responses. A *missing* status is treated as
|
|
66
|
-
// alive (the 2xx is enough); a status that is present but not "alive"
|
|
67
|
-
// (including an explicit `null`) is treated as unhealthy.
|
|
68
|
-
try {
|
|
69
|
-
const body = (await res.json());
|
|
70
|
-
const status = body?.data?.status !== undefined ? body?.data?.status : body?.status;
|
|
71
|
-
if (status === undefined)
|
|
72
|
-
return true;
|
|
73
|
-
return typeof status === 'string' && status.toLowerCase() === 'alive';
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
finally {
|
|
83
|
-
clearTimeout(timer);
|
|
84
|
-
if (abortSignal)
|
|
85
|
-
abortSignal.removeEventListener('abort', onAbort);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Probe the configured local ports in parallel and return the base URLs that
|
|
90
|
-
* responded as healthy, in the same order as the `ports` argument (which
|
|
91
|
-
* defaults to ascending). Returns an empty array when nothing local is running.
|
|
92
|
-
*/
|
|
93
|
-
export async function discoverLocalNodes(options = {}) {
|
|
94
|
-
const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
|
|
95
|
-
const results = await Promise.all(ports.map(async (port) => {
|
|
96
|
-
const url = localNodeUrl(port);
|
|
97
|
-
const ok = await probeNodeHealth(url, { timeoutMs, signal });
|
|
98
|
-
return ok ? url : null;
|
|
99
|
-
}));
|
|
100
|
-
return results.filter((url) => url !== null);
|
|
101
|
-
}
|
package/dist/owner-op/index.d.ts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export { OWNER_OP_KIND, transferOwnershipOp, groupDeleteOp, adminChangedOp, teeAuthoringPolicyOp, teeAdmissionPolicyOp, teeReleaseAdmissionPolicyOp, ownerOpDigest, ownerOpSigningPayload, signOwnerOpProof, rootGuardedOpBytes, } from './owner-op.js';
|
|
2
|
-
export type { OwnerOp, OwnerOpKind, OwnerOpPlane, OwnerOpProofInput, TeeAdmissionPolicyOpInput, TeeReleaseAdmissionPolicyOpInput, } from './owner-op.js';
|
package/dist/owner-op/index.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// Root proofs for owner-level governance ops: what a nodeless or cold-root
|
|
2
|
-
// account signs offline so a stolen device alone cannot take a group.
|
|
3
|
-
export { OWNER_OP_KIND, transferOwnershipOp, groupDeleteOp, adminChangedOp, teeAuthoringPolicyOp, teeAdmissionPolicyOp, teeReleaseAdmissionPolicyOp, ownerOpDigest, ownerOpSigningPayload, signOwnerOpProof, rootGuardedOpBytes, } from './owner-op.js';
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Which owner-level op a proof authorises. The value is the byte core signs,
|
|
3
|
-
* its `OwnerOpKind` discriminant.
|
|
4
|
-
*/
|
|
5
|
-
export declare const OWNER_OP_KIND: {
|
|
6
|
-
readonly transferOwnership: 0;
|
|
7
|
-
readonly adminChanged: 1;
|
|
8
|
-
readonly groupDelete: 2;
|
|
9
|
-
readonly teeAdmissionPolicy: 3;
|
|
10
|
-
readonly teeAuthoringPolicy: 4;
|
|
11
|
-
readonly teeReleaseAdmissionPolicy: 5;
|
|
12
|
-
};
|
|
13
|
-
export type OwnerOpKind = keyof typeof OWNER_OP_KIND;
|
|
14
|
-
/** Which plane the op is on: a `GroupOp` on a group, or a `RootOp` on the namespace. */
|
|
15
|
-
export type OwnerOpPlane = 'group' | 'root';
|
|
16
|
-
/** An encoded owner-level op: its borsh bytes, its kind and its plane. */
|
|
17
|
-
export interface OwnerOp {
|
|
18
|
-
kind: OwnerOpKind;
|
|
19
|
-
plane: OwnerOpPlane;
|
|
20
|
-
/** The op's borsh bytes: exactly what the node builds, and what the digest covers. */
|
|
21
|
-
bytes: Uint8Array;
|
|
22
|
-
}
|
|
23
|
-
/** Hand the group to `newOwner` (an account, hex), who must already be an admin. */
|
|
24
|
-
export declare function transferOwnershipOp(newOwner: string): OwnerOp;
|
|
25
|
-
/** The owner-only deletion of a group that holds no contexts. */
|
|
26
|
-
export declare function groupDeleteOp(): OwnerOp;
|
|
27
|
-
/** Repoint the namespace's admin pin at `newAdmin` (an account, hex). A root op. */
|
|
28
|
-
export declare function adminChangedOp(newAdmin: string): OwnerOp;
|
|
29
|
-
/** The TEE authoring policy `PUT`/`DELETE …/settings/tee-authoring-policy` publishes. */
|
|
30
|
-
export declare function teeAuthoringPolicyOp(allowedMrtd: string[]): OwnerOp;
|
|
31
|
-
/** A measurement-list admission policy, as the node publishes it (the V2 form). */
|
|
32
|
-
export interface TeeAdmissionPolicyOpInput {
|
|
33
|
-
allowedMrtd: string[];
|
|
34
|
-
allowedRtmr0: string[];
|
|
35
|
-
allowedRtmr1: string[];
|
|
36
|
-
allowedRtmr2: string[];
|
|
37
|
-
allowedRtmr3: string[];
|
|
38
|
-
allowedTcbStatuses: string[];
|
|
39
|
-
acceptMock: boolean;
|
|
40
|
-
mode?: 'replica' | 'relay';
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* The measurement-list admission policy `PUT …/settings/tee-admission-policy`
|
|
44
|
-
* publishes. Pass the fields exactly as you send them: the node signs over the
|
|
45
|
-
* op it builds from them, and any difference is a different op.
|
|
46
|
-
*/
|
|
47
|
-
export declare function teeAdmissionPolicyOp(input: TeeAdmissionPolicyOpInput): OwnerOp;
|
|
48
|
-
/** A signed-release admission policy, as the node publishes it (the V2 form). */
|
|
49
|
-
export interface TeeReleaseAdmissionPolicyOpInput {
|
|
50
|
-
allowedProfiles: string[];
|
|
51
|
-
/**
|
|
52
|
-
* The oldest release admitted. Give it in the node's normalised form
|
|
53
|
-
* (`X.Y.Z`, no tag prefix): the node normalises what it is sent before it
|
|
54
|
-
* builds the op, and the proof must be for the op it builds.
|
|
55
|
-
*/
|
|
56
|
-
minReleaseVersion?: string;
|
|
57
|
-
allowedTcbStatuses: string[];
|
|
58
|
-
acceptMock: boolean;
|
|
59
|
-
mode?: 'replica' | 'relay';
|
|
60
|
-
}
|
|
61
|
-
/** The signed-release admission policy `PUT …/settings/tee-admission-policy` publishes. */
|
|
62
|
-
export declare function teeReleaseAdmissionPolicyOp(input: TeeReleaseAdmissionPolicyOpInput): OwnerOp;
|
|
63
|
-
/** core's `OwnerOpAuthorization::op_digest`: the op's bytes, hashed under the body domain. */
|
|
64
|
-
export declare function ownerOpDigest(opBytes: Uint8Array): Promise<Uint8Array>;
|
|
65
|
-
/** What an owner-op proof binds, apart from the op and the key that signs it. */
|
|
66
|
-
export interface OwnerOpProofInput {
|
|
67
|
-
/** The account root's signing secret, 64 hex. Never sent anywhere. */
|
|
68
|
-
rootSecret: string;
|
|
69
|
-
/** The namespace the op is published in (`getGroupInfo(...).namespaceId`), hex. */
|
|
70
|
-
namespaceId: string;
|
|
71
|
-
/**
|
|
72
|
-
* The group the op acts on, hex. For `adminChanged` and the TEE policies,
|
|
73
|
-
* the namespace root.
|
|
74
|
-
*/
|
|
75
|
-
groupId: string;
|
|
76
|
-
/** The op, from one of the encoders here. */
|
|
77
|
-
op: OwnerOp;
|
|
78
|
-
/** The group's current guarded-op counter (`getGroupInfo(groupId).ownerOpCounter`). */
|
|
79
|
-
counter: number | bigint;
|
|
80
|
-
/**
|
|
81
|
-
* The root epoch that signs, 0 for a root that has never been handed off.
|
|
82
|
-
* A later epoch needs `chain`.
|
|
83
|
-
*/
|
|
84
|
-
keyEpoch?: number;
|
|
85
|
-
/**
|
|
86
|
-
* The account's root-key handoffs, epoch 0 upward, each the hex borsh of a
|
|
87
|
-
* `RootKeyHandoff` (account 32, from_epoch u32, new root key 32, signature
|
|
88
|
-
* 64). It must reach at least `keyEpoch`, and at least the epoch the group
|
|
89
|
-
* has recorded for the account, or the node refuses the proof.
|
|
90
|
-
*/
|
|
91
|
-
chain?: string[];
|
|
92
|
-
}
|
|
93
|
-
/** core's `OwnerOpTerms::signing_payload`. */
|
|
94
|
-
export declare function ownerOpSigningPayload(input: {
|
|
95
|
-
account: string;
|
|
96
|
-
namespaceId: string;
|
|
97
|
-
groupId: string;
|
|
98
|
-
kind: OwnerOpKind;
|
|
99
|
-
opDigest: Uint8Array;
|
|
100
|
-
counter: number | bigint;
|
|
101
|
-
keyEpoch: number;
|
|
102
|
-
}): Promise<Uint8Array>;
|
|
103
|
-
/**
|
|
104
|
-
* Sign a root proof for `op` and return it as core's `rootProof`: the hex
|
|
105
|
-
* borsh of an `AccountProof<OwnerOpAuthorization>`.
|
|
106
|
-
*
|
|
107
|
-
* Layout: `AccountGenesis` (version u8 + root pk 32), the handoff chain (u32
|
|
108
|
-
* count + 132 bytes each), then `OwnerOpAuthorization` (account 32, namespace
|
|
109
|
-
* 32, group 32, kind u8, op digest 32, counter u64, key epoch u32, signature
|
|
110
|
-
* 64).
|
|
111
|
-
*/
|
|
112
|
-
export declare function signOwnerOpProof(input: OwnerOpProofInput): Promise<string>;
|
|
113
|
-
/**
|
|
114
|
-
* The `RootGuarded` wrapper core publishes: the op and its proof, as one
|
|
115
|
-
* `GroupOp` or `RootOp`. A client never sends this to a node (the endpoints
|
|
116
|
-
* take the proof and build the wrapper); it is here so the whole encoding is
|
|
117
|
-
* checkable against core's vector.
|
|
118
|
-
*/
|
|
119
|
-
export declare function rootGuardedOpBytes(op: OwnerOp, rootProof: string): Uint8Array;
|