UNPKG

@inngest/middleware-encryption

Version:
186 lines (185 loc) 9.36 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isV0EncryptedValue = exports.isEncryptedValue = exports.getEncryptionStages = void 0; const middleware_1 = require("./middleware"); const legacy_1 = require("./strategies/legacy"); const libSodium_1 = require("./strategies/libSodium"); /** * Encrypts and decrypts data sent to and from Inngest. */ const getEncryptionStages = ( /** * Options used to configure the encryption middleware. If a custom * `encryptionService` is not provided, the `key` option is required. */ opts) => { var _a; /** * The keys used to encrypt and decrypt data. If multiple keys are provided, * the first key will be used to encrypt data and all keys will be tried when * decrypting data. * * We perform this internally to make the way users provide these keys to us * much more explicit; it is confusing to add a new key to the end of a keys * array as the first part of a migration. */ const keys = [opts.key, ...((_a = opts.fallbackDecryptionKeys) !== null && _a !== void 0 ? _a : [])].filter(Boolean); const service = opts.encryptionService || new libSodium_1.LibSodiumEncryptionService(keys); let __v0LegacyService; /** * Lazy-load the V0 service. This is used to ensure that the V0 service is * only loaded if it's needed. */ const getV0LegacyService = () => { var _a; return (__v0LegacyService !== null && __v0LegacyService !== void 0 ? __v0LegacyService : (__v0LegacyService = new legacy_1.LEGACY_V0Service(Object.assign({ key: keys, forceEncryptWithV0: Boolean((_a = opts.legacyV0Service) === null || _a === void 0 ? void 0 : _a.forceEncryptWithV0) }, opts.legacyV0Service)))); }; const encryptValue = (value) => __awaiter(void 0, void 0, void 0, function* () { var _a; // Show a warning if we believe the value is already encrypted. This may // happen if user accidentally adds encryption middleware at both the // client and function levels. if ((0, exports.isEncryptedValue)(value) || (0, exports.isV0EncryptedValue)(value)) { console.warn("Encryption middleware is encrypting a value that appears to be already encrypted. Did you add the middleware twice?"); } if ((_a = opts.legacyV0Service) === null || _a === void 0 ? void 0 : _a.forceEncryptWithV0) { return { [middleware_1.EncryptionService.ENCRYPTION_MARKER]: true, data: getV0LegacyService().service.encrypt(value), }; } return { [middleware_1.EncryptionService.ENCRYPTION_MARKER]: true, [middleware_1.EncryptionService.STRATEGY_MARKER]: service.identifier, data: yield service.encrypt(value), }; }); const decryptValue = (value) => __awaiter(void 0, void 0, void 0, function* () { if ((0, exports.isEncryptedValue)(value)) { return service.decrypt(value.data); } if ((0, exports.isV0EncryptedValue)(value)) { return getV0LegacyService().service.decrypt(value.data); } return value; }); const fieldShouldBeEncrypted = (field) => { if (typeof opts.eventEncryptionField === "undefined") { return field === middleware_1.EncryptionService.DEFAULT_ENCRYPTED_EVENT_FIELD; } return opts.eventEncryptionField === field; }; const encryptEventData = (eventData) => __awaiter(void 0, void 0, void 0, function* () { var _a; if ((_a = opts.legacyV0Service) === null || _a === void 0 ? void 0 : _a.forceEncryptWithV0) { return getV0LegacyService().encryptEventData(eventData); } const encryptedEntries = yield Promise.all(Object.keys(eventData).map((key) => __awaiter(void 0, void 0, void 0, function* () { const value = fieldShouldBeEncrypted(key) ? yield encryptValue(eventData[key]) : eventData[key]; return [key, value]; }))); const encryptedData = encryptedEntries.reduce((acc, [key, value]) => { return Object.assign(Object.assign({}, acc), { [key]: value }); }, {}); return encryptedData; }); const decryptEventData = (eventData) => __awaiter(void 0, void 0, void 0, function* () { const decryptedEntries = yield Promise.all(Object.keys(eventData).map((key) => __awaiter(void 0, void 0, void 0, function* () { return [key, yield decryptValue(eventData[key])]; }))); const decryptedData = decryptedEntries.reduce((acc, [key, value]) => { return Object.assign(Object.assign({}, acc), { [key]: value }); }, {}); return decryptedData; }); return { encrypt: { onFunctionRun: () => { if (opts.decryptOnly) { return {}; } return { transformOutput: (ctx) => __awaiter(void 0, void 0, void 0, function* () { return { result: { data: ctx.result.data && (yield encryptValue(ctx.result.data)), }, }; }), }; }, onSendEvent: () => { return { transformInput: (_a) => __awaiter(void 0, [_a], void 0, function* ({ payloads }) { return { payloads: yield Promise.all(payloads.map((payload) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, payload), { data: payload.data && (yield encryptEventData(payload.data)) })); }))), }; }), }; }, }, decrypt: { onFunctionRun: () => { return { transformInput: (_a) => __awaiter(void 0, [_a], void 0, function* ({ ctx, steps }) { var _b; const decryptedSteps = Promise.all(steps.map((step) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, step), { data: step.data && (yield decryptValue(step.data)) })); }))); const decryptedEvent = ctx.event && (() => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, ctx.event), { data: ctx.event.data && (yield decryptEventData(ctx.event.data)) })); }))(); const decryptedEvents = ctx.events && Promise.all((_b = ctx.events) === null || _b === void 0 ? void 0 : _b.map((event) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, event), { data: event.data && (yield decryptEventData(event.data)) })); }))); const inputTransformer = { steps: yield decryptedSteps, ctx: { event: yield decryptedEvent, events: yield decryptedEvents, }, }; return inputTransformer; }), }; }, }, }; }; exports.getEncryptionStages = getEncryptionStages; const isEncryptedValue = (value) => { return (typeof value === "object" && value !== null && middleware_1.EncryptionService.ENCRYPTION_MARKER in value && value[middleware_1.EncryptionService.ENCRYPTION_MARKER] === true && "data" in value && typeof value["data"] === "string" && middleware_1.EncryptionService.STRATEGY_MARKER in value && typeof value[middleware_1.EncryptionService.STRATEGY_MARKER] === "string"); }; exports.isEncryptedValue = isEncryptedValue; const isV0EncryptedValue = (value) => { return (typeof value === "object" && value !== null && middleware_1.EncryptionService.ENCRYPTION_MARKER in value && value[middleware_1.EncryptionService.ENCRYPTION_MARKER] === true && "data" in value && typeof value["data"] === "string" && !(middleware_1.EncryptionService.STRATEGY_MARKER in value)); }; exports.isV0EncryptedValue = isV0EncryptedValue;