diff --git a/.gitignore b/.gitignore index 2c7700d4..186bf9b7 100755 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ docs/* src/core/config/modules/* src/core/config/OperationConfig.json src/core/operations/index.mjs +src/node/index.mjs **/*.DS_Store \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 81d838b5..d1488182 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -26,7 +26,7 @@ module.exports = function (grunt) { grunt.registerTask("node", "Compiles CyberChef into a single NodeJS module.", - ["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]); + ["clean:node", "clean:config", "exec:generateConfig", "exec:generateNodeIndex", "webpack:node", "chmod:build"]); grunt.registerTask("test", "A task which runs all the tests in test/tests.", @@ -387,6 +387,23 @@ module.exports = function (grunt) { "echo '--- Config scripts finished. ---\n'" ].join(";") }, + generateNodeIndex: { + command: [ + "echo '\n--- Regenerating node index ---'", + "mkdir -p src/core/config/modules", + "echo 'export default {};\n' > src/core/config/modules/OpModules.mjs", + "echo '[]\n' > src/core/config/OperationConfig.json", + // Magic and Arithmetic libs 'mocked' for when called with wrap() + "cp src/core/lib/Magic.mjs src/core/lib/Magic2.mjs", + "cp src/core/lib/Arithmetic.mjs src/core/lib/Arithmetic2.mjs", + "echo 'export default {};\n' > src/core/lib/Magic.mjs", + "echo 'const div = () => 2;\n const createNumArray = () => 2;\n const mean = () => 2;\n const median = () => 2;\n const multi = () => 2;\n const stdDev = () => 2;\n const sub = () => 2;\n const sum = () => 2;\n export { div, createNumArray, mean, median, multi, stdDev, sub, sum };\n export default {};\n' > src/core/lib/Arithmetic.mjs", + "node --experimental-modules src/core/config/scripts/generateNodeIndex.mjs", + "mv src/core/lib/Magic2.mjs src/core/lib/Magic.mjs", + "mv src/core/lib/Arithmetic2.mjs src/core/lib/Arithmetic.mjs", + "echo '--- Node index finished. ---\n'" + ].join(";"), + }, tests: { command: "node --experimental-modules test/index.mjs" } diff --git a/src/core/config/scripts/generateNodeIndex.mjs b/src/core/config/scripts/generateNodeIndex.mjs new file mode 100644 index 00000000..37386260 --- /dev/null +++ b/src/core/config/scripts/generateNodeIndex.mjs @@ -0,0 +1,99 @@ +/** + * This script generates the exports functionality for the node API. + * + * it exports chef as default, but all the wrapped operations as + * other top level exports. + * + * @author d98762656 [d98762625@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +/*eslint no-console: ["off"] */ + + +import fs from "fs"; +import path from "path"; +import * as operations from "../../operations/index"; +import { decapitalise } from "../../../node/apiUtils"; + +const dir = path.join(`${process.cwd()}/src/node`); +if (!fs.existsSync(dir)) { + console.log("\nCWD: " + process.cwd()); + console.log("Error: generateNodeIndex.mjs should be run from the project root"); + console.log("Example> node --experimental-modules src/core/config/scripts/generateNodeIndex.mjs"); + process.exit(1); +} + +let code = `/** +* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs +* +* @author d98762625 [d98762625@gmail.com] +* @copyright Crown Copyright ${new Date().getUTCFullYear()} +* @license Apache-2.0 +*/ + +import { wrap } from "./apiUtils"; +import { +`; + +Object.keys(operations).forEach((op) => { + // prepend with core_ to avoid name collision later. + code += ` ${op} as core_${op},\n`; +}); + +code +=` +} from "../node/operations/index"; + +// Define global environment functions +global.ENVIRONMENT_IS_WORKER = function() { + return typeof importScripts === "function"; +}; +global.ENVIRONMENT_IS_NODE = function() { + return typeof process === "object" && typeof require === "function"; +}; +global.ENVIRONMENT_IS_WEB = function() { + return typeof window === "object"; +}; + +/** + * generateChef + * + * Creates decapitalised, wrapped ops in chef object for default export. + */ +function generateChef() { + return { +`; + +Object.keys(operations).forEach((op) => { + code += ` ${decapitalise(op)}: wrap(core_${op}),\n`; +}); + +code += ` }; +} + +const chef = generateChef(); + +`; + +Object.keys(operations).forEach((op) => { + code += `const ${decapitalise(op)} = chef[${decapitalise(op)}];\n`; +}); + +code +=` +export default chef; +export { +`; + +Object.keys(operations).forEach((op) => { + code += ` ${decapitalise(op)},\n`; +}); + + +code += "};\n"; + + +fs.writeFileSync( + path.join(dir, "/index.mjs"), + code +); diff --git a/src/node/apiUtils.mjs b/src/node/apiUtils.mjs index a076ce95..a2656939 100644 --- a/src/node/apiUtils.mjs +++ b/src/node/apiUtils.mjs @@ -163,9 +163,14 @@ export function help(operations, searchTerm) { * @returns {String} decapitalised */ export function decapitalise(name) { - // Don't decapitalise names that are purely uppercase - if (/^[A-Z0-9]+$/g.test(name)) { + // Don't decapitalise names that start with 2+ caps + if (/^[A-Z0-9]{2,}/g.test(name)) { return name; } + // reserved. Don't change for now. + if (name === "Return") { + return name; + } + return `${name.charAt(0).toLowerCase()}${name.substr(1)}`; } diff --git a/src/node/index.mjs b/src/node/index.mjs deleted file mode 100644 index cc127f2f..00000000 --- a/src/node/index.mjs +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Node view for CyberChef. - * - * @author n1474335 [n1474335@gmail.com] - * @copyright Crown Copyright 2018 - * @license Apache-2.0 - */ -import "babel-polyfill"; - -import {wrap, help, decapitalise, translateTo} from "./apiUtils"; -import * as operations from "../core/operations/index"; - -// Define global environment functions -global.ENVIRONMENT_IS_WORKER = function() { - return typeof importScripts === "function"; -}; -global.ENVIRONMENT_IS_NODE = function() { - return typeof process === "object" && typeof require === "function"; -}; -global.ENVIRONMENT_IS_WEB = function() { - return typeof window === "object"; -}; - - -const chef = {}; - -// Add in wrapped operations with camelCase names -Object.keys(operations).forEach(op => - chef[decapitalise(op)] = wrap(operations[op])); - -chef.help = help.bind(null, operations); -chef.translateTo = translateTo; - -export default chef; -export {chef};