@calimero-network/mero-js 23.4.3 → 23.5.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 +29 -4
- package/dist/cloud/account-ownership.js +34 -8
- package/dist/cloud/cloud-client.d.ts +68 -1
- package/dist/cloud/cloud-client.js +112 -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 +138 -42
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +138 -42
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19,6 +19,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/index.ts
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
|
+
ACCOUNT_HA_AUDIENCE: () => ACCOUNT_HA_AUDIENCE,
|
|
23
|
+
ACCOUNT_OWNERSHIP_AUDIENCE: () => ACCOUNT_OWNERSHIP_AUDIENCE,
|
|
24
|
+
AccountHaRefusedError: () => AccountHaRefusedError,
|
|
25
|
+
AccountLinkedToSeveralUsersError: () => AccountLinkedToSeveralUsersError,
|
|
26
|
+
AccountNotLinkedError: () => AccountNotLinkedError,
|
|
22
27
|
AdminApiClient: () => AdminApiClient,
|
|
23
28
|
AuthApiClient: () => AuthApiClient,
|
|
24
29
|
AuthRevokedError: () => AuthRevokedError,
|
|
@@ -175,6 +180,7 @@ __export(index_exports, {
|
|
|
175
180
|
rootGuardedOpBytes: () => rootGuardedOpBytes,
|
|
176
181
|
routingProofHeaders: () => routingProofHeaders,
|
|
177
182
|
shouldRetain: () => shouldRetain,
|
|
183
|
+
signAccountHaClaim: () => signAccountHaClaim,
|
|
178
184
|
signAccountLink: () => signAccountLink,
|
|
179
185
|
signAccountLogin: () => signAccountLogin,
|
|
180
186
|
signAccountOwnershipClaim: () => signAccountOwnershipClaim,
|
|
@@ -3686,6 +3692,54 @@ async function resolveSigner(secret, signer, label2) {
|
|
|
3686
3692
|
throw new Error(`${label2} or signer is required`);
|
|
3687
3693
|
}
|
|
3688
3694
|
|
|
3695
|
+
// src/cloud/account-ownership.ts
|
|
3696
|
+
var DOMAIN = new TextEncoder().encode("calimero.mdma.account-ownership-claim.v1\0");
|
|
3697
|
+
var DEFAULT_TTL_MS = 6e4;
|
|
3698
|
+
var MAX_TTL_MS = 5 * 6e4;
|
|
3699
|
+
var ACCOUNT_OWNERSHIP_AUDIENCE = "mdma:enable-ha-namespace";
|
|
3700
|
+
var ACCOUNT_HA_AUDIENCE = "mdma:enable-ha-namespace-as-account";
|
|
3701
|
+
function base64(bytes) {
|
|
3702
|
+
let binary = "";
|
|
3703
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
3704
|
+
return btoa(binary);
|
|
3705
|
+
}
|
|
3706
|
+
var hex32 = (value, what) => {
|
|
3707
|
+
if (!/^[0-9a-fA-F]{64}$/.test(value)) throw new Error(`${what} must be 64 hex characters`);
|
|
3708
|
+
return value.toLowerCase();
|
|
3709
|
+
};
|
|
3710
|
+
async function signClaim(input, audience, subject) {
|
|
3711
|
+
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
3712
|
+
if (!(ttl > 0 && ttl <= MAX_TTL_MS)) throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
3713
|
+
const groupId = hex32(input.namespaceId, "namespaceId");
|
|
3714
|
+
const accountId = hex32(input.accountId, "accountId");
|
|
3715
|
+
const salt = hex32(input.salt, "salt");
|
|
3716
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
3717
|
+
const issued = (input.now ?? Date.now)();
|
|
3718
|
+
const nonce2 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3719
|
+
const payload = new TextEncoder().encode(
|
|
3720
|
+
JSON.stringify({
|
|
3721
|
+
v: 1,
|
|
3722
|
+
audience,
|
|
3723
|
+
group_id: groupId,
|
|
3724
|
+
account_id: accountId,
|
|
3725
|
+
salt,
|
|
3726
|
+
...subject === void 0 ? {} : { subject },
|
|
3727
|
+
nonce: nonce2,
|
|
3728
|
+
issued_at_ms: issued,
|
|
3729
|
+
expires_at_ms: issued + ttl
|
|
3730
|
+
})
|
|
3731
|
+
);
|
|
3732
|
+
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
3733
|
+
return { kind: "account", credential: input.credential, signed_payload: base64(payload), signature: base64(signature) };
|
|
3734
|
+
}
|
|
3735
|
+
async function signAccountOwnershipClaim(input) {
|
|
3736
|
+
if (!input.subject) throw new Error("subject must be the cloud login email");
|
|
3737
|
+
return signClaim(input, ACCOUNT_OWNERSHIP_AUDIENCE, input.subject);
|
|
3738
|
+
}
|
|
3739
|
+
async function signAccountHaClaim(input) {
|
|
3740
|
+
return signClaim(input, ACCOUNT_HA_AUDIENCE, void 0);
|
|
3741
|
+
}
|
|
3742
|
+
|
|
3689
3743
|
// src/device-cert/device-cert.ts
|
|
3690
3744
|
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
3691
3745
|
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
@@ -5977,7 +6031,7 @@ async function signAccountLink(input) {
|
|
|
5977
6031
|
const signature = await signer.sign(
|
|
5978
6032
|
concat(ACCOUNT_LINK_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5979
6033
|
);
|
|
5980
|
-
return
|
|
6034
|
+
return base642(signature);
|
|
5981
6035
|
}
|
|
5982
6036
|
async function signAccountLogin(input) {
|
|
5983
6037
|
if (!input.nonce) throw new Error("nonce is required to sign an account login");
|
|
@@ -5985,7 +6039,7 @@ async function signAccountLogin(input) {
|
|
|
5985
6039
|
const signature = await signer.sign(
|
|
5986
6040
|
concat(ACCOUNT_LOGIN_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5987
6041
|
);
|
|
5988
|
-
return
|
|
6042
|
+
return base642(signature);
|
|
5989
6043
|
}
|
|
5990
6044
|
async function withPhrase(secret, phrase) {
|
|
5991
6045
|
return { ...await accountRootFromSecret(secret), phrase };
|
|
@@ -6038,7 +6092,7 @@ function bitsOf(bytes) {
|
|
|
6038
6092
|
for (const byte of bytes) bits += byte.toString(2).padStart(8, "0");
|
|
6039
6093
|
return bits;
|
|
6040
6094
|
}
|
|
6041
|
-
function
|
|
6095
|
+
function base642(bytes) {
|
|
6042
6096
|
let binary = "";
|
|
6043
6097
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
6044
6098
|
return btoa(binary);
|
|
@@ -6058,7 +6112,7 @@ async function signRoutingChallenge(nonce2, deviceSecret) {
|
|
|
6058
6112
|
const signature = new Uint8Array(
|
|
6059
6113
|
await crypto.subtle.sign({ name: "Ed25519" }, key, message)
|
|
6060
6114
|
);
|
|
6061
|
-
return
|
|
6115
|
+
return base643(signature);
|
|
6062
6116
|
}
|
|
6063
6117
|
async function routingProofHeaders(challenge, credential) {
|
|
6064
6118
|
return {
|
|
@@ -6070,7 +6124,7 @@ async function routingProofHeaders(challenge, credential) {
|
|
|
6070
6124
|
)
|
|
6071
6125
|
};
|
|
6072
6126
|
}
|
|
6073
|
-
function
|
|
6127
|
+
function base643(bytes) {
|
|
6074
6128
|
let binary = "";
|
|
6075
6129
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
6076
6130
|
return btoa(binary);
|
|
@@ -6087,6 +6141,39 @@ function teeRoleOf(row) {
|
|
|
6087
6141
|
function pickExecutingRelay(relays) {
|
|
6088
6142
|
return relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null;
|
|
6089
6143
|
}
|
|
6144
|
+
var AccountHaRefusedError = class extends HTTPError {
|
|
6145
|
+
constructor(code, status, statusText, url, headers, bodyText) {
|
|
6146
|
+
super(status, statusText, url, headers, bodyText);
|
|
6147
|
+
this.code = code;
|
|
6148
|
+
this.name = "AccountHaRefusedError";
|
|
6149
|
+
}
|
|
6150
|
+
};
|
|
6151
|
+
var AccountNotLinkedError = class extends AccountHaRefusedError {
|
|
6152
|
+
constructor() {
|
|
6153
|
+
super(...arguments);
|
|
6154
|
+
this.name = "AccountNotLinkedError";
|
|
6155
|
+
}
|
|
6156
|
+
};
|
|
6157
|
+
AccountNotLinkedError.CODE = "account_not_linked";
|
|
6158
|
+
var AccountLinkedToSeveralUsersError = class extends AccountHaRefusedError {
|
|
6159
|
+
constructor() {
|
|
6160
|
+
super(...arguments);
|
|
6161
|
+
this.name = "AccountLinkedToSeveralUsersError";
|
|
6162
|
+
}
|
|
6163
|
+
};
|
|
6164
|
+
AccountLinkedToSeveralUsersError.CODE = "account_linked_to_several_users";
|
|
6165
|
+
function conflictCode(bodyText) {
|
|
6166
|
+
if (!bodyText) return void 0;
|
|
6167
|
+
try {
|
|
6168
|
+
const body = JSON.parse(bodyText);
|
|
6169
|
+
if (typeof body?.error === "string") return body.error;
|
|
6170
|
+
if (typeof body?.detail === "string") return body.detail;
|
|
6171
|
+
const nested = body?.detail?.error;
|
|
6172
|
+
if (typeof nested === "string") return nested;
|
|
6173
|
+
} catch {
|
|
6174
|
+
}
|
|
6175
|
+
return void 0;
|
|
6176
|
+
}
|
|
6090
6177
|
var REFRESH_HEADER = "x-mdma-session-refresh";
|
|
6091
6178
|
var REFRESH_EXPIRES_HEADER = "x-mdma-session-expires";
|
|
6092
6179
|
var CloudClient = class {
|
|
@@ -6547,6 +6634,52 @@ var CloudClient = class {
|
|
|
6547
6634
|
{ body: { groups: [], ownership_proof: ownershipProof } }
|
|
6548
6635
|
);
|
|
6549
6636
|
}
|
|
6637
|
+
/**
|
|
6638
|
+
* Enable HA for a namespace this account founded, with **no cloud session**.
|
|
6639
|
+
*
|
|
6640
|
+
* The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
|
|
6641
|
+
* founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
|
|
6642
|
+
* audience) and posts it to
|
|
6643
|
+
* `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
|
|
6644
|
+
* cloud bills the user the account is linked to through the wallet, so the
|
|
6645
|
+
* account must be linked to exactly one:
|
|
6646
|
+
*
|
|
6647
|
+
* - not linked at all → {@link AccountNotLinkedError};
|
|
6648
|
+
* - linked to several → {@link AccountLinkedToSeveralUsersError}.
|
|
6649
|
+
*
|
|
6650
|
+
* A claim that does not verify is a `403` `HTTPError`; quota and the rest
|
|
6651
|
+
* answer as the session route does. Returns the cloud's response body, the
|
|
6652
|
+
* same shape the session route's enable-ha returns.
|
|
6653
|
+
*/
|
|
6654
|
+
async enableHaAsAccount(options) {
|
|
6655
|
+
const proof = await signAccountHaClaim({
|
|
6656
|
+
namespaceId: options.namespaceId,
|
|
6657
|
+
accountId: options.accountId,
|
|
6658
|
+
salt: options.salt,
|
|
6659
|
+
credential: options.credential,
|
|
6660
|
+
deviceSecret: options.deviceSecret,
|
|
6661
|
+
signer: options.signer,
|
|
6662
|
+
ttlMs: options.ttlMs
|
|
6663
|
+
});
|
|
6664
|
+
const account = options.accountId.toLowerCase();
|
|
6665
|
+
const namespace = options.namespaceId.toLowerCase();
|
|
6666
|
+
try {
|
|
6667
|
+
return await this.request(
|
|
6668
|
+
"POST",
|
|
6669
|
+
`/api/cloud/accounts/${encodeURIComponent(account)}/namespaces/${encodeURIComponent(namespace)}/enable-ha`,
|
|
6670
|
+
{ body: { ownership_proof: proof }, anonymous: true }
|
|
6671
|
+
);
|
|
6672
|
+
} catch (err) {
|
|
6673
|
+
if (err instanceof HTTPError && err.status === 409) {
|
|
6674
|
+
const code = conflictCode(err.bodyText);
|
|
6675
|
+
const Typed = code === AccountNotLinkedError.CODE ? AccountNotLinkedError : code === AccountLinkedToSeveralUsersError.CODE ? AccountLinkedToSeveralUsersError : void 0;
|
|
6676
|
+
if (Typed && code) {
|
|
6677
|
+
throw new Typed(code, err.status, err.statusText, err.url, err.headers, err.bodyText);
|
|
6678
|
+
}
|
|
6679
|
+
}
|
|
6680
|
+
throw err;
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6550
6683
|
/**
|
|
6551
6684
|
* Stop hosting a claimed namespace.
|
|
6552
6685
|
*
|
|
@@ -10055,43 +10188,6 @@ function assertSafeReturnTo(returnTo) {
|
|
|
10055
10188
|
);
|
|
10056
10189
|
}
|
|
10057
10190
|
|
|
10058
|
-
// src/cloud/account-ownership.ts
|
|
10059
|
-
var DOMAIN = new TextEncoder().encode("calimero.mdma.account-ownership-claim.v1\0");
|
|
10060
|
-
var DEFAULT_TTL_MS = 6e4;
|
|
10061
|
-
var MAX_TTL_MS = 5 * 6e4;
|
|
10062
|
-
function base643(bytes) {
|
|
10063
|
-
let binary = "";
|
|
10064
|
-
for (const b of bytes) binary += String.fromCharCode(b);
|
|
10065
|
-
return btoa(binary);
|
|
10066
|
-
}
|
|
10067
|
-
var hex32 = (value, what) => {
|
|
10068
|
-
if (!/^[0-9a-fA-F]{64}$/.test(value)) throw new Error(`${what} must be 64 hex characters`);
|
|
10069
|
-
return value.toLowerCase();
|
|
10070
|
-
};
|
|
10071
|
-
async function signAccountOwnershipClaim(input) {
|
|
10072
|
-
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
10073
|
-
if (!(ttl > 0 && ttl <= MAX_TTL_MS)) throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
10074
|
-
if (!input.subject) throw new Error("subject must be the cloud login email");
|
|
10075
|
-
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
10076
|
-
const issued = (input.now ?? Date.now)();
|
|
10077
|
-
const nonce2 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
10078
|
-
const payload = new TextEncoder().encode(
|
|
10079
|
-
JSON.stringify({
|
|
10080
|
-
v: 1,
|
|
10081
|
-
audience: "mdma:enable-ha-namespace",
|
|
10082
|
-
group_id: hex32(input.namespaceId, "namespaceId"),
|
|
10083
|
-
account_id: hex32(input.accountId, "accountId"),
|
|
10084
|
-
salt: hex32(input.salt, "salt"),
|
|
10085
|
-
subject: input.subject,
|
|
10086
|
-
nonce: nonce2,
|
|
10087
|
-
issued_at_ms: issued,
|
|
10088
|
-
expires_at_ms: issued + ttl
|
|
10089
|
-
})
|
|
10090
|
-
);
|
|
10091
|
-
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
10092
|
-
return { kind: "account", credential: input.credential, signed_payload: base643(payload), signature: base643(signature) };
|
|
10093
|
-
}
|
|
10094
|
-
|
|
10095
10191
|
// src/sealed/verify.ts
|
|
10096
10192
|
var MEASUREMENT_HEX = /^[0-9a-f]{96}$/;
|
|
10097
10193
|
var REGISTERS = ["mrtd", "rtmr0", "rtmr1", "rtmr2", "rtmr3"];
|