@cumulus/common
Version:
Common utilities used across tasks
138 lines • 5.78 kB
JavaScript
;
/**
* Provides encryption and decryption methods with a consistent API but
* differing mechanisms for dealing with encryption keys.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultProvider = exports.S3KeyPairProvider = exports.retrieveKey = exports.getObjectStreamContents = exports.buildS3Client = exports.KMS = void 0;
const node_forge_1 = __importDefault(require("node-forge"));
const stream_1 = require("stream");
const client_s3_1 = require("@aws-sdk/client-s3");
const util_1 = require("./util");
const test_utils_1 = require("./test-utils");
var kms_1 = require("./kms");
Object.defineProperty(exports, "KMS", { enumerable: true, get: function () { return kms_1.KMS; } });
const getLocalStackHost = () => {
if (process.env.LOCAL_S3_HOST) {
return process.env.LOCAL_S3_HOST;
}
if (!process.env.LOCALSTACK_HOST) {
throw new Error('The LOCALSTACK_HOST environment variable is not set.');
}
return process.env.LOCALSTACK_HOST;
};
const buildS3Client = () => {
const region = process.env.AWS_DEFAULT_REGION ?? 'us-east-1';
const options = {
apiVersion: '2006-03-01',
region,
};
if ((0, test_utils_1.inTestMode)()) {
options.endpoint = `http://${getLocalStackHost()}:4566`;
options.region = 'us-east-1';
options.forcePathStyle = true;
options.credentials = {
accessKeyId: 'my-access-key-id',
secretAccessKey: 'my-secret-access-key',
};
}
return new client_s3_1.S3(options);
};
exports.buildS3Client = buildS3Client;
const getObjectStreamContents = (objectReadStream) => new Promise((resolve, reject) => {
try {
const responseDataChunks = [];
objectReadStream.once('error', (error) => reject(error));
objectReadStream.on('data', (chunk) => responseDataChunks.push(chunk));
// Once the stream has no more data, join the chunks into a string and
// return the string
objectReadStream.once('end', () => resolve(responseDataChunks.join('')));
}
catch (error) {
reject(error);
}
});
exports.getObjectStreamContents = getObjectStreamContents;
const getTextObject = async (bucket, key) => {
const s3 = (0, exports.buildS3Client)();
const { Body } = await s3.getObject({
Bucket: bucket,
Key: key,
});
let data;
if (Body && Body instanceof stream_1.Readable) {
data = await (0, exports.getObjectStreamContents)(Body);
}
return data;
};
const retrieveKey = async (keyId, bucket = process.env.system_bucket, stack = process.env.stackName) => {
if (!bucket) {
throw new Error('Unable to determine bucket to retrieve key from');
}
if (!stack) {
throw new Error('Unable to determine stack to retrieve key for');
}
const key = `${stack}/crypto/${keyId}`;
try {
return await getTextObject(bucket, key);
}
catch (error) {
throw new Error(`Failed to retrieve S3KeyPair key from s3://${bucket}/${key}: ${error.message}`);
}
};
exports.retrieveKey = retrieveKey;
/**
* Provides encryption and decryption methods using a keypair stored in S3
*/
class S3KeyPairProvider {
/**
* Encrypt the given string using the given public key stored in the system_bucket.
*
* @param {string} str - The string to encrypt
* @param {string} [keyId] - The name of the public key to use for encryption
* @param {string} [bucket] - the optional bucket name. if not provided will
* use env variable "system_bucket"
* @param {stack} [stack] - the optional stack name. if not provided will
* use env variable "stackName"
* @returns {Promise.<string>} the encrypted string
*/
static async encrypt(str, keyId = 'public.pub', bucket, stack) {
(0, util_1.deprecate)('@cumulus/common/key-pair-provider', '1.17.0', '@cumulus/aws-client/KMS.encrypt');
// Download the publickey
const pki = node_forge_1.default.pki;
const pub = await (0, exports.retrieveKey)(keyId, bucket, stack);
if (!pub) {
throw new Error('Unable to retrieve public key');
}
const publicKey = pki.publicKeyFromPem(pub);
return node_forge_1.default.util.encode64(publicKey.encrypt(str));
}
/**
* Decrypt the given string using a private key stored in S3
*
* @param {string} str - The string to decrypt
* @param {string} [keyId] - The name of the public key to use for decryption
* @param {string} [bucket] - the optional bucket name. Defaults to the value
* of the "system_bucket" environment variable
* @param {string} [stack] - the optional stack name. Defaults to the value of
* the "stackName" environment variable
* @returns {Promise.<string>} the decrypted string
*/
static async decrypt(str, keyId = 'private.pem', bucket, stack) {
(0, util_1.deprecate)('@cumulus/common/key-pair-provider', '1.17.0', '@cumulus/aws-client/KMS.decryptBase64String');
const pki = node_forge_1.default.pki;
const priv = await (0, exports.retrieveKey)(keyId, bucket, stack);
if (!priv) {
throw new Error('Unable to retrieve private key');
}
const decoded = node_forge_1.default.util.decode64(str);
const privateKey = pki.privateKeyFromPem(priv);
return privateKey.decrypt(decoded);
}
}
exports.S3KeyPairProvider = S3KeyPairProvider;
exports.DefaultProvider = S3KeyPairProvider;
//# sourceMappingURL=key-pair-provider.js.map