UNPKG

@nomicfoundation/hardhat-keystore

Version:

A module for managing keystore files that store a map from IDs to encrypted string values.

140 lines (121 loc) 3.58 kB
import type { Keystore as KeystoreI } from "../types.js"; import { assertHardhatInvariant, HardhatError, } from "@nomicfoundation/hardhat-errors"; import { addSecretToKeystore, decryptSecret, doesKeyExist, HmacKeyDecryptionError, removeSecretFromKeystore, validateHmac, type EncryptedKeystore, } from "./encryption.js"; export class Keystore implements KeystoreI { #keystoreData: EncryptedKeystore; constructor(keystoreData: EncryptedKeystore) { this.#keystoreData = keystoreData; } public toJSON(): EncryptedKeystore { return this.#keystoreData; } public async listUnverifiedKeys(): Promise<string[]> { // In this scenario the keystore is not validated for integrity, so the returned keys might have been tampered with. // This is acceptable if the keys are only listed for display purposes. // This risk is considered acceptable for this use case. return Object.keys(this.#keystoreData.secrets); } public async hasKey(key: string, masterKey: Uint8Array): Promise<boolean> { try { return doesKeyExist({ masterKey, encryptedKeystore: this.#keystoreData, key, }); } catch (error) { if (error instanceof HmacKeyDecryptionError) { throw new HardhatError( HardhatError.ERRORS.HARDHAT_KEYSTORE.GENERAL.INVALID_PASSWORD_OR_CORRUPTED_KEYSTORE, ); } throw error; } } public async readValue(key: string, masterKey: Uint8Array): Promise<string> { assertHardhatInvariant( key in this.#keystoreData.secrets, "Unknown key should never be read", ); try { return decryptSecret({ masterKey, encryptedKeystore: this.#keystoreData, key, }); } catch (error) { if (error instanceof HmacKeyDecryptionError) { throw new HardhatError( HardhatError.ERRORS.HARDHAT_KEYSTORE.GENERAL.INVALID_PASSWORD_OR_CORRUPTED_KEYSTORE, ); } throw error; } } public async removeKey(key: string, masterKey: Uint8Array): Promise<void> { assertHardhatInvariant( key in this.#keystoreData.secrets, "Unknown key should never be removed", ); try { this.#keystoreData = removeSecretFromKeystore({ masterKey, encryptedKeystore: this.#keystoreData, keyToRemove: key, }); } catch (error) { if (error instanceof HmacKeyDecryptionError) { throw new HardhatError( HardhatError.ERRORS.HARDHAT_KEYSTORE.GENERAL.INVALID_PASSWORD_OR_CORRUPTED_KEYSTORE, ); } throw error; } } public async addNewValue( key: string, value: string, masterKey: Uint8Array, ): Promise<void> { try { this.#keystoreData = addSecretToKeystore({ masterKey, encryptedKeystore: this.#keystoreData, key, value, }); } catch (error) { if (error instanceof HmacKeyDecryptionError) { throw new HardhatError( HardhatError.ERRORS.HARDHAT_KEYSTORE.GENERAL.INVALID_PASSWORD_OR_CORRUPTED_KEYSTORE, ); } throw error; } } public async isValidPassword(masterKey: Uint8Array): Promise<void> { try { validateHmac({ masterKey, encryptedKeystore: this.#keystoreData, }); } catch (error) { if (error instanceof HmacKeyDecryptionError) { throw new HardhatError( HardhatError.ERRORS.HARDHAT_KEYSTORE.GENERAL.INVALID_PASSWORD_OR_CORRUPTED_KEYSTORE, ); } throw error; } } }