//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-export class Passkey {
- static create (action: string, salt: ArrayBuffer, data: Record<string, unknown>): Promise<CryptoKey | undefined> {
- // Allowlisted wallet actions
- if (['create', 'load', 'unlock', 'update'].includes(action)) {
+export async function passkey (action: string, salt: ArrayBuffer, data: Record<string, unknown>): Promise<CryptoKey | undefined> {
+ // Allowlisted wallet actions
+ if (['create', 'load', 'unlock', 'update'].includes(action)) {
- // Create local copy of password ASAP, then clear bytes from original buffer
- if (!(data.password instanceof ArrayBuffer)) {
- throw new TypeError('Password must be ArrayBuffer')
- }
+ // Create local copy of password ASAP, then clear bytes from original buffer
+ if (!(data.password instanceof ArrayBuffer)) {
+ throw new TypeError('Password must be ArrayBuffer')
+ }
- const password = data.password.slice()
- new Uint8Array(data.password).fill(0)
- delete data.password
+ const password = data.password.slice()
+ new Uint8Array(data.password).fill(0)
+ delete data.password
- // Only unlocking should decrypt the vault; other sensitive actions should
- // throw if the vault is still locked and encrypted
- const keyUsages: KeyUsage[] = action === 'unlock' ? ['decrypt'] : ['encrypt']
+ // Only unlocking should decrypt the vault; other sensitive actions should
+ // throw if the vault is still locked and encrypted
+ const keyUsages: KeyUsage[] = action === 'unlock' ? ['decrypt'] : ['encrypt']
- return crypto.subtle
- .importKey('raw', password, 'PBKDF2', false, ['deriveKey'])
- .then(derivationKey => {
- new Uint8Array(password).fill(0)
- const derivationAlgorithm: Pbkdf2Params = {
- name: 'PBKDF2',
- hash: 'SHA-512',
- iterations: 210000,
- salt
- }
- const derivedKeyType: AesKeyGenParams = {
- name: 'AES-GCM',
- length: 256
- }
- return crypto.subtle
- .deriveKey(derivationAlgorithm, derivationKey, derivedKeyType, false, keyUsages)
- })
- .catch(err => {
- console.error(err)
- throw new Error('Failed to derive CryptoKey from password', { cause: err })
- })
- } else if (data.password !== undefined) {
- throw new Error('Password is not allowed for this action', { cause: action })
- } else {
- return Promise.resolve(undefined)
- }
+ return crypto.subtle
+ .importKey('raw', password, 'PBKDF2', false, ['deriveKey'])
+ .then(derivationKey => {
+ new Uint8Array(password).fill(0)
+ const derivationAlgorithm: Pbkdf2Params = {
+ name: 'PBKDF2',
+ hash: 'SHA-512',
+ iterations: 210000,
+ salt
+ }
+ const derivedKeyType: AesKeyGenParams = {
+ name: 'AES-GCM',
+ length: 256
+ }
+ return crypto.subtle
+ .deriveKey(derivationAlgorithm, derivationKey, derivedKeyType, false, keyUsages)
+ })
+ .catch(err => {
+ console.error(err)
+ throw new Error('Failed to derive CryptoKey from password', { cause: err })
+ })
+ } else if (data.password !== undefined) {
+ throw new Error('Password is not allowed for this action', { cause: action })
+ } else {
+ return Promise.resolve(undefined)
}
}
import { Bip39, Bip44, Blake2b, WalletAesGcm } from '../crypto'
import { WalletType } from '../wallet'
import { parseAction, parseData, parseId, parseIv, parseKeySalt, parseType } from './parsers'
-import { Passkey } from './passkey'
+import { passkey } from './passkey'
import { VaultTimer } from './vault-timer'
let _locked: boolean = true
NODE: if (parentPort == null) setTimeout(() => listener(event), 0)
const action = parseAction(data)
const keySalt = parseKeySalt(action, data)
- Passkey.create(action, keySalt, data)
+ passkey(action, keySalt, data)
.then((key: CryptoKey | undefined): Promise<Record<string, boolean | number | ArrayBuffer> | void> => {
const type = parseType(action, data)
const id = parseId(action, data)