@bsv/wallet-toolbox-client
Version:
Client only Wallet Storage
437 lines • 21.4 kB
TypeScript
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