@calimero-network/mero-js 15.1.0 → 15.3.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/admin-api/admin-client.d.ts +19 -1
- package/dist/admin-api/admin-client.js +20 -0
- package/dist/admin-api/admin-types.d.ts +69 -0
- package/dist/device-cert/device-cert.d.ts +24 -0
- package/dist/device-cert/device-cert.js +27 -7
- package/dist/device-cert/index.d.ts +1 -1
- package/dist/device-cert/index.js +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +152 -13
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +152 -13
- package/dist/index.mjs.map +3 -3
- package/dist/namespace-op/index.d.ts +2 -0
- package/dist/namespace-op/index.js +3 -0
- package/dist/namespace-op/namespace-op.d.ts +64 -0
- package/dist/namespace-op/namespace-op.js +109 -0
- package/package.json +1 -1
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
|
@@ -1158,6 +1158,32 @@ var AdminApiClient = class {
|
|
|
1158
1158
|
)
|
|
1159
1159
|
);
|
|
1160
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Present a join this caller signed to a node the inviter named as an
|
|
1163
|
+
* admitter.
|
|
1164
|
+
*
|
|
1165
|
+
* For a member with no node. `joinNamespace` publishes the membership op from
|
|
1166
|
+
* the node making the call; this hands an already-signed op to somebody else's
|
|
1167
|
+
* node to publish. The distinction matters because a keyholder has nowhere to
|
|
1168
|
+
* publish from.
|
|
1169
|
+
*
|
|
1170
|
+
* The op must be signed by the **device key** in the credential it carries —
|
|
1171
|
+
* every peer checks that when applying a join. So the admitter cannot author
|
|
1172
|
+
* this, only carry it: a hostile one can refuse, and nothing else. It cannot
|
|
1173
|
+
* admit a different account, change the group, or grant a role.
|
|
1174
|
+
*
|
|
1175
|
+
* @param namespaceId the namespace being joined, 64 hex
|
|
1176
|
+
* @param request the invitation and the hex-encoded signed op
|
|
1177
|
+
*/
|
|
1178
|
+
async admitJoin(namespaceId, request) {
|
|
1179
|
+
return unwrap(
|
|
1180
|
+
await this.httpClient.post(
|
|
1181
|
+
`/admin-api/namespaces/${namespaceId}/admit`,
|
|
1182
|
+
request,
|
|
1183
|
+
{ timeoutMs: 65e3 }
|
|
1184
|
+
)
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1161
1187
|
async joinNamespace(namespaceId, request) {
|
|
1162
1188
|
const data = unwrap(
|
|
1163
1189
|
await this.httpClient.post(
|
|
@@ -2685,6 +2711,20 @@ async function deviceCertPayload(input) {
|
|
|
2685
2711
|
u32le(input.deviceEpoch)
|
|
2686
2712
|
]);
|
|
2687
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
|
+
}
|
|
2688
2728
|
async function signDeviceCert(input) {
|
|
2689
2729
|
const rootPublicKey = await derivePublicKey(input.rootSecret);
|
|
2690
2730
|
const account = hex(
|
|
@@ -2705,21 +2745,16 @@ async function signDeviceCert(input) {
|
|
|
2705
2745
|
const signature = new Uint8Array(
|
|
2706
2746
|
await crypto.subtle.sign("Ed25519", key, payload)
|
|
2707
2747
|
);
|
|
2708
|
-
const credential =
|
|
2709
|
-
// AccountGenesis
|
|
2710
|
-
new Uint8Array([ACCOUNT_GENESIS_VERSION]),
|
|
2748
|
+
const credential = accountProofBytes({
|
|
2711
2749
|
rootPublicKey,
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
2719
|
-
u32le(keyEpoch),
|
|
2720
|
-
u32le(input.deviceEpoch),
|
|
2750
|
+
account,
|
|
2751
|
+
device: input.device,
|
|
2752
|
+
signPublicKey: input.signPublicKey,
|
|
2753
|
+
kemPublicKey: input.kemPublicKey,
|
|
2754
|
+
keyEpoch,
|
|
2755
|
+
deviceEpoch: input.deviceEpoch,
|
|
2721
2756
|
signature
|
|
2722
|
-
);
|
|
2757
|
+
});
|
|
2723
2758
|
return hex(credential);
|
|
2724
2759
|
}
|
|
2725
2760
|
async function accountForRoot(rootSecret) {
|
|
@@ -2731,6 +2766,107 @@ async function accountForRoot(rootSecret) {
|
|
|
2731
2766
|
);
|
|
2732
2767
|
}
|
|
2733
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
|
+
|
|
2734
2870
|
// src/capabilities.ts
|
|
2735
2871
|
var CAPABILITIES = {
|
|
2736
2872
|
CAN_CREATE_CONTEXT: 1 << 0,
|
|
@@ -2820,6 +2956,7 @@ export {
|
|
|
2820
2956
|
MeroJs,
|
|
2821
2957
|
RpcClient,
|
|
2822
2958
|
RpcError,
|
|
2959
|
+
SIGNED_NAMESPACE_OP_SCHEMA_VERSION,
|
|
2823
2960
|
SseClient,
|
|
2824
2961
|
WebHttpClient,
|
|
2825
2962
|
WsClient,
|
|
@@ -2844,6 +2981,7 @@ export {
|
|
|
2844
2981
|
createUniversalHttpClient,
|
|
2845
2982
|
deviceCertPayload,
|
|
2846
2983
|
discoverLocalNodes,
|
|
2984
|
+
encodeSignedInvitation,
|
|
2847
2985
|
hasCap,
|
|
2848
2986
|
intentHash,
|
|
2849
2987
|
jsonCodec,
|
|
@@ -2853,6 +2991,7 @@ export {
|
|
|
2853
2991
|
parseAuthCallback,
|
|
2854
2992
|
probeNodeHealth,
|
|
2855
2993
|
signDeviceCert,
|
|
2994
|
+
signMemberJoinOp,
|
|
2856
2995
|
signWarrant,
|
|
2857
2996
|
withCap,
|
|
2858
2997
|
withRetry,
|