Customising CyberChef…

So, in the need to run some Base64 encoding + decoding using local HTML files and modern browser-based JS, I came across CyberChef

Asking Google’s “AI Mode” (even the “Pro” version) to provide instructions to strip the files down to the basic (e.g. no bloat from Tesseract OCR files or other operations/modules not needed excepting “To Base64” and “From Base64” operations) was an exercise in frustration… With “instructions” from deleting .mjs operation files from source tree, to editing the src/core/config/scripts/generateConfig.mjs (in truth, only one or the other was required – along with some other steps), to attempting hard-code edits on webpack.config.js.

None of that worked correctly – No HTML was produced at the end due to some compilation error.

Fortunately, it pointed me in the right direction, and I finally managed to “shrink” my build for easy transfer, down from the hefty 70+MB .zip file…

 

Build First, Strip Later

I ran npm run build on a “pure” git clone of version 11.0.0… I then deleted the entire build sub-directory (rm -fr build) and then started to strip out all the files.

 

Stripping Non-Required Operations

There were several files to edit:

  • delete the entire section “new CopyWebpackPlugin” section from ./webpack.config.js
  • I stripped src/core/config/Categories.json to only this:
[
  {
    "name": "Data format",
    "ops": [
      "To Base64",
      "From Base64"
    ]
  }
]
  • I also stripped src/core/config/OperationConfig.json to just the “From Base64” and “To Base64” sections (although I’m guessing this will be regenerated when rebuilding, looking at the build logs):
{
    "From Base64": {
        "module": "Default",
        "description": "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation decodes data from an ASCII Base64 string back into its raw format.<br><br>e.g. <code>aGVsbG8=</code> becomes <code>hello</code>",
        "infoURL": "https://wikipedia.org/wiki/Base64",
        "inputType": "string",
        "outputType": "byteArray",
        "flowControl": false,
        "manualBake": false,
        "args": [
            {
                "name": "Alphabet",
                "type": "editableOption",
                "value": [
                    {
                        "name": "Standard (RFC 4648): A-Za-z0-9+/=",
                        "value": "A-Za-z0-9+/="
                    },
                    <TRUNCATED FOR BREVITY>
                    {
                        "name": "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
                        "value": "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"
                    }
                ]
            },
            {
                "name": "Remove non-alphabet chars",
                "type": "boolean",
                "value": true
            },
            {
                "name": "Strict mode",
                "type": "boolean",
                "value": false
            }
        ],
        "checks": [
            {
                "pattern": "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
                "flags": "i",
                "args": [
                    "A-Za-z0-9+/=",
                    true,
                    false
                ]
            },
            <TRUNCATED FOR BREVITY>
            {
                "pattern": "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
                "flags": "i",
                "args": [
                    "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
                    true,
                    false
                ]
            }
        ]
    },
    "To Base64": {
        "module": "Default",
        "description": "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation encodes raw data into an ASCII Base64 string.<br><br>e.g. <code>hello</code> becomes <code>aGVsbG8=</code>",
        "infoURL": "https://wikipedia.org/wiki/Base64",
        "inputType": "ArrayBuffer",
        "outputType": "string",
        "flowControl": false,
        "manualBake": false,
        "args": [
            {
                "name": "Alphabet",
                "type": "editableOption",
                "value": [
                    {
                        "name": "Standard (RFC 4648): A-Za-z0-9+/=",
                        "value": "A-Za-z0-9+/="
                    },
                    <TRUNCATED FOR BREVITY> 
                    {
                        "name": "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
                        "value": "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"
                    }
                ]
            }
        ]
    }
}
  • I then removed everything from src/core/config/modules except for the following generated files (although I’m guessing these will be regenerated when rebuilding, looking at the build logs):
    • Default.mjs
    • OpModules.mjs
  • I then removed everything from src/core/operations except for the following:
    • FromBase64.mjs
    • ToBase64.mjs
  • I removed the entire src/core/vendor/tesseract directory
  • I removed everything from src/core/vendor/gost except what were dependencies (having done an “import trace”):
    • gostCipher.mjs
    • gostCoding.mjs
    • gostCrypto.mjs
    • gostDigest.mjs
    • gostEngine.mjs
    • gostRandom.mjs
    • gostSign.mjs
  • could have removed everything from src/core/lib except for the following, but did not try (just do an “import trace” to see what dependencies there are):
    • Base64.mjs
    • Hex.mjs
    • Decimal.mjs
    • Binary.mjs

 

Rebuild and Strip Some More

With all these changes, I rebuilt it (npm run build).

I then realised that the build/prod/assets directory actually contained two .gz files which contained the uncompressed versions of the files in the same directory – so I deleted them:

  • main.js (also found in main.js.gz)
  • main.css (also found in main.css.gz)

Just remember to get the uncompressed versions back from the .gz files at the destination!

 

End Result

At the end, I got a ~2.8MB .zip compressed file that I could transfer easily to help encode and decode files in Base64 using a modern browser reading local files.

I still got some compile-time errors, but the files were output and everything worked so I did not bother to dig further:

$ npm run build

> cyberchef@11.0.0 build
> npx grunt prod

Running "eslint:configs" (eslint) task

Running "eslint:core" (eslint) task

Running "eslint:web" (eslint) task

Running "eslint:node" (eslint) task

Running "eslint:tests" (eslint) task

Running "clean:prod" (clean) task
>> 0 paths cleaned.

Running "clean:config" (clean) task
>> 3 paths cleaned.

Running "exec:generateConfig" (exec) task

--- Regenerating config files. ---
Written operation index.
Written OperationConfig.json
Written Default module
Written OpModules.mjs
--- Config scripts finished. ---


Running "findModules" task
Found 0 modules.

Running "webpack:web" (webpack) task
99% done plugins webpack-bundle-analyzerError parsing bundle asset "/home/<REDACTED>/CyberChef/build/prod/ChefWorker.js": no such file {
  cause: Error: ENOENT: no such file or directory, open '/home/<REDACTED>/CyberChef/build/prod/ChefWorker.js'
      at Object.readFileSync (node:fs:441:20)
      at parseBundle (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/parseUtils.js:253:22)
      at Object.getViewerData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/analyzer.js:260:22)
      at getChartData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:82:26)
      at Object.generateReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:246:21)
      at BundleAnalyzerPlugin.generateStaticReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:203:18)
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:116:33
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:53
      at Array.map ()
      at Immediate._onImmediate (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:39)
      at process.processImmediate (node:internal/timers:504:21) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/home/<REDACTED>/CyberChef/build/prod/ChefWorker.js'
  }
}
Error parsing bundle asset "/home/<REDACTED>/CyberChef/build/prod/DishWorker.js": no such file {
  cause: Error: ENOENT: no such file or directory, open '/home/<REDACTED>/CyberChef/build/prod/DishWorker.js'
      at Object.readFileSync (node:fs:441:20)
      at parseBundle (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/parseUtils.js:253:22)
      at Object.getViewerData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/analyzer.js:260:22)
      at getChartData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:82:26)
      at Object.generateReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:246:21)
      at BundleAnalyzerPlugin.generateStaticReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:203:18)
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:116:33
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:53
      at Array.map ()
      at Immediate._onImmediate (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:39)
      at process.processImmediate (node:internal/timers:504:21) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/home/<REDACTED>/CyberChef/build/prod/DishWorker.js'
  }
}
Error parsing bundle asset "/home/<REDACTED>/CyberChef/build/prod/InputWorker.js": no such file {
  cause: Error: ENOENT: no such file or directory, open '/home/<REDACTED>/CyberChef/build/prod/InputWorker.js'
      at Object.readFileSync (node:fs:441:20)
      at parseBundle (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/parseUtils.js:253:22)
      at Object.getViewerData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/analyzer.js:260:22)
      at getChartData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:82:26)
      at Object.generateReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:246:21)
      at BundleAnalyzerPlugin.generateStaticReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:203:18)
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:116:33
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:53
      at Array.map ()
      at Immediate._onImmediate (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:39)
      at process.processImmediate (node:internal/timers:504:21) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/home/<REDACTED>/CyberChef/build/prod/InputWorker.js'
  }
}
Error parsing bundle asset "/home/<REDACTED>/CyberChef/build/prod/LoaderWorker.js": no such file {
  cause: Error: ENOENT: no such file or directory, open '/home/<REDACTED>/CyberChef/build/prod/LoaderWorker.js'
      at Object.readFileSync (node:fs:441:20)
      at parseBundle (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/parseUtils.js:253:22)
      at Object.getViewerData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/analyzer.js:260:22)
      at getChartData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:82:26)
      at Object.generateReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:246:21)
      at BundleAnalyzerPlugin.generateStaticReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:203:18)
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:116:33
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:53
      at Array.map ()
      at Immediate._onImmediate (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:39)
      at process.processImmediate (node:internal/timers:504:21) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/home/<REDACTED>/CyberChef/build/prod/LoaderWorker.js'
  }
}
Error parsing bundle asset "/home/<REDACTED>/CyberChef/build/prod/ZipWorker.js": no such file {
  cause: Error: ENOENT: no such file or directory, open '/home/<REDACTED>/CyberChef/build/prod/ZipWorker.js'
      at Object.readFileSync (node:fs:441:20)
      at parseBundle (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/parseUtils.js:253:22)
      at Object.getViewerData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/analyzer.js:260:22)
      at getChartData (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:82:26)
      at Object.generateReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/viewer.js:246:21)
      at BundleAnalyzerPlugin.generateStaticReport (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:203:18)
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:116:33
      at /home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:53
      at Array.map ()
      at Immediate._onImmediate (/home/<REDACTED>/CyberChef/node_modules/webpack-bundle-analyzer/lib/BundleAnalyzerPlugin.js:124:39)
      at process.processImmediate (node:internal/timers:504:21) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/home/<REDACTED>/CyberChef/build/prod/ZipWorker.js'
  }
}
Webpack Bundle Analyzer saved report to /home/<REDACTED>/CyberChef/build/prod/BundleAnalyzerReport.html
assets by path *.txt 23.6 KiB
  asset DishWorker.js.LICENSE.txt 5.33 KiB [emitted]
  asset ChefWorker.js.LICENSE.txt 5.32 KiB [emitted]
  + 3 assets
assets by path assets/ 7.48 MiB
  assets by chunk 7.14 MiB (name: main) 2 assets
  assets by info 347 KiB [immutable] 2 assets
assets by path images/*.png 31.7 KiB
  asset images/file-128x128.png 18.9 KiB [emitted] [from: src/web/static/images/file-128x128.png] (auxiliary name: main)
  asset images/cyberchef-128x128.png 5.83 KiB [emitted] [from: src/web/static/images/cyberchef-128x128.png]
  asset images/fork_me.png 5.33 KiB [emitted] [from: src/web/static/images/fork_me.png]
  asset images/cook_male-32x32.png 1.59 KiB [emitted] [from: src/web/static/images/cook_male-32x32.png]
asset index.html 75.6 KiB [emitted] 2 related assets
webpack 5.107.2 compiled successfully in 22582 ms

Running "copy:standalone" (copy) task
Copied 1 file

Running "zip:standalone" (zip) task
File "build/prod/CyberChef_v11.0.0.zip" created.

Running "clean:standalone" (clean) task
>> 1 path cleaned.

Running "exec:calcDownloadHash" (exec) task

Running "chmod:build" (chmod) task
>> 28 files had their `chmod` mode set to "755".

Done.

Leave a Reply