@calimero-network/mero-js 15.0.0 → 15.2.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 +63 -0
- package/dist/crypto/internal.d.ts +30 -0
- package/dist/crypto/internal.js +93 -0
- package/dist/device-cert/device-cert.d.ts +68 -0
- package/dist/device-cert/device-cert.js +110 -0
- package/dist/device-cert/index.d.ts +2 -0
- package/dist/device-cert/index.js +2 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +126 -21
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +126 -21
- package/dist/index.mjs.map +3 -3
- package/dist/warrant/warrant.d.ts +1 -0
- package/dist/warrant/warrant.js +1 -79
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
|
|
|
16
16
|
export type { Codec, EphemeralEntry } from './ephemeral/index.js';
|
|
17
17
|
export * from './cloud/index.js';
|
|
18
18
|
export { signWarrant, intentHash } from './warrant/index.js';
|
|
19
|
+
export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
|
|
20
|
+
export type { DeviceCertInput } from './device-cert/index.js';
|
|
19
21
|
export type { WarrantInput } from './warrant/index.js';
|
|
20
22
|
export * from './capabilities.js';
|
|
21
23
|
export { DEFAULT_LOCAL_NODE_PORTS, localNodeUrl, nodeEndpoint, probeNodeHealth, discoverLocalNodes, } from './nodeDiscovery.js';
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ export { EphemeralClient, jsonCodec } from './ephemeral/index.js';
|
|
|
22
22
|
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
|
+
export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from './device-cert/index.js';
|
|
25
26
|
// Member capability bitmask constants & helpers
|
|
26
27
|
export * from './capabilities.js';
|
|
27
28
|
// 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(
|
|
@@ -2522,9 +2548,7 @@ var CloudClient = class {
|
|
|
2522
2548
|
}
|
|
2523
2549
|
};
|
|
2524
2550
|
|
|
2525
|
-
// src/
|
|
2526
|
-
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v1");
|
|
2527
|
-
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
2551
|
+
// src/crypto/internal.ts
|
|
2528
2552
|
var PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
2529
2553
|
48,
|
|
2530
2554
|
46,
|
|
@@ -2543,6 +2567,11 @@ var PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
|
2543
2567
|
4,
|
|
2544
2568
|
32
|
|
2545
2569
|
]);
|
|
2570
|
+
function u32le(value) {
|
|
2571
|
+
const out = new Uint8Array(4);
|
|
2572
|
+
new DataView(out.buffer).setUint32(0, value, true);
|
|
2573
|
+
return out;
|
|
2574
|
+
}
|
|
2546
2575
|
function hex(bytes) {
|
|
2547
2576
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
2548
2577
|
}
|
|
@@ -2582,10 +2611,6 @@ async function domainHash(domain, parts) {
|
|
|
2582
2611
|
await crypto.subtle.digest("SHA-256", concat(...chunks))
|
|
2583
2612
|
);
|
|
2584
2613
|
}
|
|
2585
|
-
async function intentHash(method, argsJson) {
|
|
2586
|
-
const args = new TextEncoder().encode(JSON.stringify(argsJson));
|
|
2587
|
-
return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
|
|
2588
|
-
}
|
|
2589
2614
|
async function importSigningKey(secretHex) {
|
|
2590
2615
|
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
2591
2616
|
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
@@ -2604,6 +2629,31 @@ async function importSigningKey(secretHex) {
|
|
|
2604
2629
|
);
|
|
2605
2630
|
}
|
|
2606
2631
|
}
|
|
2632
|
+
async function derivePublicKey(secretHex) {
|
|
2633
|
+
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
2634
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
2635
|
+
const key = await crypto.subtle.importKey(
|
|
2636
|
+
"pkcs8",
|
|
2637
|
+
pkcs8,
|
|
2638
|
+
{ name: "Ed25519" },
|
|
2639
|
+
true,
|
|
2640
|
+
["sign"]
|
|
2641
|
+
);
|
|
2642
|
+
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
2643
|
+
const raw = jwk.x;
|
|
2644
|
+
return Uint8Array.from(
|
|
2645
|
+
atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
|
|
2646
|
+
(c) => c.charCodeAt(0)
|
|
2647
|
+
);
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
// src/warrant/warrant.ts
|
|
2651
|
+
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v1");
|
|
2652
|
+
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
2653
|
+
async function intentHash(method, argsJson) {
|
|
2654
|
+
const args = new TextEncoder().encode(JSON.stringify(argsJson));
|
|
2655
|
+
return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
|
|
2656
|
+
}
|
|
2607
2657
|
async function signWarrant(input) {
|
|
2608
2658
|
const context = fromHex(input.context, "context", 32);
|
|
2609
2659
|
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
@@ -2638,21 +2688,72 @@ async function signWarrant(input) {
|
|
|
2638
2688
|
)
|
|
2639
2689
|
);
|
|
2640
2690
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2691
|
+
|
|
2692
|
+
// src/device-cert/device-cert.ts
|
|
2693
|
+
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
2694
|
+
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
2695
|
+
var DEVICE_ID_DOMAIN = new TextEncoder().encode("calimero.device.id.v1");
|
|
2696
|
+
var ACCOUNT_GENESIS_VERSION = 1;
|
|
2697
|
+
async function mintDeviceId(account, nonce) {
|
|
2698
|
+
if (nonce.length !== 16) {
|
|
2699
|
+
throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);
|
|
2700
|
+
}
|
|
2701
|
+
const accountBytes = fromHex(account, "account", 32);
|
|
2702
|
+
return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));
|
|
2703
|
+
}
|
|
2704
|
+
async function deviceCertPayload(input) {
|
|
2705
|
+
return domainHash(CERT_DOMAIN, [
|
|
2706
|
+
fromHex(input.account, "account", 32),
|
|
2707
|
+
fromHex(input.device, "device", 32),
|
|
2708
|
+
fromHex(input.signPublicKey, "signPublicKey", 32),
|
|
2709
|
+
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
2710
|
+
u32le(input.keyEpoch),
|
|
2711
|
+
u32le(input.deviceEpoch)
|
|
2712
|
+
]);
|
|
2713
|
+
}
|
|
2714
|
+
async function signDeviceCert(input) {
|
|
2715
|
+
const rootPublicKey = await derivePublicKey(input.rootSecret);
|
|
2716
|
+
const account = hex(
|
|
2717
|
+
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
2718
|
+
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
2719
|
+
])
|
|
2650
2720
|
);
|
|
2651
|
-
const
|
|
2652
|
-
const
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2721
|
+
const keyEpoch = 0;
|
|
2722
|
+
const payload = await deviceCertPayload({
|
|
2723
|
+
account,
|
|
2724
|
+
device: input.device,
|
|
2725
|
+
signPublicKey: input.signPublicKey,
|
|
2726
|
+
kemPublicKey: input.kemPublicKey,
|
|
2727
|
+
keyEpoch,
|
|
2728
|
+
deviceEpoch: input.deviceEpoch
|
|
2729
|
+
});
|
|
2730
|
+
const key = await importSigningKey(input.rootSecret);
|
|
2731
|
+
const signature = new Uint8Array(
|
|
2732
|
+
await crypto.subtle.sign("Ed25519", key, payload)
|
|
2733
|
+
);
|
|
2734
|
+
const credential = concat(
|
|
2735
|
+
// AccountGenesis
|
|
2736
|
+
new Uint8Array([ACCOUNT_GENESIS_VERSION]),
|
|
2737
|
+
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),
|
|
2747
|
+
signature
|
|
2748
|
+
);
|
|
2749
|
+
return hex(credential);
|
|
2750
|
+
}
|
|
2751
|
+
async function accountForRoot(rootSecret) {
|
|
2752
|
+
const rootPublicKey = await derivePublicKey(rootSecret);
|
|
2753
|
+
return hex(
|
|
2754
|
+
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
2755
|
+
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
2756
|
+
])
|
|
2656
2757
|
);
|
|
2657
2758
|
}
|
|
2658
2759
|
|
|
@@ -2748,6 +2849,7 @@ export {
|
|
|
2748
2849
|
SseClient,
|
|
2749
2850
|
WebHttpClient,
|
|
2750
2851
|
WsClient,
|
|
2852
|
+
accountForRoot,
|
|
2751
2853
|
buildAuthLoginUrl,
|
|
2752
2854
|
combineSignals,
|
|
2753
2855
|
compareSemver,
|
|
@@ -2766,14 +2868,17 @@ export {
|
|
|
2766
2868
|
createRetryableMethod,
|
|
2767
2869
|
createTimeoutSignal,
|
|
2768
2870
|
createUniversalHttpClient,
|
|
2871
|
+
deviceCertPayload,
|
|
2769
2872
|
discoverLocalNodes,
|
|
2770
2873
|
hasCap,
|
|
2771
2874
|
intentHash,
|
|
2772
2875
|
jsonCodec,
|
|
2773
2876
|
localNodeUrl,
|
|
2877
|
+
mintDeviceId,
|
|
2774
2878
|
nodeEndpoint,
|
|
2775
2879
|
parseAuthCallback,
|
|
2776
2880
|
probeNodeHealth,
|
|
2881
|
+
signDeviceCert,
|
|
2777
2882
|
signWarrant,
|
|
2778
2883
|
withCap,
|
|
2779
2884
|
withRetry,
|