UNPKG

@kuflow/kuflow-temporal-worker

Version:

Worker library used by KuFlow SDKs and Temporal.

101 lines 5.39 kB
"use strict"; /** * The MIT License * Copyright © 2021-present KuFlow S.L. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.KuflowEncryptionPayloadCodec = void 0; const common_1 = require("@temporalio/common"); const encoding_1 = require("@temporalio/common/lib/encoding"); const proto_1 = require("@temporalio/proto"); const worker_1 = require("@temporalio/worker"); const kuflow_encryption_instrumentation_1 = require("../kuflow-encryption-instrumentation"); const kuflow_cache_1 = require("./kuflow-cache"); const kuflow_crypto_1 = require("./kuflow-crypto"); class KuflowEncryptionPayloadCodec { kmsKeyCache = kuflow_cache_1.CacheBuilder.builder() .withExpireAfterAccess(1, 'hours') .withRemovalListener(key => { worker_1.Runtime.instance().logger.info(`Removed KMS key ${key} from cache`); }) .build(); restClient; constructor({ restClient }) { this.restClient = restClient; } async encode(payloads) { return await Promise.all(payloads.map(this.encrypt)); } async decode(payloads) { return await Promise.all(payloads.map(this.decrypt)); } encrypt = async (payload) => { if (payload.metadata?.[kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING_ENCRYPTED_KEY_ID] == null) { return payload; } const keyId = (0, encoding_1.decode)(payload.metadata[kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING_ENCRYPTED_KEY_ID]); const keyValue = await this.retrieveKey(keyId); const cipherTextBytes = await kuflow_crypto_1.Ciphers.AES_256_GCM.encrypt(keyValue, proto_1.temporal.api.common.v1.Payload.encode(payload).finish()); const cipherTextValue = Buffer.from(cipherTextBytes).toString('base64'); return { metadata: { [kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING]: (0, encoding_1.encode)(kuflow_encryption_instrumentation_1.METADATA_VALUE_KUFLOW_ENCODING_ENCRYPTED), [kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING_ENCRYPTED_KEY_ID]: (0, encoding_1.encode)(keyId), }, data: (0, encoding_1.encode)(`${kuflow_crypto_1.Ciphers.AES_256_GCM.algorithm}:${cipherTextValue}`), }; }; decrypt = async (payload) => { if (payload.metadata == null || (0, encoding_1.decode)(payload.metadata?.[kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING]) !== kuflow_encryption_instrumentation_1.METADATA_VALUE_KUFLOW_ENCODING_ENCRYPTED) { return payload; } if (payload.data == null) { throw new common_1.ValueError('Payload data is missing'); } const keyIdBytes = payload.metadata[kuflow_encryption_instrumentation_1.METADATA_KEY_ENCODING_ENCRYPTED_KEY_ID]; if (keyIdBytes == null) { throw new common_1.ValueError('Payload key id is missing'); } const keyId = (0, encoding_1.decode)(keyIdBytes); const keyValue = await this.retrieveKey(keyId); const cipherText = (0, encoding_1.decode)(payload.data); const [cipherTextAlgorithm, cipherTextValue] = cipherText.split(':'); if (cipherTextAlgorithm == null || cipherTextValue == null) { throw new common_1.ValueError('Invalid ciphered data format'); } if (cipherTextAlgorithm !== kuflow_crypto_1.Ciphers.AES_256_GCM.algorithm) { throw new common_1.ValueError(`Invalid cipherText algorithm: ${cipherTextAlgorithm}`); } const cipherTextValueBuffer = Buffer.from(cipherTextValue, 'base64'); const plainText = await kuflow_crypto_1.Ciphers.AES_256_GCM.decrypt(keyValue, cipherTextValueBuffer); return proto_1.temporal.api.common.v1.Payload.decode(plainText); }; async retrieveKey(keyId) { return await this.kmsKeyCache.get(keyId, async () => { const key = await this.restClient.kmsOperations.retrieveKmsKey(keyId); worker_1.Runtime.instance().logger.info(`Loaded KMS key ${key.id} into cache`); return await kuflow_crypto_1.Ciphers.AES_256_GCM.importKey(key.value); }); } } exports.KuflowEncryptionPayloadCodec = KuflowEncryptionPayloadCodec; //# sourceMappingURL=kuflow-encryption-payload-codec.js.map