@kuflow/kuflow-temporal-worker
Version:
Worker library used by KuFlow SDKs and Temporal.
101 lines • 5.39 kB
JavaScript
;
/**
* 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