UNPKG

spartan-shield

Version:

nodejs project to package and configure common security middleware.

233 lines (231 loc) 8.54 kB
'use strict'; var chalk = require('chalk'); var uniqid = require('uniqid'); var t = require(`${__dirname}/transpose.js`); // var fs = require('fs'); var fs = require('fs-extra') var path = require('path'); const uniqueString = require('unique-string'); var pathToDefault = path.resolve(`${__dirname}/security-default.json`); /* POLICY METADATA INFO (IDs, STRUCTURE) */ /** * @name keyCount * @description counts all of the keys in the policy. Used for comparison purposes * @param {Object} p policy object * @returns {Number} raw count of keys */ function keyCount(p){ try { var count; for(var i = 0; i < Object.keys(p).length; i++){ if (p[i] === 'object'){ count += 1; keyCount(p[i]); } else { count += 1; } } return count; } catch (e){ console.log ('didn\'t make it'); } } /** * @name compare * @description compares policy ids for equality. Used for policy updating * @param {String} pid1 policy id string * @param {String} pid2 policy id string * @returns {Boolean} returns true or false depending on value equality */ function compare (pid1, pid2){ if (pid1 === pid2){ return true } else { return false } } /** * @name setPolicyId * @description sets the policy id for a given policy file * @param {Object} policy object containing policy parameters * @returns {Object} returns a policy object with a new unique policy id string */ function setPolicyId (policy){ return policy["policyId"] = uniqueString(); } /** * @name getPolicyId * @description fetches policy id from the active policy named security.json * @returns {String} returns policy id string */ function getPolicyId(){ return read('./security.json').policyId; } function uniqueId (policy){ var ids = Object.keys(audits); for (var i = 0; i < ids.length; i ++){ if (policy.policyId === ids[i]){ //the id has already been used and we need to set another one policy.policyId = setPolicyId(policy); } } return policy.policyId; } /** * @name strip * @description strips policy meta data from an existing policy file. used to convert the existing policy to default * @param {Object} p policy object file * @returns {Object} returns the policy file with empty metadata */ function strip (p){ p.policyId = ''; p.applicationName = ''; p.applicationType = ''; p.internetFacing = ''; return p } /** * @name wp * @description wp = 'write policy' responsible for actually writing the policy object to disc at the provided path * @param {Object} p policy object * @param {String} pathToPolicy string indicating where policy should be written * @returns {void} */ function wp (p, pathToPolicy){ var wp = fs.createWriteStream(pathToPolicy); var convert = JSON.stringify(p, null, ' '); wp.write(convert); wp.close(); } /* POLICY CRUD (CREATE, READ, UPDATE, DELETE)*/ /** * @name create * @description generates a new security policy (security.json) based upon answers to questions * @param {String} method defines what kind of policy to create * @param {Object} answers answers user provides from going through inquirer module will be empty for default method * @returns {Array} contains security.json, message, path to policy */ function create(method, answers = {}) { try { var policy = read(pathToDefault); // opens security-default.json var pathToPolicy; if (answers.appName === 'Get this from package.json file'){ // populates applicationName in security.json var pkgJson = read('./package.json') if (pkgJson instanceof Error) { policy.applicationName = 'No name found in package.json' } else { policy.applicationName = pkgJson.name } } else { policy.applicationName = answers.appName; } policy.policyId = uniqueString(); // creates a 36-digit policyId if (method === 'default'){ pathToPolicy = './security.json'; policy.applicationType = 'Web'; policy.internetFacing = true; wp(policy, pathToPolicy); // what to write & where to write it/name it } else if (method === 'no-overwrite'){ pathToPolicy = 'security-' + (policy.policyId).match(/.{1,8}/g)[3] + '.json'; // sets filename to security-[last 4 of the policy id] var o = t.transformer(answers, policy) // interprets the answers provided into the required policy wp(o, pathToPolicy); // what to write, where/how to write it } else { pathToPolicy = './security.json'; console.log ('Writing policy for ' + policy.applicationName + '\n'); var p = t.transformer(answers, policy); // mutates the answers into a new policy based upon the structure from security default wp(p, pathToPolicy); // what to write, where/how to write it } /* a whole bunch of stuff to translate the answers into the final policy */ var msg = chalk.magenta(`Congrats! The policy was successfully created at: ${path.resolve(pathToPolicy)}\n`); return [policy, msg, path.resolve(pathToPolicy)]; } catch (e) { console.log('Something went wrong creating the policy ' + e); } } /** * @name read * @description reads the file at the location provided by pathToRead * @param {String} pathToRead filename of the policy file * @returns {Object} returns the JSON file at the location provided in pathToRead */ function read(pathToRead) { try { var pathToPolicy = path.resolve(pathToRead); var m = JSON.parse(fs.readFileSync(pathToPolicy)); return m; } catch (e) { let err = new Error(`Could not find file ${pathToRead}`) return err } } /** * @name update * @description interprets new answers in existing policy file * @param {Object} newAnswers object containing answers from user * @returns {Array} policy object and message string */ function update(newAnswers) { try{ var oldPolicy = read('./security.json'); // opens existing policy file var newPolicy = t.transformer(newAnswers, oldPolicy); // transforms new answers into old policy if (compare(oldPolicy.policyId, newPolicy.policyId) === false) { // if the policyIds don't match throw an error throw new Error ('The policy did not update correctly. Please try again'); } else { wp(newPolicy, './security.json'); // otherwise write the new policy at the old location var message = 'The policy ' + newPolicy.policyId + ' was updated.'; return [newPolicy, message]; } } catch (e){ console.log('There was a problem updating policy ' + oldPolicy.policyId + '\n' + e.code, e.path); } } /** * @name deletePolicy * @description destroys the policy located in the default location * @returns {String} returns a confirmation message string */ function deletePolicy() { try { var pathToPolicy = path.resolve('./security.json'); // get the path to the policy file var pathToBoilerPlate = path.resolve('./security.js'); // get the path to the boilerplate code pointer file var pathToCodeFolder = path.resolve('./security/') // get the path to the code folder var m = JSON.parse(fs.readFileSync(pathToPolicy)); // read the file var policyNumber = m.policyId; // get the policyId fs.unlink(pathToBoilerPlate, function (err){ // remove the boilerplate pointer file if (err) { throw new Error (`Couldn't remove ${pathToBoilerPlate}: ${err}`) } }); fs.unlink(pathToPolicy, function (err){ // remove the policy file if (err) { throw new Error (`Couldn't remove ${pathToPolicy} : ${err}`);} }); fs.remove(pathToCodeFolder, function (err) { // remove all of the code in the code folder if (err) { throw new Error(`Couldn't remove folder ${pathToCodeFolder}: ${err}`)} }); var msg = chalk.magenta(`All artifacts related to policy ${policyNumber} have been removed from the file system.\n`); console.log(msg); return msg; } catch (e){ console.log(policyNumber + 'deleted\n' + e); } } module.exports = { deletePolicy : deletePolicy, update : update, read : read, create : create, keyCount : keyCount, compare : compare, setPolicyId : setPolicyId, getPolicyId : getPolicyId, wp : wp, strip : strip } // module.exports.deletePolicy = deletePolicy; // module.exports.update = update; // module.exports.read = read; // module.exports.create = create; // module.exports.keyCount = keyCount; // module.exports.compare = compare; // module.exports.setPolicyId = setPolicyId; // module.exports.getPolicyId = getPolicyId; // module.exports.wp = wp; // module.exports.strip = strip;