UNPKG

@bsv/wallet-toolbox-client

Version:
437 lines 21.4 kB
import { AbortActionArgs, AbortActionResult, AcquireCertificateArgs, AcquireCertificateResult, AuthenticatedResult, CreateActionArgs, CreateActionResult, CreateHmacArgs, CreateHmacResult, CreateSignatureArgs, CreateSignatureResult, DiscoverByAttributesArgs, DiscoverByIdentityKeyArgs, DiscoverCertificatesResult, GetHeaderArgs, GetHeaderResult, GetHeightResult, GetNetworkResult, GetPublicKeyArgs, GetPublicKeyResult, GetVersionResult, InternalizeActionArgs, InternalizeActionResult, ListActionsArgs, ListActionsResult, ListCertificatesArgs, ListCertificatesResult, ListOutputsArgs, ListOutputsResult, OriginatorDomainNameStringUnder250Bytes, ProveCertificateArgs, ProveCertificateResult, RelinquishCertificateArgs, RelinquishCertificateResult, RelinquishOutputArgs, RelinquishOutputResult, RevealCounterpartyKeyLinkageArgs, RevealCounterpartyKeyLinkageResult, RevealSpecificKeyLinkageArgs, RevealSpecificKeyLinkageResult, SignActionArgs, SignActionResult, VerifyHmacArgs, VerifyHmacResult, VerifySignatureArgs, VerifySignatureResult, WalletDecryptArgs, WalletDecryptResult, WalletEncryptArgs, WalletEncryptResult, WalletInterface, OutpointString, LookupResolver, SHIPBroadcaster } from '@bsv/sdk'; import { PrivilegedKeyManager } from './sdk/PrivilegedKeyManager'; /** * Number of rounds used in PBKDF2 for deriving password keys. */ export declare const PBKDF2_NUM_ROUNDS = 7777; /** * Unique Identifier for the default profile (16 zero bytes). */ export declare const DEFAULT_PROFILE_ID: number[]; /** * Describes the structure of a user profile within the wallet. */ export interface Profile { /** * User-defined name for the profile. */ name: string; /** * Unique 16-byte identifier for the profile. */ id: number[]; /** * 32-byte random pad XOR'd with the root primary key to derive the profile's primary key. */ primaryPad: number[]; /** * 32-byte random pad XOR'd with the root privileged key to derive the profile's privileged key. */ privilegedPad: number[]; /** * Timestamp (seconds since epoch) when the profile was created. */ createdAt: number; } /** * Describes the structure of a User Management Protocol (UMP) token. */ export interface UMPToken { /** * Root Primary key encrypted by the XOR of the password and presentation keys. */ passwordPresentationPrimary: number[]; /** * Root Primary key encrypted by the XOR of the password and recovery keys. */ passwordRecoveryPrimary: number[]; /** * Root Primary key encrypted by the XOR of the presentation and recovery keys. */ presentationRecoveryPrimary: number[]; /** * Root Privileged key encrypted by the XOR of the password and primary keys. */ passwordPrimaryPrivileged: number[]; /** * Root Privileged key encrypted by the XOR of the presentation and recovery keys. */ presentationRecoveryPrivileged: number[]; /** * Hash of the presentation key. */ presentationHash: number[]; /** * PBKDF2 salt used in conjunction with the password to derive the password key. */ passwordSalt: number[]; /** * Hash of the recovery key. */ recoveryHash: number[]; /** * A copy of the presentation key encrypted with the root privileged key. */ presentationKeyEncrypted: number[]; /** * A copy of the recovery key encrypted with the root privileged key. */ recoveryKeyEncrypted: number[]; /** * A copy of the password key encrypted with the root privileged key. */ passwordKeyEncrypted: number[]; /** * Optional field containing the encrypted profile data. * JSON string -> Encrypted Bytes using root privileged key. */ profilesEncrypted?: number[]; /** * Describes the token's location on-chain, if it's already been published. */ currentOutpoint?: OutpointString; } /** * Describes a system capable of finding and updating UMP tokens on the blockchain. */ export interface UMPTokenInteractor { /** * Locates the latest valid copy of a UMP token (including its outpoint) * based on the presentation key hash. * * @param hash The hash of the presentation key. * @returns The UMP token if found; otherwise, undefined. */ findByPresentationKeyHash: (hash: number[]) => Promise<UMPToken | undefined>; /** * Locates the latest valid copy of a UMP token (including its outpoint) * based on the recovery key hash. * * @param hash The hash of the recovery key. * @returns The UMP token if found; otherwise, undefined. */ findByRecoveryKeyHash: (hash: number[]) => Promise<UMPToken | undefined>; /** * Creates (and optionally consumes the previous version of) a UMP token on-chain. * * @param wallet The wallet that might be used to create a new token (MUST be operating under the DEFAULT profile). * @param adminOriginator The domain name of the administrative originator. * @param token The new UMP token to create. * @param oldTokenToConsume If provided, the old token that must be consumed in the same transaction. * @returns The newly created outpoint. */ buildAndSend: (wallet: WalletInterface, // This wallet MUST be the one built for the default profile adminOriginator: OriginatorDomainNameStringUnder250Bytes, token: UMPToken, oldTokenToConsume?: UMPToken) => Promise<OutpointString>; } /** * @class OverlayUMPTokenInteractor * * A concrete implementation of the UMPTokenInteractor interface that interacts * with Overlay Services and the UMP (User Management Protocol) topic. This class * is responsible for: * * 1) Locating UMP tokens via overlay lookups (ls_users). * 2) Creating and publishing new or updated UMP token outputs on-chain under * the "tm_users" topic. * 3) Consuming (spending) an old token if provided. */ export declare class OverlayUMPTokenInteractor implements UMPTokenInteractor { /** * A `LookupResolver` instance used to query overlay networks. */ private readonly resolver; /** * A SHIP broadcaster that can be used to publish updated UMP tokens * under the `tm_users` topic to overlay service peers. */ private readonly broadcaster; /** * Construct a new OverlayUMPTokenInteractor. * * @param resolver A LookupResolver instance for performing overlay queries (ls_users). * @param broadcaster A SHIPBroadcaster instance for sharing new or updated tokens across the `tm_users` overlay. */ constructor(resolver?: LookupResolver, broadcaster?: SHIPBroadcaster); /** * Finds a UMP token on-chain by the given presentation key hash, if it exists. * Uses the ls_users overlay service to perform the lookup. * * @param hash The 32-byte SHA-256 hash of the presentation key. * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined. */ findByPresentationKeyHash(hash: number[]): Promise<UMPToken | undefined>; /** * Finds a UMP token on-chain by the given recovery key hash, if it exists. * Uses the ls_users overlay service to perform the lookup. * * @param hash The 32-byte SHA-256 hash of the recovery key. * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined. */ findByRecoveryKeyHash(hash: number[]): Promise<UMPToken | undefined>; /** * Creates or updates (replaces) a UMP token on-chain. If `oldTokenToConsume` is provided, * it is spent in the same transaction that creates the new token output. The new token is * then broadcast and published under the `tm_users` topic using a SHIP broadcast, ensuring * overlay participants see the updated token. * * @param wallet The wallet used to build and sign the transaction (MUST be operating under the DEFAULT profile). * @param adminOriginator The domain/FQDN of the administrative originator (wallet operator). * @param token The new UMPToken to create on-chain. * @param oldTokenToConsume Optionally, an existing token to consume/spend in the same transaction. * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0"). */ buildAndSend(wallet: WalletInterface, // This wallet MUST be the one built for the default profile adminOriginator: OriginatorDomainNameStringUnder250Bytes, token: UMPToken, oldTokenToConsume?: UMPToken): Promise<OutpointString>; /** * Attempts to parse a LookupAnswer from the UMP lookup service. If successful, * extracts the token fields from the resulting transaction and constructs * a UMPToken object. * * @param answer The LookupAnswer returned by a query to ls_users. * @returns The parsed UMPToken or `undefined` if none found/decodable. */ private parseLookupAnswer; /** * Finds by outpoint for unlocking / spending previous tokens. * @param outpoint The outpoint we are searching by * @returns The result so that we can use it to unlock the transaction */ private findByOutpoint; } /** * Manages a "CWI-style" wallet that uses a UMP token and a * multi-key authentication scheme (password, presentation key, and recovery key), * supporting multiple user profiles under a single account. */ export declare class CWIStyleWalletManager implements WalletInterface { /** * Whether the user is currently authenticated (i.e., root keys are available). */ authenticated: boolean; /** * The domain name of the administrative originator (wallet operator / vendor, or your own). */ private adminOriginator; /** * The system that locates and publishes UMP tokens on-chain. */ private UMPTokenInteractor; /** * A function called to persist the newly generated recovery key. * It should generally trigger a UI prompt where the user is asked to write it down. */ private recoveryKeySaver; /** * Asks the user to enter their password, for a given reason. * The test function can be used to see if the password is correct before resolving. * Only resolve with the correct password or reject with an error. * Resolving with an incorrect password will throw an error. */ private passwordRetriever; /** * Optional function to fund a new Wallet after the new-user flow. */ private newWalletFunder?; /** * Builds the underlying wallet for a specific profile. */ private walletBuilder; /** * Current mode of authentication. */ authenticationMode: 'presentation-key-and-password' | 'presentation-key-and-recovery-key' | 'recovery-key-and-password'; /** * Indicates new user or existing user flow. */ authenticationFlow: 'new-user' | 'existing-user'; /** * The current UMP token in use. */ private currentUMPToken?; /** * Temporarily retained presentation key. */ private presentationKey?; /** * Temporarily retained recovery key. */ private recoveryKey?; /** * The user's *root* primary key, derived from authentication factors. */ private rootPrimaryKey?; /** * The currently active profile ID (null or DEFAULT_PROFILE_ID means default profile). */ private activeProfileId; /** * List of loaded non-default profiles. */ private profiles; /** * The underlying wallet instance for the *active* profile. */ private underlying?; /** * Privileged key manager associated with the *root* keys, aware of the active profile. */ private rootPrivilegedKeyManager?; /** * Constructs a new CWIStyleWalletManager. * * @param adminOriginator The domain name of the administrative originator. * @param walletBuilder A function that can build an underlying wallet instance for a profile. * @param interactor An instance of UMPTokenInteractor. * @param recoveryKeySaver A function to persist a new recovery key. * @param passwordRetriever A function to request the user's password. * @param newWalletFunder Optional function to fund a new wallet. * @param stateSnapshot Optional previously saved state snapshot. */ constructor(adminOriginator: OriginatorDomainNameStringUnder250Bytes, walletBuilder: (profilePrimaryKey: number[], profilePrivilegedKeyManager: PrivilegedKeyManager, profileId: number[]) => Promise<WalletInterface>, interactor: UMPTokenInteractor | undefined, recoveryKeySaver: (key: number[]) => Promise<true>, passwordRetriever: (reason: string, test: (passwordCandidate: string) => boolean) => Promise<string>, newWalletFunder?: (presentationKey: number[], wallet: WalletInterface, // Default profile wallet adminOriginator: OriginatorDomainNameStringUnder250Bytes) => Promise<void>, stateSnapshot?: number[]); /** * Provides the presentation key. */ providePresentationKey(key: number[]): Promise<void>; /** * Provides the password. */ providePassword(password: string): Promise<void>; /** * Provides the recovery key. */ provideRecoveryKey(recoveryKey: number[]): Promise<void>; /** * Saves the current wallet state (root key, UMP token, active profile) into an encrypted snapshot. * Version 2 format: [1 byte version=2] + [32 byte snapshot key] + [16 byte activeProfileId] + [encrypted payload] * Encrypted Payload: [32 byte rootPrimaryKey] + [varint token length + serialized UMP token] * * @returns Encrypted snapshot bytes. */ saveSnapshot(): number[]; /** * Loads a previously saved state snapshot. Restores root key, UMP token, profiles, and active profile. * Handles Version 1 (legacy) and Version 2 formats. * * @param snapshot Encrypted snapshot bytes. */ loadSnapshot(snapshot: number[]): Promise<void>; /** * Destroys the wallet state, clearing keys, tokens, and profiles. */ destroy(): void; /** * Lists all available profiles, including the default profile. * @returns Array of profile info objects, including an 'active' flag. */ listProfiles(): Array<{ id: number[]; name: string; createdAt: number | null; active: boolean; }>; /** * Adds a new profile with the given name. * Generates necessary pads and updates the UMP token. * Does not switch to the new profile automatically. * * @param name The desired name for the new profile. * @returns The ID of the newly created profile. */ addProfile(name: string): Promise<number[]>; /** * Deletes a profile by its ID. * Cannot delete the default profile. If the active profile is deleted, * it switches back to the default profile. * * @param profileId The 16-byte ID of the profile to delete. */ deleteProfile(profileId: number[]): Promise<void>; /** * Switches the active profile. This re-derives keys and rebuilds the underlying wallet. * * @param profileId The 16-byte ID of the profile to switch to (use DEFAULT_PROFILE_ID for default). */ switchProfile(profileId: number[]): Promise<void>; /** * Changes the user's password. Re-wraps keys and updates the UMP token. */ changePassword(newPassword: string): Promise<void>; /** * Retrieves the current recovery key. Requires privileged access. */ getRecoveryKey(): Promise<number[]>; /** * Changes the user's recovery key. Prompts user to save the new key. */ changeRecoveryKey(): Promise<void>; /** * Changes the user's presentation key. */ changePresentationKey(newPresentationKey: number[]): Promise<void>; /** * Performs XOR operation on two byte arrays. */ private XOR; /** * Helper to decrypt a specific factor (key) stored encrypted in the UMP token. * Requires the root privileged key manager. * @param factorName Name of the factor to decrypt ('passwordKey', 'presentationKey', 'recoveryKey', 'privilegedKey'). * @param getRoot If true and factorName is 'privilegedKey', returns the root privileged key bytes directly. * @returns The decrypted key bytes. */ private getFactor; /** * Recomputes UMP token fields with updated factors and profiles, then publishes the update. * This operation requires the *root* privileged key and the *default* profile wallet. */ private updateAuthFactors; /** * Serializes a UMP token to binary format (Version 2 with optional profiles). * Layout: [1 byte version=2] + [11 * (varint len + bytes) for standard fields] + [1 byte profile_flag] + [IF flag=1 THEN varint len + profile bytes] + [varint len + outpoint bytes] */ private serializeUMPToken; /** * Deserializes a UMP token from binary format (Handles Version 1 and 2). */ private deserializeUMPToken; /** * Sets up the root key infrastructure after authentication or loading from snapshot. * Initializes the root primary key, root privileged key manager, loads profiles, * and sets the authenticated flag. Does NOT switch profile initially. * * @param rootPrimaryKey The user's root primary key (32 bytes). * @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows). */ private setupRootInfrastructure; private checkAuthAndUnderlying; getPublicKey(args: GetPublicKeyArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetPublicKeyResult>; revealCounterpartyKeyLinkage(args: RevealCounterpartyKeyLinkageArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<RevealCounterpartyKeyLinkageResult>; revealSpecificKeyLinkage(args: RevealSpecificKeyLinkageArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<RevealSpecificKeyLinkageResult>; encrypt(args: WalletEncryptArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<WalletEncryptResult>; decrypt(args: WalletDecryptArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<WalletDecryptResult>; createHmac(args: CreateHmacArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<CreateHmacResult>; verifyHmac(args: VerifyHmacArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<VerifyHmacResult>; createSignature(args: CreateSignatureArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<CreateSignatureResult>; verifySignature(args: VerifySignatureArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<VerifySignatureResult>; createAction(args: CreateActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<CreateActionResult>; signAction(args: SignActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<SignActionResult>; abortAction(args: AbortActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<AbortActionResult>; listActions(args: ListActionsArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<ListActionsResult>; internalizeAction(args: InternalizeActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<InternalizeActionResult>; listOutputs(args: ListOutputsArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<ListOutputsResult>; relinquishOutput(args: RelinquishOutputArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<RelinquishOutputResult>; acquireCertificate(args: AcquireCertificateArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<AcquireCertificateResult>; listCertificates(args: ListCertificatesArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<ListCertificatesResult>; proveCertificate(args: ProveCertificateArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<ProveCertificateResult>; relinquishCertificate(args: RelinquishCertificateArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<RelinquishCertificateResult>; discoverByIdentityKey(args: DiscoverByIdentityKeyArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<DiscoverCertificatesResult>; discoverByAttributes(args: DiscoverByAttributesArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<DiscoverCertificatesResult>; isAuthenticated(_: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<AuthenticatedResult>; waitForAuthentication(_: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<AuthenticatedResult>; getHeight(_: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetHeightResult>; getHeaderForHeight(args: GetHeaderArgs, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetHeaderResult>; getNetwork(_: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetNetworkResult>; getVersion(_: {}, originator?: OriginatorDomainNameStringUnder250Bytes): Promise<GetVersionResult>; } //# sourceMappingURL=CWIStyleWalletManager.d.ts.map