import type { KeyType, KeyProperties, NotificationEndpointConfiguration, PageOpts, UserInOrgInfo, ApiClient, OrgInfo, MfaId, ImportKeyRequest, KeyPolicy, QueryMetricsResponse, OrgMetricName, QueryMetricsRequest, KeyTypeAndDerivationPath, JsonValue, EditPolicy, AddressMap, CreateOrgRequest, MemberRole, RolePolicy, C2FConfiguration, MfaProtectedAction, MfaType, PolicyType, PolicyAcl, ContactLabel, ContactAddressData, OrgExtProps, OrgExtData, AuditLogEntry, AuditLogRequest, MfaReceipts, InvitationInfo, ListUsersOptions, ListInvitationsOptions, } from "./index.ts"; import { Contact } from "./contact.ts"; import { C2FFunction, Key, MfaRequest, Role } from "./index.ts"; import { type NamedKeyPolicy, NamedPolicy, type NamedRolePolicy, uploadWasmFunction, type C2FInfo, } from "./policy.ts"; /** Options pased to createKey and deriveKey */ export type CreateKeyProperties = Omit & { /** * Policies to apply to the new key. * * This type makes it possible to assign values like * `[AllowEip191SigningPolicy]`, but remains backwards * compatible with prior versions of the SDK, in which * this property had type `Record[] | null`. */ policy?: KeyPolicy | unknown[] | null; }; /** Options passed to importKey and deriveKey */ export type ImportDeriveKeyProperties = CreateKeyProperties & { /** * When true, returns a 'Key' object for both new and existing keys. */ idempotent?: boolean; }; /** Options passed to deriveMultipleKeyTypes */ export type DeriveMultipleKeyTypesProperties = ImportDeriveKeyProperties & { /** * The material_id of the mnemonic used to derive new keys. * * If this argument is undefined or null, a new mnemonic is first created * and any other specified properties are applied to it (in addition to * being applied to the specified keys). * * The newly created mnemonic-id can be retrieved from the `derivation_info` * property of the `KeyInfo` value for a resulting key. */ mnemonic_id?: string; }; /** Organization id */ export type OrgId = string; /** Org-wide policy */ export type OrgPolicy = | SourceIpAllowlistPolicy | OidcAuthSourcesPolicy | OriginAllowlistPolicy | MaxDailyUnstakePolicy | WebAuthnRelyingPartiesPolicy | ExclusiveKeyAccessPolicy; /** * Whether to enforce exclusive access to keys. Concretely, * - if "LimitToKeyOwner" is set, only key owners are permitted to access * their keys for signing: a user session (not a role session) is required * for signing, and adding a key to a role is not permitted. * - if "LimitToSingleRole" is set, each key is permitted to be in at most * one role, and signing is only allowed when authenticating using a role session token. */ export interface ExclusiveKeyAccessPolicy { ExclusiveKeyAccess: "LimitToKeyOwner" | "LimitToSingleRole"; } /** * The set of relying parties to allow for webauthn registration * These correspond to domains from which browsers can successfully create credentials. */ export interface WebAuthnRelyingPartiesPolicy { WebAuthnRelyingParties: { id?: string; name: string }[]; } /** * Provides an allowlist of OIDC Issuers and audiences that are allowed to authenticate into this org. * * @example {"OidcAuthSources": { "https://accounts.google.com": [ "1234.apps.googleusercontent.com" ]}} */ export interface OidcAuthSourcesPolicy { OidcAuthSources: Record; } /** OIDC issuer configuration */ export interface IssuerConfig { /** The set of audiences supported for this issuer */ auds: string[]; /** The kinds of user allowed to authenticate with this issuer */ users: MemberRole[]; /** Optional nickname for this provider */ nickname?: string; /** Whether to make this issuer public */ public?: boolean; } /** * Only allow requests from the specified origins. * * @example {"OriginAllowlist": "*"} */ export interface OriginAllowlistPolicy { OriginAllowlist: string[] | "*"; } /** * Restrict signing to specific source IP addresses. * * @example {"SourceIpAllowlist": ["10.1.2.3/8", "169.254.17.1/16"]} */ export interface SourceIpAllowlistPolicy { SourceIpAllowlist: string[]; } /** * Restrict the number of unstakes per day. * * @example {"MaxDailyUnstake": 5 } */ export interface MaxDailyUnstakePolicy { MaxDailyUnstake: number; } /** * Filter to use when listing keys */ export interface KeyFilter { /** Filter by key type */ type?: KeyType; /** Filter by key owner */ owner?: string; /** Search by key's material id and metadata */ search?: string; /** Pagination options */ page?: PageOpts; } /** * An organization. * * Extends {@link CubeSignerClient} and provides a few org-specific methods on top. */ export class Org { readonly #apiClient: ApiClient; #orgId: OrgId; /** The org information */ #data?: OrgInfo; /** * @returns The org id * @example Org#c3b9379c-4e8c-4216-bd0a-65ace53cf98f */ get id(): OrgId { return this.#orgId; } /** * @returns The cached properties of this org. The cached properties reflect the * state of the last fetch or update. */ get cached(): OrgInfo | undefined { return this.#data; } /** * Constructor. * * @param apiClient The API client to use. * @param orgId The id of the org */ constructor(apiClient: ApiClient, orgId: string) { this.#orgId = orgId; this.#apiClient = orgId === apiClient.orgId ? apiClient : apiClient.withTargetOrg(orgId); } /** * Create a new organization. The new org is a child of the * current org and inherits its key-export policy. The new org * is created with one owner, the caller of this API. * * @param nameOrRequest The name of the new org or the properties of the new org. * @returns Information about the newly created org. */ async createOrg(nameOrRequest: string | CreateOrgRequest): Promise { const req = typeof nameOrRequest === "string" ? { name: nameOrRequest } : nameOrRequest; if (!/^[a-zA-Z0-9_]{3,30}$/.test(req.name)) { throw new Error("Org name must be alphanumeric and between 3 and 30 characters"); } return await this.#apiClient.orgCreateOrg(req); } /** * Query org metrics. * * @param metricName The metric name. * @param startTime The start date in seconds since unix epoch. * @param opt Other optional arguments * @param opt.end_time The end date in seconds since unix epoch. If omitted, defaults to 'now'. * @param opt.period The granularity, in seconds, of the returned data points. * This value is automatically rounded up to a multiple of 3600 (i.e., 1 hour). * If omitted, defaults to the duration between the start and the end date. * Must be no less than 1 hour, i.e., 3600 seconds. Additionally, this period must not * divide the `endTime - startTime` period into more than 100 data points. * @param pageOpts Pagination options. * @returns Metric values (data points) for the requested periods. */ async queryMetrics( metricName: OrgMetricName, startTime: EpochTimeStamp, opt?: Omit, pageOpts?: PageOpts, ): Promise { const req: QueryMetricsRequest = { metric_name: metricName, ...opt, start_time: startTime, // Must set end_time before fetchAll: without it the backend defaults to now() // on each page request, and a changing window invalidates the pagination token. end_time: opt?.end_time ?? Math.floor(Date.now() / 1000), }; return await this.#apiClient.orgQueryMetrics(req, pageOpts).fetchAll(); } /** * Query the org audit log. * * @param startTime The start date in seconds since unix epoch. * @param opt Other optional arguments * @param opt.end_time The end date in seconds since unix epoch. Defaults to 'now'. * @param opt.events Filter by event name. If omitted, all events are included. * @param pageOpts Pagination options. Defaults to fetching the entire result set. * @returns Matching audit log entries. */ async queryAuditLog( startTime: EpochTimeStamp, opt?: Omit, pageOpts?: PageOpts, ): Promise { const req: AuditLogRequest = { ...opt, start_time: startTime, // Must set end_time before fetchAll: without it the backend defaults to now() // on each page request, and a changing window invalidates the pagination token. end_time: opt?.end_time ?? Math.floor(Date.now() / 1000), }; return await this.#apiClient.orgQueryAuditLog(req, pageOpts).fetchAll(); } /** * Fetch the org information. * * @returns The org information. */ async fetch(): Promise { this.#data = await this.#apiClient.orgGet(); return this.#data; } /** @returns The human-readable name for the org */ async name(): Promise { const data = await this.fetch(); return data.name ?? undefined; } /** @returns Whether the org is enabled */ async enabled(): Promise { const data = await this.fetch(); return data.enabled; } /** * Enable the org. * * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async enable(opts?: { mfaReceipt?: MfaReceipts }) { return await this.update({ enabled: true }, opts?.mfaReceipt); } /** * Disable the org. * * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async disable(opts?: { mfaReceipt?: MfaReceipts }) { return await this.update({ enabled: false }, opts?.mfaReceipt); } /** @returns the policy for the org. */ async policy(): Promise { const data = await this.fetch(); return (data.policy ?? []) as unknown as OrgPolicy[]; } /** @returns the sign policy for the org. */ async signPolicy(): Promise { const data = await this.fetch(); return (data.sign_policy ?? []) as unknown as RolePolicy; } /** * Set the policy for the org. * * @param policy The new policy for the org. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setPolicy(policy: OrgPolicy[], opts?: { mfaReceipt?: MfaReceipts }) { const p = policy as unknown as Record[]; return await this.update({ policy: p }, opts?.mfaReceipt); } /** * Set the edit policy for the org. * * @param editPolicy The new edit policy for the org. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setEditPolicy(editPolicy: EditPolicy, opts?: { mfaReceipt?: MfaReceipts }) { return await this.update({ edit_policy: editPolicy }, opts?.mfaReceipt); } /** * Set the sign policy for the org. * * This is a global sign policy that applies to every sign operation (every key, every role) in the org. * It is analogous to how role policies apply to all sign requests performed by the corresponding role sessions. * * @param policy The new policy for the org. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setSignPolicy(policy: RolePolicy, opts?: { mfaReceipt?: MfaReceipts }) { return await this.update({ sign_policy: policy }, opts?.mfaReceipt); } /** * Retrieve the organization's extended properties (uncommon features not used by most users). * * @returns The extended properties */ async getExtendedProperties(): Promise { const data = await this.fetch(); return data.ext_data ? data.ext_data : null; } /** * Update the organization's extended properties (uncommon features not used by most users). * * @param props The new properties. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setExtendedProperties(props: OrgExtProps, opts?: { mfaReceipt?: MfaReceipts }) { return await this.update({ ext_props: props }, opts?.mfaReceipt); } /** * Update the per-alien key count threshold, which, once exceeded, disallows further key creation by alien users. * * This setting is checked only when an alien user requests to create or import a new key. * In other words, org admins can still assign unlimited number of keys to their alien users. * * @param alienKeyCountThreshold The new key count threshold. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setAlienKeyCountThreshold( alienKeyCountThreshold: number, opts?: { mfaReceipt?: MfaReceipts }, ) { return await this.#updateExtProps((data) => { data.alien_key_count_threshold = alienKeyCountThreshold; }, opts); } /** * Update whether the alien users should be allowed to update their own key policies. * * @param aliensCanUpdateKeyPolicy Whether alien users should be allowed to update their own key policies. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setAliensCanUpdateKeyPolicy( aliensCanUpdateKeyPolicy: boolean, opts?: { mfaReceipt?: MfaReceipts }, ) { return await this.#updateExtProps((data) => { data.aliens_can_update_key_policy = aliensCanUpdateKeyPolicy; }, opts); } /** * Update select extended properties. * * @param update The update function * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async #updateExtProps(update: (data: OrgExtProps) => void, opts?: { mfaReceipt?: MfaReceipts }) { const data = { ...((await this.getExtendedProperties()) ?? {}) }; // erase the metadata that cannot be updated data.created = undefined; data.last_modified = undefined; // execute client-supplied update function update(data); return await this.update({ ext_props: data }, opts?.mfaReceipt); } /** * Set the notification endpoints for the org. * * @param notification_endpoints Endpoints. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setNotificationEndpoints( notification_endpoints: NotificationEndpointConfiguration[], opts?: { mfaReceipt?: MfaReceipts }, ) { return await this.update({ notification_endpoints }, opts?.mfaReceipt); } /** * Set required MFA types for actions implicitly requiring MFA (see {@link MfaProtectedAction}). * * @param allowed_mfa_types Assignment of MFA types to actions that implicitly require MFA. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setAllowedMfaTypes( allowed_mfa_types: Partial>, opts?: { mfaReceipt?: MfaReceipts }, ) { return await this.update({ allowed_mfa_types }, opts?.mfaReceipt); } /** * Create a new signing key. * * @param type The type of key to create. * @param ownerId The owner of the key. Defaults to the session's user. * @param props Additional properties to set on the new key. * @returns The new keys. */ async createKey(type: KeyType, ownerId?: string, props?: CreateKeyProperties): Promise { const keys = await this.#apiClient.keysCreate(type, 1, ownerId, props); return new Key(this.#apiClient, keys[0]); } /** * Create new signing keys. * * @param type The type of key to create. * @param count The number of keys to create. * @param ownerId The owner of the keys. Defaults to the session's user. * @param props Additional properties to set on the new keys. * @returns The new keys. */ async createKeys( type: KeyType, count: number, ownerId?: string, props?: CreateKeyProperties, ): Promise { const keys = await this.#apiClient.keysCreate(type, count, ownerId, props); return keys.map((k) => new Key(this.#apiClient, k)); } /** * Create a new (first-party) user in the organization and sends an invitation to that user. * * Same as {@link ApiClient.orgUserInvite}, see its documentation for more information. * * @returns A function that invites a user */ get createUser() { return this.#apiClient.orgUserInvite.bind(this.#apiClient); } /** * List all pending invitations in the organization, i.e., those that have * neither been accepted nor canceled, and have not expired. * * @param opts Pagination and filtering options. Defaults to fetching the entire result set. * @returns The list of pending invitations */ async invitations(opts?: ListInvitationsOptions): Promise { return await this.#apiClient.orgInvitationsList(opts).fetchAll(); } /** * List pending invitations in the organization (paginated). * * Same as {@link ApiClient.orgInvitationsList}, see its documentation for more information. * * @returns A function that returns a paginated list of pending invitations */ get invitationsPaginated() { return this.#apiClient.orgInvitationsList.bind(this.#apiClient); } /** * Cancel a pending invitation. * * Same as {@link ApiClient.orgInvitationCancel}, see its documentation for more information. * * @returns A function that cancels a pending invitation */ get cancelInvitation() { return this.#apiClient.orgInvitationCancel.bind(this.#apiClient); } /** * Delete an existing user. * * Same as {@link ApiClient.orgUserDelete}, see its documentation for more information. * * @returns A function that deletes a user */ get deleteUser() { return this.#apiClient.orgUserDelete.bind(this.#apiClient); } /** * Create a new OIDC user. This can be a first-party "Member" or third-party "Alien". * * Same as {@link ApiClient.orgUserCreateOidc}, see its documentation for more information. * * @returns A function that creates an OIDC user, resolving to the new user's ID */ get createOidcUser() { return this.#apiClient.orgUserCreateOidc.bind(this.#apiClient); } /** * Delete an existing OIDC user. * * Same as {@link ApiClient.orgUserDeleteOidc}, see its documentation for more information. * * @returns A function that deletes an OIDC user */ get deleteOidcUser() { return this.#apiClient.orgUserDeleteOidc.bind(this.#apiClient); } /** * Initiate an MFA reset for a user in the org. The reset is completed by * the user via {@link CubeSignerClient.resetUserMfaComplete}. * * Same as {@link ApiClient.resetUserMfaInit}, see its documentation for more information. * * @returns A function that initiates an MFA reset for a user */ get resetUserMfaInit() { return this.#apiClient.resetUserMfaInit.bind(this.#apiClient); } /** * List all users in the organization. * * @overload * @param opts Additional options for filtering the users. * @returns The list of users */ async users(opts?: ListUsersOptions): Promise; /** * List all users in the organization. * * @overload * @param searchQuery Query string. If defined, all returned users will contain this string in their name or email. * @returns The list of users * @deprecated Use the `ListUsersOptions` parameter overload instead. */ async users(searchQuery?: string): Promise; /** * List all users in the organization. * * @param optsOrSearchQuery Either additional options for filtering the users, or (deprecated) a search query string. * @returns The list of users */ async users(optsOrSearchQuery?: ListUsersOptions | string): Promise { const opts: ListUsersOptions = typeof optsOrSearchQuery === "string" ? { searchQuery: optsOrSearchQuery } : (optsOrSearchQuery ?? {}); return await this.#apiClient.orgUsersList(opts).fetchAll(); } /** * List users in the organization (paginated). * * Same as {@link ApiClient.orgUsersList}, see its documentation for more information. * * @returns A function that returns a paginated list of users */ get usersPaginated() { return this.#apiClient.orgUsersList.bind(this.#apiClient); } /** * Get user by id. * * Same as {@link ApiClient.orgUserGet}, see its documentation for more information. * * @returns A function that resolves to a user's info */ get getUser() { return this.#apiClient.orgUserGet.bind(this.#apiClient); } /** * Get user by email. * * Same as {@link ApiClient.orgUserGetByEmail}, see its documentation for more information. * * @returns A function that resolves to a user's info */ get getUserByEmail() { return this.#apiClient.orgUserGetByEmail.bind(this.#apiClient); } /** * Get user by OIDC ID. * * Same as {@link ApiClient.orgUserGetByOidc}, see its documentation for more information. * * @returns A function that resolves to a user's info */ get getUserByOidc() { return this.#apiClient.orgUserGetByOidc.bind(this.#apiClient); } /** * Enable a user in this org * * @param userId The user whose membership to enable * @returns The updated user's membership */ async enableUser(userId: string): Promise { return await this.#apiClient.orgUpdateUserMembership(userId, { disabled: false }); } /** * Disable a user in this org * * @param userId The user whose membership to disable * @returns The updated user's membership */ async disableUser(userId: string): Promise { return await this.#apiClient.orgUpdateUserMembership(userId, { disabled: true }); } /** * Get the accessible keys in the organization * * @param props Optional filtering properties. * @returns The keys. */ async keys(props?: KeyFilter): Promise { const paginator = this.#apiClient.keysList( props?.type, props?.page, props?.owner, props?.search, ); const keys = await paginator.fetch(); return keys.map((k) => new Key(this.#apiClient, k)); } /** * Create a new role. * * @param name The name of the role. * @returns The new role. */ async createRole(name?: string): Promise { const roleId = await this.#apiClient.roleCreate(name); const roleInfo = await this.#apiClient.roleGet(roleId); return new Role(this.#apiClient, roleInfo); } /** * Get a role by id or name. * * @param roleId The id or name of the role to get. * @returns The role. */ async getRole(roleId: string): Promise { const roleInfo = await this.#apiClient.roleGet(roleId); return new Role(this.#apiClient, roleInfo); } /** * Gets all the roles in the org * * @param page The paginator options * @returns The roles */ async roles(page: PageOpts): Promise { const roles = await this.#apiClient.rolesList(page).fetch(); return roles.map((r) => new Role(this.#apiClient, r)); } /** * Create a new named policy. * * @param name The name of the policy. * @param type The type of the policy. * @param rules The policy rules. * @param acl Optional list of policy access control entries. * @returns The new policy. */ async createPolicy( name: string, type: Type, rules: Type extends "Key" ? KeyPolicy : RolePolicy, acl?: PolicyAcl, ): Promise { const policyInfo = await this.#apiClient.policyCreate(name, type, rules, acl); const policy = NamedPolicy.fromInfo(this.#apiClient, policyInfo); return policy as Type extends "Key" ? NamedKeyPolicy : NamedRolePolicy; } /** * Get a named policy by id or name. * * @param policyId The id or name of the policy to get. * @returns The policy. */ async getPolicy(policyId: string): Promise { const policyInfo = await this.#apiClient.policyGet(policyId, "latest"); return NamedPolicy.fromInfo(this.#apiClient, policyInfo); } /** * Get a Confidential Cloud Function by name or named policy ID. * * @param functionId The name or named policy ID of the function to get. * @returns The C2F function. * @throws if name or ID is not associated to a C2F function (i.e. the name/id is for a key or role named policy) */ async getFunction(functionId: string): Promise { const functionInfo = await this.#apiClient.policyGet(functionId, "latest"); if (functionInfo.policy_type !== "Wasm") { throw new Error( `${functionId} is not a Wasm function, it is a ${functionInfo.policy_type} named policy`, ); } return new C2FFunction(this.#apiClient, functionInfo as C2FInfo); } /** * Gets all the named policies in the org. * * @param page Pagination options. Defaults to fetching the entire result set. * @param policyType The optional type of policies to fetch. Defaults to fetching all named policies regardless of type. * @returns The policies. */ async policies(page?: PageOpts, policyType?: PolicyType): Promise { const policies = await this.#apiClient.policiesList(page, policyType).fetch(); return policies.map((p) => NamedPolicy.fromInfo(this.#apiClient, p)); } /** * Gets all the C2F functions in the org. * * @param page The paginator options. * @returns The C2F functions. */ async functions(page?: PageOpts): Promise { const policies = await this.#apiClient.policiesList(page, "Wasm").fetch(); return policies.map((data) => new C2FFunction(this.#apiClient, data as C2FInfo)); } /** * Create a new Confidential Cloud Function. * * @param name The name of the function. * @param policy The Wasm function. * @param acl Optional list of policy access control entries. * @returns The C2F function */ async createWasmFunction( name: string, policy: Uint8Array, acl?: PolicyAcl, ): Promise { const hash = await uploadWasmFunction(this.#apiClient, policy); const policyInfo = await this.#apiClient.policyCreate( name, "Wasm", [ { hash, }, ], acl, ); return new C2FFunction(this.#apiClient, policyInfo as C2FInfo); } /** @returns the Confidential Cloud Functions configuration for the org. */ async c2fConfiguration(): Promise { const data = await this.fetch(); return data.policy_engine_configuration; } /** * Set the Confidential Cloud Functions configuration for the org. * Note that this overwrites any existing configuration. * * @param configs Confidential Cloud Functions configuration. * @param opts Optional parameters * @param opts.mfaReceipt Optional MFA receipts * @returns Org info */ async setC2FConfiguration(configs: C2FConfiguration, opts?: { mfaReceipt?: MfaReceipts }) { return await this.update( { policy_engine_configuration: configs, }, opts?.mfaReceipt, ); } /** * Derive a key of the given type using the given derivation path and mnemonic. * The owner of the derived key will be the owner of the mnemonic. * * @param type Type of key to derive from the mnemonic. * @param derivationPath Mnemonic derivation path used to generate new key. * @param mnemonicId material_id of mnemonic key used to derive the new key. * @param props Additional properties for derivation. * * @returns newly derived key or undefined if it already exists. */ async deriveKey( type: KeyType, derivationPath: string, mnemonicId: string, props?: ImportDeriveKeyProperties, ): Promise { return (await this.deriveKeys(type, [derivationPath], mnemonicId, props))[0]; } /** * Derive a set of keys of the given type using the given derivation paths and mnemonic. * * The owner of the derived keys will be the owner of the mnemonic. * * @param type Type of key to derive from the mnemonic. * @param derivationPaths Mnemonic derivation paths used to generate new key. * @param mnemonicId material_id of mnemonic key used to derive the new key. * @param props Additional properties for derivation. * * @returns newly derived keys. */ async deriveKeys( type: KeyType, derivationPaths: string[], mnemonicId: string, props?: ImportDeriveKeyProperties, ): Promise { const keys = await this.#apiClient.keysDerive(type, derivationPaths, mnemonicId, props); return keys.map((k) => new Key(this.#apiClient, k)); } /** * Use either a new or existing mnemonic to derive keys of one or more * specified types via specified derivation paths. * * @param keyTypesAndDerivationPaths A list of `KeyTypeAndDerivationPath` objects specifying the keys to be derived * @param props Additional options for derivation. * * @returns The newly derived keys. */ async deriveMultipleKeyTypes( keyTypesAndDerivationPaths: KeyTypeAndDerivationPath[], props?: DeriveMultipleKeyTypesProperties, ): Promise { const keys = await this.#apiClient.keysDeriveMulti(keyTypesAndDerivationPaths, props); return keys.map((k) => new Key(this.#apiClient, k)); } /** * Get a key by id. * * @param keyId The id of the key to get. * @returns The key. */ async getKey(keyId: string): Promise { const keyInfo = await this.#apiClient.keyGet(keyId); return new Key(this.#apiClient, keyInfo); } /** * Get a key by its material id (e.g., address). * * @param keyType The key type. * @param materialId The material id of the key to get. * @returns The key. */ async getKeyByMaterialId(keyType: KeyType, materialId: string): Promise { const keyInfo = await this.#apiClient.keyGetByMaterialId(keyType, materialId); return new Key(this.#apiClient, keyInfo); } /** * Create a contact. * * @param name The name for the new contact. * @param addresses The addresses associated with the contact. * @param metadata Metadata associated with the contact. Intended for use as a description. * @param editPolicy The edit policy for the contact, determining when and who can edit this contact. * @param labels The optional labels associated with the contact. * @returns The newly-created contact. */ async createContact( name: string, addresses?: AddressMap, metadata?: JsonValue, editPolicy?: EditPolicy, labels?: ContactLabel[], ): Promise { const contactInfo = await this.#apiClient.contactCreate( name, addresses, metadata, editPolicy, labels, ); return new Contact(this.#apiClient, contactInfo); } /** * Get a contact by its id. * * @param contactId The id of the contact to get. * @returns The contact. */ async getContact(contactId: string): Promise { const contactInfo = await this.#apiClient.contactGet(contactId); return new Contact(this.#apiClient, contactInfo); } /** * Get all contacts in the organization, optionally matching the search query. * * @param search The optional search query. Either: * - `label:...`, which will return contacts with the label provided after the ':', * - an exact address search, which returns contacts with the provided ContactAddressData, * - or an address prefix search, where all returned contacts will have an address starting with, or equaling, the given search string. * @returns All contacts. */ async contacts( search?: `label${ContactLabel}` | ContactAddressData | string, ): Promise { let contacts; if (search !== undefined && typeof search !== "string") { contacts = await this.#apiClient.contactLookupByAddress(search); } else { const paginator = this.#apiClient.contactsList(undefined, search); contacts = await paginator.fetch(); } return contacts.map((c) => new Contact(this.#apiClient, c)); } /** * Obtain a proof of authentication. * * Same as {@link ApiClient.identityProve}, see its documentation for more information. * * @returns A function that resolves to an identity proof */ get proveIdentity() { return this.#apiClient.identityProve.bind(this.#apiClient); } /** * Check if a given proof of OIDC authentication is valid. * * Same as {@link ApiClient.identityVerify}, see its documentation for more information. * * @returns A function that verifies a proof of identity, throwing if invalid */ get verifyIdentity() { return this.#apiClient.identityVerify.bind(this.#apiClient); } /** * Get a pending MFA request by its id. * * @param mfaId MFA request ID * @returns The MFA request */ getMfaRequest(mfaId: MfaId): MfaRequest { return new MfaRequest(this.#apiClient, mfaId); } /** * List pending MFA requests accessible to the current user. * * @param page Pagination options. Defaults to fetching the entire result set. * @returns The MFA requests. */ async mfaRequests(page?: PageOpts): Promise { return await this.#apiClient .mfaList(page) .fetch() .then((mfaInfos) => mfaInfos.map((mfaInfo) => new MfaRequest(this.#apiClient, mfaInfo))); } /** * Sign an Eth2/Beacon-chain deposit (or staking) message. * * Same as {@link ApiClient.signStake}, see its documentation for more information. * * @returns A function that resolves to a stake response. */ get stake() { return this.#apiClient.signStake.bind(this.#apiClient); } /** * Create new user session (management and/or signing). The lifetime of * the new session is silently truncated to that of the current session. * * Same as {@link ApiClient.sessionCreate}, see its documentation for more information. * * @returns A function that resolves to new signer session info. */ get createSession() { return this.#apiClient.sessionCreate.bind(this.#apiClient); } /** * Create new user session (management and/or signing) whose lifetime potentially * extends the lifetime of the current session. MFA is always required. * * Same as {@link ApiClient.sessionCreateExtended}, see its documentation for more information. * * @returns A function that resolves to new signer session info. */ get createExtendedSession() { return this.#apiClient.sessionCreateExtended.bind(this.#apiClient); } /** * Revoke a session. * * Same as {@link ApiClient.sessionRevoke}, see its documentation for more info. * * @returns A function that revokes a session */ get revokeSession() { return this.#apiClient.sessionRevoke.bind(this.#apiClient); } /** * Send a heartbeat / upcheck request. * * Same as {@link ApiClient.heartbeat}, see its documentation for more info. * * @returns A function that sends a heartbeat */ get heartbeat() { return this.#apiClient.heartbeat.bind(this.#apiClient); } /** * List outstanding user-export requests. * * Same as {@link ApiClient.userExportList}, see its documentation for more info. * * @returns A function that resolves to a paginator of user-export requests */ get exports() { return this.#apiClient.userExportList.bind(this.#apiClient); } /** * Delete an outstanding user-export request. * * Same as {@link ApiClient.userExportDelete}, see its documentation for more info. * * @returns A function that deletes a user-export request */ get deleteExport() { return this.#apiClient.userExportDelete.bind(this.#apiClient); } /** * Initiate a user-export request. * * Same as {@link ApiClient.userExportInit}, see its documentation for more info. * * @returns A function that resolves to the request response. */ get initExport() { return this.#apiClient.userExportInit.bind(this.#apiClient); } /** * Complete a user-export request. * * Same as {@link ApiClient.userExportComplete}, see its documentation for more info. * * @returns A function that resolves to the request response. */ get completeExport() { return this.#apiClient.userExportComplete.bind(this.#apiClient); } /** * Update the org. * * Same as {@link ApiClient.orgUpdate}, see its documentation for more info. * * @returns A function that updates an org and returns updated org information */ get update() { return this.#apiClient.orgUpdate.bind(this.#apiClient); } /** * Request a fresh key-import key. * * Same as {@link ApiClient.createKeyImportKey}, see its documentation for more info. * * @returns A function that resolves to a fresh key-import key */ get createKeyImportKey() { return this.#apiClient.createKeyImportKey.bind(this.#apiClient); } /** * Import one or more keys. To use this functionality, you must first create an * encrypted key-import request using the `@cubist-labs/cubesigner-sdk-key-import` * library. See that library's documentation for more info. * * @param body An encrypted key-import request. * @returns The newly imported keys. */ async importKeys(body: ImportKeyRequest): Promise { const keys = await this.#apiClient.importKeys(body); return keys.map((k) => new Key(this.#apiClient, k)); } // Backwards compatibility aliases for Named Wasm Policy /** * Create a new Wasm policy. * * @param name The name of the policy. * @param policy The Wasm policy object. * @param acl Optional list of policy access control entries. * @returns The new policy. */ createWasmPolicy = this.createWasmFunction; /** @returns the Policy Engine configuration for the org. */ policyEngineConfiguration = this.c2fConfiguration; /** * Set the Policy Engine configuration for the org. * Note that this overwrites any existing configuration. * * @param configs The Policy Engine configuration. */ setPolicyEngineConfiguration = this.setC2FConfiguration; }