diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index e90ab51f..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.github/ISSUE_TEMPLATE/operation-request.md b/.github/ISSUE_TEMPLATE/operation-request.md index d88e6703..05231a86 100644 --- a/.github/ISSUE_TEMPLATE/operation-request.md +++ b/.github/ISSUE_TEMPLATE/operation-request.md @@ -7,8 +7,14 @@ assignees: '' --- -## Summary +**Is your operation request related to a problem? Please describe.** +A clear and concise description of what the problem is. E.g. I'm always frustrated when [...] -### Example Input +**Describe the solution you'd like** +A clear and concise description of the new operation you would like. -### Example Output +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Example input and output** +Provide an example input to the operation, along with the output that you would expect. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index cc66c319..c1b09d96 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -43,6 +43,8 @@ updates: versions: [ '>=0.4.0' ] - dependency-name: 'geodesy' versions: [ '>=2.0.0' ] + - dependency-name: 'jimp' + versions: [ '1.6.1' ] - dependency-name: 'otpauth' versions: [ '>=9.4.0' ] - dependency-name: 'webpack-dev-server' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..8d6cc970 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ +**Description** +Provide a description of the pull request and the changes that it makes. + +**Existing Issue** +If this pull request relates to an existing issue in the repository, please link it here. + +**Screenshots** +If the pull request changes any visual aspects of CyberChef, please include screenshots. + +**AI disclosure** +If you have used any AI tools while creating this code, **you must declare your usage along with the name of the tools that you used**. +Regardless of AI tool usage, you are responsible for any code that you submit, and we expect you to have checked the code and have enough of an understanding of it to answer any questions we might have. + +**Test Coverage** +Please ensure you have added test coverage for your changes. diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index bcf10fb7..78ec1f41 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -26,8 +26,7 @@ jobs: - name: Install run: | - export DETECT_CHROMEDRIVER_VERSION=true - npm install + npm ci npm run setheapsize - name: Lint diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index c34f357f..7c731176 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -22,8 +22,7 @@ jobs: - name: Install run: | - export DETECT_CHROMEDRIVER_VERSION=true - npm install + npm ci npm run setheapsize - name: Lint @@ -38,7 +37,22 @@ jobs: if: success() run: npx grunt prod + - name: Upload Build Artefact + if: success() + uses: actions/upload-artifact@v7 + with: + name: zipped-build + path: build/prod/*.zip + retention-days: 5 + + - name: UI Tests + if: success() + run: | + sudo apt-get install xvfb + xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui + - name: Set up Docker Buildx + if: success() uses: docker/setup-buildx-action@v3 - name: Set up QEMU @@ -50,8 +64,3 @@ jobs: uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 - - name: UI Tests - if: success() - run: | - sudo apt-get install xvfb - xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index bf977c19..8230dbfd 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -32,7 +32,6 @@ jobs: - name: Install run: | - export DETECT_CHROMEDRIVER_VERSION=true npm ci npm run setheapsize diff --git a/CHANGELOG.md b/CHANGELOG.md index 960e922b..0a8a0b79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,88 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [10.24.0] - 2026-04-27 +- Update CONTRIBUTING.md [@GCHQDeveloper581] | [#2333] +- Fix, and link, Fernet tests [@GCHQDeveloper581] | [#2335] +- [#927] added parity bit operation [@j83305] | [#1036] +- Feature md link blanks [@BjoernAkAManf] [@GCHQDeveloper581] | [#660] +- Accessibility - Add support for screenreaders in operations search [@mattnotmitt] | [#1862] +- Added metadata extraction for UUID strings. [@ko80240] | [#2322] +- chore (deps): bump the patch-updates group with 6 updates | [#2330] +- chore (deps): bump @codemirror/search from 6.6.0 to 6.7.0 | [#2331] +- (Feature) Improve CI [@GCHQDeveloper581] | [#2328] +- Update dependabot.yml [@GCHQDeveloper581] | [#2326] +- chore (deps): bump lodash, grunt-legacy-log and grunt-legacy-util | [#2327] +- chore (deps): bump the patch-updates group with 6 updates [@GCHQDeveloper581] | [#2323] +- chore (deps): bump autoprefixer from 10.4.27 to 10.5.0 | [#2324] +- chore (deps): bump dompurify from 3.3.3 to 3.4.0 | [#2321] +- chore (deps): bump follow-redirects from 1.15.11 to 1.16.0 | [#2320] +- Regular Expression operation email address regex: Support IPv4 domains [@C85297] [@GCHQDeveloper581] | [#2167] +- Rewriting fixCryptoApiImports and fixSnackbarMarkup to js to make it OS agnostic [@BigYellowHammer] | [#2298] +- chore (deps): bump basic-ftp from 5.2.1 to 5.2.2 | [#2317] +- chore (deps): bump axios from 1.13.6 to 1.15.0 | [#2316] +- chore (deps): bump webpack from 5.105.4 to 5.106.0 | [#2315] +- chore (deps): bump basic-ftp from 5.2.0 to 5.2.1 | [#2313] +- Update vulnerable dependencies [@GCHQDeveloper581] | [#2311] + +### [10.23.0] - 2026-04-06 +- Properly escape HTML entities in sampleDelim to avoid XSS issue [@GCHQDeveloper581] | [#2307] +- chore (deps): bump lodash from 4.17.23 to 4.18.1 | [#2304] +- chore (deps): bump @codemirror/view from 6.40.0 to 6.41.0 | [#2305] +- chore (deps): bump the patch-updates group with 2 updates | [#2303] +- chore (deps): bump @xmldom/xmldom from 0.8.11 to 0.8.12 | [#2302] +- chore (deps): bump picomatch | [#2299] +- chore (deps): bump node-forge from 1.3.3 to 1.4.0 | [#2297] +- chore (deps): bump the patch-updates group with 3 updates | [#2296] +- chore (deps) bump chromedriver from 130.0.4 to 146.0.6 [@GCHQDeveloper581] | [#2292] +- ParseEthernetFrame - Fix vlan calculation [@Kalkran] | [#2295] +- Add pull request template with AI usage disclosure [@C85297] | [#2279] +- fix: return empty output for zero-length To Modhex input [@saschabuehrle] | [#2249] +- Added tab focus to top banner and navigation to About/Support Modal [@j264415] | [#1733] +- Add Parse Ethernet frame Operation, allow Parse IPv4 Header to cascade [@Kalkran] | [#1722] +- Selection and Deselection of autobake checkbox using keyboard [@j264415] | [#1727] +- chore (deps): bump @babel/runtime from 7.28.6 to 7.29.2 | [#2263] +- Add more helpful error for when numerical ingredient is left empty [@Lamby777] [@C85297] | [#1540] +- chore (deps): bump @codemirror/view from 6.39.17 to 6.40.0 | [#2262] +- Bump flatted from 3.3.2 to 3.4.2 [@GCHQDeveloper581] | [#2266] +- feat: add Raw option for Jq operation [@rtpt-romankarwacik] | [#2237] +- chore (deps): bump core-js from 3.48.0 to 3.49.0 | [#2261] +- chore (deps): bump the patch-updates group with 6 updates | [#2260] +- Add Extract Audio Metadata operation [@d0s1nt] [@GCHQDeveloper581] | [#2170] +- Fix Jq issue [@GCHQDeveloper581] | [#2210] +- Configure dependabot updates [@GCHQDeveloper581] | [#2259] +- fix(A1Z26): return empty string instead of empty array for empty input [@brick-pixel] | [#2257] +- Fix broken Docker link in README [@am-periphery] | [#2250] +- Update some dependencies, including a number causing npm audit warnings [@GCHQDeveloper581] | [#2236] +- Bump axios from 1.7.9 to 1.13.6 | [#2234] +- Bump jws from 3.2.2 to 3.2.3 | [#2235] +- Bump pbkdf2 from 3.1.2 to 3.1.5 | [#2229] +- Bump form-data from 4.0.1 to 4.0.5 | [#2228] +- Bump basic-ftp from 5.0.5 to 5.2.0 | [#2231] +- feat: add ARM disassembler operation [@thomasxm] | [#2156] +- Add Text/Integer Converter operation [@p-leriche] [@GCHQDeveloper581] | [#2213] +- Feat/rc6 add RC6 Encrypt/Decrypt operations [@thomasxm] | [#2163] +- [bugfix] Add Bootstrap form style for CodeMirror editor [@Swonkie] | [#2161] +- Add Flask Session operations (Decode, Sign, Verify) [@ThePlayer372-FR] | [#2208] +- fix: `jq-web` -> `jq-wasm`, includes `jq` version `1.8.1` [@W-Floyd] [@GCHQDeveloper581] | [#2223] +- Bump jsonwebtoken from 8.5.1 to 9.0.0 [@GCHQDeveloper581] | [#2219] +- Bump basic-ftp from 5.0.5 to 5.2.0 | [#2218] +- feat: add random integer generation operation [@cktgh] | [#2151] +- Add BigInt utility functions for number theory operations [@p-leriche] [@GCHQDeveloper581] | [#2205] +- Improve SQL Beautify: use sql-formatter and support bind variables [@aby-jo] [@GCHQDeveloper581] | [#2071] +- update tesseract.js to 6.0.1 [@atsiv1] | [#2133] +- Fix hint tooltip display issues [@bartvanandel] | [#2017] +- Simplify babel dependencies [@GCHQDeveloper581] | [#2204] +- Dependency updates [@GCHQDeveloper581] | [#2201] +- Fix: Move Magic checks from Escape to Unescape Unicode Characters [@fjh1997] | [#2195] +- Paste spreadsheets as text [@C85297] | [#2200] +- Fix Roboto Mono font [@C85297] | [#2199] +- Fix return of buffer for PNG QR image generation [@GCHQDeveloper581] [@C85297] | [#2125] +- Update JIMP [@C85297] | [#2171] +- Overwrite NGINX maintainer label [@C85297] | [#2194] +- Bump v10.22.1 [@GCHQDeveloper581] | [#2193] +- Fix npm publish - Run "npm ci" and "npm run node" under node 18 then switch to node 24.5 [@GCHQDeveloper581] | [#2192] + ### [10.22.0] - 2026-02-11 - Separate npm publish out into separate job and run with Node 24.5 [@GCHQDeveloper581] | [#2188] - Fixed Percent delimiter for hex encoding [@beneri] [@C85297] | [#2137] @@ -538,6 +620,8 @@ All major and minor version changes will be documented in this file. Details of ## [4.0.0] - 2016-11-28 - Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306) +[10.24.0]: https://github.com/gchq/CyberChef/releases/tag/v10.24.0 +[10.23.0]: https://github.com/gchq/CyberChef/releases/tag/v10.23.0 [10.22.0]: https://github.com/gchq/CyberChef/releases/tag/v10.22.0 [10.21.0]: https://github.com/gchq/CyberChef/releases/tag/v10.21.0 [10.20.0]: https://github.com/gchq/CyberChef/releases/tag/v10.20.0 @@ -797,6 +881,26 @@ All major and minor version changes will be documented in this file. Details of [@t-martine]: https://github.com/t-martine [@wesinator]: https://github.com/wesinator [@Raka-loah]: https://github.com/Raka-loah +[@Kalkran]: https://github.com/Kalkran +[@saschabuehrle]: https://github.com/saschabuehrle +[@j264415]: https://github.com/j264415 +[@Lamby777]: https://github.com/Lamby777 +[@rtpt-romankarwacik]: https://github.com/rtpt-romankarwacik +[@d0s1nt]: https://github.com/d0s1nt +[@brick-pixel]: https://github.com/brick-pixel +[@am-periphery]: https://github.com/am-periphery +[@p-leriche]: https://github.com/p-leriche +[@Swonkie]: https://github.com/Swonkie +[@ThePlayer372-FR]: https://github.com/ThePlayer372-FR +[@W-Floyd]: https://github.com/W-Floyd +[@cktgh]: https://github.com/cktgh +[@aby-jo]: https://github.com/aby-jo +[@atsiv1]: https://github.com/atsiv1 +[@fjh1997]: https://github.com/fjh1997 +[@j83305]: https://github.com/j83305 +[@BjoernAkAManf]: https://github.com/BjoernAkAManf +[@ko80240]: https://github.com/ko80240 +[@BigYellowHammer]: https://github.com/BigYellowHammer [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 @@ -1010,4 +1114,82 @@ All major and minor version changes will be documented in this file. Details of [#2183]: https://github.com/gchq/CyberChef/pull/2183 [#2182]: https://github.com/gchq/CyberChef/pull/2182 [#2181]: https://github.com/gchq/CyberChef/pull/2181 +[#2307]: https://github.com/gchq/CyberChef/pull/2307 +[#2304]: https://github.com/gchq/CyberChef/pull/2304 +[#2305]: https://github.com/gchq/CyberChef/pull/2305 +[#2303]: https://github.com/gchq/CyberChef/pull/2303 +[#2302]: https://github.com/gchq/CyberChef/pull/2302 +[#2299]: https://github.com/gchq/CyberChef/pull/2299 +[#2297]: https://github.com/gchq/CyberChef/pull/2297 +[#2296]: https://github.com/gchq/CyberChef/pull/2296 +[#2292]: https://github.com/gchq/CyberChef/pull/2292 +[#2295]: https://github.com/gchq/CyberChef/pull/2295 +[#2279]: https://github.com/gchq/CyberChef/pull/2279 +[#2249]: https://github.com/gchq/CyberChef/pull/2249 +[#1733]: https://github.com/gchq/CyberChef/pull/1733 +[#1722]: https://github.com/gchq/CyberChef/pull/1722 +[#1727]: https://github.com/gchq/CyberChef/pull/1727 +[#2263]: https://github.com/gchq/CyberChef/pull/2263 +[#1540]: https://github.com/gchq/CyberChef/pull/1540 +[#2262]: https://github.com/gchq/CyberChef/pull/2262 +[#2266]: https://github.com/gchq/CyberChef/pull/2266 +[#2237]: https://github.com/gchq/CyberChef/pull/2237 +[#2261]: https://github.com/gchq/CyberChef/pull/2261 +[#2260]: https://github.com/gchq/CyberChef/pull/2260 +[#2170]: https://github.com/gchq/CyberChef/pull/2170 +[#2210]: https://github.com/gchq/CyberChef/pull/2210 +[#2259]: https://github.com/gchq/CyberChef/pull/2259 +[#2257]: https://github.com/gchq/CyberChef/pull/2257 +[#2250]: https://github.com/gchq/CyberChef/pull/2250 +[#2236]: https://github.com/gchq/CyberChef/pull/2236 +[#2234]: https://github.com/gchq/CyberChef/pull/2234 +[#2235]: https://github.com/gchq/CyberChef/pull/2235 +[#2229]: https://github.com/gchq/CyberChef/pull/2229 +[#2228]: https://github.com/gchq/CyberChef/pull/2228 +[#2231]: https://github.com/gchq/CyberChef/pull/2231 +[#2156]: https://github.com/gchq/CyberChef/pull/2156 +[#2213]: https://github.com/gchq/CyberChef/pull/2213 +[#2163]: https://github.com/gchq/CyberChef/pull/2163 +[#2161]: https://github.com/gchq/CyberChef/pull/2161 +[#2208]: https://github.com/gchq/CyberChef/pull/2208 +[#2223]: https://github.com/gchq/CyberChef/pull/2223 +[#2219]: https://github.com/gchq/CyberChef/pull/2219 +[#2218]: https://github.com/gchq/CyberChef/pull/2218 +[#2151]: https://github.com/gchq/CyberChef/pull/2151 +[#2205]: https://github.com/gchq/CyberChef/pull/2205 +[#2071]: https://github.com/gchq/CyberChef/pull/2071 +[#2133]: https://github.com/gchq/CyberChef/pull/2133 +[#2017]: https://github.com/gchq/CyberChef/pull/2017 +[#2204]: https://github.com/gchq/CyberChef/pull/2204 +[#2201]: https://github.com/gchq/CyberChef/pull/2201 +[#2195]: https://github.com/gchq/CyberChef/pull/2195 +[#2200]: https://github.com/gchq/CyberChef/pull/2200 +[#2199]: https://github.com/gchq/CyberChef/pull/2199 +[#2125]: https://github.com/gchq/CyberChef/pull/2125 +[#2171]: https://github.com/gchq/CyberChef/pull/2171 +[#2194]: https://github.com/gchq/CyberChef/pull/2194 +[#2193]: https://github.com/gchq/CyberChef/pull/2193 +[#2192]: https://github.com/gchq/CyberChef/pull/2192 +[#2333]: https://github.com/gchq/CyberChef/pull/2333 +[#2335]: https://github.com/gchq/CyberChef/pull/2335 +[#1036]: https://github.com/gchq/CyberChef/pull/1036 +[#660]: https://github.com/gchq/CyberChef/pull/660 +[#1862]: https://github.com/gchq/CyberChef/pull/1862 +[#2322]: https://github.com/gchq/CyberChef/pull/2322 +[#2330]: https://github.com/gchq/CyberChef/pull/2330 +[#2331]: https://github.com/gchq/CyberChef/pull/2331 +[#2328]: https://github.com/gchq/CyberChef/pull/2328 +[#2326]: https://github.com/gchq/CyberChef/pull/2326 +[#2327]: https://github.com/gchq/CyberChef/pull/2327 +[#2323]: https://github.com/gchq/CyberChef/pull/2323 +[#2324]: https://github.com/gchq/CyberChef/pull/2324 +[#2321]: https://github.com/gchq/CyberChef/pull/2321 +[#2320]: https://github.com/gchq/CyberChef/pull/2320 +[#2167]: https://github.com/gchq/CyberChef/pull/2167 +[#2298]: https://github.com/gchq/CyberChef/pull/2298 +[#2317]: https://github.com/gchq/CyberChef/pull/2317 +[#2316]: https://github.com/gchq/CyberChef/pull/2316 +[#2315]: https://github.com/gchq/CyberChef/pull/2315 +[#2313]: https://github.com/gchq/CyberChef/pull/2313 +[#2311]: https://github.com/gchq/CyberChef/pull/2311 diff --git a/.github/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 90% rename from .github/CONTRIBUTING.md rename to CONTRIBUTING.md index abb37d42..0cee9a7b 100644 --- a/.github/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,10 +6,13 @@ There are lots of opportunities to contribute to CyberChef. If you want ideas, t Before your contributions can be accepted, you must: - - Sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) + - Fork the CyberChef repo + - Create a new branch within your fork for the changes - Push your changes to your fork. + - Sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) - Submit a pull request. +Please note that we will ***reject*** pull requests from the master branch of your fork owing to the mess it makes of our own working repositories and the extra work entailed. ## Coding conventions diff --git a/Dockerfile b/Dockerfile index 8511dc72..b0a1024d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ RUN npm run build ######################################### # Package static build files into nginx # ######################################### -FROM nginx:stable-alpine AS cyberchef +FROM nginxinc/nginx-unprivileged:stable-alpine AS cyberchef LABEL maintainer="GCHQ " diff --git a/Gruntfile.js b/Gruntfile.js index a67aa5b8..b04f3048 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -411,25 +411,11 @@ module.exports = function (grunt) { stdout: false, }, fixCryptoApiImports: { - command: function () { - switch (process.platform) { - case "darwin": - return `find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i '' -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`; - default: - return `find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`; - } - }, + command: `node ${nodeFlags} src/core/config/scripts/fixCryptoApiImports.mjs`, stdout: false }, fixSnackbarMarkup: { - command: function () { - switch (process.platform) { - case "darwin": - return `sed -i '' 's/
/
/g' ./node_modules/snackbarjs/src/snackbar.js`; - default: - return `sed -i 's/
/
/g' ./node_modules/snackbarjs/src/snackbar.js`; - } - }, + command: `node ${nodeFlags} src/core/config/scripts/fixSnackBarMarkup.mjs`, stdout: false }, }, diff --git a/README.md b/README.md index 4b99cf35..c1c90f2e 100755 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ docker build --tag cyberchef --ulimit nofile=10000 . ``` 2. Run the docker container ```bash -docker run -it -p 8080:80 cyberchef +docker run -it -p 8080:8080 cyberchef ``` 3. Navigate to `http://localhost:8080` in your browser @@ -45,7 +45,7 @@ docker run -it -p 8080:80 cyberchef If you prefer to skip the build process, you can use the pre-built image ```bash -docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest +docker run -it -p 8080:8080 ghcr.io/gchq/cyberchef:latest ``` Just like before, navigate to `http://localhost:8080` in your browser. diff --git a/package-lock.json b/package-lock.json index 607aeca3..66cec577 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "10.22.1", + "version": "10.24.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "10.22.1", + "version": "10.24.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -14,9 +14,9 @@ "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", - "@xmldom/xmldom": "^0.8.11", + "@xmldom/xmldom": "^0.8.13", "argon2-browser": "^1.18.0", - "arrive": "^2.5.2", + "arrive": "^2.5.3", "assert": "^2.1.0", "avsc": "^5.7.9", "bcryptjs": "^2.4.3", @@ -38,7 +38,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.2", - "dompurify": "^3.3.3", + "dompurify": "^3.4.1", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -48,11 +48,11 @@ "file-saver": "^2.0.5", "flat": "^6.0.1", "geodesy": "1.1.3", - "handlebars": "^4.7.8", + "handlebars": "^4.7.9", "hash-wasm": "^4.12.0", "highlight.js": "^11.11.1", "ieee754": "^1.2.1", - "jimp": "^1.6.0", + "jimp": "1.6.0", "jq-web": "^0.5.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", @@ -62,11 +62,11 @@ "jsonpath-plus": "^10.4.0", "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", - "jsrsasign": "^11.1.1", + "jsrsasign": "^11.1.3", "kbpgp": "^2.1.17", "libbzip2-wasm": "0.0.4", "libyara-wasm": "^1.2.1", - "lodash": "^4.17.23", + "lodash": "^4.18.1", "loglevel": "^1.9.2", "loglevel-message-prefix": "^3.0.0", "lz-string": "^1.5.0", @@ -75,7 +75,7 @@ "moment": "^2.30.1", "moment-timezone": "^0.6.1", "ngeohash": "^0.6.3", - "node-forge": "^1.3.3", + "node-forge": "^1.4.0", "node-md6": "^0.1.0", "nodom": "^2.4.0", "notepack.io": "^3.0.1", @@ -85,7 +85,7 @@ "path": "^0.12.7", "popper.js": "^1.16.1", "process": "^0.11.10", - "protobufjs": "^7.5.4", + "protobufjs": "^7.5.5", "qr-image": "^3.2.0", "reflect-metadata": "^0.2.2", "rison": "^0.1.1", @@ -93,7 +93,7 @@ "snackbarjs": "^1.1.0", "sortablejs": "^1.15.7", "split.js": "^1.6.5", - "sql-formatter": "^15.6.12", + "sql-formatter": "^15.7.3", "ssdeep.js": "0.0.3", "stream-browserify": "^3.0.0", "tesseract.js": "^6.0.1", @@ -114,14 +114,14 @@ "@babel/preset-env": "^7.29.2", "@babel/runtime": "^7.29.2", "@codemirror/commands": "^6.10.3", - "@codemirror/language": "^6.12.2", - "@codemirror/search": "^6.6.0", + "@codemirror/language": "^6.12.3", + "@codemirror/search": "^6.7.0", "@codemirror/state": "^6.5.4", - "@codemirror/view": "^6.40.0", - "autoprefixer": "^10.4.27", + "@codemirror/view": "^6.41.1", + "autoprefixer": "^10.5.0", "babel-loader": "^10.1.1", "base64-loader": "^1.0.0", - "chromedriver": "^130.0.4", + "chromedriver": "^146.0.6", "cli-progress": "^3.12.0", "colors": "^1.4.0", "compression-webpack-plugin": "^11.1.0", @@ -132,7 +132,7 @@ "eslint": "^9.39.4", "eslint-plugin-jsdoc": "^50.8.0", "globals": "^15.15.0", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-chmod": "~1.1.1", "grunt-concurrent": "^3.0.0", "grunt-contrib-clean": "~2.0.1", @@ -143,19 +143,19 @@ "grunt-exec": "~3.0.0", "grunt-webpack": "^6.0.0", "grunt-zip": "^1.0.0", - "html-webpack-plugin": "^5.6.6", + "html-webpack-plugin": "^5.6.7", "imports-loader": "^5.0.0", - "mini-css-extract-plugin": "2.10.1", + "mini-css-extract-plugin": "2.10.2", "modify-source-webpack-plugin": "^4.1.0", "nightwatch": "^3.15.0", - "postcss": "^8.5.8", + "postcss": "^8.5.10", "postcss-css-variables": "^0.19.0", "postcss-import": "^16.1.1", "postcss-loader": "^8.2.1", "prompt": "^1.3.0", "sitemap": "^8.0.3", - "terser": "^5.46.1", - "webpack": "^5.105.4", + "terser": "^5.46.2", + "webpack": "^5.106.2", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "5.0.4", "webpack-node-externals": "^3.0.0", @@ -1853,9 +1853,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz", - "integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz", + "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==", "dev": true, "license": "MIT", "dependencies": { @@ -1868,9 +1868,9 @@ } }, "node_modules/@codemirror/search": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz", - "integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz", + "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==", "dev": true, "license": "MIT", "dependencies": { @@ -1890,9 +1890,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.40.0", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.40.0.tgz", - "integrity": "sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg==", + "version": "6.41.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.41.1.tgz", + "integrity": "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==", "dev": true, "license": "MIT", "dependencies": { @@ -4524,9 +4524,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5003,9 +5003,9 @@ } }, "node_modules/arrive": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/arrive/-/arrive-2.5.2.tgz", - "integrity": "sha512-A9asXhuUR6pgHtwUciZw4FRZDR09ZwVsz1ckEGE6W9gXWrYM9cAkuKzHplpYN0bd/iobg0xqQ9fpRr/GHPsXUw==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/arrive/-/arrive-2.5.3.tgz", + "integrity": "sha512-FsZjDDxS2BZ1TuGvqhTf8KbGaH0hOx+DS7HhYIvsreCkAuSUFgJ9NUhIC4f3SM3c5T/1he1KAn566GZjzqJarA==", "license": "MIT" }, "node_modules/asn1.js": { @@ -5089,9 +5089,9 @@ "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.27", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", - "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", "dev": true, "funding": [ { @@ -5109,8 +5109,8 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001774", + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -5169,15 +5169,25 @@ } }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/babel-loader": { @@ -5283,9 +5293,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "version": "2.10.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", + "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5316,9 +5326,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", - "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.2.tgz", + "integrity": "sha512-1tDrzKsdCg70WGvbFss/ulVAxupNauGnOlgpyjKzeQxzyllBLS0CGLV7tjIXTK3ZQA9/FBEm9qyFFN1bciA6pw==", "dev": true, "license": "MIT", "engines": { @@ -5738,9 +5748,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -5855,9 +5865,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -5875,11 +5885,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -6087,9 +6097,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", "dev": true, "funding": [ { @@ -6246,26 +6256,36 @@ } }, "node_modules/chromedriver": { - "version": "130.0.4", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-130.0.4.tgz", - "integrity": "sha512-lpR+PWXszij1k4Ig3t338Zvll9HtCTiwoLM7n4pCCswALHxzmgwaaIFBh3rt9+5wRk9D07oFblrazrBxwaYYAQ==", + "version": "146.0.6", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-146.0.6.tgz", + "integrity": "sha512-FIRi3hy0nRiyirK03etVXEpYTIodevFcvTBAM5ZCq+pX3w31jLm6JE8BVW1ypAVLvSp6HJDvboCcdgUroS3miw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@testim/chrome-version": "^1.1.4", - "axios": "^1.7.4", + "axios": "^1.13.5", "compare-versions": "^6.1.0", "extract-zip": "^2.0.1", - "proxy-agent": "^6.4.0", - "proxy-from-env": "^1.1.0", + "proxy-agent": "^6.5.0", + "proxy-from-env": "^2.0.0", "tcp-port-used": "^1.0.2" }, "bin": { "chromedriver": "bin/chromedriver" }, "engines": { - "node": ">=18" + "node": ">=20" + } + }, + "node_modules/chromedriver/node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/ci-info": { @@ -7127,9 +7147,9 @@ } }, "node_modules/cspell-glob/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -8276,9 +8296,9 @@ } }, "node_modules/dompurify": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", - "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.1.tgz", + "integrity": "sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -8397,9 +8417,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "version": "1.5.339", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.339.tgz", + "integrity": "sha512-Is+0BBHJ4NrdpAYiperrmp53pLywG/yV/6lIMTAnhxvzj/Cmn5Q/ogSHC6AKe7X+8kPLxxFk0cs5oc/3j/fxIg==", "dev": true, "license": "ISC" }, @@ -9128,6 +9148,16 @@ "node": ">= 0.8.0" } }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -9469,9 +9499,9 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -9634,9 +9664,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -10150,9 +10180,9 @@ "license": "ISC" }, "node_modules/grunt": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz", - "integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.2.tgz", + "integrity": "sha512-bUzh5nA/P5L66ihXTDP6J5BGnMB/8lXJXejYWSbH4Y4TvWM9t2S39sggQDYYQlx06cYcCsmu63HMYHGCIzUVfg==", "dev": true, "license": "MIT", "dependencies": { @@ -10161,14 +10191,14 @@ "exit": "~0.1.2", "findup-sync": "~5.0.0", "glob": "~7.1.6", - "grunt-cli": "~1.4.3", + "grunt-cli": "^1.4.3", "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.6.3", "js-yaml": "~3.14.0", - "minimatch": "~3.0.4", - "nopt": "~3.0.6" + "minimatch": "^3.1.5", + "nopt": "^5.0.0" }, "bin": { "grunt": "bin/grunt" @@ -10410,30 +10440,29 @@ } }, "node_modules/grunt-legacy-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", - "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.1.tgz", + "integrity": "sha512-vytI3IUC8qUK9TcvvpHpGJzDojua/sfJV4TdLB4FtCFzospqduzBuL3+dEfpvO+tGECv7/273+33hjjMXSa92g==", "dev": true, "license": "MIT", "dependencies": { "colors": "~1.1.2", - "grunt-legacy-log-utils": "~2.1.0", + "grunt-legacy-log-utils": "^2.1.3", "hooker": "~0.2.3", - "lodash": "~4.17.19" + "lodash": "^4.18.0" }, "engines": { "node": ">= 0.10.0" } }, "node_modules/grunt-legacy-log-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", - "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.3.tgz", + "integrity": "sha512-sgG+QvKmdb44wZyzJP+ejDsy3jYxG2wzohpol+JTMlXqMUBDoZb01JPQ5jKAedtZBFwhmABAc88T9hEBLy3U+Q==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "~4.1.0", - "lodash": "~4.17.19" + "chalk": "^4.1.0" }, "engines": { "node": ">=10" @@ -10496,17 +10525,17 @@ } }, "node_modules/grunt-legacy-util": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", - "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.2.tgz", + "integrity": "sha512-0xoDILyR4BVJel5uJwnhjdWN9evOQ8A0uXbQUIJ0hgVthIA6kloXHSoqATQPj6BRrHrHkcQtCeGVb0ixFoHyEQ==", "dev": true, "license": "MIT", "dependencies": { "async": "~3.2.0", - "exit": "~0.1.2", + "exit-x": "~0.2.2", "getobject": "~1.0.0", "hooker": "~0.2.3", - "lodash": "~4.17.21", + "lodash": "^4.18.0", "underscore.string": "~3.3.5", "which": "~2.0.2" }, @@ -10585,9 +10614,9 @@ } }, "node_modules/grunt/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10628,9 +10657,9 @@ "license": "MIT" }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "license": "MIT", "dependencies": { "minimist": "^1.2.5", @@ -10898,9 +10927,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.6", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz", - "integrity": "sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==", + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", + "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", "dev": true, "license": "MIT", "dependencies": { @@ -12383,13 +12412,10 @@ "license": "Apache-2.0" }, "node_modules/jsrsasign": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.1.tgz", - "integrity": "sha512-6w95OOXH8DNeGxakqLndBEqqwQ6A70zGaky1oxfg8WVLWOnghTfJsc5Tknx+Z88MHSb1bGLcqQHImOF8Lk22XA==", - "license": "MIT", - "funding": { - "url": "https://github.com/kjur/jsrsasign#donations" - } + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.3.tgz", + "integrity": "sha512-nPnK5D/4lv0Dwr7TlzrKtAd8JlLZwFTqTUUB3NQCbtdobcRcohGFxjbPySDVh74iWUudcCsapYT6OxoyhJLhhA==", + "license": "MIT" }, "node_modules/jszip": { "version": "3.10.1", @@ -12666,9 +12692,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -13103,9 +13129,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.1.tgz", - "integrity": "sha512-k7G3Y5QOegl380tXmZ68foBRRjE9Ljavx835ObdvmZjQ639izvZD8CS7BkWw1qKPPzHsGL/JDhl0uyU1zc2rJw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", "dev": true, "license": "MIT", "dependencies": { @@ -13204,9 +13230,9 @@ } }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -13768,9 +13794,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", - "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -13805,9 +13831,9 @@ } }, "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, "license": "ISC", "dependencies": { @@ -13815,6 +13841,9 @@ }, "bin": { "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/normalize-path": { @@ -14608,9 +14637,9 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -14678,9 +14707,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -14786,9 +14815,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -15045,9 +15074,9 @@ "license": "MIT" }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -15429,9 +15458,9 @@ } }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -16623,9 +16652,9 @@ "license": "BSD-3-Clause" }, "node_modules/sql-formatter": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.7.2.tgz", - "integrity": "sha512-b0BGoM81KFRVSpZFwPpIPU5gng4YD8DI/taLD96NXCFRf5af3FzSE4aSwjKmxcyTmf/MfPu91j75883nRrWDBw==", + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.7.3.tgz", + "integrity": "sha512-5+zl9Nqg5aNjss0tb1G+StpC4dJKbjv3+g8CL/+V+00PfZop+2RKGyi53ScFl0dr+Dkx1LjmUO54Q3N7K3EtMw==", "license": "MIT", "dependencies": { "argparse": "^2.0.1", @@ -17033,9 +17062,9 @@ "license": "MIT" }, "node_modules/terser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", - "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "version": "5.46.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz", + "integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -17214,9 +17243,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -17861,9 +17890,9 @@ } }, "node_modules/webpack": { - "version": "5.105.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", - "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", + "version": "5.106.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz", + "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==", "dev": true, "license": "MIT", "dependencies": { @@ -17883,9 +17912,8 @@ "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", @@ -18075,9 +18103,9 @@ } }, "node_modules/webpack-dev-server/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -18206,6 +18234,16 @@ "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -18705,9 +18743,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", "bin": { diff --git a/package.json b/package.json index fe3d7a19..a6dd4979 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "10.22.1", + "version": "10.24.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", @@ -45,14 +45,14 @@ "@babel/preset-env": "^7.29.2", "@babel/runtime": "^7.29.2", "@codemirror/commands": "^6.10.3", - "@codemirror/language": "^6.12.2", - "@codemirror/search": "^6.6.0", + "@codemirror/language": "^6.12.3", + "@codemirror/search": "^6.7.0", "@codemirror/state": "^6.5.4", - "@codemirror/view": "^6.40.0", - "autoprefixer": "^10.4.27", + "@codemirror/view": "^6.41.1", + "autoprefixer": "^10.5.0", "babel-loader": "^10.1.1", "base64-loader": "^1.0.0", - "chromedriver": "^130.0.4", + "chromedriver": "^146.0.6", "cli-progress": "^3.12.0", "colors": "^1.4.0", "compression-webpack-plugin": "^11.1.0", @@ -63,7 +63,7 @@ "eslint": "^9.39.4", "eslint-plugin-jsdoc": "^50.8.0", "globals": "^15.15.0", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-chmod": "~1.1.1", "grunt-concurrent": "^3.0.0", "grunt-contrib-clean": "~2.0.1", @@ -74,19 +74,19 @@ "grunt-exec": "~3.0.0", "grunt-webpack": "^6.0.0", "grunt-zip": "^1.0.0", - "html-webpack-plugin": "^5.6.6", + "html-webpack-plugin": "^5.6.7", "imports-loader": "^5.0.0", - "mini-css-extract-plugin": "2.10.1", + "mini-css-extract-plugin": "2.10.2", "modify-source-webpack-plugin": "^4.1.0", "nightwatch": "^3.15.0", - "postcss": "^8.5.8", + "postcss": "^8.5.10", "postcss-css-variables": "^0.19.0", "postcss-import": "^16.1.1", "postcss-loader": "^8.2.1", "prompt": "^1.3.0", "sitemap": "^8.0.3", - "terser": "^5.46.1", - "webpack": "^5.105.4", + "terser": "^5.46.2", + "webpack": "^5.106.2", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "5.0.4", "webpack-node-externals": "^3.0.0", @@ -97,9 +97,9 @@ "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", - "@xmldom/xmldom": "^0.8.11", + "@xmldom/xmldom": "^0.8.13", "argon2-browser": "^1.18.0", - "arrive": "^2.5.2", + "arrive": "^2.5.3", "assert": "^2.1.0", "avsc": "^5.7.9", "bcryptjs": "^2.4.3", @@ -121,7 +121,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.2", - "dompurify": "^3.3.3", + "dompurify": "^3.4.1", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -131,11 +131,11 @@ "file-saver": "^2.0.5", "flat": "^6.0.1", "geodesy": "1.1.3", - "handlebars": "^4.7.8", + "handlebars": "^4.7.9", "hash-wasm": "^4.12.0", "highlight.js": "^11.11.1", "ieee754": "^1.2.1", - "jimp": "^1.6.0", + "jimp": "1.6.0", "jq-web": "^0.5.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", @@ -145,11 +145,11 @@ "jsonpath-plus": "^10.4.0", "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", - "jsrsasign": "^11.1.1", + "jsrsasign": "^11.1.3", "kbpgp": "^2.1.17", "libbzip2-wasm": "0.0.4", "libyara-wasm": "^1.2.1", - "lodash": "^4.17.23", + "lodash": "^4.18.1", "loglevel": "^1.9.2", "loglevel-message-prefix": "^3.0.0", "lz-string": "^1.5.0", @@ -158,7 +158,7 @@ "moment": "^2.30.1", "moment-timezone": "^0.6.1", "ngeohash": "^0.6.3", - "node-forge": "^1.3.3", + "node-forge": "^1.4.0", "node-md6": "^0.1.0", "nodom": "^2.4.0", "notepack.io": "^3.0.1", @@ -168,7 +168,7 @@ "path": "^0.12.7", "popper.js": "^1.16.1", "process": "^0.11.10", - "protobufjs": "^7.5.4", + "protobufjs": "^7.5.5", "qr-image": "^3.2.0", "reflect-metadata": "^0.2.2", "rison": "^0.1.1", @@ -176,7 +176,7 @@ "snackbarjs": "^1.1.0", "sortablejs": "^1.15.7", "split.js": "^1.6.5", - "sql-formatter": "^15.6.12", + "sql-formatter": "^15.7.3", "ssdeep.js": "0.0.3", "stream-browserify": "^3.0.0", "tesseract.js": "^6.0.1", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index a2bd2d08..ab1dafb0 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -465,7 +465,8 @@ "Luhn Checksum", "CRC Checksum", "TCP/IP Checksum", - "XOR Checksum" + "XOR Checksum", + "Parity Bit" ] }, { diff --git a/src/core/config/scripts/fixCryptoApiImports.mjs b/src/core/config/scripts/fixCryptoApiImports.mjs new file mode 100644 index 00000000..f4b7c767 --- /dev/null +++ b/src/core/config/scripts/fixCryptoApiImports.mjs @@ -0,0 +1,54 @@ +/** + * This script updates crypto-api package + * It adds .mjs to local imports where its missing + * + * before: + * import foo from "./bar"; + * after + * import foo from "./bar.mjs"; + * + */ + +/* eslint no-console: ["off"] */ + +import { readdirSync, readFileSync, writeFileSync } from "fs"; +import { join } from "path"; + +// Base directory of crypto-api source +const baseDir = join(process.cwd(), "node_modules/crypto-api/src"); + +/** + * Recursively walk a directory, updating import statements + * to include ".mjs" if missing + */ +function walk(dir) { + const entries = readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.name === ".git") continue; + + const fullPath = join(dir, entry.name); + + if (entry.isDirectory()) { + walk(fullPath); + } else if (entry.isFile()) { + const content = readFileSync(fullPath, "utf8"); + + // Add .mjs to imports if not present + const updated = content.replace( + /from "(\.[^"]*)";/g, + (match, p1) => { + if (p1.endsWith(".mjs")) return match; + return `from "${p1}.mjs";`; + } + ); + + if (updated !== content) { + writeFileSync(fullPath, updated, "utf8"); + } + } + } +} + +// Run the walker +walk(baseDir); diff --git a/src/core/config/scripts/fixSnackBarMarkup.mjs b/src/core/config/scripts/fixSnackBarMarkup.mjs new file mode 100644 index 00000000..eba011ab --- /dev/null +++ b/src/core/config/scripts/fixSnackBarMarkup.mjs @@ -0,0 +1,28 @@ +/** + * This script updates snackbarjs package + * Replaces self-closing div with standard opening div + * + * before: + *
+ * after: + *
+ * + */ + +/* eslint no-console: ["off"] */ + +import { readFileSync, writeFileSync } from "fs"; +import { join } from "path"; + +// Base directory of snackbarjs source +const filePath = join(process.cwd(), "node_modules/snackbarjs/src/snackbar.js"); + +const content = readFileSync(filePath, "utf8"); + +// Replace self-closing div with standard opening div +const updated = content.replace( + /
/g, + "
" +); + +writeFileSync(filePath, updated, "utf8"); diff --git a/src/core/lib/Extract.mjs b/src/core/lib/Extract.mjs index 3de2dd6d..8828671e 100644 --- a/src/core/lib/Extract.mjs +++ b/src/core/lib/Extract.mjs @@ -45,6 +45,11 @@ export function search(input, searchRegex, removeRegex=null, sortBy=null, unique return results; } +/** + * Email regular expression + */ +export const EMAIL_REGEX = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\])/ig; + /** * URL regular expression diff --git a/src/core/lib/Modhex.mjs b/src/core/lib/Modhex.mjs index 4f28e9a1..ab4a7c8b 100644 --- a/src/core/lib/Modhex.mjs +++ b/src/core/lib/Modhex.mjs @@ -50,6 +50,7 @@ const HEX_ALPHABET_MAP = HEX_ALPHABET.split(""); export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) { if (!data) return ""; if (data instanceof ArrayBuffer) data = new Uint8Array(data); + if (data.length === 0) return ""; const regularHexString = toHex(data, "", padding, "", 0); @@ -100,6 +101,7 @@ export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) export function toModhexFast(data) { if (!data) return ""; if (data instanceof ArrayBuffer) data = new Uint8Array(data); + if (data.length === 0) return ""; const output = []; diff --git a/src/core/lib/ParityBit.mjs b/src/core/lib/ParityBit.mjs new file mode 100644 index 00000000..9675b46c --- /dev/null +++ b/src/core/lib/ParityBit.mjs @@ -0,0 +1,50 @@ +/** + * Parity Bit functions. + * + * @author j83305 [awz22@protonmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + * + */ + +import OperationError from "../errors/OperationError.mjs"; + +/** + * Function to take the user input and encode using the given arguments + * @param input string of binary + * @param args array + */ +export function calculateParityBit(input, args) { + let count1s = 0; + for (let i = 0; i < input.length; i++) { + const character = input.charAt(i); + if (character === "1") { + count1s++; + } else if (character !== args[3] && character !== "0" && character !== " ") { + throw new OperationError("unexpected character encountered: \"" + character + "\""); + } + } + let parityBit = "1"; + const flipflop = args[0] === "Even Parity" ? 0 : 1; + if (count1s % 2 === flipflop) { + parityBit = "0"; + } + if (args[1] === "End") { + return input + parityBit; + } else { + return parityBit + input; + } +} + +/** + * just removes the parity bit to return the original data + * @param input string of binary, encoded + * @param args array + */ +export function decodeParityBit(input, args) { + if (args[1] === "End") { + return input.slice(0, -1); + } else { + return input.slice(1); + } +} diff --git a/src/core/operations/AnalyseUUID.mjs b/src/core/operations/AnalyseUUID.mjs index b3506017..6f960c8a 100644 --- a/src/core/operations/AnalyseUUID.mjs +++ b/src/core/operations/AnalyseUUID.mjs @@ -1,5 +1,6 @@ /** * @author n1474335 [n1474335@gmail.com] + * @author ko80240 [csk.dev@proton.me] * @copyright Crown Copyright 2023 * @license Apache-2.0 */ @@ -8,6 +9,7 @@ import * as uuid from "uuid"; import Operation from "../Operation.mjs"; import OperationError from "../errors/OperationError.mjs"; +import { toHex } from "../lib/Hex.mjs"; /** * Analyse UUID operation @@ -22,27 +24,128 @@ class AnalyseUUID extends Operation { this.name = "Analyse UUID"; this.module = "Crypto"; - this.description = "Tries to determine information about a given UUID and suggests which version may have been used to generate it"; + this.description = "Operation for extracting metadata and detecting the version of a given UUID."; this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier"; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + name: "Include Metadata", + type: "boolean", + value: true + } + ]; } /** - * @param {string} input + * @param {string} input - Expects a valid UUID string * @param {Object[]} args * @returns {string} */ run(input, args) { + input = input.trim(); + + let uuidVersion, uuidBytes; try { - const uuidVersion = uuid.version(input); - return "UUID version: " + uuidVersion; + uuidVersion = uuid.version(input); // Re-using the uuid library to extract version + uuidBytes = uuid.parse(input); // Re-using the uuid library to parse bytes } catch (error) { throw new OperationError("Invalid UUID"); } - } + const [includeMetadata] = args; + const dv = new DataView(uuidBytes.buffer, uuidBytes.byteOffset, uuidBytes.byteLength); // Dataview helps handle the multi-byte ints + const uuidInteger = (dv.getBigUint64(0) << 64n) | dv.getBigUint64(8); + + const sections = [`Version:\n${uuidVersion}`]; + + if (includeMetadata) { + const parser = UUID_PARSERS[uuidVersion]; + const decoded = parser?.(uuidBytes, dv); + sections.push(formatDecoded(decoded)); + } + + sections.push(`UUID Integer:\n${uuidInteger}`); + + return sections.filter(Boolean).join("\n\n"); + } } export default AnalyseUUID; + +/** + * Metadata can be extracted for versions 1, 6, and 7. + * Enum-like frozen mapping of UUID version to parser function. + */ +const UUID_PARSERS = Object.freeze({ + 1: parsev1v6, + 6: parsev1v6, + 7: parsev7, +}); + +/** + * Versions 1 and 6. Note 6 is a re-order of 1. + * Version 1 == layout: timeLow(32) | timeMid(16) | timeHi(12) + * Version 6 == layout: timeHi(32) | timeMid(16) | timeLow(12) + */ +function parsev1v6(uuidBytes, dv) { + const isV1 = (uuidBytes[6] >> 4) === 1; + + const timeStamp = + isV1 ? ( + (BigInt(dv.getUint16(6) & 0x0fff) << 48n) | // mask off version bits + (BigInt(dv.getUint16(4)) << 32n) | + BigInt(dv.getUint32(0)) + ) : ( + (BigInt(dv.getUint32(0)) << 28n) | + (BigInt(dv.getUint16(4)) << 12n) | + (BigInt(dv.getUint16(6) & 0x0fff)) + ); + + // Convert to Unix time + const milliseconds = + Number( + (timeStamp - 122192928000000000n) / 10000n + ); + + return { + timestamp: milliseconds, + isoTimestamp: new Date(milliseconds).toISOString(), + clock: ((uuidBytes[8] & 0x3f) << 8) | uuidBytes[9], + node: toHex(uuidBytes.slice(10), ":").toUpperCase() + }; +} + +/** Version 7 */ +function parsev7(uuidBytes, dv) { + const milliseconds = Number((BigInt(dv.getUint32(0)) << 16n) | BigInt(dv.getUint16(4))); + + return { + timestamp: milliseconds, + isoTimestamp: new Date(milliseconds).toISOString(), + randA: ((uuidBytes[6] & 0x0f) << 8) | uuidBytes[7], + randB: toHex(uuidBytes.slice(8), "").toUpperCase() + }; +} + +/** + * Formats metadata + * + * @param {Object|undefined} decoded + * @returns {string} + */ +function formatDecoded(decoded) { + if (!decoded) return "No metadata available. Only versions 1, 6, 7 are supported."; + + return Object.entries({ + "Timestamp": decoded.timestamp, + "Timestamp (ISO)": decoded.isoTimestamp, + "Node": decoded.node, + "Clock": decoded.clock, + "Rand A": decoded.randA, + "Rand B": decoded.randB + }) + .filter(([, value]) => value !== undefined) + .map(([label, value]) => `${label}:\n${value}`) + .join("\n\n"); +} diff --git a/src/core/operations/ExtractEmailAddresses.mjs b/src/core/operations/ExtractEmailAddresses.mjs index 34b838ab..fe368a12 100644 --- a/src/core/operations/ExtractEmailAddresses.mjs +++ b/src/core/operations/ExtractEmailAddresses.mjs @@ -5,7 +5,7 @@ */ import Operation from "../Operation.mjs"; -import { search } from "../lib/Extract.mjs"; +import { EMAIL_REGEX, search } from "../lib/Extract.mjs"; import { caseInsensitiveSort } from "../lib/Sort.mjs"; /** @@ -50,8 +50,7 @@ class ExtractEmailAddresses extends Operation { */ run(input, args) { const [displayTotal, sort, unique] = args, - // email regex from: https://www.regextester.com/98066 - regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\])/ig; + regex = EMAIL_REGEX; const results = search( input, diff --git a/src/core/operations/OffsetChecker.mjs b/src/core/operations/OffsetChecker.mjs index 0f66e591..2a417e4b 100644 --- a/src/core/operations/OffsetChecker.mjs +++ b/src/core/operations/OffsetChecker.mjs @@ -99,7 +99,7 @@ class OffsetChecker extends Operation { } } - return outputs.join(sampleDelim); + return outputs.join(Utils.escapeHtml(sampleDelim)); } } diff --git a/src/core/operations/ParityBit.mjs b/src/core/operations/ParityBit.mjs new file mode 100644 index 00000000..c5ac1d1e --- /dev/null +++ b/src/core/operations/ParityBit.mjs @@ -0,0 +1,128 @@ +/** + * @author j83305 [awz22@protonmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import { calculateParityBit, decodeParityBit } from "../lib/ParityBit.mjs"; + +/** + * Parity Bit operation + */ +class ParityBit extends Operation { + + /** + * ParityBit constructor + */ + constructor() { + super(); + + this.name = "Parity Bit"; + this.module = "Default"; + this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.

If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each occurence of the delimiter character"; + this.infoURL = "https://wikipedia.org/wiki/Parity_bit"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Mode", + type: "option", + value: [ + "Even Parity", + "Odd Parity" + ] + }, + { + name: "Postion", + type: "option", + value: [ + "Start", + "End" + ] + }, + { + name: "Encode or Decode", + type: "option", + value: [ + "Encode", + "Decode" + ] + }, + { + name: "Delimiter", + type: "shortString", + value: "" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (input.length === 0) { + return input; + } + /** + * determines weather to use the encode or decode method based off args[2] + * @param input input to be encoded or decoded + * @param args array + */ + const method = (input, args) => args[2] === "Encode" ? calculateParityBit(input, args) : decodeParityBit(input, args); + if (args[3].length > 0) { + const byteStrings = input.split(args[3]); + for (let byteStringsArrayIndex = 0; byteStringsArrayIndex < byteStrings.length; byteStringsArrayIndex++) { + byteStrings[byteStringsArrayIndex] = method(byteStrings[byteStringsArrayIndex], args); + } + return byteStrings.join(args[3]); + } + return method(input, args); + } + + /** + * Highlight Parity Bit + * + * @param {Object[]} pos + * @param {number} pos[].start + * @param {number} pos[].end + * @param {Object[]} args + * @returns {Object[]} pos + */ + highlight(pos, args) { + if (args[3].length === 0) { + if (args[1] === "Prepend") { + pos[0].start += 1; + pos[0].end += 1; + } + return pos; + } + // need to be able to read input to do the highlighting when there is a delimiter + } + + /** + * Highlight Parity Bit in reverse + * + * @param {Object[]} pos + * @param {number} pos[].start + * @param {number} pos[].end + * @param {Object[]} args + * @returns {Object[]} pos + */ + highlightReverse(pos, args) { + if (args[3].length === 0) { + if (args[1] === "Prepend") { + if (pos[0].start > 0) { + pos[0].start -= 1; + } + pos[0].end -= 1; + } + return pos; + } + } + +} + +export default ParityBit; diff --git a/src/core/operations/ParseEthernetFrame.mjs b/src/core/operations/ParseEthernetFrame.mjs index 9dac5d57..0be5e1a4 100644 --- a/src/core/operations/ParseEthernetFrame.mjs +++ b/src/core/operations/ParseEthernetFrame.mjs @@ -74,17 +74,14 @@ class ParseEthernetFrame extends Operation { const ethType = Utils.byteArrayToChars(input.slice(offset, offset+2)); offset += 2; - - if (ethType === "\x08\x00") { - break; - } else if (ethType === "\x81\x00" || ethType === "\x88\xA8") { + if (ethType === "\x81\x00" || ethType === "\x88\xA8") { // Parse the VLAN tag: // [0000] 0000 0000 0000 // ^^^ PRIO - Ignored // ^ DEI - Ignored // ^^^^ ^^^^ ^^^^ VLAN ID - const vlanTag = input.slice(offset+2, offset+4); - vlans.push((vlanTag[0] & 0b00001111) << 4 | vlanTag[1]); + const vlanTag = input.slice(offset, offset+2); + vlans.push(((vlanTag[0] & 0b00001111) << 8) | vlanTag[1]); offset += 2; } else { diff --git a/src/core/operations/RegularExpression.mjs b/src/core/operations/RegularExpression.mjs index 9ea17e83..c3ab5b1d 100644 --- a/src/core/operations/RegularExpression.mjs +++ b/src/core/operations/RegularExpression.mjs @@ -7,6 +7,7 @@ import XRegExp from "xregexp"; import Operation from "../Operation.mjs"; import Utils from "../Utils.mjs"; +import { EMAIL_REGEX } from "../lib/Extract.mjs"; import OperationError from "../errors/OperationError.mjs"; /** @@ -45,7 +46,7 @@ class RegularExpression extends Operation { }, { name: "Email address", - value: "(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFF-a-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?\\.)+[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}\\])" + value: EMAIL_REGEX.source // We use a different regex library, so just take the source regex string here }, { name: "URL", diff --git a/src/core/operations/RenderMarkdown.mjs b/src/core/operations/RenderMarkdown.mjs index c656bf5b..20966cca 100644 --- a/src/core/operations/RenderMarkdown.mjs +++ b/src/core/operations/RenderMarkdown.mjs @@ -35,6 +35,11 @@ class RenderMarkdown extends Operation { name: "Enable syntax highlighting", type: "boolean", value: true + }, + { + name: "Open links in new tab.", + type: "boolean", + value: false } ]; } @@ -45,7 +50,7 @@ class RenderMarkdown extends Operation { * @returns {html} */ run(input, args) { - const [convertLinks, enableHighlighting] = args, + const [convertLinks, enableHighlighting, openLinksBlank] = args, md = new MarkdownIt({ linkify: convertLinks, html: false, // Explicitly disable HTML rendering @@ -58,12 +63,38 @@ class RenderMarkdown extends Operation { return ""; } - }), - rendered = md.render(input); - + }); + if (openLinksBlank) { + this.makeLinksOpenInNewTab(md); + } + const rendered = md.render(input); return `
${rendered}
`; } + /** + * Adds target="_blank" to links. + * @param {MarkdownIt} md + */ + makeLinksOpenInNewTab(md) { + // Adapted from: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer + // Remember old renderer, if overridden, or proxy to default renderer + const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options); + }; + + // eslint-disable-next-line camelcase + md.renderer.rules.link_open = function (tokens, idx, options, env, self) { + const token = tokens[idx]; + if (token.attrIndex("target") >= 0) { + // Target attribute already set, do not replace. + return; + } + token.attrPush(["target", "_blank"]); // add new attribute + + // pass token to default renderer. + return defaultRender(tokens, idx, options, env, self); + }; + } } export default RenderMarkdown; diff --git a/src/web/HTMLOperation.mjs b/src/web/HTMLOperation.mjs index 30cfd1d9..725f0b5f 100755 --- a/src/web/HTMLOperation.mjs +++ b/src/web/HTMLOperation.mjs @@ -43,17 +43,23 @@ class HTMLOperation { /** * Renders the operation in HTML as a stub operation with no ingredients. * + * @param {boolean} removeIcon - show icon for removing operation + * @param {string} elementId - element ID for aria usage * @returns {string} */ - toStubHtml(removeIcon) { + toStubHtml(removeIcon = false, elementId = null) { let html = "
  • ${titleFromWikiLink(this.infoURL)}` : ""; html += ` data-container='body' data-toggle='popover' data-placement='right' data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover' - data-boundary='viewport'`; + data-boundary='viewport' role='button'`; } html += ">" + this.name; diff --git a/src/web/html/index.html b/src/web/html/index.html index 2d4de4bd..335f8c44 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -173,7 +173,7 @@ Operations
  • - +
      diff --git a/src/web/waiters/OperationsWaiter.mjs b/src/web/waiters/OperationsWaiter.mjs index 45a40c82..6c2de064 100755 --- a/src/web/waiters/OperationsWaiter.mjs +++ b/src/web/waiters/OperationsWaiter.mjs @@ -28,17 +28,16 @@ class OperationsWaiter { this.removeIntent = false; } - /** * Handler for search events. * Finds operations which match the given search term and displays them under the search box. * - * @param {event} e + * @param {KeyboardEvent | ClipboardEvent | Event} e */ searchOperations(e) { let ops, selected; - if (e.type === "search" || e.keyCode === 13) { // Search or Return + if ((e.type === "search" && e.target.value !== "") || e.keyCode === 13) { // Search (non-empty) or Return e.preventDefault(); ops = document.querySelectorAll("#search-results li"); if (ops.length) { @@ -49,27 +48,43 @@ class OperationsWaiter { } } + /** + * Sets up the operation element with the correct attributes when selected + * @param {HTMLElement} element + */ + const _selectOperation = (element) => { + element.classList.add("selected-op"); + element.scrollIntoView({block: "nearest"}); + $(element).popover("show"); + e.target.setAttribute("aria-activedescendant", element.id); + }; + + /** + * Sets up the operation element with the correct attributes when deselected + * @param {HTMLElement} element + */ + const _deselectOperation = (element) => { + element.classList.remove("selected-op"); + $(element).popover("hide"); + }; + if (e.keyCode === 40) { // Down e.preventDefault(); ops = document.querySelectorAll("#search-results li"); if (ops.length) { selected = this.getSelectedOp(ops); - if (selected > -1) { - ops[selected].classList.remove("selected-op"); - } + if (selected > -1) _deselectOperation(ops[selected]); if (selected === ops.length-1) selected = -1; - ops[selected+1].classList.add("selected-op"); + _selectOperation(ops[selected+1]); } } else if (e.keyCode === 38) { // Up e.preventDefault(); ops = document.querySelectorAll("#search-results li"); if (ops.length) { selected = this.getSelectedOp(ops); - if (selected > -1) { - ops[selected].classList.remove("selected-op"); - } + if (selected > -1) _deselectOperation(ops[selected]); if (selected === 0) selected = ops.length; - ops[selected-1].classList.add("selected-op"); + _selectOperation(ops[selected-1]); } } else { const searchResultsEl = document.getElementById("search-results"); @@ -83,11 +98,13 @@ class OperationsWaiter { searchResultsEl.removeChild(searchResultsEl.firstChild); } + document.querySelector("#search").removeAttribute("aria-activedescendant"); + $("#categories .show").collapse("hide"); if (str) { const matchedOps = this.filterOperations(str, true); const matchedOpsHtml = matchedOps - .map(v => v.toStubHtml()) + .map((operation, idx) => operation.toStubHtml(false, `search-result-${idx}`)) .join(""); searchResultsEl.innerHTML = matchedOpsHtml; @@ -103,7 +120,7 @@ class OperationsWaiter { * @param {string} searchStr * @param {boolean} highlight - Whether or not to highlight the matching string in the operation * name and description - * @returns {string[]} + * @returns {HTMLOperation[]} */ filterOperations(inStr, highlight) { const matchedOps = []; diff --git a/tests/browser/02_ops.js b/tests/browser/02_ops.js index 5ab55451..896de7b0 100644 --- a/tests/browser/02_ops.js +++ b/tests/browser/02_ops.js @@ -354,6 +354,7 @@ module.exports = { // testOp(browser, "Tail", "test input", "test_output"); // testOp(browser, "Take bytes", "test input", "test_output"); testOp(browser, "Tar", "test input", /^file\.txt\x00{92}/); + testOp(browser, "Template", "{\"one\": 1, \"two\": 2}", "1 2", ["{{ one }} {{ two }}"]); testOpHtml(browser, "Text Encoding Brute Force", "test input", "tr:nth-of-type(4) td:last-child", /t\u2400e\u2400s\u2400t\u2400/); // testOp(browser, "To BCD", "test input", "test_output"); // testOp(browser, "To Base", "test input", "test_output"); diff --git a/tests/node/tests/operations.mjs b/tests/node/tests/operations.mjs index 41eddd82..a97f5ccb 100644 --- a/tests/node/tests/operations.mjs +++ b/tests/node/tests/operations.mjs @@ -589,8 +589,7 @@ Password: 282760`; ...[1, 3, 4, 5, 6, 7].map(version => it(`Analyze UUID v${version}`, () => { const uuid = chef.generateUUID("", { "version": `v${version}` }).toString(); const result = chef.analyseUUID(uuid).toString(); - const expected = `UUID version: ${version}`; - assert.strictEqual(result, expected); + assert.ok(result.startsWith(`Version:\n${version}\n`), `Expected output to start with "Version:\\n${version}\\n", got: ${result}`); })), it("Generate UUID using defaults", () => { @@ -598,7 +597,7 @@ Password: 282760`; assert.ok(uuid); const analysis = chef.analyseUUID(uuid).toString(); - assert.strictEqual(analysis, "UUID version: 4"); + assert.ok(analysis.startsWith("Version:\n4\n"), `Expected output to start with "Version:\\n4\\n", got: ${analysis}`); }), it("Gzip, Gunzip", () => { diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index f030349d..bb81d32e 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -16,6 +16,7 @@ import { setLongTestFailure, logTestReport } from "../lib/utils.mjs"; import TestRegister from "../lib/TestRegister.mjs"; import "./tests/A1Z26CipherDecode.mjs"; import "./tests/AESKeyWrap.mjs"; +import "./tests/AnalyseUUID.mjs"; import "./tests/AlternatingCaps.mjs"; import "./tests/AvroToJSON.mjs"; import "./tests/BaconCipher.mjs"; @@ -71,6 +72,7 @@ import "./tests/ExtractAudioMetadata.mjs"; import "./tests/ExtractEmailAddresses.mjs"; import "./tests/ExtractHashes.mjs"; import "./tests/ExtractIPAddresses.mjs"; +import "./tests/Fernet.mjs"; import "./tests/Float.mjs"; import "./tests/FileTree.mjs"; import "./tests/FletcherChecksum.mjs"; @@ -134,6 +136,7 @@ import "./tests/ParseUDP.mjs"; import "./tests/PEMtoHex.mjs"; import "./tests/PGP.mjs"; import "./tests/PHP.mjs"; +import "./tests/ParityBit.mjs"; import "./tests/PHPSerialize.mjs"; import "./tests/PowerSet.mjs"; import "./tests/Protobuf.mjs"; @@ -143,6 +146,8 @@ import "./tests/Rabbit.mjs"; import "./tests/RAKE.mjs"; import "./tests/Regex.mjs"; import "./tests/Register.mjs"; +import "./tests/RegularExpression.mjs"; +import "./tests/RenderMarkdown.mjs"; import "./tests/RisonEncodeDecode.mjs"; import "./tests/Rotate.mjs"; import "./tests/RSA.mjs"; diff --git a/tests/operations/tests/AnalyseUUID.mjs b/tests/operations/tests/AnalyseUUID.mjs new file mode 100644 index 00000000..89118421 --- /dev/null +++ b/tests/operations/tests/AnalyseUUID.mjs @@ -0,0 +1,66 @@ +/** + * Analyse UUID tests + * + * @author ko80240 [csk.dev@proton.me] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + "name": "Analyse UUID: v1 UUID extracts timestamp, clock, and node", + "input": "cefa1760-28ee-11f1-9f95-1fb76af3e239", + "expectedOutput": "Version:\n1\n\nTimestamp:\n1774514156502\n\nTimestamp (ISO):\n2026-03-26T08:35:56.502Z\n\nNode:\n1F:B7:6A:F3:E2:39\n\nClock:\n8085\n\nUUID Integer:\n275119515460318071558429785403790975545", + "recipeConfig": [ + { + "op": "Analyse UUID", + "args": [true] + } + ] + }, + { + "name": "Analyse UUID: v7 UUID extracts timestamp, randA, and randB", + "input": "019d294a-af64-7728-9524-26da08f50708", + "expectedOutput": "Version:\n7\n\nTimestamp:\n1774514253668\n\nTimestamp (ISO):\n2026-03-26T08:37:33.668Z\n\nRand A:\n1832\n\nRand B:\n952426DA08F50708\n\nUUID Integer:\n2145256098533991595556290452700595976", + "recipeConfig": [ + { + "op": "Analyse UUID", + "args": [true] + } + ] + }, + { + "name": "Analyse UUID: v4 UUID should show no metadata - not possible", + "input": "f47ac10b-58cc-4372-a567-0e02b2c3d479", + "expectedOutput": "Version:\n4\n\nNo metadata available. Only versions 1, 6, 7 are supported.\n\nUUID Integer:\n324969006592305634633390616021200786553", + "recipeConfig": [ + { + "op": "Analyse UUID", + "args": [true] + } + ] + }, + { + "name": "Analyse UUID: if the 'Include Metadata' option is false it should return not metadata", + "input": "cefa1760-28ee-11f1-9f95-1fb76af3e239", + "expectedOutput": "Version:\n1\n\nUUID Integer:\n275119515460318071558429785403790975545", + "recipeConfig": [ + { + "op": "Analyse UUID", + "args": [false] + } + ] + }, + { + "name": "Analyse UUID: invalid UUID should return error message", + "input": "not-a-uuid", + "expectedOutput": "Invalid UUID", + "recipeConfig": [ + { + "op": "Analyse UUID", + "args": [true] + } + ] + } +]); diff --git a/tests/operations/tests/ExtractEmailAddresses.mjs b/tests/operations/tests/ExtractEmailAddresses.mjs index 658484cf..97ff7e3e 100644 --- a/tests/operations/tests/ExtractEmailAddresses.mjs +++ b/tests/operations/tests/ExtractEmailAddresses.mjs @@ -11,44 +11,70 @@ TestRegister.addTests([ { name: "Extract email address", input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com", - expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com", + expectedOutput: + "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com", recipeConfig: [ { - "op": "Extract email addresses", - "args": [false] + op: "Extract email addresses", + args: [false], }, ], }, { name: "Extract email address - Display total", input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com", - expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com", + expectedOutput: + "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com", recipeConfig: [ { - "op": "Extract email addresses", - "args": [true] + op: "Extract email addresses", + args: [true], }, ], }, { name: "Extract email address (Internationalized)", input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", - expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", + expectedOutput: + "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", recipeConfig: [ { - "op": "Extract email addresses", - "args": [false] + op: "Extract email addresses", + args: [false], }, ], }, { name: "Extract email address - Display total (Internationalized)", input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", - expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", + expectedOutput: + "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com", recipeConfig: [ { - "op": "Extract email addresses", - "args": [true] + op: "Extract email addresses", + args: [true], + }, + ], + }, + { + name: "Extract email address - IP address", + input: "yaunwfkb\nexample@[127.0.0.1]\n091nvka", + expectedOutput: "example@[127.0.0.1]", + recipeConfig: [ + { + op: "Extract email addresses", + args: [false], + }, + ], + }, + { + name: "Extract email address - invalid IP address", + input: "yaunwfkb\nfalse_positive@[1.2.3.]\n091nvka", + expectedOutput: "", + recipeConfig: [ + { + op: "Extract email addresses", + args: [false], }, ], }, diff --git a/tests/operations/tests/Fernet.mjs b/tests/operations/tests/Fernet.mjs index ee9ba2f1..7a17a675 100644 --- a/tests/operations/tests/Fernet.mjs +++ b/tests/operations/tests/Fernet.mjs @@ -5,7 +5,7 @@ * @copyright Karsten Silkenbäumer 2019 * @license Apache-2.0 */ -import TestRegister from "../TestRegister"; +import TestRegister from "../../lib/TestRegister.mjs"; TestRegister.addTests([ { @@ -47,7 +47,7 @@ TestRegister.addTests([ { name: "Fernet Encrypt: no input", input: "", - expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/, + expectedMatch: /^gAAA[\w-]+={0,2}$/, recipeConfig: [ { op: "Fernet Encrypt", @@ -69,12 +69,27 @@ TestRegister.addTests([ { name: "Fernet Encrypt: valid arguments", input: "This is a secret message.\n", - expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/, + expectedMatch: /^gAAA[\w-]+={0,2}$/, recipeConfig: [ { op: "Fernet Encrypt", args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="] } ], + }, + { + name: "Fernet Encrypt/Decrypt: round trip", + input: "This is a secret message.\n", + expectedOutput: "This is a secret message.\n", + recipeConfig: [ + { + op: "Fernet Encrypt", + args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="] + }, + { + op: "Fernet Decrypt", + args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="] + }, + ], } ]); diff --git a/tests/operations/tests/Modhex.mjs b/tests/operations/tests/Modhex.mjs index 1e0f2791..07f38910 100644 --- a/tests/operations/tests/Modhex.mjs +++ b/tests/operations/tests/Modhex.mjs @@ -147,4 +147,24 @@ dc;ii;hv;ig;hr;hf;dc;he;hj;hv;hv;ie;hg;du", } ] }, + { + name: "Empty input through From Hex and To Modhex returns empty output", + input: "", + expectedOutput: "", + recipeConfig: [ + { + "op": "From Hex", + "args": [ + "Auto" + ] + }, + { + "op": "To Modhex", + "args": [ + "Space", + 0 + ] + } + ] + }, ]); diff --git a/tests/operations/tests/ParityBit.mjs b/tests/operations/tests/ParityBit.mjs new file mode 100644 index 00000000..bc42b9f8 --- /dev/null +++ b/tests/operations/tests/ParityBit.mjs @@ -0,0 +1,147 @@ +/** + * Parity Bit tests + * + * @author j83305 [awz22@protonmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, prepend, even number of 1s", + input: "01010101 10101010", + expectedOutput: "001010101 10101010", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Even Parity", + "Start", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, prepend, odd number of 1s", + input: "01010101 10101011", + expectedOutput: "101010101 10101011", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Even Parity", + "Start", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in even parity, 1 block of binary of arbitrary length, append, odd number of 1s", + input: "01010101 10101011", + expectedOutput: "01010101 101010111", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Even Parity", + "End", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, prepend, even number of 1s", + input: "01010101 10101010", + expectedOutput: "101010101 10101010", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Odd Parity", + "Start", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, prepend, odd number of 1s", + input: "01010101 10101011", + expectedOutput: "001010101 10101011", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Odd Parity", + "Start", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in odd parity, 1 block of binary of arbitrary length, append, odd number of 1s", + input: "01010101 10101011", + expectedOutput: "01010101 101010110", + recipeConfig: [ + { + "op": "Parity Bit", + "args": [ + "Odd Parity", + "End", + "Encode", + "" + ] + } + ] + }, + { + name: "Parity bit encode in even parity, binary for 'hello world!', prepend to each byte", + input: "hello world!", + expectedOutput: "101101000 001100101 001101100 001101100 001101111 100100000 001110111 001101111 001110010 001101100 101100100 000100001", + recipeConfig: [ + { + "op": "To Binary", + "args": ["Space"] + }, + { + "op": "Parity Bit", + "args": [ + "Even Parity", + "Start", + "Encode", + " " + ] + } + ] + }, + { + name: "Parity bit encode in odd parity, binary for 'hello world!', append to each byte", + input: "hello world!", + expectedOutput: "011010000 011001011 011011001 011011001 011011111 001000000 011101111 011011111 011100101 011011001 011001000 001000011", + recipeConfig: [ + { + "op": "To Binary", + "args": ["Space"] + }, + { + "op": "Parity Bit", + "args": [ + "Odd Parity", + "End", + "Encode", + " " + ] + } + ] + }, +]); diff --git a/tests/operations/tests/ParseEthernetFrame.mjs b/tests/operations/tests/ParseEthernetFrame.mjs index c849e207..063255ed 100644 --- a/tests/operations/tests/ParseEthernetFrame.mjs +++ b/tests/operations/tests/ParseEthernetFrame.mjs @@ -23,7 +23,7 @@ TestRegister.addTests([ { name: "Parse Ethernet frame with one VLAN tag (802.1q)", input: "01000ccdcdd00013c3dfae188100a0760165aaaa", - expectedOutput: "Source MAC: 00:13:c3:df:ae:18\nDestination MAC: 01:00:0c:cd:cd:d0\nVLAN: 117\nData:\naa aa", + expectedOutput: "Source MAC: 00:13:c3:df:ae:18\nDestination MAC: 01:00:0c:cd:cd:d0\nVLAN: 118\nData:\naa aa", recipeConfig: [ { "op": "Parse Ethernet frame", @@ -34,7 +34,7 @@ TestRegister.addTests([ { name: "Parse Ethernet frame with two VLAN tags (802.1ad)", input: "0019aa7de688002155c8f13c810000d18100001408004500", - expectedOutput: "Source MAC: 00:21:55:c8:f1:3c\nDestination MAC: 00:19:aa:7d:e6:88\nVLAN: 16, 128\nData:\n45 00", + expectedOutput: "Source MAC: 00:21:55:c8:f1:3c\nDestination MAC: 00:19:aa:7d:e6:88\nVLAN: 209, 20\nData:\n45 00", recipeConfig: [ { "op": "Parse Ethernet frame", diff --git a/tests/operations/tests/RegularExpression.mjs b/tests/operations/tests/RegularExpression.mjs new file mode 100644 index 00000000..80af3ce7 --- /dev/null +++ b/tests/operations/tests/RegularExpression.mjs @@ -0,0 +1,75 @@ +/** + * Regular Expression tests. + * + * @author C85297 [95289555+C85297@users.noreply.github.com] + * @copyright Crown Copyright 2017 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; +import { EMAIL_REGEX } from "../../../src/core/lib/Extract.mjs"; + +TestRegister.addTests([ + { + name: "Regular Expression - built in email regex - IP address", + input: "yaunwfkb\nexample@[127.0.0.1]\n091nvka", + expectedOutput: "example@[127.0.0.1]", + recipeConfig: [ + { + op: "Regular expression", + args: [ + "Email address", + EMAIL_REGEX.source, + true, + true, + false, + false, + false, + false, + "List matches", + ], + }, + ], + }, + { + name: "Regular Expression - built in email regex - invalid IP address", + input: "yaunwfkb\nfalse_positive@[1.2.3.]\n091nvka", + expectedOutput: "", + recipeConfig: [ + { + op: "Regular expression", + args: [ + "Email address", + EMAIL_REGEX.source, + true, + true, + false, + false, + false, + false, + "List matches", + ], + }, + ], + }, + { + name: "Regular Expression - built in email regex - IPv4 from #2318", + input: "user@[1.2.3.4]\ntest@[192.168.0.1]\nno-match@[1.2.3.]", + expectedOutput: "user@[1.2.3.4]\ntest@[192.168.0.1]", + recipeConfig: [ + { + op: "Regular expression", + args: [ + "Email address", + EMAIL_REGEX.source, + true, + true, + false, + false, + false, + false, + "List matches", + ], + }, + ], + }, +]); diff --git a/tests/operations/tests/RenderMarkdown.mjs b/tests/operations/tests/RenderMarkdown.mjs new file mode 100644 index 00000000..47781e5e --- /dev/null +++ b/tests/operations/tests/RenderMarkdown.mjs @@ -0,0 +1,110 @@ +/** + * RenderMarkdown tests. + * + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Render Markdown: Nothing", + input: "", + expectedOutput: '
      ', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [] + } + ] + }, + { + name: "Render Markdown: Basic Text", + input: "Hello World!", + expectedOutput: '

      Hello World!

      \n
      ', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [] + } + ] + }, + { + name: "Render Markdown: Simple Markdown", + input: "# Hello World!", + expectedOutput: '

      Hello World!

      \n
      ', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [] + } + ] + }, + { + name: "Render Markdown: URL (not expanded)", + input: "https://gchq.github.io/CyberChef/", + expectedOutput: '

      https://gchq.github.io/CyberChef/

      \n
      ', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [false, false, false] + } + ] + }, + { + name: "Render Markdown: URL (expanded)", + input: "https://gchq.github.io/CyberChef/", + expectedOutput: '', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [true, false, false] + } + ] + }, + { + name: "Render Markdown: Link (not expanded)", + input: "[CyberChef](https://gchq.github.io/CyberChef/)", + expectedOutput: '', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [false, false, false] + } + ] + }, + { + name: "Render Markdown: Link (expanded)", + input: "[CyberChef](https://gchq.github.io/CyberChef/)", + expectedOutput: '', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [true, false, false] + } + ] + }, + { + name: "Render Markdown: Link (open in new window)", + input: "[CyberChef](https://gchq.github.io/CyberChef/)", + expectedOutput: '', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [true, false, true] + } + ] + }, + { + name: "Render Markdown: URL (open in new window)", + input: "https://gchq.github.io/CyberChef/", + expectedOutput: '', + recipeConfig: [ + { + "op": "Render Markdown", + "args": [true, false, true] + } + ] + }, +]);