@calimero-network/mero-js 22.2.0 → 22.4.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/README.md +5 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +295 -21
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +295 -21
- package/dist/index.mjs.map +4 -4
- package/dist/relay/index.d.ts +1 -1
- package/dist/relay/relay-client.d.ts +76 -0
- package/dist/relay/relay-client.js +77 -0
- package/dist/sealed/release.d.ts +16 -4
- package/dist/sealed/release.js +35 -5
- package/dist/warrant/creation-warrant.d.ts +145 -0
- package/dist/warrant/creation-warrant.js +189 -0
- package/dist/warrant/index.d.ts +2 -0
- package/dist/warrant/index.js +1 -0
- package/dist/warrant/warrant.d.ts +5 -0
- package/dist/warrant/warrant.js +5 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -18,14 +18,14 @@ export type { Codec, EphemeralEntry } from "./ephemeral/index.js";
|
|
|
18
18
|
export * from "./cloud/index.js";
|
|
19
19
|
export * from "./sealed/index.js";
|
|
20
20
|
export * from "./relay/index.js";
|
|
21
|
-
export { signWarrant, intentHash } from "./warrant/index.js";
|
|
21
|
+
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, } from "./warrant/index.js";
|
|
22
22
|
export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, signAccountLink, signAccountLogin, } from "./account/index.js";
|
|
23
23
|
export type { AccountRoot, RecoverableAccountRoot, AccountLinkInput, AccountLoginInput, } from "./account/index.js";
|
|
24
24
|
export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from "./device-cert/index.js";
|
|
25
25
|
export type { DeviceCertInput } from "./device-cert/index.js";
|
|
26
26
|
export { signMemberJoinOp, encodeSignedInvitation, SIGNED_NAMESPACE_OP_SCHEMA_VERSION, } from "./namespace-op/index.js";
|
|
27
27
|
export type { SignMemberJoinInput } from "./namespace-op/index.js";
|
|
28
|
-
export type { WarrantInput } from "./warrant/index.js";
|
|
28
|
+
export type { WarrantInput, CreationWarrantInput, CreationWarrantFields, SignedCreationWarrant, } from "./warrant/index.js";
|
|
29
29
|
export { requestBodyHash, signRequest, callerProof, createProofSigner, } from "./request/index.js";
|
|
30
30
|
export type { CallerProofInput, ProofRequest, ProofSignerOptions, } from "./request/index.js";
|
|
31
31
|
export type { RequestSigInput } from "./request/index.js";
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export * from "./sealed/index.js";
|
|
|
27
27
|
// Relay client — write through delegated execution, holding only a signing key
|
|
28
28
|
export * from "./relay/index.js";
|
|
29
29
|
// Warrant signing — mint the author's consent for a relay to run one intent
|
|
30
|
-
export { signWarrant, intentHash } from "./warrant/index.js";
|
|
30
|
+
export { signWarrant, intentHash, signCreationWarrant, parseCreationWarrant, creationInitHash, } from "./warrant/index.js";
|
|
31
31
|
// Account roots — mint one with a recovery phrase, or prove you hold one
|
|
32
32
|
export { generateAccountRoot, accountRootFromPhrase, accountRootFromSecret, signAccountLink, signAccountLogin, } from "./account/index.js";
|
|
33
33
|
export { signDeviceCert, mintDeviceId, deviceCertPayload, accountForRoot, } from "./device-cert/index.js";
|
package/dist/index.mjs
CHANGED
|
@@ -2183,11 +2183,11 @@ function u32le(value) {
|
|
|
2183
2183
|
function hex(bytes) {
|
|
2184
2184
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
2185
2185
|
}
|
|
2186
|
-
function fromHex(value,
|
|
2186
|
+
function fromHex(value, label2, expectedBytes) {
|
|
2187
2187
|
const clean = value.trim();
|
|
2188
2188
|
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
|
|
2189
2189
|
throw new Error(
|
|
2190
|
-
`${
|
|
2190
|
+
`${label2} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
|
|
2191
2191
|
);
|
|
2192
2192
|
}
|
|
2193
2193
|
const bytes = new Uint8Array(expectedBytes);
|
|
@@ -2196,10 +2196,10 @@ function fromHex(value, label, expectedBytes) {
|
|
|
2196
2196
|
}
|
|
2197
2197
|
return bytes;
|
|
2198
2198
|
}
|
|
2199
|
-
function fromHexUnsized(value,
|
|
2199
|
+
function fromHexUnsized(value, label2) {
|
|
2200
2200
|
const clean = value.trim();
|
|
2201
2201
|
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
|
|
2202
|
-
throw new Error(`${
|
|
2202
|
+
throw new Error(`${label2} must be an even number of hex characters`);
|
|
2203
2203
|
}
|
|
2204
2204
|
const bytes = new Uint8Array(clean.length / 2);
|
|
2205
2205
|
for (let i = 0; i < bytes.length; i += 1) {
|
|
@@ -6513,14 +6513,172 @@ async function signWarrant(input) {
|
|
|
6513
6513
|
)
|
|
6514
6514
|
);
|
|
6515
6515
|
}
|
|
6516
|
-
function citedHeads(heads,
|
|
6516
|
+
function citedHeads(heads, label2) {
|
|
6517
6517
|
const list = heads ?? [];
|
|
6518
6518
|
if (list.length > MAX_CITED_HEADS) {
|
|
6519
6519
|
throw new Error(
|
|
6520
|
-
`${
|
|
6520
|
+
`${label2} cites ${list.length} heads, over the ${MAX_CITED_HEADS} a node accepts`
|
|
6521
6521
|
);
|
|
6522
6522
|
}
|
|
6523
|
-
return list.map((head, i) => fromHex(head, `${
|
|
6523
|
+
return list.map((head, i) => fromHex(head, `${label2}[${i}]`, 32));
|
|
6524
|
+
}
|
|
6525
|
+
|
|
6526
|
+
// src/warrant/creation-warrant.ts
|
|
6527
|
+
var SIGN_DOMAIN3 = new TextEncoder().encode("calimero.context-creation-warrant.v1");
|
|
6528
|
+
var INIT_DOMAIN = new TextEncoder().encode("calimero.context-creation.init.v1");
|
|
6529
|
+
var MAX_LABEL_BYTES = 256;
|
|
6530
|
+
async function creationInitHash(initArgs) {
|
|
6531
|
+
const bytes = new TextEncoder().encode(JSON.stringify(initArgs));
|
|
6532
|
+
return domainHash(INIT_DOMAIN, [bytes]);
|
|
6533
|
+
}
|
|
6534
|
+
async function creationWarrantPreimage(p) {
|
|
6535
|
+
return domainHash(SIGN_DOMAIN3, [
|
|
6536
|
+
p.group,
|
|
6537
|
+
p.seed,
|
|
6538
|
+
p.authorAccount,
|
|
6539
|
+
p.deviceKey,
|
|
6540
|
+
p.executor,
|
|
6541
|
+
p.applicationId,
|
|
6542
|
+
new Uint8Array([p.serviceName === null ? 0 : 1]),
|
|
6543
|
+
p.serviceName ?? new Uint8Array(0),
|
|
6544
|
+
new Uint8Array([p.name === null ? 0 : 1]),
|
|
6545
|
+
p.name ?? new Uint8Array(0),
|
|
6546
|
+
p.initHash,
|
|
6547
|
+
u64le(p.accountHeads.length),
|
|
6548
|
+
...p.accountHeads,
|
|
6549
|
+
u64le(p.governanceFloor.length),
|
|
6550
|
+
...p.governanceFloor,
|
|
6551
|
+
u64le(p.nonce),
|
|
6552
|
+
u64le(p.notAfter)
|
|
6553
|
+
]);
|
|
6554
|
+
}
|
|
6555
|
+
async function signCreationWarrant(input) {
|
|
6556
|
+
const group = fromHex(input.group, "group", 32);
|
|
6557
|
+
const seed = input.seed === void 0 ? crypto.getRandomValues(new Uint8Array(32)) : fromHex(input.seed, "seed", 32);
|
|
6558
|
+
const authorAccount = fromHex(input.authorAccount, "authorAccount", 32);
|
|
6559
|
+
const executor = fromHex(input.executor, "executor", 32);
|
|
6560
|
+
const applicationId = fromHex(input.applicationId, "applicationId", 32);
|
|
6561
|
+
const serviceName = label(input.serviceName, "serviceName");
|
|
6562
|
+
const name = label(input.name, "name");
|
|
6563
|
+
const accountHeads = citedHeads(input.accountHeads, "accountHeads");
|
|
6564
|
+
const governanceFloor = citedHeads(input.governanceFloor, "governanceFloor");
|
|
6565
|
+
const key = await importSigningKey(input.deviceSecret);
|
|
6566
|
+
const deviceKey = await derivePublicKey(input.deviceSecret);
|
|
6567
|
+
const initHash = await creationInitHash(input.initArgs);
|
|
6568
|
+
const preimage = await creationWarrantPreimage({
|
|
6569
|
+
group,
|
|
6570
|
+
seed,
|
|
6571
|
+
authorAccount,
|
|
6572
|
+
deviceKey,
|
|
6573
|
+
executor,
|
|
6574
|
+
applicationId,
|
|
6575
|
+
serviceName,
|
|
6576
|
+
name,
|
|
6577
|
+
initHash,
|
|
6578
|
+
accountHeads,
|
|
6579
|
+
governanceFloor,
|
|
6580
|
+
nonce: input.nonce,
|
|
6581
|
+
notAfter: input.notAfter
|
|
6582
|
+
});
|
|
6583
|
+
const signature = new Uint8Array(
|
|
6584
|
+
await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
|
|
6585
|
+
);
|
|
6586
|
+
const warrant = hex(
|
|
6587
|
+
concat(
|
|
6588
|
+
group,
|
|
6589
|
+
seed,
|
|
6590
|
+
authorAccount,
|
|
6591
|
+
deviceKey,
|
|
6592
|
+
executor,
|
|
6593
|
+
applicationId,
|
|
6594
|
+
borshOption(serviceName),
|
|
6595
|
+
borshOption(name),
|
|
6596
|
+
initHash,
|
|
6597
|
+
u32le(accountHeads.length),
|
|
6598
|
+
...accountHeads,
|
|
6599
|
+
u32le(governanceFloor.length),
|
|
6600
|
+
...governanceFloor,
|
|
6601
|
+
u64le(input.nonce),
|
|
6602
|
+
u64le(input.notAfter),
|
|
6603
|
+
signature
|
|
6604
|
+
)
|
|
6605
|
+
);
|
|
6606
|
+
return { warrant, seed: hex(seed) };
|
|
6607
|
+
}
|
|
6608
|
+
function parseCreationWarrant(warrant) {
|
|
6609
|
+
const clean = warrant.trim();
|
|
6610
|
+
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
|
|
6611
|
+
throw new Error("creation warrant must be an even number of hex characters");
|
|
6612
|
+
}
|
|
6613
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
6614
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
6615
|
+
bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
6616
|
+
}
|
|
6617
|
+
const view = new DataView(bytes.buffer);
|
|
6618
|
+
let o = 0;
|
|
6619
|
+
const take = (n, what) => {
|
|
6620
|
+
if (o + n > bytes.length) {
|
|
6621
|
+
throw new Error(`creation warrant ends inside ${what} (${bytes.length} bytes)`);
|
|
6622
|
+
}
|
|
6623
|
+
const out = bytes.subarray(o, o + n);
|
|
6624
|
+
o += n;
|
|
6625
|
+
return out;
|
|
6626
|
+
};
|
|
6627
|
+
const u32 = (what) => view.getUint32(take(4, what).byteOffset, true);
|
|
6628
|
+
const u64 = (what) => view.getBigUint64(take(8, what).byteOffset, true);
|
|
6629
|
+
const option = (what) => {
|
|
6630
|
+
const tag = take(1, what)[0];
|
|
6631
|
+
if (tag === 0) return null;
|
|
6632
|
+
if (tag !== 1) throw new Error(`${what} has option tag ${tag}, expected 0 or 1`);
|
|
6633
|
+
const len = u32(what);
|
|
6634
|
+
if (len > MAX_LABEL_BYTES) {
|
|
6635
|
+
throw new Error(`${what} is ${len} bytes, over the ${MAX_LABEL_BYTES} a node accepts`);
|
|
6636
|
+
}
|
|
6637
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(take(len, what));
|
|
6638
|
+
};
|
|
6639
|
+
const heads = (what) => {
|
|
6640
|
+
const count = u32(what);
|
|
6641
|
+
if (count > 64) {
|
|
6642
|
+
throw new Error(`${what} cites ${count} heads, over the 64 a node accepts`);
|
|
6643
|
+
}
|
|
6644
|
+
return Array.from({ length: count }, () => hex(take(32, what)));
|
|
6645
|
+
};
|
|
6646
|
+
const fields = {
|
|
6647
|
+
group: hex(take(32, "group")),
|
|
6648
|
+
seed: hex(take(32, "seed")),
|
|
6649
|
+
authorAccount: hex(take(32, "authorAccount")),
|
|
6650
|
+
deviceKey: hex(take(32, "deviceKey")),
|
|
6651
|
+
executor: hex(take(32, "executor")),
|
|
6652
|
+
applicationId: hex(take(32, "applicationId")),
|
|
6653
|
+
serviceName: option("serviceName"),
|
|
6654
|
+
name: option("name"),
|
|
6655
|
+
initHash: hex(take(32, "initHash")),
|
|
6656
|
+
accountHeads: heads("accountHeads"),
|
|
6657
|
+
governanceFloor: heads("governanceFloor"),
|
|
6658
|
+
nonce: u64("nonce"),
|
|
6659
|
+
notAfter: u64("notAfter"),
|
|
6660
|
+
signature: hex(take(64, "signature"))
|
|
6661
|
+
};
|
|
6662
|
+
if (o !== bytes.length) {
|
|
6663
|
+
throw new Error(
|
|
6664
|
+
`creation warrant is ${bytes.length} bytes but its fields account for ${o}`
|
|
6665
|
+
);
|
|
6666
|
+
}
|
|
6667
|
+
return fields;
|
|
6668
|
+
}
|
|
6669
|
+
function label(value, what) {
|
|
6670
|
+
if (value === void 0) return null;
|
|
6671
|
+
const bytes = new TextEncoder().encode(value);
|
|
6672
|
+
if (bytes.length > MAX_LABEL_BYTES) {
|
|
6673
|
+
throw new Error(
|
|
6674
|
+
`${what} is ${bytes.length} UTF-8 bytes, over the ${MAX_LABEL_BYTES} a node accepts`
|
|
6675
|
+
);
|
|
6676
|
+
}
|
|
6677
|
+
return bytes;
|
|
6678
|
+
}
|
|
6679
|
+
function borshOption(bytes) {
|
|
6680
|
+
if (bytes === null) return new Uint8Array([0]);
|
|
6681
|
+
return concat(new Uint8Array([1]), u32le(bytes.length), bytes);
|
|
6524
6682
|
}
|
|
6525
6683
|
|
|
6526
6684
|
// src/relay/relay-client.ts
|
|
@@ -6583,6 +6741,94 @@ var RelayClient = class {
|
|
|
6583
6741
|
);
|
|
6584
6742
|
return { rootHash: body.data.rootHash, returns: body.data.returns ?? null };
|
|
6585
6743
|
}
|
|
6744
|
+
/**
|
|
6745
|
+
* Ask the relay what it can do about creating contexts in `groupId`.
|
|
6746
|
+
*
|
|
6747
|
+
* Pass `author` (an account, hex) to also learn whether that account may
|
|
6748
|
+
* create here — `authorMayCreate` is present only then.
|
|
6749
|
+
*/
|
|
6750
|
+
async describeCreation(groupId, opts = {}) {
|
|
6751
|
+
const query = opts.author ? `?author=${encodeURIComponent(opts.author)}` : "";
|
|
6752
|
+
const body = await this.json(
|
|
6753
|
+
"GET",
|
|
6754
|
+
`/admin-api/groups/${encodeURIComponent(groupId)}/context-intents${query}`
|
|
6755
|
+
);
|
|
6756
|
+
return body.data;
|
|
6757
|
+
}
|
|
6758
|
+
/**
|
|
6759
|
+
* Create a context in a group through the relay, as the author.
|
|
6760
|
+
*
|
|
6761
|
+
* Always asks {@link describeCreation} first — with the author, so both
|
|
6762
|
+
* standing checks happen before anything is signed. A relay without standing
|
|
6763
|
+
* in the group, or an author without `CAN_CREATE_CONTEXT`, is refused here as
|
|
6764
|
+
* an {@link IntentRefusedError} *before* a nonce is taken: the nonce source
|
|
6765
|
+
* is monotonic, and a warrant nobody will spend burns one for nothing.
|
|
6766
|
+
*
|
|
6767
|
+
* The creation warrant's nonce is spent in the new context's per-device
|
|
6768
|
+
* ledger — the same one later `execute` calls in that context draw from — so
|
|
6769
|
+
* it comes from the configured {@link NonceSource} like any other warrant.
|
|
6770
|
+
*
|
|
6771
|
+
* Sealing: nothing here is plaintext-specific. The request goes through the
|
|
6772
|
+
* injected `fetch`, so a `createAttestedSealedFetch` seals it exactly as it
|
|
6773
|
+
* seals `execute`. Whether the relay *accepts* it sealed is the node's call:
|
|
6774
|
+
* a proxy-auth relay only admits sealed requests for routes `merod` serves
|
|
6775
|
+
* without a credential, so `/admin-api/groups/:id/context-intents` must be on
|
|
6776
|
+
* that list on the core side or the request comes back
|
|
6777
|
+
* `403 sealed_route_unguarded`.
|
|
6778
|
+
*/
|
|
6779
|
+
async createContext(input) {
|
|
6780
|
+
const described = await this.describeCreation(input.groupId, {
|
|
6781
|
+
author: this.config.authorAccount
|
|
6782
|
+
});
|
|
6783
|
+
if (!described.canCreateOnBehalf) {
|
|
6784
|
+
throw new IntentRefusedError(
|
|
6785
|
+
`the relay (${described.executorAccount}) has no standing to act for members of group ${described.groupId}; an admin must admit it as a relay or grant it CAN_AUTHOR_ON_BEHALF (checked before signing \u2014 no nonce was spent)`,
|
|
6786
|
+
false,
|
|
6787
|
+
403
|
|
6788
|
+
);
|
|
6789
|
+
}
|
|
6790
|
+
if (described.authorMayCreate === false) {
|
|
6791
|
+
throw new IntentRefusedError(
|
|
6792
|
+
`the author (${this.config.authorAccount}) may not create contexts in group ${described.groupId}; it needs CAN_CREATE_CONTEXT or admin (checked before signing \u2014 no nonce was spent)`,
|
|
6793
|
+
false,
|
|
6794
|
+
403
|
|
6795
|
+
);
|
|
6796
|
+
}
|
|
6797
|
+
const configured = this.config.executorAccount;
|
|
6798
|
+
if (configured && configured.toLowerCase() !== described.executorAccount.toLowerCase()) {
|
|
6799
|
+
throw new Error(
|
|
6800
|
+
`configured executorAccount ${configured} is not the relay's account ${described.executorAccount}; a warrant naming it would be unspendable`
|
|
6801
|
+
);
|
|
6802
|
+
}
|
|
6803
|
+
const executor = described.executorAccount;
|
|
6804
|
+
this.executorAccount = executor;
|
|
6805
|
+
const initArgs = input.initArgs ?? {};
|
|
6806
|
+
const nonce2 = await this.config.nonces.next();
|
|
6807
|
+
const ttl = this.config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
6808
|
+
const { warrant } = await signCreationWarrant({
|
|
6809
|
+
group: input.groupId,
|
|
6810
|
+
seed: input.seed,
|
|
6811
|
+
authorAccount: this.config.authorAccount,
|
|
6812
|
+
executor,
|
|
6813
|
+
applicationId: input.applicationId,
|
|
6814
|
+
serviceName: input.serviceName,
|
|
6815
|
+
name: input.name,
|
|
6816
|
+
initArgs,
|
|
6817
|
+
nonce: nonce2,
|
|
6818
|
+
notAfter: BigInt(Math.floor(Date.now() / 1e3)) + BigInt(ttl),
|
|
6819
|
+
deviceSecret: this.config.deviceSecret
|
|
6820
|
+
});
|
|
6821
|
+
const body = await this.json(
|
|
6822
|
+
"POST",
|
|
6823
|
+
`/admin-api/groups/${encodeURIComponent(input.groupId)}/context-intents`,
|
|
6824
|
+
{ warrant, authorProof: this.config.authorProof, initArgs }
|
|
6825
|
+
);
|
|
6826
|
+
return {
|
|
6827
|
+
contextId: body.data.contextId,
|
|
6828
|
+
groupId: body.data.groupId,
|
|
6829
|
+
memberPublicKey: body.data.memberPublicKey
|
|
6830
|
+
};
|
|
6831
|
+
}
|
|
6586
6832
|
async json(method, path, body) {
|
|
6587
6833
|
const headers = { Accept: "application/json" };
|
|
6588
6834
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
@@ -7282,8 +7528,8 @@ var REGISTERS = ["mrtd", "rtmr0", "rtmr1", "rtmr2", "rtmr3"];
|
|
|
7282
7528
|
function createQuoteVerifier(options) {
|
|
7283
7529
|
const allowedMrtd = measurements(options.allowedMrtd ?? [], "allowedMrtd");
|
|
7284
7530
|
const allowedImages = (options.allowedMeasurements ?? []).map((image, index) => {
|
|
7285
|
-
const
|
|
7286
|
-
return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${
|
|
7531
|
+
const label2 = `allowedMeasurements[${index}]`;
|
|
7532
|
+
return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${label2}.${register}`)[0]).join();
|
|
7287
7533
|
});
|
|
7288
7534
|
const allowedRtmr = [
|
|
7289
7535
|
measurements(options.allowedRtmr0 ?? [], "allowedRtmr0"),
|
|
@@ -7352,11 +7598,11 @@ function createQuoteVerifier(options) {
|
|
|
7352
7598
|
};
|
|
7353
7599
|
return Object.assign(verifier, { includeCollateral: true });
|
|
7354
7600
|
}
|
|
7355
|
-
function measurements(values,
|
|
7601
|
+
function measurements(values, label2) {
|
|
7356
7602
|
return values.map((value) => {
|
|
7357
7603
|
const normalized = value.trim().toLowerCase();
|
|
7358
7604
|
if (!MEASUREMENT_HEX.test(normalized)) {
|
|
7359
|
-
throw new Error(`${
|
|
7605
|
+
throw new Error(`${label2} holds ${JSON.stringify(value)}, which is not a 48-byte hex measurement`);
|
|
7360
7606
|
}
|
|
7361
7607
|
return normalized;
|
|
7362
7608
|
});
|
|
@@ -7842,8 +8088,24 @@ function nodeReleaseVersionFromImage(osImage) {
|
|
|
7842
8088
|
return `${Number(match[1])}.${Number(match[2])}.${Number(match[3])}`;
|
|
7843
8089
|
}
|
|
7844
8090
|
async function fetchNodeReleaseVersion(baseUrl, options = {}) {
|
|
7845
|
-
const
|
|
7846
|
-
|
|
8091
|
+
const version = await readNodeReleaseVersion(baseUrl, options.fetch ?? fetch);
|
|
8092
|
+
if (version === void 0) {
|
|
8093
|
+
throw new Error(
|
|
8094
|
+
`${infoUrl(baseUrl)} was refused unsealed: the node requires sealing and is too old to name its release before a session exists. Name the release it runs yourself (createSignedReleaseSealedFetch's \`releaseVersion\`), or upgrade the node`
|
|
8095
|
+
);
|
|
8096
|
+
}
|
|
8097
|
+
return version;
|
|
8098
|
+
}
|
|
8099
|
+
function infoUrl(baseUrl) {
|
|
8100
|
+
return `${baseUrl.replace(/\/+$/, "")}/admin-api/tee/info`;
|
|
8101
|
+
}
|
|
8102
|
+
async function readNodeReleaseVersion(baseUrl, givenFetch) {
|
|
8103
|
+
const url = infoUrl(baseUrl);
|
|
8104
|
+
const response = await givenFetch(url, { headers: { accept: "application/json" } });
|
|
8105
|
+
if (response.status === 403) {
|
|
8106
|
+
const code = await response.json().then((body) => body?.error?.code).catch(() => void 0);
|
|
8107
|
+
if (code === "sealed_required") return void 0;
|
|
8108
|
+
}
|
|
7847
8109
|
if (!response.ok) throw new Error(`Fetching ${url} failed: HTTP ${response.status}`);
|
|
7848
8110
|
let osImage;
|
|
7849
8111
|
try {
|
|
@@ -7890,10 +8152,19 @@ function createSignedReleaseVerifier(options) {
|
|
|
7890
8152
|
return Object.assign(verifier, { includeCollateral: true });
|
|
7891
8153
|
}
|
|
7892
8154
|
function createSignedReleaseSealedFetch(options) {
|
|
7893
|
-
const {
|
|
8155
|
+
const {
|
|
8156
|
+
baseUrl,
|
|
8157
|
+
releaseSource,
|
|
8158
|
+
releaseVersion: fallbackVersion,
|
|
8159
|
+
applicationId,
|
|
8160
|
+
applicationHash,
|
|
8161
|
+
fetch: givenFetch,
|
|
8162
|
+
...verifierOptions
|
|
8163
|
+
} = options;
|
|
8164
|
+
if (fallbackVersion !== void 0) releaseVersion(fallbackVersion, "releaseVersion");
|
|
7894
8165
|
const baseFetch = givenFetch ?? ((input, init) => fetch(input, init));
|
|
7895
8166
|
const release = async () => {
|
|
7896
|
-
const version = await fetchNodeReleaseVersion(baseUrl, { fetch: baseFetch });
|
|
8167
|
+
const version = fallbackVersion === void 0 ? await fetchNodeReleaseVersion(baseUrl, { fetch: baseFetch }) : await readNodeReleaseVersion(baseUrl, baseFetch) ?? fallbackVersion;
|
|
7897
8168
|
return typeof releaseSource === "function" ? releaseSource({ baseUrl, version, fetch: baseFetch }) : fetchNodeRelease(cloudNodeReleaseUrl(releaseSource ?? DEFAULT_RELEASE_MIRROR, version), { fetch: baseFetch });
|
|
7898
8169
|
};
|
|
7899
8170
|
return createAttestedSealedFetch({
|
|
@@ -7953,18 +8224,18 @@ var ROOT_OP = {
|
|
|
7953
8224
|
NamespaceCreatedV2: 9,
|
|
7954
8225
|
MemberJoinedViaTeeAttestation: 10
|
|
7955
8226
|
};
|
|
7956
|
-
function bytes32(value,
|
|
8227
|
+
function bytes32(value, label2) {
|
|
7957
8228
|
if (value.length !== 32) {
|
|
7958
|
-
throw new Error(`${
|
|
8229
|
+
throw new Error(`${label2} must be 32 bytes, got ${value.length}`);
|
|
7959
8230
|
}
|
|
7960
8231
|
return new Uint8Array(value);
|
|
7961
8232
|
}
|
|
7962
|
-
function optionalBytes32(value,
|
|
8233
|
+
function optionalBytes32(value, label2) {
|
|
7963
8234
|
if (value === null || value === void 0) {
|
|
7964
8235
|
return new Uint8Array([0]);
|
|
7965
8236
|
}
|
|
7966
8237
|
if (value.length !== 32) {
|
|
7967
|
-
throw new Error(`${
|
|
8238
|
+
throw new Error(`${label2} must be 32 bytes, got ${value.length}`);
|
|
7968
8239
|
}
|
|
7969
8240
|
return concat(new Uint8Array([1]), new Uint8Array(value));
|
|
7970
8241
|
}
|
|
@@ -8046,7 +8317,7 @@ async function signMemberJoinOp(input) {
|
|
|
8046
8317
|
}
|
|
8047
8318
|
|
|
8048
8319
|
// src/login/login.ts
|
|
8049
|
-
var
|
|
8320
|
+
var SIGN_DOMAIN4 = new TextEncoder().encode("calimero.auth.login.v1");
|
|
8050
8321
|
var AUDIENCE_TAG = {
|
|
8051
8322
|
webOrigin: 0,
|
|
8052
8323
|
codeSigningId: 1,
|
|
@@ -8085,7 +8356,7 @@ async function signLoginStatement(input) {
|
|
|
8085
8356
|
const deviceKey = await derivePublicKey(input.deviceSecret);
|
|
8086
8357
|
const issuedAt = u64le(input.issuedAt);
|
|
8087
8358
|
const expiresAt = u64le(input.expiresAt);
|
|
8088
|
-
const preimage = await domainHash(
|
|
8359
|
+
const preimage = await domainHash(SIGN_DOMAIN4, [
|
|
8089
8360
|
node,
|
|
8090
8361
|
audienceSigningBytes(input.audience),
|
|
8091
8362
|
challenge,
|
|
@@ -8320,6 +8591,7 @@ export {
|
|
|
8320
8591
|
createSignedReleaseVerifier,
|
|
8321
8592
|
createTimeoutSignal,
|
|
8322
8593
|
createUniversalHttpClient,
|
|
8594
|
+
creationInitHash,
|
|
8323
8595
|
deviceCertPayload,
|
|
8324
8596
|
discoverLocalNodes,
|
|
8325
8597
|
encodeSignedInvitation,
|
|
@@ -8339,6 +8611,7 @@ export {
|
|
|
8339
8611
|
nodeEndpoint,
|
|
8340
8612
|
nodeReleaseVersionFromImage,
|
|
8341
8613
|
parseAuthCallback,
|
|
8614
|
+
parseCreationWarrant,
|
|
8342
8615
|
probeNodeHealth,
|
|
8343
8616
|
redeemInvitation,
|
|
8344
8617
|
requestBodyHash,
|
|
@@ -8346,6 +8619,7 @@ export {
|
|
|
8346
8619
|
shouldRetain,
|
|
8347
8620
|
signAccountLink,
|
|
8348
8621
|
signAccountLogin,
|
|
8622
|
+
signCreationWarrant,
|
|
8349
8623
|
signDeviceCert,
|
|
8350
8624
|
signLoginStatement,
|
|
8351
8625
|
signMemberJoinOp,
|