@calimero-network/mero-js 15.2.0 → 15.3.1

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.d.ts CHANGED
@@ -18,6 +18,8 @@ export * from './cloud/index.js';
18
18
  export { signWarrant, intentHash } from './warrant/index.js';
19
19
  export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
20
20
  export type { DeviceCertInput } from './device-cert/index.js';
21
+ export { signMemberJoinOp, encodeSignedInvitation, SIGNED_NAMESPACE_OP_SCHEMA_VERSION, } from './namespace-op/index.js';
22
+ export type { SignMemberJoinInput } from './namespace-op/index.js';
21
23
  export type { WarrantInput } from './warrant/index.js';
22
24
  export * from './capabilities.js';
23
25
  export { DEFAULT_LOCAL_NODE_PORTS, localNodeUrl, nodeEndpoint, probeNodeHealth, discoverLocalNodes, } from './nodeDiscovery.js';
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ export * from './cloud/index.js';
23
23
  // Warrant signing — mint the author's consent for a relay to run one intent
24
24
  export { signWarrant, intentHash } from './warrant/index.js';
25
25
  export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
26
+ export { signMemberJoinOp, encodeSignedInvitation, SIGNED_NAMESPACE_OP_SCHEMA_VERSION, } from './namespace-op/index.js';
26
27
  // Member capability bitmask constants & helpers
27
28
  export * from './capabilities.js';
28
29
  // Utilities
package/dist/index.mjs CHANGED
@@ -2711,6 +2711,20 @@ async function deviceCertPayload(input) {
2711
2711
  u32le(input.deviceEpoch)
2712
2712
  ]);
2713
2713
  }
2714
+ function accountProofBytes(input) {
2715
+ return concat(
2716
+ new Uint8Array([ACCOUNT_GENESIS_VERSION]),
2717
+ input.rootPublicKey,
2718
+ u32le(0),
2719
+ fromHex(input.account, "account", 32),
2720
+ fromHex(input.device, "device", 32),
2721
+ fromHex(input.signPublicKey, "signPublicKey", 32),
2722
+ fromHex(input.kemPublicKey, "kemPublicKey", 32),
2723
+ u32le(input.keyEpoch),
2724
+ u32le(input.deviceEpoch),
2725
+ input.signature
2726
+ );
2727
+ }
2714
2728
  async function signDeviceCert(input) {
2715
2729
  const rootPublicKey = await derivePublicKey(input.rootSecret);
2716
2730
  const account = hex(
@@ -2731,21 +2745,16 @@ async function signDeviceCert(input) {
2731
2745
  const signature = new Uint8Array(
2732
2746
  await crypto.subtle.sign("Ed25519", key, payload)
2733
2747
  );
2734
- const credential = concat(
2735
- // AccountGenesis
2736
- new Uint8Array([ACCOUNT_GENESIS_VERSION]),
2748
+ const credential = accountProofBytes({
2737
2749
  rootPublicKey,
2738
- // chain: Vec<RootKeyHandoff>, empty
2739
- u32le(0),
2740
- // DeviceCert
2741
- fromHex(account, "account", 32),
2742
- fromHex(input.device, "device", 32),
2743
- fromHex(input.signPublicKey, "signPublicKey", 32),
2744
- fromHex(input.kemPublicKey, "kemPublicKey", 32),
2745
- u32le(keyEpoch),
2746
- u32le(input.deviceEpoch),
2750
+ account,
2751
+ device: input.device,
2752
+ signPublicKey: input.signPublicKey,
2753
+ kemPublicKey: input.kemPublicKey,
2754
+ keyEpoch,
2755
+ deviceEpoch: input.deviceEpoch,
2747
2756
  signature
2748
- );
2757
+ });
2749
2758
  return hex(credential);
2750
2759
  }
2751
2760
  async function accountForRoot(rootSecret) {
@@ -2757,6 +2766,107 @@ async function accountForRoot(rootSecret) {
2757
2766
  );
2758
2767
  }
2759
2768
 
2769
+ // src/namespace-op/namespace-op.ts
2770
+ var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 7;
2771
+ var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
2772
+ var NAMESPACE_OP_ROOT = 0;
2773
+ var ROOT_OP = {
2774
+ GroupCreated: 0,
2775
+ GroupReparented: 1,
2776
+ GroupDeleted: 2,
2777
+ AdminChanged: 3,
2778
+ PolicyUpdated: 4,
2779
+ MemberJoined: 5,
2780
+ KeyDelivery: 6,
2781
+ MemberJoinedOpen: 7,
2782
+ MemberJoinedAt: 8,
2783
+ NamespaceCreated: 9,
2784
+ MemberJoinedViaTeeAttestation: 10
2785
+ };
2786
+ function bytes32(value, label) {
2787
+ if (value.length !== 32) {
2788
+ throw new Error(`${label} must be 32 bytes, got ${value.length}`);
2789
+ }
2790
+ return new Uint8Array(value);
2791
+ }
2792
+ function optionalBytes32(value, label) {
2793
+ if (value === null || value === void 0) {
2794
+ return new Uint8Array([0]);
2795
+ }
2796
+ if (value.length !== 32) {
2797
+ throw new Error(`${label} must be 32 bytes, got ${value.length}`);
2798
+ }
2799
+ return concat(new Uint8Array([1]), new Uint8Array(value));
2800
+ }
2801
+ function borshString(value) {
2802
+ const bytes = new TextEncoder().encode(value);
2803
+ return concat(u32le(bytes.length), bytes);
2804
+ }
2805
+ function encodeAdmitterHint(hint) {
2806
+ if ("multiaddr" in hint) {
2807
+ return concat(new Uint8Array([0]), borshString(hint.multiaddr));
2808
+ }
2809
+ return concat(new Uint8Array([1]), borshString(hint.url));
2810
+ }
2811
+ function encodeSignedInvitation(signed) {
2812
+ const body = signed.invitation;
2813
+ const admitters = body.admitters ?? [];
2814
+ const hints = signed.admitter_hints ?? [];
2815
+ return concat(
2816
+ // GroupInvitationFromAdmin.
2817
+ //
2818
+ // `SignerId` and `ContextGroupId` cross JSON as 32 numbers; `AccountId`
2819
+ // crosses as hex. Same width, different spelling, and reading either the
2820
+ // wrong way yields 32 bytes that encode cleanly and verify as nothing.
2821
+ bytes32(body.inviter_identity, "inviter_identity"),
2822
+ bytes32(body.group_id, "group_id"),
2823
+ u64le(body.expiration_timestamp),
2824
+ bytes32(body.secret_salt, "secret_salt"),
2825
+ new Uint8Array([body.invited_role]),
2826
+ u32le(admitters.length),
2827
+ ...admitters.map((a, i) => fromHex(a, `admitters[${i}]`, 32)),
2828
+ // ...then the enclosing SignedGroupOpenInvitation, in declaration order.
2829
+ // `inviter_account` sits between the signature and the hints; putting it
2830
+ // anywhere else still encodes 32 bytes and still verifies as nothing.
2831
+ borshString(signed.inviter_signature),
2832
+ signed.inviter_account ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, "inviter_account", 32)) : new Uint8Array([0]),
2833
+ u32le(hints.length),
2834
+ ...hints.map(encodeAdmitterHint),
2835
+ optionalBytes32(signed.application_id, "application_id"),
2836
+ // Borsh order follows core's field order, where this is `bytecode_id`; the
2837
+ // JSON key is `app_key`, a rename covering both directions that core pins in
2838
+ // a test. Encoding by the Rust name would read `undefined` and emit a None
2839
+ // where the inviter signed a Some.
2840
+ optionalBytes32(signed.app_key, "app_key")
2841
+ );
2842
+ }
2843
+ async function signMemberJoinOp(input) {
2844
+ const parents = input.parentOpHashes ?? [];
2845
+ const credential = fromHex(input.credential, "credential", input.credential.length / 2);
2846
+ const rootOp = concat(
2847
+ new Uint8Array([input.at ? ROOT_OP.MemberJoinedAt : ROOT_OP.MemberJoined]),
2848
+ fromHex(input.member, "member", 32),
2849
+ encodeSignedInvitation(input.invitation),
2850
+ credential
2851
+ );
2852
+ const op = concat(new Uint8Array([NAMESPACE_OP_ROOT]), rootOp);
2853
+ const key = await importSigningKey(input.deviceSecret);
2854
+ const signer = await derivePublicKey(input.deviceSecret);
2855
+ const signable = concat(
2856
+ new Uint8Array([SIGNED_NAMESPACE_OP_SCHEMA_VERSION]),
2857
+ fromHex(input.namespaceId, "namespaceId", 32),
2858
+ u32le(parents.length),
2859
+ ...parents.map((p, i) => fromHex(p, `parentOpHashes[${i}]`, 32)),
2860
+ signer,
2861
+ u64le(input.nonce),
2862
+ op
2863
+ );
2864
+ const signature = new Uint8Array(
2865
+ await crypto.subtle.sign("Ed25519", key, concat(NAMESPACE_SIGN_DOMAIN, signable))
2866
+ );
2867
+ return hex(concat(signable, signature));
2868
+ }
2869
+
2760
2870
  // src/capabilities.ts
2761
2871
  var CAPABILITIES = {
2762
2872
  CAN_CREATE_CONTEXT: 1 << 0,
@@ -2846,6 +2956,7 @@ export {
2846
2956
  MeroJs,
2847
2957
  RpcClient,
2848
2958
  RpcError,
2959
+ SIGNED_NAMESPACE_OP_SCHEMA_VERSION,
2849
2960
  SseClient,
2850
2961
  WebHttpClient,
2851
2962
  WsClient,
@@ -2870,6 +2981,7 @@ export {
2870
2981
  createUniversalHttpClient,
2871
2982
  deviceCertPayload,
2872
2983
  discoverLocalNodes,
2984
+ encodeSignedInvitation,
2873
2985
  hasCap,
2874
2986
  intentHash,
2875
2987
  jsonCodec,
@@ -2879,6 +2991,7 @@ export {
2879
2991
  parseAuthCallback,
2880
2992
  probeNodeHealth,
2881
2993
  signDeviceCert,
2994
+ signMemberJoinOp,
2882
2995
  signWarrant,
2883
2996
  withCap,
2884
2997
  withRetry,