UNPKG

crawlee-storage-extensions

Version:

Package for Apify/Crawlee that allows to store encrypted text values into the Storages

60 lines (59 loc) 2.08 kB
import crypto from 'node:crypto'; export class EncryptedKeyValueStore { kvstore; #cryptSecret; constructor(kvstore, secretKey) { this.kvstore = kvstore; this.#cryptSecret = crypto .createHash('sha256') .update(secretKey) .digest('hex') .slice(0, 32); } async getValue(key, defaultValue) { const encryptedValue = await this.kvstore.getValue(key); if (encryptedValue == null) { if (defaultValue !== undefined) { return defaultValue; } return null; } try { return this.#decrypt(encryptedValue); } catch (error) { if (error?.['code'] === 'ERR_OSSL_EVP_BAD_DECRYPT') { throw new Error(`Unable to decrypt key: "${key}". Possibly wrong secret key is used...`); } throw error; } } async setValue(key, value) { if (value === null) { return await this.kvstore.setValue(key, null); } else { return await this.kvstore.setValue(key, this.#encrypt(value)); } } #encrypt(dataToEncrypt) { const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(this.#cryptSecret), iv); const result = { data: Buffer.concat([ cipher.update(Buffer.from(JSON.stringify(dataToEncrypt))), cipher.final(), ]).toString('base64'), iv: iv.toString('base64'), }; return Buffer.from(JSON.stringify(result)).toString('base64'); } #decrypt(dataToDecrypt) { const { data, iv } = JSON.parse(Buffer.from(dataToDecrypt, 'base64').toString()); const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(this.#cryptSecret), Buffer.from(iv, 'base64')); return JSON.parse(Buffer.concat([ decipher.update(Buffer.from(data, 'base64')), decipher.final(), ]).toString()); } }