@calimero-network/mero-js 23.4.3 → 23.6.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/cloud/account-ownership.d.ts +37 -4
- package/dist/cloud/account-ownership.js +40 -8
- package/dist/cloud/cloud-client.d.ts +100 -1
- package/dist/cloud/cloud-client.js +148 -0
- package/dist/cloud/index.d.ts +4 -4
- package/dist/cloud/index.js +2 -2
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +172 -42
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +172 -42
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3471,6 +3471,59 @@ async function resolveSigner(secret, signer, label2) {
|
|
|
3471
3471
|
throw new Error(`${label2} or signer is required`);
|
|
3472
3472
|
}
|
|
3473
3473
|
|
|
3474
|
+
// src/cloud/account-ownership.ts
|
|
3475
|
+
var DOMAIN = new TextEncoder().encode("calimero.mdma.account-ownership-claim.v1\0");
|
|
3476
|
+
var DEFAULT_TTL_MS = 6e4;
|
|
3477
|
+
var MAX_TTL_MS = 5 * 6e4;
|
|
3478
|
+
var MAX_RELAY_URL = 1024;
|
|
3479
|
+
var ACCOUNT_OWNERSHIP_AUDIENCE = "mdma:enable-ha-namespace";
|
|
3480
|
+
var ACCOUNT_HA_AUDIENCE = "mdma:enable-ha-namespace-as-account";
|
|
3481
|
+
function base64(bytes) {
|
|
3482
|
+
let binary = "";
|
|
3483
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
3484
|
+
return btoa(binary);
|
|
3485
|
+
}
|
|
3486
|
+
var hex32 = (value, what) => {
|
|
3487
|
+
if (!/^[0-9a-fA-F]{64}$/.test(value)) throw new Error(`${what} must be 64 hex characters`);
|
|
3488
|
+
return value.toLowerCase();
|
|
3489
|
+
};
|
|
3490
|
+
async function signClaim(input, audience, subject, relayUrl) {
|
|
3491
|
+
if (relayUrl !== void 0 && !(relayUrl.length > 0 && relayUrl.length <= MAX_RELAY_URL)) {
|
|
3492
|
+
throw new Error(`relayUrl must be a non-empty string of at most ${MAX_RELAY_URL} characters`);
|
|
3493
|
+
}
|
|
3494
|
+
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
3495
|
+
if (!(ttl > 0 && ttl <= MAX_TTL_MS)) throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
3496
|
+
const groupId = hex32(input.namespaceId, "namespaceId");
|
|
3497
|
+
const accountId = hex32(input.accountId, "accountId");
|
|
3498
|
+
const salt = hex32(input.salt, "salt");
|
|
3499
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
3500
|
+
const issued = (input.now ?? Date.now)();
|
|
3501
|
+
const nonce2 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3502
|
+
const payload = new TextEncoder().encode(
|
|
3503
|
+
JSON.stringify({
|
|
3504
|
+
v: 1,
|
|
3505
|
+
audience,
|
|
3506
|
+
group_id: groupId,
|
|
3507
|
+
account_id: accountId,
|
|
3508
|
+
salt,
|
|
3509
|
+
...subject === void 0 ? {} : { subject },
|
|
3510
|
+
nonce: nonce2,
|
|
3511
|
+
issued_at_ms: issued,
|
|
3512
|
+
expires_at_ms: issued + ttl,
|
|
3513
|
+
...relayUrl === void 0 ? {} : { relay_url: relayUrl }
|
|
3514
|
+
})
|
|
3515
|
+
);
|
|
3516
|
+
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
3517
|
+
return { kind: "account", credential: input.credential, signed_payload: base64(payload), signature: base64(signature) };
|
|
3518
|
+
}
|
|
3519
|
+
async function signAccountOwnershipClaim(input) {
|
|
3520
|
+
if (!input.subject) throw new Error("subject must be the cloud login email");
|
|
3521
|
+
return signClaim(input, ACCOUNT_OWNERSHIP_AUDIENCE, input.subject);
|
|
3522
|
+
}
|
|
3523
|
+
async function signAccountHaClaim(input) {
|
|
3524
|
+
return signClaim(input, ACCOUNT_HA_AUDIENCE, void 0, input.relayUrl);
|
|
3525
|
+
}
|
|
3526
|
+
|
|
3474
3527
|
// src/device-cert/device-cert.ts
|
|
3475
3528
|
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
3476
3529
|
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
@@ -5762,7 +5815,7 @@ async function signAccountLink(input) {
|
|
|
5762
5815
|
const signature = await signer.sign(
|
|
5763
5816
|
concat(ACCOUNT_LINK_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5764
5817
|
);
|
|
5765
|
-
return
|
|
5818
|
+
return base642(signature);
|
|
5766
5819
|
}
|
|
5767
5820
|
async function signAccountLogin(input) {
|
|
5768
5821
|
if (!input.nonce) throw new Error("nonce is required to sign an account login");
|
|
@@ -5770,7 +5823,7 @@ async function signAccountLogin(input) {
|
|
|
5770
5823
|
const signature = await signer.sign(
|
|
5771
5824
|
concat(ACCOUNT_LOGIN_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5772
5825
|
);
|
|
5773
|
-
return
|
|
5826
|
+
return base642(signature);
|
|
5774
5827
|
}
|
|
5775
5828
|
async function withPhrase(secret, phrase) {
|
|
5776
5829
|
return { ...await accountRootFromSecret(secret), phrase };
|
|
@@ -5823,7 +5876,7 @@ function bitsOf(bytes) {
|
|
|
5823
5876
|
for (const byte of bytes) bits += byte.toString(2).padStart(8, "0");
|
|
5824
5877
|
return bits;
|
|
5825
5878
|
}
|
|
5826
|
-
function
|
|
5879
|
+
function base642(bytes) {
|
|
5827
5880
|
let binary = "";
|
|
5828
5881
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5829
5882
|
return btoa(binary);
|
|
@@ -5843,7 +5896,7 @@ async function signRoutingChallenge(nonce2, deviceSecret) {
|
|
|
5843
5896
|
const signature = new Uint8Array(
|
|
5844
5897
|
await crypto.subtle.sign({ name: "Ed25519" }, key, message)
|
|
5845
5898
|
);
|
|
5846
|
-
return
|
|
5899
|
+
return base643(signature);
|
|
5847
5900
|
}
|
|
5848
5901
|
async function routingProofHeaders(challenge, credential) {
|
|
5849
5902
|
return {
|
|
@@ -5855,7 +5908,7 @@ async function routingProofHeaders(challenge, credential) {
|
|
|
5855
5908
|
)
|
|
5856
5909
|
};
|
|
5857
5910
|
}
|
|
5858
|
-
function
|
|
5911
|
+
function base643(bytes) {
|
|
5859
5912
|
let binary = "";
|
|
5860
5913
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5861
5914
|
return btoa(binary);
|
|
@@ -5872,6 +5925,64 @@ function teeRoleOf(row) {
|
|
|
5872
5925
|
function pickExecutingRelay(relays) {
|
|
5873
5926
|
return relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null;
|
|
5874
5927
|
}
|
|
5928
|
+
var AccountHaRefusedError = class extends HTTPError {
|
|
5929
|
+
constructor(code, status, statusText, url, headers, bodyText) {
|
|
5930
|
+
super(status, statusText, url, headers, bodyText);
|
|
5931
|
+
this.code = code;
|
|
5932
|
+
this.name = "AccountHaRefusedError";
|
|
5933
|
+
}
|
|
5934
|
+
};
|
|
5935
|
+
var AccountNotLinkedError = class extends AccountHaRefusedError {
|
|
5936
|
+
constructor() {
|
|
5937
|
+
super(...arguments);
|
|
5938
|
+
this.name = "AccountNotLinkedError";
|
|
5939
|
+
}
|
|
5940
|
+
};
|
|
5941
|
+
AccountNotLinkedError.CODE = "account_not_linked";
|
|
5942
|
+
var AccountLinkedToSeveralUsersError = class extends AccountHaRefusedError {
|
|
5943
|
+
constructor() {
|
|
5944
|
+
super(...arguments);
|
|
5945
|
+
this.name = "AccountLinkedToSeveralUsersError";
|
|
5946
|
+
}
|
|
5947
|
+
};
|
|
5948
|
+
AccountLinkedToSeveralUsersError.CODE = "account_linked_to_several_users";
|
|
5949
|
+
var HaRequestPendingError = class extends AccountHaRefusedError {
|
|
5950
|
+
constructor() {
|
|
5951
|
+
super(...arguments);
|
|
5952
|
+
this.name = "HaRequestPendingError";
|
|
5953
|
+
}
|
|
5954
|
+
};
|
|
5955
|
+
HaRequestPendingError.CODE = "ha_request_pending";
|
|
5956
|
+
var UnknownRelayError = class extends AccountHaRefusedError {
|
|
5957
|
+
constructor() {
|
|
5958
|
+
super(...arguments);
|
|
5959
|
+
this.name = "UnknownRelayError";
|
|
5960
|
+
}
|
|
5961
|
+
};
|
|
5962
|
+
UnknownRelayError.CODE = "unknown_relay";
|
|
5963
|
+
var RelayNotDialableError = class extends AccountHaRefusedError {
|
|
5964
|
+
constructor() {
|
|
5965
|
+
super(...arguments);
|
|
5966
|
+
this.name = "RelayNotDialableError";
|
|
5967
|
+
}
|
|
5968
|
+
};
|
|
5969
|
+
RelayNotDialableError.CODE = "relay_not_dialable";
|
|
5970
|
+
var ACCOUNT_HA_REFUSALS = {
|
|
5971
|
+
409: [AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError],
|
|
5972
|
+
422: [UnknownRelayError, RelayNotDialableError]
|
|
5973
|
+
};
|
|
5974
|
+
function conflictCode(bodyText) {
|
|
5975
|
+
if (!bodyText) return void 0;
|
|
5976
|
+
try {
|
|
5977
|
+
const body = JSON.parse(bodyText);
|
|
5978
|
+
if (typeof body?.error === "string") return body.error;
|
|
5979
|
+
if (typeof body?.detail === "string") return body.detail;
|
|
5980
|
+
const nested = body?.detail?.error;
|
|
5981
|
+
if (typeof nested === "string") return nested;
|
|
5982
|
+
} catch {
|
|
5983
|
+
}
|
|
5984
|
+
return void 0;
|
|
5985
|
+
}
|
|
5875
5986
|
var REFRESH_HEADER = "x-mdma-session-refresh";
|
|
5876
5987
|
var REFRESH_EXPIRES_HEADER = "x-mdma-session-expires";
|
|
5877
5988
|
var CloudClient = class {
|
|
@@ -6332,6 +6443,53 @@ var CloudClient = class {
|
|
|
6332
6443
|
{ body: { groups: [], ownership_proof: ownershipProof } }
|
|
6333
6444
|
);
|
|
6334
6445
|
}
|
|
6446
|
+
/**
|
|
6447
|
+
* Enable HA for a namespace this account founded, with **no cloud session**.
|
|
6448
|
+
*
|
|
6449
|
+
* The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
|
|
6450
|
+
* founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
|
|
6451
|
+
* audience) and posts it to
|
|
6452
|
+
* `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
|
|
6453
|
+
* cloud bills the user the account is linked to through the wallet, so the
|
|
6454
|
+
* account must be linked to exactly one:
|
|
6455
|
+
*
|
|
6456
|
+
* - not linked at all → {@link AccountNotLinkedError};
|
|
6457
|
+
* - linked to several → {@link AccountLinkedToSeveralUsersError}.
|
|
6458
|
+
*
|
|
6459
|
+
* A claim that does not verify is a `403` `HTTPError`; quota and the rest
|
|
6460
|
+
* answer as the session route does. Returns the cloud's response body, the
|
|
6461
|
+
* same shape the session route's enable-ha returns.
|
|
6462
|
+
*/
|
|
6463
|
+
async enableHaAsAccount(options) {
|
|
6464
|
+
const proof = await signAccountHaClaim({
|
|
6465
|
+
namespaceId: options.namespaceId,
|
|
6466
|
+
accountId: options.accountId,
|
|
6467
|
+
salt: options.salt,
|
|
6468
|
+
credential: options.credential,
|
|
6469
|
+
deviceSecret: options.deviceSecret,
|
|
6470
|
+
signer: options.signer,
|
|
6471
|
+
ttlMs: options.ttlMs,
|
|
6472
|
+
relayUrl: options.relayUrl
|
|
6473
|
+
});
|
|
6474
|
+
const account = options.accountId.toLowerCase();
|
|
6475
|
+
const namespace = options.namespaceId.toLowerCase();
|
|
6476
|
+
try {
|
|
6477
|
+
return await this.request(
|
|
6478
|
+
"POST",
|
|
6479
|
+
`/api/cloud/accounts/${encodeURIComponent(account)}/namespaces/${encodeURIComponent(namespace)}/enable-ha`,
|
|
6480
|
+
{ body: { ownership_proof: proof }, anonymous: true }
|
|
6481
|
+
);
|
|
6482
|
+
} catch (err) {
|
|
6483
|
+
if (err instanceof HTTPError && ACCOUNT_HA_REFUSALS[err.status]) {
|
|
6484
|
+
const code = conflictCode(err.bodyText);
|
|
6485
|
+
const Typed = ACCOUNT_HA_REFUSALS[err.status].find((t) => t.CODE === code);
|
|
6486
|
+
if (Typed && code) {
|
|
6487
|
+
throw new Typed(code, err.status, err.statusText, err.url, err.headers, err.bodyText);
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
throw err;
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6335
6493
|
/**
|
|
6336
6494
|
* Stop hosting a claimed namespace.
|
|
6337
6495
|
*
|
|
@@ -9840,43 +9998,6 @@ function assertSafeReturnTo(returnTo) {
|
|
|
9840
9998
|
);
|
|
9841
9999
|
}
|
|
9842
10000
|
|
|
9843
|
-
// src/cloud/account-ownership.ts
|
|
9844
|
-
var DOMAIN = new TextEncoder().encode("calimero.mdma.account-ownership-claim.v1\0");
|
|
9845
|
-
var DEFAULT_TTL_MS = 6e4;
|
|
9846
|
-
var MAX_TTL_MS = 5 * 6e4;
|
|
9847
|
-
function base643(bytes) {
|
|
9848
|
-
let binary = "";
|
|
9849
|
-
for (const b of bytes) binary += String.fromCharCode(b);
|
|
9850
|
-
return btoa(binary);
|
|
9851
|
-
}
|
|
9852
|
-
var hex32 = (value, what) => {
|
|
9853
|
-
if (!/^[0-9a-fA-F]{64}$/.test(value)) throw new Error(`${what} must be 64 hex characters`);
|
|
9854
|
-
return value.toLowerCase();
|
|
9855
|
-
};
|
|
9856
|
-
async function signAccountOwnershipClaim(input) {
|
|
9857
|
-
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
9858
|
-
if (!(ttl > 0 && ttl <= MAX_TTL_MS)) throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
9859
|
-
if (!input.subject) throw new Error("subject must be the cloud login email");
|
|
9860
|
-
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
9861
|
-
const issued = (input.now ?? Date.now)();
|
|
9862
|
-
const nonce2 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
9863
|
-
const payload = new TextEncoder().encode(
|
|
9864
|
-
JSON.stringify({
|
|
9865
|
-
v: 1,
|
|
9866
|
-
audience: "mdma:enable-ha-namespace",
|
|
9867
|
-
group_id: hex32(input.namespaceId, "namespaceId"),
|
|
9868
|
-
account_id: hex32(input.accountId, "accountId"),
|
|
9869
|
-
salt: hex32(input.salt, "salt"),
|
|
9870
|
-
subject: input.subject,
|
|
9871
|
-
nonce: nonce2,
|
|
9872
|
-
issued_at_ms: issued,
|
|
9873
|
-
expires_at_ms: issued + ttl
|
|
9874
|
-
})
|
|
9875
|
-
);
|
|
9876
|
-
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
9877
|
-
return { kind: "account", credential: input.credential, signed_payload: base643(payload), signature: base643(signature) };
|
|
9878
|
-
}
|
|
9879
|
-
|
|
9880
10001
|
// src/sealed/verify.ts
|
|
9881
10002
|
var MEASUREMENT_HEX = /^[0-9a-f]{96}$/;
|
|
9882
10003
|
var REGISTERS = ["mrtd", "rtmr0", "rtmr1", "rtmr2", "rtmr3"];
|
|
@@ -11074,6 +11195,11 @@ async function attestRelayNodeKey(opts) {
|
|
|
11074
11195
|
return { nodeKey: hex(nodeKey), mock };
|
|
11075
11196
|
}
|
|
11076
11197
|
export {
|
|
11198
|
+
ACCOUNT_HA_AUDIENCE,
|
|
11199
|
+
ACCOUNT_OWNERSHIP_AUDIENCE,
|
|
11200
|
+
AccountHaRefusedError,
|
|
11201
|
+
AccountLinkedToSeveralUsersError,
|
|
11202
|
+
AccountNotLinkedError,
|
|
11077
11203
|
AdminApiClient,
|
|
11078
11204
|
AuthApiClient,
|
|
11079
11205
|
AuthRevokedError,
|
|
@@ -11085,6 +11211,7 @@ export {
|
|
|
11085
11211
|
EphemeralClient,
|
|
11086
11212
|
HANDSHAKE_PATH,
|
|
11087
11213
|
HTTPError,
|
|
11214
|
+
HaRequestPendingError,
|
|
11088
11215
|
INVITED_ROLE,
|
|
11089
11216
|
IntentRefusedError,
|
|
11090
11217
|
LocalStorageTokenStore,
|
|
@@ -11097,6 +11224,7 @@ export {
|
|
|
11097
11224
|
PRESENCE_DOMAIN,
|
|
11098
11225
|
REQUEST_PROOF_HEADER,
|
|
11099
11226
|
RelayClient,
|
|
11227
|
+
RelayNotDialableError,
|
|
11100
11228
|
RelayObserver,
|
|
11101
11229
|
RelayPresenceClient,
|
|
11102
11230
|
RelayTransport,
|
|
@@ -11108,6 +11236,7 @@ export {
|
|
|
11108
11236
|
SealedTransportError,
|
|
11109
11237
|
SseClient,
|
|
11110
11238
|
StaleTransportKeyError,
|
|
11239
|
+
UnknownRelayError,
|
|
11111
11240
|
WarrantNonceExhaustedError,
|
|
11112
11241
|
WarrantNonceRouteUnavailableError,
|
|
11113
11242
|
WebHttpClient,
|
|
@@ -11230,6 +11359,7 @@ export {
|
|
|
11230
11359
|
rootGuardedOpBytes,
|
|
11231
11360
|
routingProofHeaders,
|
|
11232
11361
|
shouldRetain,
|
|
11362
|
+
signAccountHaClaim,
|
|
11233
11363
|
signAccountLink,
|
|
11234
11364
|
signAccountLogin,
|
|
11235
11365
|
signAccountOwnershipClaim,
|