2023-05-26 14:25:03 +02:00
|
|
|
import {
|
|
|
|
bytesToString,
|
|
|
|
createEddsaKeyPair,
|
|
|
|
decodeCrock,
|
2023-05-26 15:54:42 +02:00
|
|
|
decryptWithDerivedKey,
|
|
|
|
eddsaGetPublic,
|
2023-05-26 14:25:03 +02:00
|
|
|
encodeCrock,
|
|
|
|
encryptWithDerivedKey,
|
|
|
|
getRandomBytesF,
|
|
|
|
stringToBytes,
|
|
|
|
} from "@gnu-taler/taler-util";
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-25 23:08:20 +02:00
|
|
|
export interface Account {
|
2023-05-26 15:54:42 +02:00
|
|
|
accountId: AccountId;
|
|
|
|
signingKey: SigningKey;
|
2023-05-25 23:08:20 +02:00
|
|
|
}
|
|
|
|
|
2023-05-19 18:26:47 +02:00
|
|
|
/**
|
|
|
|
* Restore previous session and unlock account
|
|
|
|
*
|
2023-05-25 23:08:20 +02:00
|
|
|
* @param salt string from which crypto params will be derived
|
|
|
|
* @param key secured private key
|
2023-05-19 18:26:47 +02:00
|
|
|
* @param password password for the private key
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
export async function unlockAccount(
|
2023-05-26 15:54:42 +02:00
|
|
|
account: LockedAccount,
|
2023-05-19 18:26:47 +02:00
|
|
|
password: string,
|
2023-05-25 23:08:20 +02:00
|
|
|
): Promise<Account> {
|
2023-05-26 15:54:42 +02:00
|
|
|
const rawKey = decodeCrock(account);
|
|
|
|
const rawPassword = stringToBytes(password);
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
const signingKey = (await decryptWithDerivedKey(
|
|
|
|
rawKey,
|
|
|
|
rawPassword,
|
|
|
|
password,
|
|
|
|
).catch((e: Error) => {
|
|
|
|
throw new UnwrapKeyError(e.message);
|
|
|
|
})) as SigningKey;
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
const publicKey = eddsaGetPublic(signingKey);
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
const accountId = encodeCrock(publicKey) as AccountId;
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
return { accountId, signingKey };
|
2023-05-19 18:26:47 +02:00
|
|
|
}
|
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
declare const opaque_Account: unique symbol;
|
|
|
|
export type LockedAccount = string & { [opaque_Account]: true };
|
|
|
|
|
|
|
|
declare const opaque_AccountId: unique symbol;
|
|
|
|
export type AccountId = string & { [opaque_AccountId]: true };
|
|
|
|
|
|
|
|
declare const opaque_SigningKey: unique symbol;
|
|
|
|
export type SigningKey = Uint8Array & { [opaque_SigningKey]: true };
|
|
|
|
|
2023-05-19 18:26:47 +02:00
|
|
|
/**
|
|
|
|
* Create new account (secured private key) under session
|
|
|
|
* secured with the given password
|
|
|
|
*
|
|
|
|
* @param sessionId
|
|
|
|
* @param password
|
|
|
|
* @returns
|
|
|
|
*/
|
2023-05-26 15:54:42 +02:00
|
|
|
export async function createNewAccount(
|
|
|
|
password: string,
|
|
|
|
): Promise<LockedAccount> {
|
2023-05-26 14:25:03 +02:00
|
|
|
const { eddsaPriv } = createEddsaKeyPair();
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 14:25:03 +02:00
|
|
|
const key = stringToBytes(password);
|
|
|
|
|
|
|
|
const protectedPrivKey = await encryptWithDerivedKey(
|
|
|
|
getRandomBytesF(24),
|
|
|
|
key,
|
|
|
|
eddsaPriv,
|
2023-05-26 15:54:42 +02:00
|
|
|
password,
|
2023-05-19 18:26:47 +02:00
|
|
|
);
|
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
const protectedPriv = encodeCrock(protectedPrivKey);
|
2023-05-19 18:26:47 +02:00
|
|
|
|
2023-05-26 15:54:42 +02:00
|
|
|
return protectedPriv as LockedAccount;
|
2023-05-19 18:26:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export class UnwrapKeyError extends Error {
|
|
|
|
public cause: string;
|
2023-05-26 15:54:42 +02:00
|
|
|
constructor(cause: string) {
|
|
|
|
super(`Recovering private key failed on: ${cause}`);
|
2023-05-19 18:26:47 +02:00
|
|
|
this.cause = cause;
|
|
|
|
}
|
|
|
|
}
|