@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
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* this producing well-formed warrants whose signatures verify nowhere, surfacing
|
|
22
22
|
* at a relay as a 403: an authorization refusal, nowhere near the cause.
|
|
23
23
|
*/
|
|
24
|
+
/** Ed25519 PKCS#8 prefix, so a raw 32-byte seed can be imported by WebCrypto. */
|
|
24
25
|
/** What a warrant authorises. */
|
|
25
26
|
export interface WarrantInput {
|
|
26
27
|
/**
|
package/dist/warrant/warrant.js
CHANGED
|
@@ -21,56 +21,9 @@
|
|
|
21
21
|
* this producing well-formed warrants whose signatures verify nowhere, surfacing
|
|
22
22
|
* at a relay as a 403: an authorization refusal, nowhere near the cause.
|
|
23
23
|
*/
|
|
24
|
+
import { concat, derivePublicKey, domainHash, fromHex, hex, importSigningKey, u64le, } from '../crypto/internal.js';
|
|
24
25
|
const SIGN_DOMAIN = new TextEncoder().encode('calimero.warrant.v1');
|
|
25
26
|
const INTENT_DOMAIN = new TextEncoder().encode('calimero.warrant.intent.v1');
|
|
26
|
-
/** Ed25519 PKCS#8 prefix, so a raw 32-byte seed can be imported by WebCrypto. */
|
|
27
|
-
const PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
28
|
-
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04,
|
|
29
|
-
0x22, 0x04, 0x20,
|
|
30
|
-
]);
|
|
31
|
-
function hex(bytes) {
|
|
32
|
-
return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
33
|
-
}
|
|
34
|
-
function fromHex(value, label, expectedBytes) {
|
|
35
|
-
const clean = value.trim();
|
|
36
|
-
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
|
|
37
|
-
throw new Error(`${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`);
|
|
38
|
-
}
|
|
39
|
-
// Indexed rather than `match(/../g)!`: the length is already validated above,
|
|
40
|
-
// so the assertion would only be telling the compiler what the guard proved,
|
|
41
|
-
// and this needs no assertion at all.
|
|
42
|
-
const bytes = new Uint8Array(expectedBytes);
|
|
43
|
-
for (let i = 0; i < expectedBytes; i += 1) {
|
|
44
|
-
bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
45
|
-
}
|
|
46
|
-
return bytes;
|
|
47
|
-
}
|
|
48
|
-
function u64le(value) {
|
|
49
|
-
const out = new Uint8Array(8);
|
|
50
|
-
new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
|
|
51
|
-
return out;
|
|
52
|
-
}
|
|
53
|
-
function concat(...parts) {
|
|
54
|
-
const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
|
|
55
|
-
let offset = 0;
|
|
56
|
-
for (const part of parts) {
|
|
57
|
-
out.set(part, offset);
|
|
58
|
-
offset += part.length;
|
|
59
|
-
}
|
|
60
|
-
return out;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* core's `domain_hash`: SHA-256 over the length-prefixed domain, then each
|
|
64
|
-
* length-prefixed part. The lengths are what stop two different field splits from
|
|
65
|
-
* hashing alike.
|
|
66
|
-
*/
|
|
67
|
-
async function domainHash(domain, parts) {
|
|
68
|
-
const chunks = [u64le(domain.length), domain];
|
|
69
|
-
for (const part of parts) {
|
|
70
|
-
chunks.push(u64le(part.length), part);
|
|
71
|
-
}
|
|
72
|
-
return new Uint8Array(await crypto.subtle.digest('SHA-256', concat(...chunks)));
|
|
73
|
-
}
|
|
74
27
|
/**
|
|
75
28
|
* The commitment a warrant carries in place of the intent itself.
|
|
76
29
|
*
|
|
@@ -81,22 +34,6 @@ export async function intentHash(method, argsJson) {
|
|
|
81
34
|
const args = new TextEncoder().encode(JSON.stringify(argsJson));
|
|
82
35
|
return domainHash(INTENT_DOMAIN, [new TextEncoder().encode(method), args]);
|
|
83
36
|
}
|
|
84
|
-
async function importSigningKey(secretHex) {
|
|
85
|
-
const seed = fromHex(secretHex, 'deviceSecret', 32);
|
|
86
|
-
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
87
|
-
try {
|
|
88
|
-
return await crypto.subtle.importKey('pkcs8', pkcs8, { name: 'Ed25519' }, false, ['sign']);
|
|
89
|
-
}
|
|
90
|
-
catch (cause) {
|
|
91
|
-
// The original message is folded in rather than passed as `cause`: this
|
|
92
|
-
// package targets ES2020, where `Error` has no `cause` option.
|
|
93
|
-
const detail = cause instanceof Error ? `: ${cause.message}` : '';
|
|
94
|
-
throw new Error('this runtime has no WebCrypto Ed25519, so a warrant cannot be signed ' +
|
|
95
|
-
'here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; ' +
|
|
96
|
-
'otherwise mint the warrant with `merod account warrant`' +
|
|
97
|
-
detail);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
37
|
/**
|
|
101
38
|
* Sign a warrant and return it hex-encoded, ready for `performIntent`.
|
|
102
39
|
*
|
|
@@ -126,18 +63,3 @@ export async function signWarrant(input) {
|
|
|
126
63
|
const signature = new Uint8Array(await crypto.subtle.sign({ name: 'Ed25519' }, key, preimage));
|
|
127
64
|
return hex(concat(context, authorAccount, publicKey, executor, commitment, nonce, notAfter, signature));
|
|
128
65
|
}
|
|
129
|
-
/**
|
|
130
|
-
* The public half of an ed25519 seed.
|
|
131
|
-
*
|
|
132
|
-
* Derived rather than taken as an argument, for the reason core does the same: a
|
|
133
|
-
* caller able to name a key it does not hold could produce a warrant it cannot
|
|
134
|
-
* sign, and the field would stop meaning "who authorised this".
|
|
135
|
-
*/
|
|
136
|
-
async function derivePublicKey(secretHex) {
|
|
137
|
-
const seed = fromHex(secretHex, 'deviceSecret', 32);
|
|
138
|
-
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
139
|
-
const key = await crypto.subtle.importKey('pkcs8', pkcs8, { name: 'Ed25519' }, true, ['sign']);
|
|
140
|
-
const jwk = await crypto.subtle.exportKey('jwk', key);
|
|
141
|
-
const raw = jwk.x;
|
|
142
|
-
return Uint8Array.from(atob(raw.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
|
|
143
|
-
}
|