@robotti.io/escrypt
Version:
Enterprise Secret Encryptor
98 lines (87 loc) • 3.1 kB
JavaScript
const fs = require('fs');
const { Validator } = require('jsonschema');
const path = require('path');
const configSchema = {
id: '/configSchema',
type: 'object',
additionalProperties: false,
properties: {
directory: { type: 'string' },
filename: { type: 'string' },
type: { type: 'string', enum: ['json'] }
},
required: ['directory', 'filename', 'type']
};
module.exports = class ConfigurationInteractor {
// Private Declarations
#encryptedFilePath;
#secrets;
#type;
/**
* Configuration Interactor Constructor
* @param {Object} config - Configuration Object
* @param {string} config.directory - Directory for secrets file
* @param {string} config.filename - Filename for secrets file
* @param {string} config.type - Storage type for secrets file
*/
constructor(config) {
try {
const validator = new Validator();
const validationResults = validator.validate(config, configSchema);
if (!validationResults.valid) throw new Error(validationResults);
const directory = path.resolve(config.directory);
if (!fs.existsSync(directory) || !fs.lstatSync(directory).isDirectory()) throw new Error('Invalid directory provided');
this.#encryptedFilePath = path.join(directory, config.filename);
if (!fs.existsSync(this.#encryptedFilePath)) throw new Error('Configuration files does not exists');
this.#type = config.type;
this.#readSecretsFile();
} catch (err) {
throw new Error(err);
}
}
/**
* Read the secrets file
* @returns {string}
*/
#readSecretsFile() {
const secrets = fs.readFileSync(this.#encryptedFilePath, 'utf8');
if (this.#type === 'json') return this.#readJSON(secrets);
throw new Error('Invalid configuration type');
}
/**
* JSON Parser
* @param {string} secrets - The content of the secrets file
*/
#readJSON(secrets) {
if (typeof secrets !== 'string') throw new Error('Invalid configuration file');
if (secrets === '') this.#secrets = {};
else this.#secrets = JSON.parse(secrets);
}
/**
* Write the secrets file JSON
*/
#writeJSON() {
fs.writeFileSync(this.#encryptedFilePath, JSON.stringify(this.#secrets));
}
/**
* Store encrypted secret into secrets file
* @param {string} key - Secret key name
* @param {string} encryptedSecret - Encrypted secret value
*/
storeEncryptedSecret(key, encryptedSecret) {
if (typeof key !== 'string' || key === '') throw new Error('Invalid key provided');
if (typeof encryptedSecret !== 'string') throw new Error('Expected encrypted secret to be a string');
this.#secrets[key] = encryptedSecret;
if (this.#type === 'json') this.#writeJSON();
}
/**
* Retrieve encrypted secret from secrets file
* @param {string} key - Secret key name
* @returns {string}
*/
retrieveEncryptedSecret(key) {
if (typeof key !== 'string' || key === '') throw new Error('Invalid key provided');
if (Object.keys(this.#secrets).indexOf(key) < 0) throw new Error('Secret does not exist');
return this.#secrets[key];
}
};