@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.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,
|
|
@@ -30,6 +35,7 @@ __export(index_exports, {
|
|
|
30
35
|
EphemeralClient: () => EphemeralClient,
|
|
31
36
|
HANDSHAKE_PATH: () => HANDSHAKE_PATH,
|
|
32
37
|
HTTPError: () => HTTPError,
|
|
38
|
+
HaRequestPendingError: () => HaRequestPendingError,
|
|
33
39
|
INVITED_ROLE: () => INVITED_ROLE,
|
|
34
40
|
IntentRefusedError: () => IntentRefusedError,
|
|
35
41
|
LocalStorageTokenStore: () => LocalStorageTokenStore,
|
|
@@ -42,6 +48,7 @@ __export(index_exports, {
|
|
|
42
48
|
PRESENCE_DOMAIN: () => PRESENCE_DOMAIN,
|
|
43
49
|
REQUEST_PROOF_HEADER: () => REQUEST_PROOF_HEADER,
|
|
44
50
|
RelayClient: () => RelayClient,
|
|
51
|
+
RelayNotDialableError: () => RelayNotDialableError,
|
|
45
52
|
RelayObserver: () => RelayObserver,
|
|
46
53
|
RelayPresenceClient: () => RelayPresenceClient,
|
|
47
54
|
RelayTransport: () => RelayTransport,
|
|
@@ -53,6 +60,7 @@ __export(index_exports, {
|
|
|
53
60
|
SealedTransportError: () => SealedTransportError,
|
|
54
61
|
SseClient: () => SseClient,
|
|
55
62
|
StaleTransportKeyError: () => StaleTransportKeyError,
|
|
63
|
+
UnknownRelayError: () => UnknownRelayError,
|
|
56
64
|
WarrantNonceExhaustedError: () => WarrantNonceExhaustedError,
|
|
57
65
|
WarrantNonceRouteUnavailableError: () => WarrantNonceRouteUnavailableError,
|
|
58
66
|
WebHttpClient: () => WebHttpClient,
|
|
@@ -175,6 +183,7 @@ __export(index_exports, {
|
|
|
175
183
|
rootGuardedOpBytes: () => rootGuardedOpBytes,
|
|
176
184
|
routingProofHeaders: () => routingProofHeaders,
|
|
177
185
|
shouldRetain: () => shouldRetain,
|
|
186
|
+
signAccountHaClaim: () => signAccountHaClaim,
|
|
178
187
|
signAccountLink: () => signAccountLink,
|
|
179
188
|
signAccountLogin: () => signAccountLogin,
|
|
180
189
|
signAccountOwnershipClaim: () => signAccountOwnershipClaim,
|
|
@@ -3686,6 +3695,59 @@ async function resolveSigner(secret, signer, label2) {
|
|
|
3686
3695
|
throw new Error(`${label2} or signer is required`);
|
|
3687
3696
|
}
|
|
3688
3697
|
|
|
3698
|
+
// src/cloud/account-ownership.ts
|
|
3699
|
+
var DOMAIN = new TextEncoder().encode("calimero.mdma.account-ownership-claim.v1\0");
|
|
3700
|
+
var DEFAULT_TTL_MS = 6e4;
|
|
3701
|
+
var MAX_TTL_MS = 5 * 6e4;
|
|
3702
|
+
var MAX_RELAY_URL = 1024;
|
|
3703
|
+
var ACCOUNT_OWNERSHIP_AUDIENCE = "mdma:enable-ha-namespace";
|
|
3704
|
+
var ACCOUNT_HA_AUDIENCE = "mdma:enable-ha-namespace-as-account";
|
|
3705
|
+
function base64(bytes) {
|
|
3706
|
+
let binary = "";
|
|
3707
|
+
for (const b of bytes) binary += String.fromCharCode(b);
|
|
3708
|
+
return btoa(binary);
|
|
3709
|
+
}
|
|
3710
|
+
var hex32 = (value, what) => {
|
|
3711
|
+
if (!/^[0-9a-fA-F]{64}$/.test(value)) throw new Error(`${what} must be 64 hex characters`);
|
|
3712
|
+
return value.toLowerCase();
|
|
3713
|
+
};
|
|
3714
|
+
async function signClaim(input, audience, subject, relayUrl) {
|
|
3715
|
+
if (relayUrl !== void 0 && !(relayUrl.length > 0 && relayUrl.length <= MAX_RELAY_URL)) {
|
|
3716
|
+
throw new Error(`relayUrl must be a non-empty string of at most ${MAX_RELAY_URL} characters`);
|
|
3717
|
+
}
|
|
3718
|
+
const ttl = input.ttlMs ?? DEFAULT_TTL_MS;
|
|
3719
|
+
if (!(ttl > 0 && ttl <= MAX_TTL_MS)) throw new Error(`ttlMs must be in (0, ${MAX_TTL_MS}]`);
|
|
3720
|
+
const groupId = hex32(input.namespaceId, "namespaceId");
|
|
3721
|
+
const accountId = hex32(input.accountId, "accountId");
|
|
3722
|
+
const salt = hex32(input.salt, "salt");
|
|
3723
|
+
const signer = await resolveSigner(input.deviceSecret, input.signer, "deviceSecret");
|
|
3724
|
+
const issued = (input.now ?? Date.now)();
|
|
3725
|
+
const nonce2 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3726
|
+
const payload = new TextEncoder().encode(
|
|
3727
|
+
JSON.stringify({
|
|
3728
|
+
v: 1,
|
|
3729
|
+
audience,
|
|
3730
|
+
group_id: groupId,
|
|
3731
|
+
account_id: accountId,
|
|
3732
|
+
salt,
|
|
3733
|
+
...subject === void 0 ? {} : { subject },
|
|
3734
|
+
nonce: nonce2,
|
|
3735
|
+
issued_at_ms: issued,
|
|
3736
|
+
expires_at_ms: issued + ttl,
|
|
3737
|
+
...relayUrl === void 0 ? {} : { relay_url: relayUrl }
|
|
3738
|
+
})
|
|
3739
|
+
);
|
|
3740
|
+
const signature = await signer.sign(concat(DOMAIN, payload));
|
|
3741
|
+
return { kind: "account", credential: input.credential, signed_payload: base64(payload), signature: base64(signature) };
|
|
3742
|
+
}
|
|
3743
|
+
async function signAccountOwnershipClaim(input) {
|
|
3744
|
+
if (!input.subject) throw new Error("subject must be the cloud login email");
|
|
3745
|
+
return signClaim(input, ACCOUNT_OWNERSHIP_AUDIENCE, input.subject);
|
|
3746
|
+
}
|
|
3747
|
+
async function signAccountHaClaim(input) {
|
|
3748
|
+
return signClaim(input, ACCOUNT_HA_AUDIENCE, void 0, input.relayUrl);
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3689
3751
|
// src/device-cert/device-cert.ts
|
|
3690
3752
|
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
3691
3753
|
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
@@ -5977,7 +6039,7 @@ async function signAccountLink(input) {
|
|
|
5977
6039
|
const signature = await signer.sign(
|
|
5978
6040
|
concat(ACCOUNT_LINK_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5979
6041
|
);
|
|
5980
|
-
return
|
|
6042
|
+
return base642(signature);
|
|
5981
6043
|
}
|
|
5982
6044
|
async function signAccountLogin(input) {
|
|
5983
6045
|
if (!input.nonce) throw new Error("nonce is required to sign an account login");
|
|
@@ -5985,7 +6047,7 @@ async function signAccountLogin(input) {
|
|
|
5985
6047
|
const signature = await signer.sign(
|
|
5986
6048
|
concat(ACCOUNT_LOGIN_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
5987
6049
|
);
|
|
5988
|
-
return
|
|
6050
|
+
return base642(signature);
|
|
5989
6051
|
}
|
|
5990
6052
|
async function withPhrase(secret, phrase) {
|
|
5991
6053
|
return { ...await accountRootFromSecret(secret), phrase };
|
|
@@ -6038,7 +6100,7 @@ function bitsOf(bytes) {
|
|
|
6038
6100
|
for (const byte of bytes) bits += byte.toString(2).padStart(8, "0");
|
|
6039
6101
|
return bits;
|
|
6040
6102
|
}
|
|
6041
|
-
function
|
|
6103
|
+
function base642(bytes) {
|
|
6042
6104
|
let binary = "";
|
|
6043
6105
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
6044
6106
|
return btoa(binary);
|
|
@@ -6058,7 +6120,7 @@ async function signRoutingChallenge(nonce2, deviceSecret) {
|
|
|
6058
6120
|
const signature = new Uint8Array(
|
|
6059
6121
|
await crypto.subtle.sign({ name: "Ed25519" }, key, message)
|
|
6060
6122
|
);
|
|
6061
|
-
return
|
|
6123
|
+
return base643(signature);
|
|
6062
6124
|
}
|
|
6063
6125
|
async function routingProofHeaders(challenge, credential) {
|
|
6064
6126
|
return {
|
|
@@ -6070,7 +6132,7 @@ async function routingProofHeaders(challenge, credential) {
|
|
|
6070
6132
|
)
|
|
6071
6133
|
};
|
|
6072
6134
|
}
|
|
6073
|
-
function
|
|
6135
|
+
function base643(bytes) {
|
|
6074
6136
|
let binary = "";
|
|
6075
6137
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
6076
6138
|
return btoa(binary);
|
|
@@ -6087,6 +6149,64 @@ function teeRoleOf(row) {
|
|
|
6087
6149
|
function pickExecutingRelay(relays) {
|
|
6088
6150
|
return relays.find((r) => r.canExecute && r.relayUrl !== null && r.executorAccount !== null) ?? null;
|
|
6089
6151
|
}
|
|
6152
|
+
var AccountHaRefusedError = class extends HTTPError {
|
|
6153
|
+
constructor(code, status, statusText, url, headers, bodyText) {
|
|
6154
|
+
super(status, statusText, url, headers, bodyText);
|
|
6155
|
+
this.code = code;
|
|
6156
|
+
this.name = "AccountHaRefusedError";
|
|
6157
|
+
}
|
|
6158
|
+
};
|
|
6159
|
+
var AccountNotLinkedError = class extends AccountHaRefusedError {
|
|
6160
|
+
constructor() {
|
|
6161
|
+
super(...arguments);
|
|
6162
|
+
this.name = "AccountNotLinkedError";
|
|
6163
|
+
}
|
|
6164
|
+
};
|
|
6165
|
+
AccountNotLinkedError.CODE = "account_not_linked";
|
|
6166
|
+
var AccountLinkedToSeveralUsersError = class extends AccountHaRefusedError {
|
|
6167
|
+
constructor() {
|
|
6168
|
+
super(...arguments);
|
|
6169
|
+
this.name = "AccountLinkedToSeveralUsersError";
|
|
6170
|
+
}
|
|
6171
|
+
};
|
|
6172
|
+
AccountLinkedToSeveralUsersError.CODE = "account_linked_to_several_users";
|
|
6173
|
+
var HaRequestPendingError = class extends AccountHaRefusedError {
|
|
6174
|
+
constructor() {
|
|
6175
|
+
super(...arguments);
|
|
6176
|
+
this.name = "HaRequestPendingError";
|
|
6177
|
+
}
|
|
6178
|
+
};
|
|
6179
|
+
HaRequestPendingError.CODE = "ha_request_pending";
|
|
6180
|
+
var UnknownRelayError = class extends AccountHaRefusedError {
|
|
6181
|
+
constructor() {
|
|
6182
|
+
super(...arguments);
|
|
6183
|
+
this.name = "UnknownRelayError";
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6186
|
+
UnknownRelayError.CODE = "unknown_relay";
|
|
6187
|
+
var RelayNotDialableError = class extends AccountHaRefusedError {
|
|
6188
|
+
constructor() {
|
|
6189
|
+
super(...arguments);
|
|
6190
|
+
this.name = "RelayNotDialableError";
|
|
6191
|
+
}
|
|
6192
|
+
};
|
|
6193
|
+
RelayNotDialableError.CODE = "relay_not_dialable";
|
|
6194
|
+
var ACCOUNT_HA_REFUSALS = {
|
|
6195
|
+
409: [AccountNotLinkedError, AccountLinkedToSeveralUsersError, HaRequestPendingError],
|
|
6196
|
+
422: [UnknownRelayError, RelayNotDialableError]
|
|
6197
|
+
};
|
|
6198
|
+
function conflictCode(bodyText) {
|
|
6199
|
+
if (!bodyText) return void 0;
|
|
6200
|
+
try {
|
|
6201
|
+
const body = JSON.parse(bodyText);
|
|
6202
|
+
if (typeof body?.error === "string") return body.error;
|
|
6203
|
+
if (typeof body?.detail === "string") return body.detail;
|
|
6204
|
+
const nested = body?.detail?.error;
|
|
6205
|
+
if (typeof nested === "string") return nested;
|
|
6206
|
+
} catch {
|
|
6207
|
+
}
|
|
6208
|
+
return void 0;
|
|
6209
|
+
}
|
|
6090
6210
|
var REFRESH_HEADER = "x-mdma-session-refresh";
|
|
6091
6211
|
var REFRESH_EXPIRES_HEADER = "x-mdma-session-expires";
|
|
6092
6212
|
var CloudClient = class {
|
|
@@ -6547,6 +6667,53 @@ var CloudClient = class {
|
|
|
6547
6667
|
{ body: { groups: [], ownership_proof: ownershipProof } }
|
|
6548
6668
|
);
|
|
6549
6669
|
}
|
|
6670
|
+
/**
|
|
6671
|
+
* Enable HA for a namespace this account founded, with **no cloud session**.
|
|
6672
|
+
*
|
|
6673
|
+
* The anonymous sibling of {@link enableFoundedNamespaceHa}: it signs the
|
|
6674
|
+
* founder's claim itself ({@link signAccountHaClaim} — no `subject`, its own
|
|
6675
|
+
* audience) and posts it to
|
|
6676
|
+
* `/api/cloud/accounts/{accountId}/namespaces/{namespaceId}/enable-ha`. The
|
|
6677
|
+
* cloud bills the user the account is linked to through the wallet, so the
|
|
6678
|
+
* account must be linked to exactly one:
|
|
6679
|
+
*
|
|
6680
|
+
* - not linked at all → {@link AccountNotLinkedError};
|
|
6681
|
+
* - linked to several → {@link AccountLinkedToSeveralUsersError}.
|
|
6682
|
+
*
|
|
6683
|
+
* A claim that does not verify is a `403` `HTTPError`; quota and the rest
|
|
6684
|
+
* answer as the session route does. Returns the cloud's response body, the
|
|
6685
|
+
* same shape the session route's enable-ha returns.
|
|
6686
|
+
*/
|
|
6687
|
+
async enableHaAsAccount(options) {
|
|
6688
|
+
const proof = await signAccountHaClaim({
|
|
6689
|
+
namespaceId: options.namespaceId,
|
|
6690
|
+
accountId: options.accountId,
|
|
6691
|
+
salt: options.salt,
|
|
6692
|
+
credential: options.credential,
|
|
6693
|
+
deviceSecret: options.deviceSecret,
|
|
6694
|
+
signer: options.signer,
|
|
6695
|
+
ttlMs: options.ttlMs,
|
|
6696
|
+
relayUrl: options.relayUrl
|
|
6697
|
+
});
|
|
6698
|
+
const account = options.accountId.toLowerCase();
|
|
6699
|
+
const namespace = options.namespaceId.toLowerCase();
|
|
6700
|
+
try {
|
|
6701
|
+
return await this.request(
|
|
6702
|
+
"POST",
|
|
6703
|
+
`/api/cloud/accounts/${encodeURIComponent(account)}/namespaces/${encodeURIComponent(namespace)}/enable-ha`,
|
|
6704
|
+
{ body: { ownership_proof: proof }, anonymous: true }
|
|
6705
|
+
);
|
|
6706
|
+
} catch (err) {
|
|
6707
|
+
if (err instanceof HTTPError && ACCOUNT_HA_REFUSALS[err.status]) {
|
|
6708
|
+
const code = conflictCode(err.bodyText);
|
|
6709
|
+
const Typed = ACCOUNT_HA_REFUSALS[err.status].find((t) => t.CODE === code);
|
|
6710
|
+
if (Typed && code) {
|
|
6711
|
+
throw new Typed(code, err.status, err.statusText, err.url, err.headers, err.bodyText);
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
throw err;
|
|
6715
|
+
}
|
|
6716
|
+
}
|
|
6550
6717
|
/**
|
|
6551
6718
|
* Stop hosting a claimed namespace.
|
|
6552
6719
|
*
|
|
@@ -10055,43 +10222,6 @@ function assertSafeReturnTo(returnTo) {
|
|
|
10055
10222
|
);
|
|
10056
10223
|
}
|
|
10057
10224
|
|
|
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
10225
|
// src/sealed/verify.ts
|
|
10096
10226
|
var MEASUREMENT_HEX = /^[0-9a-f]{96}$/;
|
|
10097
10227
|
var REGISTERS = ["mrtd", "rtmr0", "rtmr1", "rtmr2", "rtmr3"];
|