Merge branch 'master' into fix-2281
This commit is contained in:
commit
17e4ab4e30
@ -3,7 +3,7 @@
|
||||
{
|
||||
"name": "CyberChef",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bookworm",
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:24-trixie",
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
"features": {
|
||||
|
||||
30
.github/dependabot.yml
vendored
30
.github/dependabot.yml
vendored
@ -33,8 +33,6 @@ updates:
|
||||
versions: [ '>=5.0.0' ]
|
||||
- dependency-name: 'cbor'
|
||||
versions: [ '>=10.0.0' ]
|
||||
- dependency-name: 'cspell'
|
||||
versions: [ '>=9.0.0' ]
|
||||
- dependency-name: 'eslint'
|
||||
versions: [ '>=10.0.0' ]
|
||||
- dependency-name: 'eslint-plugin-jsdoc'
|
||||
@ -43,8 +41,8 @@ updates:
|
||||
versions: [ '>=0.4.0' ]
|
||||
- dependency-name: 'geodesy'
|
||||
versions: [ '>=2.0.0' ]
|
||||
- dependency-name: 'otpauth'
|
||||
versions: [ '>=9.4.0' ]
|
||||
- dependency-name: 'jimp'
|
||||
versions: [ '1.6.1' ]
|
||||
- dependency-name: 'webpack-dev-server'
|
||||
versions: [ '>=5.1.0' ]
|
||||
groups:
|
||||
@ -58,15 +56,15 @@ updates:
|
||||
update-types:
|
||||
- 'patch'
|
||||
|
||||
# Can't enable this until we are using Node 24 as the latest actions all require this version
|
||||
# - package-ecosystem: "github-actions"
|
||||
# # Workflow files stored in the default location of `.github/workflows`; no need to
|
||||
# # specify `/.github/workflows` for `directory`
|
||||
# directory: '/'
|
||||
# schedule:
|
||||
# interval: 'weekly'
|
||||
# day: 'friday'
|
||||
# time: '03:00'
|
||||
# timezone: Europe/London
|
||||
# commit-message:
|
||||
# prefix: 'chore (deps): '
|
||||
# Versioning on Github Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
# Workflow files stored in the default location of `.github/workflows`; no need to
|
||||
# specify `/.github/workflows` for `directory`
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
day: 'friday'
|
||||
time: '03:00'
|
||||
timezone: Europe/London
|
||||
commit-message:
|
||||
prefix: 'chore (deps): '
|
||||
|
||||
7
.github/workflows/master.yml
vendored
7
.github/workflows/master.yml
vendored
@ -21,13 +21,12 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
export DETECT_CHROMEDRIVER_VERSION=true
|
||||
npm install
|
||||
npm ci
|
||||
npm run setheapsize
|
||||
|
||||
- name: Lint
|
||||
@ -57,7 +56,7 @@ jobs:
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: success() && github.ref == 'refs/heads/master'
|
||||
uses: crazy-max/ghaction-github-pages@v3
|
||||
uses: crazy-max/ghaction-github-pages@v5
|
||||
with:
|
||||
target_branch: gh-pages
|
||||
build_dir: ./build/prod
|
||||
|
||||
29
.github/workflows/pull_requests.yml
vendored
29
.github/workflows/pull_requests.yml
vendored
@ -17,13 +17,12 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
export DETECT_CHROMEDRIVER_VERSION=true
|
||||
npm install
|
||||
npm ci
|
||||
npm run setheapsize
|
||||
|
||||
- name: Lint
|
||||
@ -38,11 +37,26 @@ 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
|
||||
uses: docker/setup-buildx-action@v3
|
||||
if: success()
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Production Image Build
|
||||
if: success()
|
||||
@ -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
|
||||
|
||||
19
.github/workflows/releases.yml
vendored
19
.github/workflows/releases.yml
vendored
@ -27,12 +27,11 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
export DETECT_CHROMEDRIVER_VERSION=true
|
||||
npm ci
|
||||
npm run setheapsize
|
||||
|
||||
@ -53,14 +52,14 @@ jobs:
|
||||
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Image Metadata
|
||||
id: image-metadata
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@ -69,7 +68,7 @@ jobs:
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.REGISTRY_USER }}
|
||||
@ -107,7 +106,7 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install
|
||||
@ -116,11 +115,5 @@ jobs:
|
||||
- name: Create machine generated files
|
||||
run: npm run node
|
||||
|
||||
- name: Reset node version ready for publish
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ^24.5
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Publish to NPM
|
||||
run: npm publish
|
||||
|
||||
210
CHANGELOG.md
210
CHANGELOG.md
@ -13,6 +13,104 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
## Details
|
||||
|
||||
## [11.0.0] - 2026-04-28
|
||||
- Revert sitemap to v8.0.X to fix build/deploy on master [@GCHQDeveloper581] | [#2348]
|
||||
- Node version update from 22 to 24 [@lzandman] [@GCHQDeveloper581] | [#2347]
|
||||
- Fix XSS in Show Base64 offsets [@C85297] | [#2346]
|
||||
- Make compatible with node >=22 [@GCHQDeveloper581] | [#2273]
|
||||
- Fix(node): enable asynchronous operation support in Node.js API [@engin0223] [@GCHQDeveloper581] | [#2342]
|
||||
- Feature: Change to nginx-unprivileged image for better kubernetes support [@hsolberg] | [#1922]
|
||||
|
||||
Breaking changes:
|
||||
- Minimum supported node version - now v24 (was v16)
|
||||
- Change of exported port on Docker Container - now 8080 (was 80)
|
||||
- Node API now exports "bake" and "execute" functions as async.
|
||||
|
||||
<details>
|
||||
<summary>Click to expand v10 minor versions</summary>
|
||||
|
||||
### [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]
|
||||
@ -195,6 +293,8 @@ All major and minor version changes will be documented in this file. Details of
|
||||
- Added 'Levenshtein Distance' operation [@mikecat] | [#1498]
|
||||
- Added 'Swap case' operation [@mikecat] | [#1499]
|
||||
|
||||
</details>
|
||||
|
||||
## [10.0.0] - 2023-03-22
|
||||
- [Full details explained here](https://github.com/gchq/CyberChef/wiki/Character-encoding,-EOL-separators,-and-editor-features)
|
||||
- Status bars added to the Input and Output [@n1474335] | [#1405]
|
||||
@ -538,6 +638,9 @@ 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)
|
||||
|
||||
[11.0.0]: https://github.com/gchq/CyberChef/releases/tag/v11.0.0
|
||||
[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 +900,29 @@ 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
|
||||
[@hsolberg]: https://github.com/hsolberg
|
||||
[@lzandman]: https://github.com/lzandman
|
||||
[@engin0223]: https://github.com/engin0223
|
||||
|
||||
|
||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||
@ -1010,4 +1136,88 @@ 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
|
||||
[#2348]: https://github.com/gchq/CyberChef/pull/2348
|
||||
[#2347]: https://github.com/gchq/CyberChef/pull/2347
|
||||
[#2346]: https://github.com/gchq/CyberChef/pull/2346
|
||||
[#2273]: https://github.com/gchq/CyberChef/pull/2273
|
||||
[#2342]: https://github.com/gchq/CyberChef/pull/2342
|
||||
[#1922]: https://github.com/gchq/CyberChef/pull/1922
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
# Modifier --platform=$BUILDPLATFORM limits the platform to "BUILDPLATFORM" during buildx multi-platform builds
|
||||
# This is because npm "chromedriver" package is not compatiable with all platforms
|
||||
# For more info see: https://docs.docker.com/build/building/multi-platform/#cross-compilation
|
||||
FROM --platform=$BUILDPLATFORM node:18-alpine AS builder
|
||||
FROM --platform=$BUILDPLATFORM node:24-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@ -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 <oss@gchq.gov.uk>"
|
||||
|
||||
|
||||
20
Gruntfile.js
20
Gruntfile.js
@ -6,7 +6,7 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPl
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
|
||||
const nodeFlags = "--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
|
||||
const nodeFlags = "--no-warnings --no-deprecation";
|
||||
|
||||
/**
|
||||
* Grunt configuration for building the app in various formats.
|
||||
@ -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/<div id=snackbar-container\\/>/<div id=snackbar-container>/g' ./node_modules/snackbarjs/src/snackbar.js`;
|
||||
default:
|
||||
return `sed -i 's/<div id=snackbar-container\\/>/<div id=snackbar-container>/g' ./node_modules/snackbarjs/src/snackbar.js`;
|
||||
}
|
||||
},
|
||||
command: `node ${nodeFlags} src/core/config/scripts/fixSnackBarMarkup.mjs`,
|
||||
stdout: false
|
||||
},
|
||||
},
|
||||
|
||||
@ -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.
|
||||
@ -120,7 +120,7 @@ CyberChef is built to support
|
||||
|
||||
## Node.js support
|
||||
|
||||
CyberChef is built to fully support Node.js `v16`. For more information, see the ["Node API" wiki page](https://github.com/gchq/CyberChef/wiki/Node-API)
|
||||
CyberChef is built to fully support Node.js `v24`. For more information, see the ["Node API" wiki page](https://github.com/gchq/CyberChef/wiki/Node-API)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
@ -16,6 +16,9 @@ module.exports = function(api) {
|
||||
"regenerator": true
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
"generatorOpts": {
|
||||
"importAttributesKeyword": "with"
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
4662
package-lock.json
generated
4662
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "10.22.1",
|
||||
"version": "11.0.0",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@ -36,34 +36,34 @@
|
||||
"browserslist": [
|
||||
"Chrome >= 50",
|
||||
"Firefox >= 38",
|
||||
"node >= 16"
|
||||
"node >= 24"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.28.6",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.28.6",
|
||||
"@babel/plugin-transform-runtime": "^7.29.0",
|
||||
"@babel/preset-env": "^7.29.2",
|
||||
"@babel/preset-env": "^7.29.5",
|
||||
"@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",
|
||||
"copy-webpack-plugin": "^13.0.1",
|
||||
"compression-webpack-plugin": "^12.0.0",
|
||||
"copy-webpack-plugin": "^14.0.0",
|
||||
"core-js": "^3.49.0",
|
||||
"cspell": "^8.19.4",
|
||||
"css-loader": "7.1.4",
|
||||
"cspell": "^9.7.0",
|
||||
"css-loader": "^7.1.4",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-plugin-jsdoc": "^50.8.0",
|
||||
"globals": "^15.15.0",
|
||||
"grunt": "^1.6.1",
|
||||
"globals": "^17.4.0",
|
||||
"grunt": "^1.6.2",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.1",
|
||||
@ -74,21 +74,21 @@
|
||||
"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.14",
|
||||
"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",
|
||||
"webpack-bundle-analyzer": "^4.10.2",
|
||||
"webpack-dev-server": "5.0.4",
|
||||
"terser": "^5.46.2",
|
||||
"webpack": "^5.106.2",
|
||||
"webpack-bundle-analyzer": "^5.3.0",
|
||||
"webpack-dev-server": "^5.0.4",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@ -97,13 +97,14 @@
|
||||
"@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",
|
||||
"bignumber.js": "^9.3.1",
|
||||
"@noble/hashes": "2.2.0",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@ -121,7 +122,7 @@
|
||||
"d3": "7.9.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^5.2.2",
|
||||
"dompurify": "^3.3.3",
|
||||
"dompurify": "^3.4.2",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1",
|
||||
@ -131,11 +132,10 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^6.0.1",
|
||||
"geodesy": "1.1.3",
|
||||
"handlebars": "^4.7.8",
|
||||
"hash-wasm": "^4.12.0",
|
||||
"handlebars": "^4.7.9",
|
||||
"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,30 +145,31 @@
|
||||
"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",
|
||||
"lz4js": "^0.2.0",
|
||||
"markdown-it": "^14.1.1",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.6.1",
|
||||
"moment-timezone": "^0.6.2",
|
||||
"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",
|
||||
"ntlm": "^0.1.3",
|
||||
"nwmatcher": "^1.4.4",
|
||||
"otpauth": "9.3.6",
|
||||
"otpauth": "^9.5.0",
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^7.5.4",
|
||||
"protobufjs": "^7.5.6",
|
||||
"punycode.js": "^2.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rison": "^0.1.1",
|
||||
@ -176,7 +177,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",
|
||||
@ -184,7 +185,7 @@
|
||||
"unorm": "^1.6.0",
|
||||
"url": "^0.11.4",
|
||||
"utf8": "^3.0.0",
|
||||
"uuid": "^13.0.0",
|
||||
"uuid": "^14.0.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xpath": "0.0.34",
|
||||
"xregexp": "^5.1.2",
|
||||
@ -194,18 +195,21 @@
|
||||
"start": "npx grunt dev",
|
||||
"build": "npx grunt prod",
|
||||
"node": "npx grunt node",
|
||||
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-experimental-fetch --no-warnings src/node/repl.mjs",
|
||||
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch --trace-uncaught tests/operations/index.mjs",
|
||||
"repl": "node --no-warnings src/node/repl.mjs",
|
||||
"test": "npx grunt configTests && node --no-warnings --no-deprecation --openssl-legacy-provider tests/node/index.mjs && node --no-warnings --no-deprecation --openssl-legacy-provider --trace-uncaught tests/operations/index.mjs",
|
||||
"testnodeconsumer": "npx grunt testnodeconsumer",
|
||||
"testui": "npx grunt testui",
|
||||
"testuidev": "npx nightwatch --env=dev",
|
||||
"lint": "npx grunt lint",
|
||||
"lint:grammar": "cspell ./src",
|
||||
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup",
|
||||
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
||||
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs && npm version minor --git-tag-version=false && echo \"Updated to version v$(npm pkg get version | xargs), please create a pull request and once merged use 'npm run tag'\"",
|
||||
"newop": "node src/core/config/scripts/newOperation.mjs",
|
||||
"minor": "node src/core/config/scripts/newMinorVersion.mjs && npm version minor --git-tag-version=false && echo \"Updated to version v$(npm pkg get version | xargs), please create a pull request and once merged use 'npm run tag'\"",
|
||||
"tag": "git tag -s \"v$(npm pkg get version | xargs)\" -m \"$(npm pkg get version | xargs)\" && echo \"Created v$(npm pkg get version | xargs), now check and push the tag\"",
|
||||
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
||||
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24 <25"
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import Chef from "./Chef.mjs";
|
||||
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
|
||||
import OperationConfig from "./config/OperationConfig.json" with { type: "json" };
|
||||
import OpModules from "./config/modules/OpModules.mjs";
|
||||
import loglevelMessagePrefix from "loglevel-message-prefix";
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
|
||||
import OperationConfig from "./config/OperationConfig.json" with { type: "json" };
|
||||
import OperationError from "./errors/OperationError.mjs";
|
||||
import Operation from "./Operation.mjs";
|
||||
import DishError from "./errors/DishError.mjs";
|
||||
|
||||
@ -348,6 +348,7 @@
|
||||
"Pseudo-Random Number Generator",
|
||||
"Sleep",
|
||||
"File Tree",
|
||||
"Wrap",
|
||||
"Take nth bytes",
|
||||
"Drop nth bytes"
|
||||
]
|
||||
@ -465,7 +466,8 @@
|
||||
"Luhn Checksum",
|
||||
"CRC Checksum",
|
||||
"TCP/IP Checksum",
|
||||
"XOR Checksum"
|
||||
"XOR Checksum",
|
||||
"Parity Bit"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
54
src/core/config/scripts/fixCryptoApiImports.mjs
Normal file
54
src/core/config/scripts/fixCryptoApiImports.mjs
Normal file
@ -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);
|
||||
28
src/core/config/scripts/fixSnackBarMarkup.mjs
Normal file
28
src/core/config/scripts/fixSnackBarMarkup.mjs
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* This script updates snackbarjs package
|
||||
* Replaces self-closing div with standard opening div
|
||||
*
|
||||
* before:
|
||||
* <div id=snackbar-container/>
|
||||
* after:
|
||||
* <div id=snackbar-container>
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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(
|
||||
/<div id=snackbar-container\/>/g,
|
||||
"<div id=snackbar-container>"
|
||||
);
|
||||
|
||||
writeFileSync(filePath, updated, "utf8");
|
||||
@ -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
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import OperationConfig from "../config/OperationConfig.json" assert {type: "json"};
|
||||
import OperationConfig from "../config/OperationConfig.json" with { type: "json" };
|
||||
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import Recipe from "../Recipe.mjs";
|
||||
import Dish from "../Dish.mjs";
|
||||
|
||||
50
src/core/lib/ParityBit.mjs
Normal file
50
src/core/lib/ParityBit.mjs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -6,7 +6,10 @@
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { blake3 } from "hash-wasm";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { blake3 } from "@noble/hashes/blake3.js";
|
||||
import { bytesToHex } from "@noble/hashes/utils.js";
|
||||
|
||||
/**
|
||||
* BLAKE3 operation
|
||||
*/
|
||||
@ -44,13 +47,16 @@ class BLAKE3 extends Operation {
|
||||
run(input, args) {
|
||||
const key = args[1];
|
||||
const size = args[0];
|
||||
// Check if the user want a key hash or not
|
||||
if (key === "") {
|
||||
return blake3(input, size*8);
|
||||
} if (key.length !== 32) {
|
||||
throw new OperationError("The key must be exactly 32 bytes long");
|
||||
const opts = { dkLen: size };
|
||||
const inputBytes = new Uint8Array(Utils.strToArrayBuffer(input));
|
||||
if (key !== "") {
|
||||
const keyBytes = new Uint8Array(Utils.strToArrayBuffer(key));
|
||||
if (keyBytes.length !== 32) {
|
||||
throw new OperationError("The key must be exactly 32 bytes long");
|
||||
}
|
||||
opts.key = keyBytes;
|
||||
}
|
||||
return blake3(input, size*8, key);
|
||||
return bytesToHex(blake3(inputBytes, opts));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import punycode from "punycode";
|
||||
import punycode from "punycode.js";
|
||||
|
||||
/**
|
||||
* From Punycode operation
|
||||
|
||||
@ -99,7 +99,7 @@ class OffsetChecker extends Operation {
|
||||
}
|
||||
}
|
||||
|
||||
return outputs.join(sampleDelim);
|
||||
return outputs.join(Utils.escapeHtml(sampleDelim));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
128
src/core/operations/ParityBit.mjs
Normal file
128
src/core/operations/ParityBit.mjs
Normal file
@ -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.<br><br>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;
|
||||
@ -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 {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 `<div style="font-family: var(--primary-font-family)">${rendered}</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -77,84 +77,84 @@ class ShowBase64Offsets extends Operation {
|
||||
staticSection = offset0.slice(0, -3);
|
||||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset0.substr(offset0.length - 3, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset0.substr(offset0.length - 2)) + "</span>";
|
||||
} else if (len0 % 4 === 3) {
|
||||
staticSection = offset0.slice(0, -2);
|
||||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset0.substr(offset0.length - 2, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset0.substr(offset0.length - 1)) + "</span>";
|
||||
} else {
|
||||
staticSection = offset0;
|
||||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64(staticSection, alphabet)) + "'>" +
|
||||
staticSection + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>";
|
||||
}
|
||||
|
||||
if (!showVariable) {
|
||||
offset0 = staticSection;
|
||||
offset0 = Utils.escapeHtml(staticSection);
|
||||
}
|
||||
|
||||
|
||||
// Highlight offset 1
|
||||
padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
|
||||
"<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
|
||||
padding = "<span class='hl3'>" + Utils.escapeHtml(offset1.substr(0, 1)) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset1.substr(1, 1)) + "</span>";
|
||||
offset1 = offset1.substr(2);
|
||||
if (len1 % 4 === 2) {
|
||||
staticSection = offset1.slice(0, -3);
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset1.substr(offset1.length - 3, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset1.substr(offset1.length - 2)) + "</span>";
|
||||
} else if (len1 % 4 === 3) {
|
||||
staticSection = offset1.slice(0, -2);
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset1.substr(offset1.length - 2, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset1.substr(offset1.length - 1)) + "</span>";
|
||||
} else {
|
||||
staticSection = offset1;
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1)) + "'>" +
|
||||
staticSection + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>";
|
||||
}
|
||||
|
||||
if (!showVariable) {
|
||||
offset1 = staticSection;
|
||||
offset1 = Utils.escapeHtml(staticSection);
|
||||
}
|
||||
|
||||
// Highlight offset 2
|
||||
padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
|
||||
"<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
|
||||
padding = "<span class='hl3'>" + Utils.escapeHtml(offset2.substr(0, 2)) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset2.substr(2, 1)) + "</span>";
|
||||
offset2 = offset2.substr(3);
|
||||
if (len2 % 4 === 2) {
|
||||
staticSection = offset2.slice(0, -3);
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset2.substr(offset2.length - 3, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset2.substr(offset2.length - 2)) + "</span>";
|
||||
} else if (len2 % 4 === 3) {
|
||||
staticSection = offset2.slice(0, -2);
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>" +
|
||||
"<span class='hl5'>" + Utils.escapeHtml(offset2.substr(offset2.length - 2, 1)) + "</span>" +
|
||||
"<span class='hl3'>" + Utils.escapeHtml(offset2.substr(offset2.length - 1)) + "</span>";
|
||||
} else {
|
||||
staticSection = offset2;
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2)) + "'>" +
|
||||
staticSection + "</span>";
|
||||
Utils.escapeHtml(staticSection) + "</span>";
|
||||
}
|
||||
|
||||
if (!showVariable) {
|
||||
offset2 = staticSection;
|
||||
offset2 = Utils.escapeHtml(staticSection);
|
||||
}
|
||||
|
||||
return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import punycode from "punycode";
|
||||
import punycode from "punycode.js";
|
||||
|
||||
/**
|
||||
* To Punycode operation
|
||||
|
||||
47
src/core/operations/Wrap.mjs
Normal file
47
src/core/operations/Wrap.mjs
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @author 0xff1ce [github.com/0xff1ce]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Wrap operation
|
||||
*/
|
||||
class Wrap extends Operation {
|
||||
|
||||
/**
|
||||
* Wrap constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Wrap";
|
||||
this.module = "Default";
|
||||
this.description = "Wraps the input text at a specified number of characters per line.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Line Width",
|
||||
"type": "number",
|
||||
"value": 64,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input) return ""; // Handle empty input
|
||||
const lineWidth = args[0];
|
||||
const regex = new RegExp(`.{1,${lineWidth}}`, "g");
|
||||
return input.match(regex).join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
export default Wrap;
|
||||
@ -88,16 +88,17 @@ class NodeRecipe {
|
||||
* @param {NodeDish} dish
|
||||
* @returns {NodeDish}
|
||||
*/
|
||||
execute(dish) {
|
||||
return this.opList.reduce((prev, curr) => {
|
||||
// CASE where opList item is op and args
|
||||
async execute(dish) {
|
||||
let prev = dish;
|
||||
for (const curr of this.opList) {
|
||||
if (Object.prototype.hasOwnProperty.call(curr, "op") &&
|
||||
Object.prototype.hasOwnProperty.call(curr, "args")) {
|
||||
return curr.op(prev, curr.args);
|
||||
prev = await curr.op(prev, curr.args);
|
||||
} else {
|
||||
prev = await curr(prev);
|
||||
}
|
||||
// CASE opList item is just op.
|
||||
return curr(prev);
|
||||
}, dish);
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
import NodeDish from "./NodeDish.mjs";
|
||||
import NodeRecipe from "./NodeRecipe.mjs";
|
||||
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
|
||||
import OperationConfig from "../core/config/OperationConfig.json" with { type: "json" };
|
||||
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
|
||||
import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";
|
||||
|
||||
@ -324,10 +324,10 @@ export function help(input) {
|
||||
* @returns {NodeDish} of the result
|
||||
* @throws {TypeError} if invalid recipe given.
|
||||
*/
|
||||
export function bake(input, recipeConfig) {
|
||||
const recipe = new NodeRecipe(recipeConfig);
|
||||
export async function bake(input, recipeConfig) {
|
||||
const recipe = new NodeRecipe(recipeConfig);
|
||||
const dish = ensureIsDish(input);
|
||||
return recipe.execute(dish);
|
||||
return await recipe.execute(dish);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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 = "<li class='operation'";
|
||||
|
||||
if (elementId) {
|
||||
html += ` id='${elementId}'`;
|
||||
}
|
||||
|
||||
if (this.description) {
|
||||
const infoLink = this.infoURL ? `<hr>${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;
|
||||
|
||||
@ -173,7 +173,7 @@
|
||||
Operations
|
||||
<span class="op-count"></span>
|
||||
</div>
|
||||
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>">
|
||||
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>" aria-owns="search-results">
|
||||
<ul id="search-results" class="op-list"></ul>
|
||||
<div id="categories" class="panel-group no-select"></div>
|
||||
</div>
|
||||
|
||||
@ -17,8 +17,8 @@ import * as CanvasComponents from "../core/lib/CanvasComponents.mjs";
|
||||
|
||||
// CyberChef
|
||||
import App from "./App.mjs";
|
||||
import Categories from "../core/config/Categories.json" assert {type: "json"};
|
||||
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
|
||||
import Categories from "../core/config/Categories.json" with { type: "json" };
|
||||
import OperationConfig from "../core/config/OperationConfig.json" with { type: "json" };
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import sm from "sitemap";
|
||||
import OperationConfig from "../../core/config/OperationConfig.json" assert { type: "json" };
|
||||
import OperationConfig from "../../core/config/OperationConfig.json" with { type: "json" };
|
||||
|
||||
/**
|
||||
* Generates an XML sitemap for all CyberChef operations and a number of recipes.
|
||||
|
||||
@ -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 = [];
|
||||
|
||||
@ -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");
|
||||
|
||||
31
tests/lib/wasmFetchPolyfill.mjs
Normal file
31
tests/lib/wasmFetchPolyfill.mjs
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Polyfill for Node.js 22+ where globalThis.fetch is built-in but rejects
|
||||
* bare filesystem paths. WASM libraries like argon2-browser call fetch() with
|
||||
* an absolute path (e.g. "/path/to/argon2.wasm") expecting a browser-style
|
||||
* fallback, but Node.js 22's fetch throws synchronously for non-URL strings.
|
||||
*
|
||||
* This wrapper intercepts such calls and serves the file via Node's fs module,
|
||||
* returning a synthetic Response so the WASM module loads correctly.
|
||||
*/
|
||||
|
||||
import { readFile } from "fs/promises";
|
||||
|
||||
if (globalThis.fetch) {
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async function patchedFetch(url, options) {
|
||||
const urlStr = typeof url === "string" ?
|
||||
url :
|
||||
url instanceof URL ?
|
||||
url.href :
|
||||
String(url);
|
||||
// Intercept bare filesystem paths (absolute POSIX or Windows)
|
||||
if (urlStr.startsWith("/") || /^[A-Za-z]:[/\\]/.test(urlStr)) {
|
||||
const buffer = await readFile(urlStr);
|
||||
return new Response(buffer, {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/wasm" },
|
||||
});
|
||||
}
|
||||
return originalFetch(url, options);
|
||||
};
|
||||
}
|
||||
@ -8,9 +8,9 @@
|
||||
|
||||
const assert = require("assert");
|
||||
|
||||
require("cyberchef").then(chef => {
|
||||
require("cyberchef").then(async chef => {
|
||||
|
||||
const d = chef.bake("Testing, 1 2 3", [
|
||||
const d = await chef.bake("Testing, 1 2 3", [
|
||||
chef.toHex,
|
||||
chef.reverse,
|
||||
{
|
||||
|
||||
@ -9,7 +9,7 @@ import assert from "assert";
|
||||
import chef from "cyberchef";
|
||||
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
|
||||
|
||||
const a = bake("Testing, 1 2 3", [
|
||||
const a = await bake("Testing, 1 2 3", [
|
||||
toHex,
|
||||
reverse,
|
||||
{
|
||||
@ -28,7 +28,7 @@ const a = bake("Testing, 1 2 3", [
|
||||
|
||||
assert.equal(a.value, "630957449041920");
|
||||
|
||||
const b = chef.bake("Testing, 1 2 3", [
|
||||
const b = await chef.bake("Testing, 1 2 3", [
|
||||
chef.toHex,
|
||||
chef.reverse,
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
import Categories from "../../../src/core/config/Categories.json" assert {type: "json"};
|
||||
import OperationConfig from "../../../src/core/config/OperationConfig.json" assert {type: "json"};
|
||||
import Categories from "../../../src/core/config/Categories.json" with { type: "json" };
|
||||
import OperationConfig from "../../../src/core/config/OperationConfig.json" with { type: "json" };
|
||||
import it from "../assertionHandler.mjs";
|
||||
import assert from "assert";
|
||||
|
||||
|
||||
@ -170,77 +170,77 @@ TestRegister.addApiTests([
|
||||
assert(chef.bake);
|
||||
}),
|
||||
|
||||
it("chef.bake: should return NodeDish", () => {
|
||||
const result = chef.bake("input", "to base 64");
|
||||
it("chef.bake: should return NodeDish", async () => {
|
||||
const result = await chef.bake("input", "to base 64");
|
||||
assert(result instanceof NodeDish);
|
||||
}),
|
||||
|
||||
it("chef.bake: should take an input and an op name and perform it", () => {
|
||||
const result = chef.bake("some input", "to base 32");
|
||||
it("chef.bake: should take an input and an op name and perform it", async () => {
|
||||
const result = await chef.bake("some input", "to base 32");
|
||||
assert.strictEqual(result.toString(), "ONXW2ZJANFXHA5LU");
|
||||
}),
|
||||
|
||||
it("chef.bake: should complain if recipe isnt a valid object", () => {
|
||||
assert.throws(() => chef.bake("some input", 3264), {
|
||||
it("chef.bake: should complain if recipe isnt a valid object", async () => {
|
||||
await assert.rejects(() => chef.bake("some input", 3264), {
|
||||
name: "TypeError",
|
||||
message: "Recipe can only contain function names or functions"
|
||||
});
|
||||
}),
|
||||
|
||||
it("chef.bake: Should complain if string op is invalid", () => {
|
||||
assert.throws(() => chef.bake("some input", "not a valid operation"), {
|
||||
it("chef.bake: Should complain if string op is invalid", async () => {
|
||||
await assert.rejects(() => chef.bake("some input", "not a valid operation"), {
|
||||
name: "TypeError",
|
||||
message: "Couldn't find an operation with name 'not a valid operation'."
|
||||
});
|
||||
}),
|
||||
|
||||
it("chef.bake: Should take an input and an operation and perform it", () => {
|
||||
const result = chef.bake("https://google.com/search?q=help", chef.parseURI);
|
||||
it("chef.bake: Should take an input and an operation and perform it", async () => {
|
||||
const result = await chef.bake("https://google.com/search?q=help", chef.parseURI);
|
||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = help\n");
|
||||
}),
|
||||
|
||||
it("chef.bake: Should complain if an invalid operation is inputted", () => {
|
||||
assert.throws(() => chef.bake("https://google.com/search?q=help", () => {}), {
|
||||
it("chef.bake: Should complain if an invalid operation is inputted", async () => {
|
||||
await assert.rejects(() => chef.bake("https://google.com/search?q=help", () => {}), {
|
||||
name: "TypeError",
|
||||
message: "Inputted function not a Chef operation."
|
||||
});
|
||||
}),
|
||||
|
||||
it("chef.bake: accepts an array of operation names and performs them all in order", () => {
|
||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
||||
it("chef.bake: accepts an array of operation names and performs them all in order", async () => {
|
||||
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||
}),
|
||||
|
||||
it("chef.bake: forgiving with operation names", () =>{
|
||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
||||
it("chef.bake: forgiving with operation names", async () =>{
|
||||
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||
}),
|
||||
|
||||
it("chef.bake: forgiving with operation names", () =>{
|
||||
const result = chef.bake("hello", ["to base 64"]);
|
||||
it("chef.bake: forgiving with operation names", async () =>{
|
||||
const result = await chef.bake("hello", ["to base 64"]);
|
||||
assert.strictEqual(result.toString(), "aGVsbG8=");
|
||||
}),
|
||||
|
||||
it("chef.bake: if recipe is empty array, return input as dish", () => {
|
||||
const result = chef.bake("some input", []);
|
||||
it("chef.bake: if recipe is empty array, return input as dish", async () => {
|
||||
const result = await chef.bake("some input", []);
|
||||
assert.strictEqual(result.toString(), "some input");
|
||||
assert(result instanceof NodeDish, "Result is not instance of NodeDish");
|
||||
}),
|
||||
|
||||
it("chef.bake: accepts an array of operations as recipe", () => {
|
||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
||||
it("chef.bake: accepts an array of operations as recipe", async () => {
|
||||
const result = await chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||
}),
|
||||
|
||||
it("should complain if an invalid operation is inputted as part of array", () => {
|
||||
assert.throws(() => chef.bake("something", [() => {}]), {
|
||||
it("should complain if an invalid operation is inputted as part of array", async () => {
|
||||
await assert.rejects(() => chef.bake("something", [() => {}]), {
|
||||
name: "TypeError",
|
||||
message: "Inputted function not a Chef operation."
|
||||
});
|
||||
}),
|
||||
|
||||
it("chef.bake: should take single JSON object describing op and args OBJ", () => {
|
||||
const result = chef.bake("some input", {
|
||||
it("chef.bake: should take single JSON object describing op and args OBJ", async () => {
|
||||
const result = await chef.bake("some input", {
|
||||
op: chef.toHex,
|
||||
args: {
|
||||
Delimiter: "Colon"
|
||||
@ -249,23 +249,23 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
||||
}),
|
||||
|
||||
it("chef.bake: should take single JSON object desribing op with optional args", () => {
|
||||
const result = chef.bake("some input", {
|
||||
it("chef.bake: should take single JSON object desribing op with optional args", async () => {
|
||||
const result = await chef.bake("some input", {
|
||||
op: chef.toHex,
|
||||
});
|
||||
assert.strictEqual(result.toString(), "73 6f 6d 65 20 69 6e 70 75 74");
|
||||
}),
|
||||
|
||||
it("chef.bake: should take single JSON object describing op and args ARRAY", () => {
|
||||
const result = chef.bake("some input", {
|
||||
it("chef.bake: should take single JSON object describing op and args ARRAY", async () => {
|
||||
const result = await chef.bake("some input", {
|
||||
op: chef.toHex,
|
||||
args: ["Colon"]
|
||||
});
|
||||
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
||||
}),
|
||||
|
||||
it("chef.bake: should error if op in JSON is not chef op", () => {
|
||||
assert.throws(() => chef.bake("some input", {
|
||||
it("chef.bake: should error if op in JSON is not chef op", async () => {
|
||||
await assert.rejects(() => chef.bake("some input", {
|
||||
op: () => {},
|
||||
args: ["Colon"],
|
||||
}), {
|
||||
@ -274,8 +274,8 @@ TestRegister.addApiTests([
|
||||
});
|
||||
}),
|
||||
|
||||
it("chef.bake: should take multiple ops in JSON object form, some ops by string", () => {
|
||||
const result = chef.bake("some input", [
|
||||
it("chef.bake: should take multiple ops in JSON object form, some ops by string", async () => {
|
||||
const result = await chef.bake("some input", [
|
||||
{
|
||||
op: chef.toHex,
|
||||
args: ["Colon"]
|
||||
@ -290,8 +290,8 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "67;63;72;66;146;72;66;144;72;66;65;72;62;60;72;66;71;72;66;145;72;67;60;72;67;65;72;67;64");
|
||||
}),
|
||||
|
||||
it("chef.bake: should take multiple ops in JSON object form, some without args", () => {
|
||||
const result = chef.bake("some input", [
|
||||
it("chef.bake: should take multiple ops in JSON object form, some without args", async () => {
|
||||
const result = await chef.bake("some input", [
|
||||
{
|
||||
op: chef.toHex,
|
||||
},
|
||||
@ -305,8 +305,8 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "67;63;40;66;146;40;66;144;40;66;65;40;62;60;40;66;71;40;66;145;40;67;60;40;67;65;40;67;64");
|
||||
}),
|
||||
|
||||
it("chef.bake: should handle op with multiple args", () => {
|
||||
const result = chef.bake("some input", {
|
||||
it("chef.bake: should handle op with multiple args", async () => {
|
||||
const result = await chef.bake("some input", {
|
||||
op: "to morse code",
|
||||
args: {
|
||||
formatOptions: "Dash/Dot",
|
||||
@ -317,13 +317,13 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "DotDotDot\\DashDashDash\\DashDash\\Dot,DotDot\\DashDot\\DotDashDashDot\\DotDotDash\\Dash");
|
||||
}),
|
||||
|
||||
it("chef.bake: should take compact JSON format from Chef Website as recipe", () => {
|
||||
const result = chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
||||
it("chef.bake: should take compact JSON format from Chef Website as recipe", async () => {
|
||||
const result = await chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
||||
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
||||
}),
|
||||
|
||||
it("chef.bake: should accept Clean JSON format from Chef website as recipe", () => {
|
||||
const result = chef.bake("some input", [
|
||||
it("chef.bake: should accept Clean JSON format from Chef website as recipe", async () => {
|
||||
const result = await chef.bake("some input", [
|
||||
{ "op": "To Morse Code",
|
||||
"args": ["Dash/Dot", "Backslash", "Comma"] },
|
||||
{ "op": "Hex to PEM",
|
||||
@ -334,8 +334,8 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
||||
}),
|
||||
|
||||
it("chef.bake: should accept Clean JSON format from Chef website - args optional", () => {
|
||||
const result = chef.bake("some input", [
|
||||
it("chef.bake: should accept Clean JSON format from Chef website - args optional", async () => {
|
||||
const result = await chef.bake("some input", [
|
||||
{ "op": "To Morse Code" },
|
||||
{ "op": "Hex to PEM",
|
||||
"args": ["SOMETHING"] },
|
||||
@ -345,31 +345,28 @@ TestRegister.addApiTests([
|
||||
assert.strictEqual(result.toString(), "begin_something_aaaaaaaaaaaaaa_end_something");
|
||||
}),
|
||||
|
||||
it("chef.bake: should accept operation names from Chef Website which contain forward slash", () => {
|
||||
const result = chef.bake("I'll have the test salmon", [
|
||||
it("chef.bake: should accept operation names from Chef Website which contain forward slash", async () => {
|
||||
const result = await chef.bake("I'll have the test salmon", [
|
||||
{ "op": "Find / Replace",
|
||||
"args": [{ "option": "Regex", "string": "test" }, "good", true, false, true, false]}
|
||||
]);
|
||||
assert.strictEqual(result.toString(), "I'll have the good salmon");
|
||||
}),
|
||||
|
||||
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", () => {
|
||||
const result = chef.bake("I'll have the test salmon", [
|
||||
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", async () => {
|
||||
const result = await chef.bake("I'll have the test salmon", [
|
||||
{ "op": "Adler-32 Checksum",
|
||||
"args": [] }
|
||||
]);
|
||||
assert.strictEqual(result.toString(), "6e4208f8");
|
||||
}),
|
||||
|
||||
it("chef.bake: should accept operation names from Chef Website which contain a period", () => {
|
||||
const result = chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
||||
it("chef.bake: should accept operation names from Chef Website which contain a period", async () => {
|
||||
const result = await chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
||||
{ "op": "Parse ASN.1 hex string",
|
||||
"args": [0, 32] }
|
||||
]);
|
||||
assert.strictEqual(result.toString(), `SEQUENCE
|
||||
INTEGER 05
|
||||
IA5String 'Anybody there?'
|
||||
`);
|
||||
assert.strictEqual(result.toString(), `SEQUENCE\n INTEGER 05\n IA5String 'Anybody there?'\n`);
|
||||
}),
|
||||
|
||||
it("Excluded operations: throw a sensible error when you try and call one", () => {
|
||||
@ -381,16 +378,16 @@ TestRegister.addApiTests([
|
||||
}
|
||||
}),
|
||||
|
||||
it("chef.bake: cannot accept flowControl operations in recipe", () => {
|
||||
assert.throws(() => chef.bake("some input", "magic"), {
|
||||
it("chef.bake: cannot accept flowControl operations in recipe", async () => {
|
||||
await assert.rejects(() => chef.bake("some input", "magic"), {
|
||||
name: "TypeError",
|
||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||
});
|
||||
assert.throws(() => chef.bake("some input", magic), {
|
||||
await assert.rejects(() => chef.bake("some input", magic), {
|
||||
name: "TypeError",
|
||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||
});
|
||||
assert.throws(() => chef.bake("some input", ["to base 64", "magic"]), {
|
||||
await assert.rejects(() => chef.bake("some input", ["to base 64", "magic"]), {
|
||||
name: "TypeError",
|
||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||
});
|
||||
|
||||
@ -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", () => {
|
||||
|
||||
@ -11,11 +11,13 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import "../lib/wasmFetchPolyfill.mjs";
|
||||
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 +73,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 +137,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 +147,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";
|
||||
@ -175,6 +181,7 @@ import "./tests/TranslateDateTimeFormat.mjs";
|
||||
import "./tests/Typex.mjs";
|
||||
import "./tests/UnescapeString.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/Wrap.mjs";
|
||||
import "./tests/URLEncodeDecode.mjs";
|
||||
import "./tests/RSA.mjs";
|
||||
import "./tests/CBOREncode.mjs";
|
||||
|
||||
66
tests/operations/tests/AnalyseUUID.mjs
Normal file
66
tests/operations/tests/AnalyseUUID.mjs
Normal file
@ -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]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
@ -51,5 +51,23 @@ TestRegister.addTests([
|
||||
{ "op": "BLAKE3",
|
||||
"args": [8, "ThiskeyisexactlythirtytwoByteslo"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: 16390 - test",
|
||||
input: "test",
|
||||
expectedMatch: /4878.{32760}555fe06b242738d5/,
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [16390, ""] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: 16390 - key test",
|
||||
input: "test",
|
||||
expectedMatch: /a8d0.{32760}19ccd9b9726b46ae/,
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [16390, "ThiskeyisexactlythirtytwoBytesLo"] }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
@ -116,4 +116,15 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Show Base64 offsets: escapes static output",
|
||||
input: "\x00\x10\x83\x10\x51\x87",
|
||||
expectedOutput: "<script>\n<AQmsBRk66\n<ia1AEIM6",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Show Base64 offsets",
|
||||
args: ["<script>ale(1)/.ABCDEFGHIJKLMNOPQRSTUVWXYZbdfghjkmnoquvwxyz023456", false, "Raw"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
@ -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],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -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="]
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
|
||||
147
tests/operations/tests/ParityBit.mjs
Normal file
147
tests/operations/tests/ParityBit.mjs
Normal file
@ -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",
|
||||
" "
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
@ -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",
|
||||
|
||||
75
tests/operations/tests/RegularExpression.mjs
Normal file
75
tests/operations/tests/RegularExpression.mjs
Normal file
@ -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",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
110
tests/operations/tests/RenderMarkdown.mjs
Normal file
110
tests/operations/tests/RenderMarkdown.mjs
Normal file
@ -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: '<div style="font-family: var(--primary-font-family)"></div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: Basic Text",
|
||||
input: "Hello World!",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p>Hello World!</p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: Simple Markdown",
|
||||
input: "# Hello World!",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><h1>Hello World!</h1>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: URL (not expanded)",
|
||||
input: "https://gchq.github.io/CyberChef/",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p>https://gchq.github.io/CyberChef/</p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [false, false, false]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: URL (expanded)",
|
||||
input: "https://gchq.github.io/CyberChef/",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p><a href="https://gchq.github.io/CyberChef/">https://gchq.github.io/CyberChef/</a></p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [true, false, false]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: Link (not expanded)",
|
||||
input: "[CyberChef](https://gchq.github.io/CyberChef/)",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p><a href="https://gchq.github.io/CyberChef/">CyberChef</a></p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [false, false, false]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: Link (expanded)",
|
||||
input: "[CyberChef](https://gchq.github.io/CyberChef/)",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p><a href="https://gchq.github.io/CyberChef/">CyberChef</a></p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [true, false, false]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: Link (open in new window)",
|
||||
input: "[CyberChef](https://gchq.github.io/CyberChef/)",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p><a href="https://gchq.github.io/CyberChef/" target="_blank">CyberChef</a></p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [true, false, true]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Render Markdown: URL (open in new window)",
|
||||
input: "https://gchq.github.io/CyberChef/",
|
||||
expectedOutput: '<div style="font-family: var(--primary-font-family)"><p><a href="https://gchq.github.io/CyberChef/" target="_blank">https://gchq.github.io/CyberChef/</a></p>\n</div>',
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Render Markdown",
|
||||
"args": [true, false, true]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
44
tests/operations/tests/Wrap.mjs
Normal file
44
tests/operations/tests/Wrap.mjs
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @author 0xff1ce [github.com/0xff1ce]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
// Add tests specific to the Wrap operation
|
||||
{
|
||||
name: "Wrap text at 64 characters",
|
||||
input: "A".repeat(128), // Generate an input string of 128 'A' characters
|
||||
expectedOutput: "A".repeat(64) + "\n" + "A".repeat(64), // Expected output with a line break after 64 characters
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Wrap",
|
||||
"args": [64]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Wrap text at 32 characters",
|
||||
input: "B".repeat(96), // Generate an input string of 96 'B' characters
|
||||
expectedOutput: "B".repeat(32) + "\n" + "B".repeat(32) + "\n" + "B".repeat(32), // Expected output with line breaks after every 32 characters
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Wrap",
|
||||
"args": [32]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Wrap text at 10 characters",
|
||||
input: "1234567890".repeat(10), // Generate an input string by repeating '1234567890'
|
||||
expectedOutput: Array(10).fill("1234567890").join("\n"), // Expected output with line breaks every 10 characters
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Wrap",
|
||||
"args": [10]
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user