UNPKG

@saleor/app-sdk

Version:

SDK for building great Saleor Apps

147 lines (144 loc) 5.09 kB
// src/settings-manager/encrypted-metadata-manager.ts import crypto from "crypto"; // src/settings-manager/metadata-manager.ts var deserializeMetadata = ({ key, value }) => { const [newKey, domain] = key.split("__"); return { key: newKey, domain, value }; }; var constructDomainSpecificKey = (key, saleorApiUrl) => [key, saleorApiUrl].join("__"); var serializeSettingsToMetadata = ({ key, value, domain }) => { if (!domain) { return { key, value }; } return { key: constructDomainSpecificKey(key, domain), value }; }; var MetadataManager = class { constructor({ fetchMetadata, mutateMetadata, deleteMetadata }) { this.settings = []; this.fetchMetadata = fetchMetadata; this.mutateMetadata = mutateMetadata; this.deleteMetadata = deleteMetadata; } async get(key, domain) { if (!this.settings.length) { const metadata = await this.fetchMetadata(); this.settings = metadata.map(deserializeMetadata); } const setting = this.settings.find((md) => md.key === key && md.domain === domain); return setting?.value; } async set(settings) { let serializedMetadata = []; if (Array.isArray(settings)) { serializedMetadata = settings.map(serializeSettingsToMetadata); } else { serializedMetadata = [serializeSettingsToMetadata(settings)]; } const metadata = await this.mutateMetadata(serializedMetadata); this.settings = metadata.map(deserializeMetadata); } /** * Typescript doesn't properly infer arguments, so they have to be rewritten explicitly */ async delete(args) { if (!this.deleteMetadata) { throw new Error( "Delete not implemented. Ensure MetadataManager is configured with deleteMetadata param in constructor" ); } const argsArray = Array.isArray(args) ? args : [args]; const keysToDelete = argsArray.map((keyOrDomainPair) => { if (typeof keyOrDomainPair === "string") { return keyOrDomainPair; } const { key, domain } = keyOrDomainPair; return constructDomainSpecificKey(key, domain); }); await this.deleteMetadata(keysToDelete); this.settings = this.settings.filter((setting) => !argsArray.includes(setting.key)); } }; // src/settings-manager/encrypted-metadata-manager.ts var prepareKey = (key) => crypto.createHash("sha256").update(String(key)).digest("base64").substr(0, 32); var encrypt = (data, key) => { const iv = crypto.randomBytes(16).toString("hex").slice(0, 16); const cipher = crypto.createCipheriv("aes256", prepareKey(key), iv); let encrypted = cipher.update(data, "utf8", "hex"); encrypted += cipher.final("hex"); return `${iv}${encrypted}`; }; var decrypt = (data, key) => { const [iv, encrypted] = [data.slice(0, 16), data.slice(16)]; const decipher = crypto.createDecipheriv("aes256", prepareKey(key), iv); let message = decipher.update(encrypted, "hex", "utf8"); message += decipher.final("utf8"); return message; }; var EncryptedMetadataManager = class { constructor({ fetchMetadata, mutateMetadata, encryptionKey, encryptionMethod, decryptionMethod, deleteMetadata }) { this.metadataManager = new MetadataManager({ fetchMetadata, mutateMetadata, deleteMetadata }); if (encryptionKey) { this.encryptionKey = encryptionKey; } else { console.warn("Encrypted Metadata Manager secret key has not been set."); if (process.env.NODE_ENV === "production") { console.error("Can't start the application without the secret key."); throw new Error( "Encryption key for the EncryptedMetadataManager has not been set. Setting it for the production environments is necessary. You can find more in the documentation: https://docs.saleor.io/docs/3.x/developer/extending/apps/developing-apps/app-sdk/settings-manager" ); } console.warn( "WARNING: Encrypted Metadata Manager encryption key has not been set. For production deployments, it need's to be set" ); console.warn("Using placeholder value for the development."); this.encryptionKey = "CHANGE_ME"; } this.encryptionMethod = encryptionMethod || encrypt; this.decryptionMethod = decryptionMethod || decrypt; } async get(key, domain) { const encryptedValue = await this.metadataManager.get(key, domain); if (!encryptedValue) { return void 0; } return this.decryptionMethod(encryptedValue, this.encryptionKey); } async set(settings) { if (!Array.isArray(settings)) { const encryptedValue = this.encryptionMethod(settings.value, this.encryptionKey); return this.metadataManager.set({ ...settings, value: encryptedValue }); } const encryptedSettings = settings.map((s) => ({ ...s, value: this.encryptionMethod(s.value, this.encryptionKey) })); return this.metadataManager.set(encryptedSettings); } async delete(args) { await this.metadataManager.delete(args); } }; export { EncryptedMetadataManager, MetadataManager, decrypt, encrypt };