@calimero-network/mero-js 18.0.0 → 18.1.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 +92 -1
- package/dist/admin-api/admin-client.js +106 -0
- package/dist/admin-api/admin-types.d.ts +336 -0
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +122 -0
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +122 -0
- package/dist/index.mjs.map +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HttpClient } from '../http-client/index.js';
|
|
2
|
-
import type { HealthStatus, AdminAuthStatus, InstallApplicationRequest, InstallApplicationResponseData, InstallDevApplicationRequest, UninstallApplicationResponseData, ListApplicationsResponseData, GetApplicationResponseData, ApplicationVersionEntry, GetApplicationAbiResponseData, GetLatestVersionResponseData, ListPackagesResponseData, ListVersionsResponseData, CreateContextRequest, CreateContextResponseData, DeleteContextRequest, DeleteContextResponseData, GetContextsResponseData, Context, GenerateContextIdentityResponseData, GetContextIdentitiesResponseData, JoinContextResponseData, JoinSubgroupInheritanceResponseData, ContextGroupResponseData, ContextStorageResponseData, InviteSpecializedNodeRequest, InviteSpecializedNodeResponseData, UpdateContextApplicationRequest, ResyncContextRequest, ResyncContextResponseData, ContextsWithExecutorsResponseData, UploadBlobRequest, UploadBlobResponseData, DeleteBlobResponseData, ListBlobsResponseData, GetBlobInfoResponseData, CreateContextAliasRequest, CreateApplicationAliasRequest, CreateAliasResponseData, LookupAliasResponseData, DeleteAliasResponseData, ListAliasesResponseData, ListNamespacesResponseData, CreateNamespaceRequest, CreateNamespaceResponseData, DeleteNamespaceRequest, DeleteNamespaceResponseData, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, JoinNamespaceRequest, JoinNamespaceResponseData, CreateGroupInNamespaceRequest, CreateGroupInNamespaceResponseData, SubgroupEntry, Namespace, NamespaceIdentity, NodeIdentity, GroupInfoResponseData, DeleteGroupRequest, DeleteGroupResponseData, ListGroupMembersResponseData, ListGroupContextsResponseData, AddGroupMembersRequest, RemoveGroupMembersRequest, UpdateMemberRoleRequest, MemberCapabilities, SetMemberCapabilitiesRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, GetTeeAdmissionPolicyResponseData, SetGroupMetadataRequest, SetMemberMetadataRequest, SetContextMetadataRequest, MetadataRecord, SyncGroupRequest, SyncGroupResponseData, UpgradeGroupRequest, UpgradeGroupResponseData, GroupUpgradeStatusResponseData, MigrationStatus, CascadeStatusEntry, RetryGroupUpgradeRequest, RetryGroupUpgradeResponseData, ReparentGroupRequest, ReparentGroupResponseData, DetachContextFromGroupRequest, CreateGroupInvitationRequest, CreateGroupInvitationResponseData, CreateRecursiveGroupInvitationResponseData, JoinGroupRequest, JoinGroupResponseData, TeeInfoResponseData, TeeAttestRequest, TeeAttestResponseData, TeeVerifyQuoteRequest, TeeVerifyQuoteResponseData, PerformIntentRequest, PerformIntentResponseData, AdmitJoinRequest, AdmitJoinResponseData } from './admin-types.js';
|
|
2
|
+
import type { HealthStatus, AdminAuthStatus, InstallApplicationRequest, InstallApplicationResponseData, InstallDevApplicationRequest, UninstallApplicationResponseData, ListApplicationsResponseData, GetApplicationResponseData, ApplicationVersionEntry, GetApplicationAbiResponseData, GetLatestVersionResponseData, ListPackagesResponseData, ListVersionsResponseData, CreateContextRequest, CreateContextResponseData, DeleteContextRequest, DeleteContextResponseData, GetContextsResponseData, Context, GenerateContextIdentityResponseData, GetContextIdentitiesResponseData, JoinContextResponseData, JoinSubgroupInheritanceResponseData, ContextGroupResponseData, ContextStorageResponseData, InviteSpecializedNodeRequest, InviteSpecializedNodeResponseData, UpdateContextApplicationRequest, ResyncContextRequest, ResyncContextResponseData, ContextsWithExecutorsResponseData, UploadBlobRequest, UploadBlobResponseData, DeleteBlobResponseData, ListBlobsResponseData, GetBlobInfoResponseData, CreateContextAliasRequest, CreateApplicationAliasRequest, CreateAliasResponseData, LookupAliasResponseData, DeleteAliasResponseData, ListAliasesResponseData, ListNamespacesResponseData, CreateNamespaceRequest, CreateNamespaceResponseData, DeleteNamespaceRequest, DeleteNamespaceResponseData, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, JoinNamespaceRequest, JoinNamespaceResponseData, CreateGroupInNamespaceRequest, CreateGroupInNamespaceResponseData, SubgroupEntry, Namespace, NamespaceIdentity, NodeIdentity, AccountPairInitRequest, AccountPairInitResponseData, AccountPairCompleteRequest, AccountPairCompleteResponseData, RelinkDeviceRequest, RelinkDeviceResponseData, AccountDeviceEntry, AccountApplicationEntry, RevokeAccountDeviceRequest, RevokeAccountDeviceResponseData, GroupInfoResponseData, DeleteGroupRequest, DeleteGroupResponseData, ListGroupMembersResponseData, ListGroupContextsResponseData, AddGroupMembersRequest, RemoveGroupMembersRequest, UpdateMemberRoleRequest, MemberCapabilities, SetMemberCapabilitiesRequest, SetDefaultCapabilitiesRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, GetTeeAdmissionPolicyResponseData, SetGroupMetadataRequest, SetMemberMetadataRequest, SetContextMetadataRequest, MetadataRecord, SyncGroupRequest, SyncGroupResponseData, UpgradeGroupRequest, UpgradeGroupResponseData, GroupUpgradeStatusResponseData, MigrationStatus, CascadeStatusEntry, RetryGroupUpgradeRequest, RetryGroupUpgradeResponseData, ReparentGroupRequest, ReparentGroupResponseData, DetachContextFromGroupRequest, CreateGroupInvitationRequest, CreateGroupInvitationResponseData, CreateRecursiveGroupInvitationResponseData, JoinGroupRequest, JoinGroupResponseData, TeeInfoResponseData, TeeAttestRequest, TeeAttestResponseData, TeeVerifyQuoteRequest, TeeVerifyQuoteResponseData, PerformIntentRequest, PerformIntentResponseData, AdmitJoinRequest, AdmitJoinResponseData } from './admin-types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Compare two version strings by SemVer 2.0 precedence, ascending: negative if
|
|
5
5
|
* `a < b`, positive if `a > b`, `0` if equal. Build metadata (`+...`) is stripped
|
|
@@ -178,6 +178,97 @@ export declare class AdminApiClient {
|
|
|
178
178
|
joinNamespace(namespaceId: string, request: JoinNamespaceRequest): Promise<JoinNamespaceResponseData>;
|
|
179
179
|
createGroupInNamespace(namespaceId: string, request?: CreateGroupInNamespaceRequest): Promise<CreateGroupInNamespaceResponseData>;
|
|
180
180
|
listNamespaceGroups(namespaceId: string): Promise<SubgroupEntry[]>;
|
|
181
|
+
/**
|
|
182
|
+
* Mint this node a device for an account that already lives somewhere else -
|
|
183
|
+
* the first half of pairing, run on the joining node.
|
|
184
|
+
*
|
|
185
|
+
* Publishes nothing and needs no key: it produces the device id, the two
|
|
186
|
+
* public keys and the signature that the account holder's
|
|
187
|
+
* {@link completeAccountPairing} certifies, plus a code to read out to them
|
|
188
|
+
* over a channel the payload does not travel on. Until that second half runs,
|
|
189
|
+
* the device this mints is inert.
|
|
190
|
+
*
|
|
191
|
+
* Takes a set of namespaces rather than one, and takes it from the caller
|
|
192
|
+
* because this node cannot discover it: a node that is a member of nothing can
|
|
193
|
+
* neither read the account's namespace set off a DAG nor derive it. One device
|
|
194
|
+
* covers however many are named - the certificate is over the account, not a
|
|
195
|
+
* scope - so there is one id and one code to hand over regardless.
|
|
196
|
+
*/
|
|
197
|
+
initAccountPairing(request: AccountPairInitRequest): Promise<AccountPairInitResponseData>;
|
|
198
|
+
/**
|
|
199
|
+
* Certify a device another node minted, link it, and deliver its scope keys -
|
|
200
|
+
* the second half of pairing, run on the node that holds the account root.
|
|
201
|
+
*
|
|
202
|
+
* Every field but `applications` is copied verbatim out of that node's
|
|
203
|
+
* {@link initAccountPairing} answer. Only this side can complete it: the
|
|
204
|
+
* certificate is signed by the account root, which never leaves the node that
|
|
205
|
+
* holds it.
|
|
206
|
+
*
|
|
207
|
+
* The scope is named in applications, not namespaces, because that is the
|
|
208
|
+
* question a person can answer - a namespace is an implementation unit they
|
|
209
|
+
* never chose. Leave it out to grant every application.
|
|
210
|
+
*/
|
|
211
|
+
completeAccountPairing(request: AccountPairCompleteRequest): Promise<AccountPairCompleteResponseData>;
|
|
212
|
+
/**
|
|
213
|
+
* Re-run the pairing fan-out for a device this account already certified,
|
|
214
|
+
* against the namespaces this node takes part in now.
|
|
215
|
+
*
|
|
216
|
+
* Pairing is a snapshot, and this is how it is repeated. A namespace created
|
|
217
|
+
* or joined afterwards holds no binding for a device paired before it, and the
|
|
218
|
+
* symptom is silence - the device simply never sees that namespace. Nothing
|
|
219
|
+
* but the id is needed to repair it: the certificate is already held here,
|
|
220
|
+
* root-signed and naming no namespace, so a fresh endorsement and a key wrap
|
|
221
|
+
* are all a later namespace is missing. The device does not have to be online.
|
|
222
|
+
*
|
|
223
|
+
* Passing `applications` widens the device's stored scope as well as
|
|
224
|
+
* repairing. Passing none - or an empty list - repairs against the scope
|
|
225
|
+
* already stored, which is deliberately NOT the "every application" that an
|
|
226
|
+
* empty list means on {@link completeAccountPairing}: overloading it here
|
|
227
|
+
* would make the accidental request the widest one.
|
|
228
|
+
*/
|
|
229
|
+
relinkAccountDevice(deviceId: string, request?: RelinkDeviceRequest): Promise<RelinkDeviceResponseData>;
|
|
230
|
+
/**
|
|
231
|
+
* Every device of this account, as this node sees them - its own included.
|
|
232
|
+
*
|
|
233
|
+
* Joined from the node-local certificate cache and the live bindings of every
|
|
234
|
+
* namespace this node takes part in, so it is this node's view rather than a
|
|
235
|
+
* global one: a device certified by another holder appears with an empty
|
|
236
|
+
* `applications`, because the certificate that would name its scope is not
|
|
237
|
+
* cached here.
|
|
238
|
+
*
|
|
239
|
+
* The wire wraps this in `devices` rather than the usual `data`; the array is
|
|
240
|
+
* what a caller wants, so that wrapper is not passed on.
|
|
241
|
+
*/
|
|
242
|
+
listAccountDevices(): Promise<AccountDeviceEntry[]>;
|
|
243
|
+
/**
|
|
244
|
+
* Every application this account speaks in, with the namespaces targeting each.
|
|
245
|
+
*
|
|
246
|
+
* What a device-scoping UI lists: {@link completeAccountPairing} and
|
|
247
|
+
* {@link relinkAccountDevice} both take applications, and this is where the
|
|
248
|
+
* ids they take come from. Derived from the namespaces this node takes part
|
|
249
|
+
* in, so an application installed with no namespace yet is absent - it has
|
|
250
|
+
* nothing to scope a device to until one exists.
|
|
251
|
+
*
|
|
252
|
+
* Wrapped in `applications` on the wire rather than `data`, unwrapped here for
|
|
253
|
+
* the same reason {@link listAccountDevices} unwraps `devices`.
|
|
254
|
+
*/
|
|
255
|
+
listAccountApplications(): Promise<AccountApplicationEntry[]>;
|
|
256
|
+
/**
|
|
257
|
+
* Withdraw a device from this account, terminally.
|
|
258
|
+
*
|
|
259
|
+
* Two authorities reach the same endpoint. An admin may revoke any device and
|
|
260
|
+
* rotates the scope key as it goes. The account holder may revoke its own with
|
|
261
|
+
* a root-signed `proof`, which does not rotate - so read
|
|
262
|
+
* {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the
|
|
263
|
+
* device lost its access: a namespace reporting `keyRotated: false` has
|
|
264
|
+
* stopped the device writing but leaves it able to read until an admin
|
|
265
|
+
* rotates.
|
|
266
|
+
*
|
|
267
|
+
* `namespaceId` names where to publish from, not the extent of the revocation:
|
|
268
|
+
* a device belongs to the account, so every namespace holding a binding for it
|
|
269
|
+
* is withdrawn from and reported back.
|
|
270
|
+
*/
|
|
271
|
+
revokeAccountDevice(namespaceId: string, request: RevokeAccountDeviceRequest): Promise<RevokeAccountDeviceResponseData>;
|
|
181
272
|
getGroupInfo(groupId: string): Promise<GroupInfoResponseData>;
|
|
182
273
|
/** Thin wrapper over {@link getGroupInfo}: returns the group's `defaultCapabilities` bitmask. */
|
|
183
274
|
getDefaultCapabilities(groupId: string): Promise<number>;
|
|
@@ -486,6 +486,112 @@ export class AdminApiClient {
|
|
|
486
486
|
async listNamespaceGroups(namespaceId) {
|
|
487
487
|
return unwrap(await this.httpClient.get(`/admin-api/namespaces/${namespaceId}/groups`));
|
|
488
488
|
}
|
|
489
|
+
// ---- Account Devices & Pairing ----
|
|
490
|
+
/**
|
|
491
|
+
* Mint this node a device for an account that already lives somewhere else -
|
|
492
|
+
* the first half of pairing, run on the joining node.
|
|
493
|
+
*
|
|
494
|
+
* Publishes nothing and needs no key: it produces the device id, the two
|
|
495
|
+
* public keys and the signature that the account holder's
|
|
496
|
+
* {@link completeAccountPairing} certifies, plus a code to read out to them
|
|
497
|
+
* over a channel the payload does not travel on. Until that second half runs,
|
|
498
|
+
* the device this mints is inert.
|
|
499
|
+
*
|
|
500
|
+
* Takes a set of namespaces rather than one, and takes it from the caller
|
|
501
|
+
* because this node cannot discover it: a node that is a member of nothing can
|
|
502
|
+
* neither read the account's namespace set off a DAG nor derive it. One device
|
|
503
|
+
* covers however many are named - the certificate is over the account, not a
|
|
504
|
+
* scope - so there is one id and one code to hand over regardless.
|
|
505
|
+
*/
|
|
506
|
+
async initAccountPairing(request) {
|
|
507
|
+
return unwrap(await this.httpClient.post('/admin-api/account/pair-init', request));
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Certify a device another node minted, link it, and deliver its scope keys -
|
|
511
|
+
* the second half of pairing, run on the node that holds the account root.
|
|
512
|
+
*
|
|
513
|
+
* Every field but `applications` is copied verbatim out of that node's
|
|
514
|
+
* {@link initAccountPairing} answer. Only this side can complete it: the
|
|
515
|
+
* certificate is signed by the account root, which never leaves the node that
|
|
516
|
+
* holds it.
|
|
517
|
+
*
|
|
518
|
+
* The scope is named in applications, not namespaces, because that is the
|
|
519
|
+
* question a person can answer - a namespace is an implementation unit they
|
|
520
|
+
* never chose. Leave it out to grant every application.
|
|
521
|
+
*/
|
|
522
|
+
async completeAccountPairing(request) {
|
|
523
|
+
return unwrap(await this.httpClient.post('/admin-api/account/pair-complete', request));
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Re-run the pairing fan-out for a device this account already certified,
|
|
527
|
+
* against the namespaces this node takes part in now.
|
|
528
|
+
*
|
|
529
|
+
* Pairing is a snapshot, and this is how it is repeated. A namespace created
|
|
530
|
+
* or joined afterwards holds no binding for a device paired before it, and the
|
|
531
|
+
* symptom is silence - the device simply never sees that namespace. Nothing
|
|
532
|
+
* but the id is needed to repair it: the certificate is already held here,
|
|
533
|
+
* root-signed and naming no namespace, so a fresh endorsement and a key wrap
|
|
534
|
+
* are all a later namespace is missing. The device does not have to be online.
|
|
535
|
+
*
|
|
536
|
+
* Passing `applications` widens the device's stored scope as well as
|
|
537
|
+
* repairing. Passing none - or an empty list - repairs against the scope
|
|
538
|
+
* already stored, which is deliberately NOT the "every application" that an
|
|
539
|
+
* empty list means on {@link completeAccountPairing}: overloading it here
|
|
540
|
+
* would make the accidental request the widest one.
|
|
541
|
+
*/
|
|
542
|
+
async relinkAccountDevice(deviceId, request) {
|
|
543
|
+
return unwrap(await this.httpClient.post(`/admin-api/account/devices/${deviceId}/relink`, request ?? {}));
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Every device of this account, as this node sees them - its own included.
|
|
547
|
+
*
|
|
548
|
+
* Joined from the node-local certificate cache and the live bindings of every
|
|
549
|
+
* namespace this node takes part in, so it is this node's view rather than a
|
|
550
|
+
* global one: a device certified by another holder appears with an empty
|
|
551
|
+
* `applications`, because the certificate that would name its scope is not
|
|
552
|
+
* cached here.
|
|
553
|
+
*
|
|
554
|
+
* The wire wraps this in `devices` rather than the usual `data`; the array is
|
|
555
|
+
* what a caller wants, so that wrapper is not passed on.
|
|
556
|
+
*/
|
|
557
|
+
async listAccountDevices() {
|
|
558
|
+
const response = await this.httpClient.get('/admin-api/account/devices');
|
|
559
|
+
return response.devices;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Every application this account speaks in, with the namespaces targeting each.
|
|
563
|
+
*
|
|
564
|
+
* What a device-scoping UI lists: {@link completeAccountPairing} and
|
|
565
|
+
* {@link relinkAccountDevice} both take applications, and this is where the
|
|
566
|
+
* ids they take come from. Derived from the namespaces this node takes part
|
|
567
|
+
* in, so an application installed with no namespace yet is absent - it has
|
|
568
|
+
* nothing to scope a device to until one exists.
|
|
569
|
+
*
|
|
570
|
+
* Wrapped in `applications` on the wire rather than `data`, unwrapped here for
|
|
571
|
+
* the same reason {@link listAccountDevices} unwraps `devices`.
|
|
572
|
+
*/
|
|
573
|
+
async listAccountApplications() {
|
|
574
|
+
const response = await this.httpClient.get('/admin-api/account/applications');
|
|
575
|
+
return response.applications;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Withdraw a device from this account, terminally.
|
|
579
|
+
*
|
|
580
|
+
* Two authorities reach the same endpoint. An admin may revoke any device and
|
|
581
|
+
* rotates the scope key as it goes. The account holder may revoke its own with
|
|
582
|
+
* a root-signed `proof`, which does not rotate - so read
|
|
583
|
+
* {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the
|
|
584
|
+
* device lost its access: a namespace reporting `keyRotated: false` has
|
|
585
|
+
* stopped the device writing but leaves it able to read until an admin
|
|
586
|
+
* rotates.
|
|
587
|
+
*
|
|
588
|
+
* `namespaceId` names where to publish from, not the extent of the revocation:
|
|
589
|
+
* a device belongs to the account, so every namespace holding a binding for it
|
|
590
|
+
* is withdrawn from and reported back.
|
|
591
|
+
*/
|
|
592
|
+
async revokeAccountDevice(namespaceId, request) {
|
|
593
|
+
return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/account/revoke`, request));
|
|
594
|
+
}
|
|
489
595
|
// ---- Group Management ----
|
|
490
596
|
async getGroupInfo(groupId) {
|
|
491
597
|
return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}`));
|
|
@@ -441,6 +441,18 @@ export interface NodeIdentity {
|
|
|
441
441
|
* claim something the node the caller chose may not report.
|
|
442
442
|
*/
|
|
443
443
|
accountRootPublicKey?: string;
|
|
444
|
+
/**
|
|
445
|
+
* Whether this node holds the root key of the account it speaks for. `false`
|
|
446
|
+
* means it runs on a delegate device key, so it cannot certify another device
|
|
447
|
+
* into the account — which is what a pairing invite needs to know before
|
|
448
|
+
* offering the option.
|
|
449
|
+
*
|
|
450
|
+
* Optional for the same reason as `accountRootPublicKey`: a node at or below
|
|
451
|
+
* `0.11.0-rc.30` does not send it. `undefined` is therefore "this node is too
|
|
452
|
+
* old to say", which is not the same answer as `false`, and a caller gating an
|
|
453
|
+
* invite on it should not collapse the two.
|
|
454
|
+
*/
|
|
455
|
+
holdsAccountRoot?: boolean;
|
|
444
456
|
}
|
|
445
457
|
/**
|
|
446
458
|
* @deprecated Use {@link AdminApiClient.getNodeIdentity} instead. Nothing here
|
|
@@ -530,6 +542,330 @@ export interface SubgroupEntry {
|
|
|
530
542
|
groupId: string;
|
|
531
543
|
name?: string;
|
|
532
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Adopt an account that already lives on another device, and mint this node a
|
|
547
|
+
* device of its own for it.
|
|
548
|
+
*
|
|
549
|
+
* The first half of pairing, run on the joining node. It publishes nothing and
|
|
550
|
+
* needs no key: it produces the values the account holder's
|
|
551
|
+
* {@link AdminApiClient.completeAccountPairing} certifies, plus a confirmation
|
|
552
|
+
* code to read out to them.
|
|
553
|
+
*
|
|
554
|
+
* Account-level, and that is the whole point of it: both credentials pairing
|
|
555
|
+
* mints were always account-wide - the certificate is root-signed and the
|
|
556
|
+
* endorsement node-level, so neither ever named a namespace - while the older
|
|
557
|
+
* per-namespace route still made the caller name one, and the device then
|
|
558
|
+
* listened on that one topic while its holder's link fanned out across all of
|
|
559
|
+
* them.
|
|
560
|
+
*/
|
|
561
|
+
export interface AccountPairInitRequest {
|
|
562
|
+
/**
|
|
563
|
+
* The epoch-0 root **public** key of the account to join, 64 hex characters -
|
|
564
|
+
* exactly what {@link NodeIdentity.accountRootPublicKey} reports on the node
|
|
565
|
+
* that already holds the account.
|
|
566
|
+
*
|
|
567
|
+
* Named for the half it carries. An ed25519 private and public key are both 32
|
|
568
|
+
* bytes and both hex, so nothing but the name tells them apart; the private
|
|
569
|
+
* root never crosses this boundary at all.
|
|
570
|
+
*/
|
|
571
|
+
accountRootPublicKey: string;
|
|
572
|
+
/**
|
|
573
|
+
* Ids of the namespaces to enroll into, 64 hex characters each. At least one:
|
|
574
|
+
* a device certified into nothing listens on no topic.
|
|
575
|
+
*
|
|
576
|
+
* The caller has to supply these, because the joining node cannot discover
|
|
577
|
+
* them - it is a member of nothing and holds no scope key, so it can neither
|
|
578
|
+
* read the account's namespace set off a DAG nor derive it. The device that
|
|
579
|
+
* already holds the account is the only party that knows it.
|
|
580
|
+
*
|
|
581
|
+
* This decides what the new device *listens* on, and it does not have to agree
|
|
582
|
+
* with the applications the holder scopes `pair-complete` to: a binding
|
|
583
|
+
* published where the device is not listening is picked up whenever it does
|
|
584
|
+
* subscribe, and a subscription the holder never reaches costs nothing.
|
|
585
|
+
*/
|
|
586
|
+
namespaces: string[];
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* What the joining device minted, for the account holder to certify.
|
|
590
|
+
*
|
|
591
|
+
* These are round-trip tokens: a caller copies them verbatim into
|
|
592
|
+
* {@link AdminApiClient.completeAccountPairing}. The signing key is the NEW
|
|
593
|
+
* device's, so it appears in no member listing yet and there is nothing here to
|
|
594
|
+
* compare it against.
|
|
595
|
+
*
|
|
596
|
+
* One device is minted however many namespaces were named, so there is one of
|
|
597
|
+
* each of these to hand over, not one per namespace.
|
|
598
|
+
*/
|
|
599
|
+
export interface AccountPairInitResponseData {
|
|
600
|
+
/** The account this device will speak for once linked, 64 hex characters. */
|
|
601
|
+
accountId: string;
|
|
602
|
+
/** The device that was minted, 64 hex characters. */
|
|
603
|
+
deviceId: string;
|
|
604
|
+
/** X25519 agreement key a scope key must be wrapped under to reach this device, hex. */
|
|
605
|
+
kemPublicKey: string;
|
|
606
|
+
/**
|
|
607
|
+
* The Ed25519 key this device signs its ops with, hex.
|
|
608
|
+
*
|
|
609
|
+
* The account holder cannot derive this - it is minted here - and the
|
|
610
|
+
* certificate names it, so it has to travel with the other two.
|
|
611
|
+
*/
|
|
612
|
+
signPublicKey: string;
|
|
613
|
+
/**
|
|
614
|
+
* Ed25519 signature over the account, the device id and both keys above, hex.
|
|
615
|
+
*
|
|
616
|
+
* Carried so the three values arrive as a statement by the device that minted
|
|
617
|
+
* them rather than as assertions by whoever relayed them; `pair-complete`
|
|
618
|
+
* refuses without it.
|
|
619
|
+
*/
|
|
620
|
+
statement: string;
|
|
621
|
+
/**
|
|
622
|
+
* The value to read out to the account holder, who compares it against what
|
|
623
|
+
* their `pair-complete` reports.
|
|
624
|
+
*
|
|
625
|
+
* The part a substituting attacker cannot fake: it can re-sign its own
|
|
626
|
+
* statement, but it would have to make its own keys derive the code the other
|
|
627
|
+
* side is already reading.
|
|
628
|
+
*/
|
|
629
|
+
confirmationCode: string;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Certify a device another node minted, link it, and deliver its scope keys.
|
|
633
|
+
*
|
|
634
|
+
* The second half of pairing, run on the node that holds the account root - the
|
|
635
|
+
* only party that can sign the certificate that makes the device real. Every
|
|
636
|
+
* field but `applications` is copied verbatim from that other node's
|
|
637
|
+
* {@link AccountPairInitResponseData}.
|
|
638
|
+
*/
|
|
639
|
+
export interface AccountPairCompleteRequest {
|
|
640
|
+
/** The `deviceId` the other node minted, 64 hex characters. */
|
|
641
|
+
deviceId: string;
|
|
642
|
+
/** That device's X25519 agreement key, 64 hex characters. */
|
|
643
|
+
kemPublicKey: string;
|
|
644
|
+
/** That device's Ed25519 signing key, 64 hex characters. */
|
|
645
|
+
signPublicKey: string;
|
|
646
|
+
/**
|
|
647
|
+
* The signature from that node's pair-init, 128 hex characters (64 bytes).
|
|
648
|
+
*
|
|
649
|
+
* Not optional: without it the three values above are only claims by whoever
|
|
650
|
+
* sent them, and certifying those would make attacker-supplied keys a trusted
|
|
651
|
+
* device of this account.
|
|
652
|
+
*/
|
|
653
|
+
statement: string;
|
|
654
|
+
/**
|
|
655
|
+
* The code the account holder read off the pairing device, e.g.
|
|
656
|
+
* `7BC0-DAAC-CCB4-84A4`. Grouping and case are ignored.
|
|
657
|
+
*
|
|
658
|
+
* Required so the comparison cannot be skipped: this side re-derives the code
|
|
659
|
+
* for the key material that actually arrived and refuses a mismatch. Its value
|
|
660
|
+
* rests on the code reaching the holder independently of this payload - sent
|
|
661
|
+
* beside the keys, it proves nothing. One code covers the whole pairing,
|
|
662
|
+
* because one device was minted for it.
|
|
663
|
+
*/
|
|
664
|
+
confirmationCode: string;
|
|
665
|
+
/**
|
|
666
|
+
* Which applications this device may speak for, 64 hex each. Omitted or empty means
|
|
667
|
+
* every one of them.
|
|
668
|
+
*
|
|
669
|
+
* Scoped by application rather than by namespace because a person can answer
|
|
670
|
+
* "which apps may this device use" and cannot answer "which namespaces" - a
|
|
671
|
+
* namespace is an implementation unit they never named. The node resolves
|
|
672
|
+
* these to namespaces through the same lookup
|
|
673
|
+
* {@link AdminApiClient.listNamespacesForApplication} reads.
|
|
674
|
+
*/
|
|
675
|
+
applications?: string[];
|
|
676
|
+
}
|
|
677
|
+
/** What pairing established. */
|
|
678
|
+
export interface AccountPairCompleteResponseData {
|
|
679
|
+
/** The account the device now speaks for, 64 hex characters. */
|
|
680
|
+
accountId: string;
|
|
681
|
+
/** The device that was linked, 64 hex characters. */
|
|
682
|
+
deviceId: string;
|
|
683
|
+
/**
|
|
684
|
+
* Whether the current scope key was wrapped and published for the device.
|
|
685
|
+
*
|
|
686
|
+
* `false` does not mean pairing failed - the link is what confers authority,
|
|
687
|
+
* and the device's own sync pull re-requests the key. It does mean the device
|
|
688
|
+
* cannot read until that lands.
|
|
689
|
+
*/
|
|
690
|
+
keyDelivered: boolean;
|
|
691
|
+
/**
|
|
692
|
+
* The code for the key material this certified - the same value the request
|
|
693
|
+
* carried, echoed so the operator can see what the certificate names.
|
|
694
|
+
*/
|
|
695
|
+
confirmationCode: string;
|
|
696
|
+
/**
|
|
697
|
+
* The `AccountProof<DeviceCert>` this pairing minted, hex-encoded borsh.
|
|
698
|
+
*
|
|
699
|
+
* The certified device needs this to present itself as a device of the
|
|
700
|
+
* account, and cannot read it off the DAG: doing so means being a member of a
|
|
701
|
+
* group the account speaks in, which a thin client never is. Not a secret - a
|
|
702
|
+
* certificate is public and proves nothing without the device key it names.
|
|
703
|
+
*/
|
|
704
|
+
credential: string;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Repair or widen the reach of a device this account already certified.
|
|
708
|
+
*
|
|
709
|
+
* Pairing is a snapshot: it bound the device wherever this node took part at the
|
|
710
|
+
* time, so a namespace created or joined afterwards holds no binding for it and
|
|
711
|
+
* the paired device silently never sees that namespace. This re-runs the fan-out
|
|
712
|
+
* against the namespaces this node takes part in now. The device need not be
|
|
713
|
+
* online, and nothing but its id is required - the certificate is already held
|
|
714
|
+
* here, root-signed and naming no namespace, so a fresh endorsement and a key
|
|
715
|
+
* wrap are all a later namespace is missing.
|
|
716
|
+
*/
|
|
717
|
+
export interface RelinkDeviceRequest {
|
|
718
|
+
/**
|
|
719
|
+
* Applications to add to the device's stored scope, 64 hex each.
|
|
720
|
+
*
|
|
721
|
+
* **Omitted or empty changes nothing** and repairs against the scope already
|
|
722
|
+
* stored, which is the request an operator makes to heal drift. Note that this
|
|
723
|
+
* is the one place an empty list does not mean "all": widening a narrow scope
|
|
724
|
+
* to every application is deliberately not expressible here, because
|
|
725
|
+
* overloading the empty list would make the accidental request the widest one.
|
|
726
|
+
*/
|
|
727
|
+
applications?: string[];
|
|
728
|
+
}
|
|
729
|
+
/** One namespace the relink published the device's link into. */
|
|
730
|
+
export interface RelinkOutcomeEntry {
|
|
731
|
+
/** The namespace id, 64 hex characters. */
|
|
732
|
+
namespaceId: string;
|
|
733
|
+
/**
|
|
734
|
+
* Whether the scope key was wrapped and published for the device here.
|
|
735
|
+
*
|
|
736
|
+
* `false` means the link landed and the delivery did not; the link is what
|
|
737
|
+
* confers authority, and the device's own sync pull re-requests the key.
|
|
738
|
+
*/
|
|
739
|
+
keyDelivered: boolean;
|
|
740
|
+
}
|
|
741
|
+
/** One namespace the relink published nothing into, and why. */
|
|
742
|
+
export interface RelinkSkipEntry {
|
|
743
|
+
/** The namespace id, 64 hex characters. */
|
|
744
|
+
namespaceId: string;
|
|
745
|
+
/**
|
|
746
|
+
* Why nothing was published there. Currently one of `outOfScope`,
|
|
747
|
+
* `alreadyBound`, `noScopeKey`, `revoked`, `ownDevice`, `failed`; left as a
|
|
748
|
+
* string because a node may report a reason newer than this SDK.
|
|
749
|
+
*/
|
|
750
|
+
reason: string;
|
|
751
|
+
}
|
|
752
|
+
/** What the relink repaired, and what it left alone. */
|
|
753
|
+
export interface RelinkDeviceResponseData {
|
|
754
|
+
/** The account the device speaks for, 64 hex characters. */
|
|
755
|
+
accountId: string;
|
|
756
|
+
/** The device that was repaired, 64 hex characters. */
|
|
757
|
+
deviceId: string;
|
|
758
|
+
/**
|
|
759
|
+
* The device's scope after the request, 64 hex each. Empty means every
|
|
760
|
+
* application, which is what a pairing that named none asked for.
|
|
761
|
+
*/
|
|
762
|
+
applications: string[];
|
|
763
|
+
/**
|
|
764
|
+
* Namespaces the link was published into by this call. Reported per namespace
|
|
765
|
+
* because publication is per-DAG, so which namespaces a device actually
|
|
766
|
+
* reached is a state the caller has to be able to see.
|
|
767
|
+
*/
|
|
768
|
+
linkedIn: RelinkOutcomeEntry[];
|
|
769
|
+
/** Namespaces nothing was published into. */
|
|
770
|
+
skipped: RelinkSkipEntry[];
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* One device of this account, joined from the node-local certificate cache and
|
|
774
|
+
* the live bindings of every namespace this node takes part in.
|
|
775
|
+
*/
|
|
776
|
+
export interface AccountDeviceEntry {
|
|
777
|
+
/** This device's id, 64 hex characters. */
|
|
778
|
+
deviceId: string;
|
|
779
|
+
/** The key this device signs its ops with, 64 hex. */
|
|
780
|
+
signingKey: string;
|
|
781
|
+
/** Set only on the device this node itself presents. */
|
|
782
|
+
isSelf: boolean;
|
|
783
|
+
revoked: boolean;
|
|
784
|
+
/**
|
|
785
|
+
* Applications this device may speak for, 64 hex each. **Empty means every
|
|
786
|
+
* application**, the same convention the stored certificate uses - and the
|
|
787
|
+
* opposite of what an empty {@link RelinkDeviceRequest.applications} asks for.
|
|
788
|
+
* Empty also for a device this node holds no cached certificate for: one bound
|
|
789
|
+
* before the cache existed, or certified by another holder.
|
|
790
|
+
*/
|
|
791
|
+
applications: string[];
|
|
792
|
+
/**
|
|
793
|
+
* Ids of the namespaces currently holding a live binding for this device, 64
|
|
794
|
+
* hex characters each. Empty for a certified device not yet bound anywhere.
|
|
795
|
+
*/
|
|
796
|
+
namespaces: string[];
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* One application this account speaks in, derived from the namespaces this node
|
|
800
|
+
* takes part in that target it.
|
|
801
|
+
*
|
|
802
|
+
* An application installed with no namespace yet is absent here: it has no
|
|
803
|
+
* cross-device meaning until a namespace exists, so there is nothing to scope a
|
|
804
|
+
* device to.
|
|
805
|
+
*/
|
|
806
|
+
export interface AccountApplicationEntry {
|
|
807
|
+
/** The application id, 64 hex. */
|
|
808
|
+
applicationId: string;
|
|
809
|
+
/** Ids of the namespaces targeting it, 64 hex characters each. */
|
|
810
|
+
namespaces: string[];
|
|
811
|
+
}
|
|
812
|
+
/** Withdraw a device from an account, terminally. */
|
|
813
|
+
export interface RevokeAccountDeviceRequest {
|
|
814
|
+
/** The device to withdraw, 64 hex. */
|
|
815
|
+
deviceId: string;
|
|
816
|
+
/**
|
|
817
|
+
* A hex-encoded, borsh-serialized signed revocation minted elsewhere -
|
|
818
|
+
* the output of `merod account revoke-proof`.
|
|
819
|
+
*
|
|
820
|
+
* The lost-device path: the account root that owns the device is not on this
|
|
821
|
+
* node, so the proof is signed offline and this node only publishes it. Omit
|
|
822
|
+
* it and the node mints its own proof if it owns the account, and otherwise
|
|
823
|
+
* revokes as an admin.
|
|
824
|
+
*
|
|
825
|
+
* Not a credential and not a secret - it authorises this one revocation of
|
|
826
|
+
* this one device, and only alongside a stored binding naming the same
|
|
827
|
+
* account.
|
|
828
|
+
*/
|
|
829
|
+
proof?: string;
|
|
830
|
+
}
|
|
831
|
+
/** What a revocation withdrew in one namespace. */
|
|
832
|
+
export interface RevocationOutcome {
|
|
833
|
+
/** The namespace, 64 hex. */
|
|
834
|
+
namespaceId: string;
|
|
835
|
+
/**
|
|
836
|
+
* Whether the scope key rotated in the same op, in THIS namespace.
|
|
837
|
+
*
|
|
838
|
+
* `false` means the device stopped writing there at once but still holds the
|
|
839
|
+
* key it had, so it can keep READING until an admin rotates. Only an admin
|
|
840
|
+
* may rotate and an account holder revoking their own device usually is not
|
|
841
|
+
* one, so this is commonly owed rather than exceptional.
|
|
842
|
+
*/
|
|
843
|
+
keyRotated: boolean;
|
|
844
|
+
}
|
|
845
|
+
export interface RevokeAccountDeviceResponseData {
|
|
846
|
+
/** The account the device spoke for, 64 hex. */
|
|
847
|
+
accountId: string;
|
|
848
|
+
/** The device that was withdrawn, 64 hex. */
|
|
849
|
+
deviceId: string;
|
|
850
|
+
/**
|
|
851
|
+
* Whether the scope key rotated in the namespace named in the request.
|
|
852
|
+
*
|
|
853
|
+
* {@link revokedIn} is the full picture; prefer it. This reports only the one
|
|
854
|
+
* namespace the caller asked about and is retained because core keeps it for
|
|
855
|
+
* a released `calimero-client-py` wheel that requires the field.
|
|
856
|
+
*/
|
|
857
|
+
keyRotated: boolean;
|
|
858
|
+
/**
|
|
859
|
+
* Every namespace the revocation was published into.
|
|
860
|
+
*
|
|
861
|
+
* A device belongs to an account rather than to a scope, so revoking it
|
|
862
|
+
* withdraws it from every namespace holding a binding for it - not only the
|
|
863
|
+
* one named in the request. Per namespace because publication is per-DAG: a
|
|
864
|
+
* namespace absent here did not receive the op, and a partially propagated
|
|
865
|
+
* revocation is a state the caller has to be able to see.
|
|
866
|
+
*/
|
|
867
|
+
revokedIn: RevocationOutcome[];
|
|
868
|
+
}
|
|
533
869
|
export interface CreateGroupRequest {
|
|
534
870
|
applicationId: string;
|
|
535
871
|
groupId?: string;
|