@calimero-network/mero-js 22.9.0 → 23.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/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  MeroClient: () => MeroClient,
39
39
  MeroJs: () => MeroJs,
40
40
  NODE_RELEASE_SIGNER: () => NODE_RELEASE_SIGNER,
41
+ OWNER_OP_KIND: () => OWNER_OP_KIND,
41
42
  REQUEST_PROOF_HEADER: () => REQUEST_PROOF_HEADER,
42
43
  RelayClient: () => RelayClient,
43
44
  RelayObserver: () => RelayObserver,
@@ -59,6 +60,7 @@ __export(index_exports, {
59
60
  accountRootFromPhrase: () => accountRootFromPhrase,
60
61
  accountRootFromSecret: () => accountRootFromSecret,
61
62
  accountRootSignerFromPhrase: () => accountRootSignerFromPhrase,
63
+ adminChangedOp: () => adminChangedOp,
62
64
  admitterAddrsFromNetworkStatus: () => admitterAddrsFromNetworkStatus,
63
65
  attestKeyBinding: () => attestKeyBinding,
64
66
  attestRelayNodeKey: () => attestRelayNodeKey,
@@ -106,6 +108,7 @@ __export(index_exports, {
106
108
  createSignedReleaseVerifier: () => createSignedReleaseVerifier,
107
109
  createTimeoutSignal: () => createTimeoutSignal,
108
110
  createUniversalHttpClient: () => createUniversalHttpClient,
111
+ createdSubgroupId: () => createdSubgroupId,
109
112
  creationInitHash: () => creationInitHash,
110
113
  defaultAdmitters: () => defaultAdmitters,
111
114
  defaultAudience: () => defaultAudience,
@@ -124,6 +127,7 @@ __export(index_exports, {
124
127
  generateSessionKey: () => generateSessionKey,
125
128
  governanceOpHash: () => governanceOpHash,
126
129
  groupCreatedOp: () => groupCreatedOp,
130
+ groupDeleteOp: () => groupDeleteOp,
127
131
  groupDeletedOp: () => groupDeletedOp,
128
132
  groupInvitationHash: () => groupInvitationHash,
129
133
  groupReparentedOp: () => groupReparentedOp,
@@ -142,6 +146,8 @@ __export(index_exports, {
142
146
  namespaceCreatedOp: () => namespaceCreatedOp,
143
147
  nodeEndpoint: () => nodeEndpoint,
144
148
  nodeReleaseVersionFromImage: () => nodeReleaseVersionFromImage,
149
+ ownerOpDigest: () => ownerOpDigest,
150
+ ownerOpSigningPayload: () => ownerOpSigningPayload,
145
151
  parseAuthCallback: () => parseAuthCallback,
146
152
  parseCreationWarrant: () => parseCreationWarrant,
147
153
  parseDeviceCredential: () => parseDeviceCredential,
@@ -155,6 +161,7 @@ __export(index_exports, {
155
161
  requestBodyHash: () => requestBodyHash,
156
162
  resolveRoot: () => resolveRoot,
157
163
  resolveRootPair: () => resolveRootPair,
164
+ rootGuardedOpBytes: () => rootGuardedOpBytes,
158
165
  routingProofHeaders: () => routingProofHeaders,
159
166
  shouldRetain: () => shouldRetain,
160
167
  signAccountLink: () => signAccountLink,
@@ -166,6 +173,7 @@ __export(index_exports, {
166
173
  signGroupInvitation: () => signGroupInvitation,
167
174
  signLoginStatement: () => signLoginStatement,
168
175
  signMemberJoinOp: () => signMemberJoinOp,
176
+ signOwnerOpProof: () => signOwnerOpProof,
169
177
  signRequest: () => signRequest,
170
178
  signRequestProof: () => signRequestProof,
171
179
  signRoutingChallenge: () => signRoutingChallenge,
@@ -173,6 +181,11 @@ __export(index_exports, {
173
181
  signedPath: () => signedPath,
174
182
  signerFromCryptoKey: () => signerFromCryptoKey,
175
183
  signerFromSecret: () => signerFromSecret,
184
+ subgroupCreation: () => subgroupCreation,
185
+ teeAdmissionPolicyOp: () => teeAdmissionPolicyOp,
186
+ teeAuthoringPolicyOp: () => teeAuthoringPolicyOp,
187
+ teeReleaseAdmissionPolicyOp: () => teeReleaseAdmissionPolicyOp,
188
+ transferOwnershipOp: () => transferOwnershipOp,
176
189
  transportKeyBinding: () => transportKeyBinding,
177
190
  trustSignedRelease: () => trustSignedRelease,
178
191
  trustedMeasurementsFromReleases: () => trustedMeasurementsFromReleases,
@@ -2353,9 +2366,45 @@ var AdminApiClient = class {
2353
2366
  * and admitted TEEs stay members. The node applies the same op as
2354
2367
  * `setTeeAuthoringPolicy(groupId, { allowedMrtd: [] })`. `groupId` must be a
2355
2368
  * namespace root.
2369
+ *
2370
+ * `rootProof` is the signing admin's own root proof for that empty policy
2371
+ * (`teeAuthoringPolicyOp([])`); omit it on a node that holds that root.
2356
2372
  */
2357
- async disableTeeAuthoringPolicy(groupId) {
2358
- await this.httpClient.delete(`/admin-api/groups/${groupId}/settings/tee-authoring-policy`);
2373
+ async disableTeeAuthoringPolicy(groupId, options = {}) {
2374
+ const path = `/admin-api/groups/${groupId}/settings/tee-authoring-policy`;
2375
+ if (options.rootProof === void 0) {
2376
+ await this.httpClient.delete(path);
2377
+ return;
2378
+ }
2379
+ await this.httpClient.request(path, {
2380
+ method: "DELETE",
2381
+ body: JSON.stringify({ rootProof: options.rootProof }),
2382
+ headers: { "Content-Type": "application/json" }
2383
+ });
2384
+ }
2385
+ // ---- Root-guarded owner ops (core schema 18) ----
2386
+ /**
2387
+ * Hand the group to `newOwner`, who must already be one of its admins.
2388
+ * Owner-only, and it needs the owner account's root proof; see
2389
+ * {@link RootGuardedOpRequest}.
2390
+ */
2391
+ async transferOwnership(groupId, request) {
2392
+ await this.httpClient.post(`/admin-api/groups/${groupId}/transfer-ownership`, request);
2393
+ }
2394
+ /**
2395
+ * Repoint the namespace's admin pin at `newAdmin`, a member of its root.
2396
+ * Owner-only, with the owner account's root proof; see {@link RootGuardedOpRequest}.
2397
+ */
2398
+ async changeNamespaceAdmin(namespaceId, request) {
2399
+ await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/admin`, request);
2400
+ }
2401
+ /**
2402
+ * Delete a group through the owner-only path: it must hold no contexts, and
2403
+ * the op needs the owner account's root proof. {@link deleteGroup} is the
2404
+ * admin-level cascading delete.
2405
+ */
2406
+ async ownerDeleteGroup(groupId, request = {}) {
2407
+ await this.httpClient.post(`/admin-api/groups/${groupId}/owner-delete`, request);
2359
2408
  }
2360
2409
  // ---- Group / member / context metadata ----
2361
2410
  async setGroupMetadata(groupId, request) {
@@ -7349,9 +7398,9 @@ function parseCreationWarrant(warrant) {
7349
7398
  const u32 = (what) => view.getUint32(take(4, what).byteOffset, true);
7350
7399
  const u64 = (what) => view.getBigUint64(take(8, what).byteOffset, true);
7351
7400
  const option = (what) => {
7352
- const tag2 = take(1, what)[0];
7353
- if (tag2 === 0) return null;
7354
- if (tag2 !== 1) throw new Error(`${what} has option tag ${tag2}, expected 0 or 1`);
7401
+ const tag3 = take(1, what)[0];
7402
+ if (tag3 === 0) return null;
7403
+ if (tag3 !== 1) throw new Error(`${what} has option tag ${tag3}, expected 0 or 1`);
7355
7404
  const len = u32(what);
7356
7405
  if (len > MAX_LABEL_BYTES) {
7357
7406
  throw new Error(`${what} is ${len} bytes, over the ${MAX_LABEL_BYTES} a node accepts`);
@@ -7595,6 +7644,17 @@ function memberRoleSetOp(member, memberRole) {
7595
7644
  bytes: concat(tag(GROUP_OP.MemberRoleSet), fromHex(member, "member", 32), role(memberRole))
7596
7645
  };
7597
7646
  }
7647
+ var SUBGROUP_ID_DOMAIN = new TextEncoder().encode("calimero.subgroup.id.v1");
7648
+ async function createdSubgroupId(admin, parentId, restricted, salt) {
7649
+ return hex(
7650
+ await domainHash(SUBGROUP_ID_DOMAIN, [
7651
+ fromHex(admin, "admin", 32),
7652
+ fromHex(parentId, "parentId", 32),
7653
+ new Uint8Array([restricted ? 1 : 0]),
7654
+ fromHex(salt, "salt", 32)
7655
+ ])
7656
+ );
7657
+ }
7598
7658
  function defaultCapabilitiesSetOp(capabilities) {
7599
7659
  if (!Number.isInteger(capabilities) || capabilities < 0 || capabilities > 4294967295) {
7600
7660
  throw new Error(`capabilities must be a u32 bit mask, got ${String(capabilities)}`);
@@ -7617,10 +7677,16 @@ function groupCreatedOp(input) {
7617
7677
  fromHex(input.groupId, "groupId", 32),
7618
7678
  fromHex(input.parentId, "parentId", 32),
7619
7679
  tag(input.restricted ? 1 : 0),
7620
- fromHex(input.admin, "admin", 32)
7680
+ fromHex(input.admin, "admin", 32),
7681
+ fromHex(input.salt, "salt", 32)
7621
7682
  )
7622
7683
  };
7623
7684
  }
7685
+ async function subgroupCreation(input) {
7686
+ const salt = input.salt ?? hex(crypto.getRandomValues(new Uint8Array(32)));
7687
+ const groupId = await createdSubgroupId(input.admin, input.parentId, input.restricted, salt);
7688
+ return { groupId, salt, op: groupCreatedOp({ ...input, groupId, salt }) };
7689
+ }
7624
7690
  function groupReparentedOp(childGroupId, newParentId) {
7625
7691
  return {
7626
7692
  kind: "root",
@@ -8178,12 +8244,12 @@ function audienceSigningBytes(audience) {
8178
8244
  );
8179
8245
  }
8180
8246
  function audienceWire(audience) {
8181
- const tag2 = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);
8247
+ const tag3 = Uint8Array.from([AUDIENCE_TAG[audience.kind]]);
8182
8248
  if (audience.kind === "cli") {
8183
- return tag2;
8249
+ return tag3;
8184
8250
  }
8185
8251
  const body = audienceBody(audience);
8186
- return concat(tag2, u32le(body.length), body);
8252
+ return concat(tag3, u32le(body.length), body);
8187
8253
  }
8188
8254
  async function signLoginStatement(input) {
8189
8255
  const node = fromHex(input.node, "node", 32);
@@ -9868,8 +9934,8 @@ var SIGNATURE_HASHES = {
9868
9934
  };
9869
9935
  function read(bytes, offset, limit) {
9870
9936
  if (offset + 2 > limit) throw new Error("it is truncated");
9871
- const tag2 = bytes[offset];
9872
- if ((tag2 & 31) === 31) throw new Error("it uses a tag this parser does not read");
9937
+ const tag3 = bytes[offset];
9938
+ if ((tag3 & 31) === 31) throw new Error("it uses a tag this parser does not read");
9873
9939
  let length = bytes[offset + 1];
9874
9940
  let start = offset + 2;
9875
9941
  if (length & 128) {
@@ -9881,7 +9947,7 @@ function read(bytes, offset, limit) {
9881
9947
  }
9882
9948
  const end = start + length;
9883
9949
  if (end > limit) throw new Error("it is truncated");
9884
- return { tag: tag2, bytes, offset, start, end };
9950
+ return { tag: tag3, bytes, offset, start, end };
9885
9951
  }
9886
9952
  function parseDer(bytes) {
9887
9953
  const element = read(bytes, 0, bytes.length);
@@ -9897,8 +9963,8 @@ function children(element) {
9897
9963
  }
9898
9964
  return out;
9899
9965
  }
9900
- function expectTag(element, tag2, what) {
9901
- if (!element || element.tag !== tag2) throw new Error(`${what} is not where it should be`);
9966
+ function expectTag(element, tag3, what) {
9967
+ if (!element || element.tag !== tag3) throw new Error(`${what} is not where it should be`);
9902
9968
  return element;
9903
9969
  }
9904
9970
  function contents(element) {
@@ -10456,7 +10522,7 @@ function bytes32(value, label2) {
10456
10522
  }
10457
10523
 
10458
10524
  // src/namespace-op/namespace-op.ts
10459
- var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 16;
10525
+ var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 20;
10460
10526
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
10461
10527
  var NAMESPACE_OP_ROOT = 0;
10462
10528
  var ROOT_OP2 = {
@@ -10546,6 +10612,183 @@ async function signMemberJoinOp(input) {
10546
10612
  return hex(concat(signable, signature, unendorsed));
10547
10613
  }
10548
10614
 
10615
+ // src/owner-op/owner-op.ts
10616
+ var OWNER_OP_SIGN_DOMAIN = new TextEncoder().encode("calimero.account.owner-op.v1");
10617
+ var OWNER_OP_BODY_DOMAIN = new TextEncoder().encode("calimero.account.owner-op.body.v1");
10618
+ var ACCOUNT_ID_DOMAIN2 = new TextEncoder().encode("calimero.account.genesis.v1");
10619
+ var ACCOUNT_GENESIS_VERSION2 = 2;
10620
+ var OWNER_OP_KIND = {
10621
+ transferOwnership: 0,
10622
+ adminChanged: 1,
10623
+ groupDelete: 2,
10624
+ teeAdmissionPolicy: 3,
10625
+ teeAuthoringPolicy: 4,
10626
+ teeReleaseAdmissionPolicy: 5
10627
+ };
10628
+ var GROUP_OP2 = {
10629
+ GroupDelete: 14,
10630
+ TransferOwnership: 21,
10631
+ TeeAuthoringPolicySet: 33,
10632
+ TeeAdmissionPolicySetV2: 37,
10633
+ TeeReleaseAdmissionPolicySetV2: 38,
10634
+ RootGuarded: 42
10635
+ };
10636
+ var ROOT_OP3 = {
10637
+ AdminChanged: 3,
10638
+ RootGuarded: 12
10639
+ };
10640
+ var TEE_MODE = { replica: 0, relay: 1 };
10641
+ var te = new TextEncoder();
10642
+ function tag2(byte) {
10643
+ return new Uint8Array([byte]);
10644
+ }
10645
+ function borshString3(value) {
10646
+ const bytes = te.encode(value);
10647
+ return concat(u32le(bytes.length), bytes);
10648
+ }
10649
+ function borshStrings(values) {
10650
+ return concat(u32le(values.length), ...values.map(borshString3));
10651
+ }
10652
+ function borshBool(value) {
10653
+ return tag2(value ? 1 : 0);
10654
+ }
10655
+ function teeMode(mode) {
10656
+ const byte = TEE_MODE[mode ?? "replica"];
10657
+ if (byte === void 0) {
10658
+ throw new Error(`mode must be replica or relay, got ${String(mode)}`);
10659
+ }
10660
+ return tag2(byte);
10661
+ }
10662
+ function transferOwnershipOp(newOwner) {
10663
+ return {
10664
+ kind: "transferOwnership",
10665
+ plane: "group",
10666
+ bytes: concat(tag2(GROUP_OP2.TransferOwnership), fromHex(newOwner, "newOwner", 32))
10667
+ };
10668
+ }
10669
+ function groupDeleteOp() {
10670
+ return { kind: "groupDelete", plane: "group", bytes: tag2(GROUP_OP2.GroupDelete) };
10671
+ }
10672
+ function adminChangedOp(newAdmin) {
10673
+ return {
10674
+ kind: "adminChanged",
10675
+ plane: "root",
10676
+ bytes: concat(tag2(ROOT_OP3.AdminChanged), fromHex(newAdmin, "newAdmin", 32))
10677
+ };
10678
+ }
10679
+ function teeAuthoringPolicyOp(allowedMrtd) {
10680
+ return {
10681
+ kind: "teeAuthoringPolicy",
10682
+ plane: "group",
10683
+ bytes: concat(tag2(GROUP_OP2.TeeAuthoringPolicySet), borshStrings(allowedMrtd))
10684
+ };
10685
+ }
10686
+ function teeAdmissionPolicyOp(input) {
10687
+ return {
10688
+ kind: "teeAdmissionPolicy",
10689
+ plane: "group",
10690
+ bytes: concat(
10691
+ tag2(GROUP_OP2.TeeAdmissionPolicySetV2),
10692
+ borshStrings(input.allowedMrtd),
10693
+ borshStrings(input.allowedRtmr0),
10694
+ borshStrings(input.allowedRtmr1),
10695
+ borshStrings(input.allowedRtmr2),
10696
+ borshStrings(input.allowedRtmr3),
10697
+ borshStrings(input.allowedTcbStatuses),
10698
+ borshBool(input.acceptMock),
10699
+ teeMode(input.mode)
10700
+ )
10701
+ };
10702
+ }
10703
+ function teeReleaseAdmissionPolicyOp(input) {
10704
+ const minRelease = input.minReleaseVersion === void 0 ? tag2(0) : concat(tag2(1), borshString3(input.minReleaseVersion));
10705
+ return {
10706
+ kind: "teeReleaseAdmissionPolicy",
10707
+ plane: "group",
10708
+ bytes: concat(
10709
+ tag2(GROUP_OP2.TeeReleaseAdmissionPolicySetV2),
10710
+ borshStrings(input.allowedProfiles),
10711
+ minRelease,
10712
+ borshStrings(input.allowedTcbStatuses),
10713
+ borshBool(input.acceptMock),
10714
+ teeMode(input.mode)
10715
+ )
10716
+ };
10717
+ }
10718
+ async function ownerOpDigest(opBytes) {
10719
+ return domainHash(OWNER_OP_BODY_DOMAIN, [opBytes]);
10720
+ }
10721
+ async function ownerOpSigningPayload(input) {
10722
+ return domainHash(OWNER_OP_SIGN_DOMAIN, [
10723
+ fromHex(input.account, "account", 32),
10724
+ fromHex(input.namespaceId, "namespaceId", 32),
10725
+ fromHex(input.groupId, "groupId", 32),
10726
+ tag2(kindByte2(input.kind)),
10727
+ input.opDigest,
10728
+ u64le(input.counter),
10729
+ u32le(input.keyEpoch)
10730
+ ]);
10731
+ }
10732
+ function kindByte2(kind) {
10733
+ const byte = OWNER_OP_KIND[kind];
10734
+ if (byte === void 0) {
10735
+ throw new Error(`unknown owner-op kind ${String(kind)}`);
10736
+ }
10737
+ return byte;
10738
+ }
10739
+ var HANDOFF_BYTES = 32 + 4 + 32 + 64;
10740
+ async function signOwnerOpProof(input) {
10741
+ const rootPublicKey = await derivePublicKey(input.rootSecret);
10742
+ const genesis = concat(tag2(ACCOUNT_GENESIS_VERSION2), rootPublicKey);
10743
+ const account = hex(await domainHash(ACCOUNT_ID_DOMAIN2, [genesis]));
10744
+ const keyEpoch = input.keyEpoch ?? 0;
10745
+ const chain = (input.chain ?? []).map((handoff, index) => {
10746
+ const bytes = fromHexUnsized(handoff, `chain[${index}]`);
10747
+ if (bytes.length !== HANDOFF_BYTES) {
10748
+ throw new Error(
10749
+ `chain[${index}] must be a ${HANDOFF_BYTES}-byte RootKeyHandoff, got ${bytes.length}`
10750
+ );
10751
+ }
10752
+ return bytes;
10753
+ });
10754
+ if (keyEpoch > chain.length) {
10755
+ throw new Error(
10756
+ `keyEpoch ${keyEpoch} needs ${keyEpoch} handoffs in chain, got ${chain.length}`
10757
+ );
10758
+ }
10759
+ const opDigest = await ownerOpDigest(input.op.bytes);
10760
+ const payload = await ownerOpSigningPayload({
10761
+ account,
10762
+ namespaceId: input.namespaceId,
10763
+ groupId: input.groupId,
10764
+ kind: input.op.kind,
10765
+ opDigest,
10766
+ counter: input.counter,
10767
+ keyEpoch
10768
+ });
10769
+ const key = await importSigningKey(input.rootSecret);
10770
+ const signature = new Uint8Array(await crypto.subtle.sign("Ed25519", key, payload));
10771
+ return hex(
10772
+ concat(
10773
+ genesis,
10774
+ u32le(chain.length),
10775
+ ...chain,
10776
+ fromHex(account, "account", 32),
10777
+ fromHex(input.namespaceId, "namespaceId", 32),
10778
+ fromHex(input.groupId, "groupId", 32),
10779
+ tag2(kindByte2(input.op.kind)),
10780
+ opDigest,
10781
+ u64le(input.counter),
10782
+ u32le(keyEpoch),
10783
+ signature
10784
+ )
10785
+ );
10786
+ }
10787
+ function rootGuardedOpBytes(op, rootProof) {
10788
+ const wrapper = op.plane === "group" ? GROUP_OP2.RootGuarded : ROOT_OP3.RootGuarded;
10789
+ return concat(tag2(wrapper), op.bytes, fromHexUnsized(rootProof, "rootProof"));
10790
+ }
10791
+
10549
10792
  // src/nodeDiscovery.ts
10550
10793
  var DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529];
10551
10794
  var LOCAL_HOST = "localhost";