Merge remote-tracking branch 'upstream/master' into 181-responsive-ui
This commit is contained in:
commit
a01f3d9b4c
1
.github/ISSUE_TEMPLATE.md
vendored
1
.github/ISSUE_TEMPLATE.md
vendored
@ -1 +0,0 @@
|
|||||||
<!-- Prefix the title above with 'Misc:' -->
|
|
||||||
12
.github/ISSUE_TEMPLATE/operation-request.md
vendored
12
.github/ISSUE_TEMPLATE/operation-request.md
vendored
@ -7,8 +7,14 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Summary
|
**Is your operation request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. E.g. I'm always frustrated when [...]
|
||||||
|
|
||||||
### Example Input
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of the new operation you would like.
|
||||||
|
|
||||||
### Example Output
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Example input and output**
|
||||||
|
Provide an example input to the operation, along with the output that you would expect.
|
||||||
|
|||||||
74
.github/dependabot.yml
vendored
Normal file
74
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# See the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
#
|
||||||
|
# Check for minor/patch versions only on a weekly basis - we are likely to be able to
|
||||||
|
# merge these routinely. Major versions we'll check for and update manually.
|
||||||
|
#
|
||||||
|
- package-ecosystem: 'npm'
|
||||||
|
directory: '/'
|
||||||
|
versioning-strategy: increase
|
||||||
|
schedule:
|
||||||
|
interval: 'weekly'
|
||||||
|
day: 'friday'
|
||||||
|
time: '03:00'
|
||||||
|
timezone: Europe/London
|
||||||
|
commit-message:
|
||||||
|
prefix: 'chore (deps): '
|
||||||
|
ignore:
|
||||||
|
# we'll do any major version updates manually
|
||||||
|
- dependency-name: '*'
|
||||||
|
update-types: ['version-update:semver-major']
|
||||||
|
# packages we can't currently update
|
||||||
|
# see issue #2214 for rationale for each of these
|
||||||
|
- dependency-name: '@xmldom/xmldom'
|
||||||
|
versions: [ '>=0.9.0' ]
|
||||||
|
- dependency-name: 'bcryptjs'
|
||||||
|
versions: [ '>=3.0.0' ]
|
||||||
|
- dependency-name: 'bootstrap'
|
||||||
|
versions: [ '>=5.0.0' ]
|
||||||
|
- dependency-name: 'bson'
|
||||||
|
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'
|
||||||
|
versions: [ '>=51.0.0' ]
|
||||||
|
- dependency-name: 'fernet'
|
||||||
|
versions: [ '>=0.4.0' ]
|
||||||
|
- dependency-name: 'geodesy'
|
||||||
|
versions: [ '>=2.0.0' ]
|
||||||
|
- dependency-name: 'jimp'
|
||||||
|
versions: [ '1.6.1' ]
|
||||||
|
- dependency-name: 'otpauth'
|
||||||
|
versions: [ '>=9.4.0' ]
|
||||||
|
- dependency-name: 'webpack-dev-server'
|
||||||
|
versions: [ '>=5.1.0' ]
|
||||||
|
groups:
|
||||||
|
#
|
||||||
|
# Grouping so we don't get a seperate PR for every patch version.
|
||||||
|
#
|
||||||
|
patch-updates:
|
||||||
|
applies-to: version-updates
|
||||||
|
patterns:
|
||||||
|
- '*'
|
||||||
|
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): '
|
||||||
15
.github/pull_request_template.md
vendored
Normal file
15
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
**Description**
|
||||||
|
Provide a description of the pull request and the changes that it makes.
|
||||||
|
|
||||||
|
**Existing Issue**
|
||||||
|
If this pull request relates to an existing issue in the repository, please link it here.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If the pull request changes any visual aspects of CyberChef, please include screenshots.
|
||||||
|
|
||||||
|
**AI disclosure**
|
||||||
|
If you have used any AI tools while creating this code, **you must declare your usage along with the name of the tools that you used**.
|
||||||
|
Regardless of AI tool usage, you are responsible for any code that you submit, and we expect you to have checked the code and have enough of an understanding of it to answer any questions we might have.
|
||||||
|
|
||||||
|
**Test Coverage**
|
||||||
|
Please ensure you have added test coverage for your changes.
|
||||||
3
.github/workflows/master.yml
vendored
3
.github/workflows/master.yml
vendored
@ -26,8 +26,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
export DETECT_CHROMEDRIVER_VERSION=true
|
npm ci
|
||||||
npm install
|
|
||||||
npm run setheapsize
|
npm run setheapsize
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
|
|||||||
23
.github/workflows/pull_requests.yml
vendored
23
.github/workflows/pull_requests.yml
vendored
@ -22,8 +22,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
export DETECT_CHROMEDRIVER_VERSION=true
|
npm ci
|
||||||
npm install
|
|
||||||
npm run setheapsize
|
npm run setheapsize
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
@ -38,7 +37,22 @@ jobs:
|
|||||||
if: success()
|
if: success()
|
||||||
run: npx grunt prod
|
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
|
- name: Set up Docker Buildx
|
||||||
|
if: success()
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
@ -50,8 +64,3 @@ jobs:
|
|||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64,linux/arm64
|
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
|
|
||||||
|
|||||||
1
.github/workflows/releases.yml
vendored
1
.github/workflows/releases.yml
vendored
@ -32,7 +32,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
export DETECT_CHROMEDRIVER_VERSION=true
|
|
||||||
npm ci
|
npm ci
|
||||||
npm run setheapsize
|
npm run setheapsize
|
||||||
|
|
||||||
|
|||||||
131
CHANGELOG.md
131
CHANGELOG.md
@ -13,6 +13,64 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
### [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
|
### [10.22.0] - 2026-02-11
|
||||||
- Separate npm publish out into separate job and run with Node 24.5 [@GCHQDeveloper581] | [#2188]
|
- Separate npm publish out into separate job and run with Node 24.5 [@GCHQDeveloper581] | [#2188]
|
||||||
- Fixed Percent delimiter for hex encoding [@beneri] [@C85297] | [#2137]
|
- Fixed Percent delimiter for hex encoding [@beneri] [@C85297] | [#2137]
|
||||||
@ -538,6 +596,7 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
## [4.0.0] - 2016-11-28
|
## [4.0.0] - 2016-11-28
|
||||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||||
|
|
||||||
|
[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.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.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
|
[10.20.0]: https://github.com/gchq/CyberChef/releases/tag/v10.20.0
|
||||||
@ -797,6 +856,22 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[@t-martine]: https://github.com/t-martine
|
[@t-martine]: https://github.com/t-martine
|
||||||
[@wesinator]: https://github.com/wesinator
|
[@wesinator]: https://github.com/wesinator
|
||||||
[@Raka-loah]: https://github.com/Raka-loah
|
[@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
|
||||||
|
|
||||||
|
|
||||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||||
@ -1010,4 +1085,60 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[#2183]: https://github.com/gchq/CyberChef/pull/2183
|
[#2183]: https://github.com/gchq/CyberChef/pull/2183
|
||||||
[#2182]: https://github.com/gchq/CyberChef/pull/2182
|
[#2182]: https://github.com/gchq/CyberChef/pull/2182
|
||||||
[#2181]: https://github.com/gchq/CyberChef/pull/2181
|
[#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
|
||||||
|
|
||||||
|
|||||||
18
Gruntfile.js
18
Gruntfile.js
@ -412,25 +412,11 @@ module.exports = function (grunt) {
|
|||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
fixCryptoApiImports: {
|
fixCryptoApiImports: {
|
||||||
command: function () {
|
command: `node ${nodeFlags} src/core/config/scripts/fixCryptoApiImports.mjs`,
|
||||||
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'`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stdout: false
|
stdout: false
|
||||||
},
|
},
|
||||||
fixSnackbarMarkup: {
|
fixSnackbarMarkup: {
|
||||||
command: function () {
|
command: `node ${nodeFlags} src/core/config/scripts/fixSnackBarMarkup.mjs`,
|
||||||
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`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stdout: false
|
stdout: false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
466
package-lock.json
generated
466
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.22.1",
|
"version": "10.23.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.22.1",
|
"version": "10.23.0",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -14,9 +14,9 @@
|
|||||||
"@astronautlabs/amf": "^0.0.6",
|
"@astronautlabs/amf": "^0.0.6",
|
||||||
"@blu3r4y/lzma": "^2.3.3",
|
"@blu3r4y/lzma": "^2.3.3",
|
||||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||||
"@xmldom/xmldom": "^0.8.11",
|
"@xmldom/xmldom": "^0.8.13",
|
||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
"arrive": "^2.5.2",
|
"arrive": "^2.5.3",
|
||||||
"assert": "^2.1.0",
|
"assert": "^2.1.0",
|
||||||
"avsc": "^5.7.9",
|
"avsc": "^5.7.9",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"d3": "7.9.0",
|
"d3": "7.9.0",
|
||||||
"d3-hexbin": "^0.2.2",
|
"d3-hexbin": "^0.2.2",
|
||||||
"diff": "^5.2.2",
|
"diff": "^5.2.2",
|
||||||
"dompurify": "^3.3.3",
|
"dompurify": "^3.4.1",
|
||||||
"es6-promisify": "^7.0.0",
|
"es6-promisify": "^7.0.0",
|
||||||
"escodegen": "^2.1.0",
|
"escodegen": "^2.1.0",
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
@ -48,12 +48,12 @@
|
|||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^6.0.1",
|
"flat": "^6.0.1",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.9",
|
||||||
"hash-wasm": "^4.12.0",
|
"hash-wasm": "^4.12.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"ieee754": "^1.2.1",
|
"ieee754": "^1.2.1",
|
||||||
"jimp": "^1.6.0",
|
"jimp": "1.6.0",
|
||||||
"jq-wasm": "^1.1.0-jq-1.8.1",
|
"jq-web": "^0.5.1",
|
||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"js-sha3": "^0.9.3",
|
"js-sha3": "^0.9.3",
|
||||||
"jsesc": "^3.1.0",
|
"jsesc": "^3.1.0",
|
||||||
@ -62,20 +62,20 @@
|
|||||||
"jsonpath-plus": "^10.4.0",
|
"jsonpath-plus": "^10.4.0",
|
||||||
"jsonwebtoken": "9.0.3",
|
"jsonwebtoken": "9.0.3",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^11.1.1",
|
"jsrsasign": "^11.1.3",
|
||||||
"kbpgp": "^2.1.17",
|
"kbpgp": "^2.1.17",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.2.1",
|
"libyara-wasm": "^1.2.1",
|
||||||
"lodash": "^4.17.23",
|
"lodash": "^4.18.1",
|
||||||
"loglevel": "^1.9.2",
|
"loglevel": "^1.9.2",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"lz-string": "^1.5.0",
|
"lz-string": "^1.5.0",
|
||||||
"lz4js": "^0.2.0",
|
"lz4js": "^0.2.0",
|
||||||
"markdown-it": "^14.1.1",
|
"markdown-it": "^14.1.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.6.0",
|
"moment-timezone": "^0.6.1",
|
||||||
"ngeohash": "^0.6.3",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^1.3.3",
|
"node-forge": "^1.4.0",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
"nodom": "^2.4.0",
|
"nodom": "^2.4.0",
|
||||||
"notepack.io": "^3.0.1",
|
"notepack.io": "^3.0.1",
|
||||||
@ -85,7 +85,7 @@
|
|||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"protobufjs": "^7.5.4",
|
"protobufjs": "^7.5.5",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rison": "^0.1.1",
|
"rison": "^0.1.1",
|
||||||
@ -93,7 +93,7 @@
|
|||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
"sortablejs": "^1.15.7",
|
"sortablejs": "^1.15.7",
|
||||||
"split.js": "^1.6.5",
|
"split.js": "^1.6.5",
|
||||||
"sql-formatter": "^15.6.12",
|
"sql-formatter": "^15.7.3",
|
||||||
"ssdeep.js": "0.0.3",
|
"ssdeep.js": "0.0.3",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"tesseract.js": "^6.0.1",
|
"tesseract.js": "^6.0.1",
|
||||||
@ -111,28 +111,28 @@
|
|||||||
"@babel/eslint-parser": "^7.28.6",
|
"@babel/eslint-parser": "^7.28.6",
|
||||||
"@babel/plugin-syntax-import-assertions": "^7.28.6",
|
"@babel/plugin-syntax-import-assertions": "^7.28.6",
|
||||||
"@babel/plugin-transform-runtime": "^7.29.0",
|
"@babel/plugin-transform-runtime": "^7.29.0",
|
||||||
"@babel/preset-env": "^7.29.0",
|
"@babel/preset-env": "^7.29.2",
|
||||||
"@babel/runtime": "^7.28.6",
|
"@babel/runtime": "^7.29.2",
|
||||||
"@codemirror/commands": "^6.10.2",
|
"@codemirror/commands": "^6.10.3",
|
||||||
"@codemirror/language": "^6.12.2",
|
"@codemirror/language": "^6.12.3",
|
||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.7.0",
|
||||||
"@codemirror/state": "^6.5.4",
|
"@codemirror/state": "^6.5.4",
|
||||||
"@codemirror/view": "^6.39.17",
|
"@codemirror/view": "^6.41.1",
|
||||||
"autoprefixer": "^10.4.27",
|
"autoprefixer": "^10.5.0",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.1.1",
|
||||||
"base64-loader": "^1.0.0",
|
"base64-loader": "^1.0.0",
|
||||||
"chromedriver": "^130.0.4",
|
"chromedriver": "^146.0.6",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
"copy-webpack-plugin": "^13.0.1",
|
"copy-webpack-plugin": "^13.0.1",
|
||||||
"core-js": "^3.48.0",
|
"core-js": "^3.49.0",
|
||||||
"cspell": "^8.19.4",
|
"cspell": "^8.19.4",
|
||||||
"css-loader": "7.1.4",
|
"css-loader": "7.1.4",
|
||||||
"eslint": "^9.39.4",
|
"eslint": "^9.39.4",
|
||||||
"eslint-plugin-jsdoc": "^50.8.0",
|
"eslint-plugin-jsdoc": "^50.8.0",
|
||||||
"globals": "^15.15.0",
|
"globals": "^15.15.0",
|
||||||
"grunt": "^1.6.1",
|
"grunt": "^1.6.2",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^3.0.0",
|
"grunt-concurrent": "^3.0.0",
|
||||||
"grunt-contrib-clean": "~2.0.1",
|
"grunt-contrib-clean": "~2.0.1",
|
||||||
@ -143,19 +143,19 @@
|
|||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-webpack": "^6.0.0",
|
"grunt-webpack": "^6.0.0",
|
||||||
"grunt-zip": "^1.0.0",
|
"grunt-zip": "^1.0.0",
|
||||||
"html-webpack-plugin": "^5.6.6",
|
"html-webpack-plugin": "^5.6.7",
|
||||||
"imports-loader": "^5.0.0",
|
"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",
|
"modify-source-webpack-plugin": "^4.1.0",
|
||||||
"nightwatch": "^3.15.0",
|
"nightwatch": "^3.15.0",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.5.10",
|
||||||
"postcss-css-variables": "^0.19.0",
|
"postcss-css-variables": "^0.19.0",
|
||||||
"postcss-import": "^16.1.1",
|
"postcss-import": "^16.1.1",
|
||||||
"postcss-loader": "^8.2.1",
|
"postcss-loader": "^8.2.1",
|
||||||
"prompt": "^1.3.0",
|
"prompt": "^1.3.0",
|
||||||
"sitemap": "^8.0.3",
|
"sitemap": "^8.0.3",
|
||||||
"terser": "^5.46.0",
|
"terser": "^5.46.2",
|
||||||
"webpack": "^5.105.4",
|
"webpack": "^5.106.2",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-server": "5.0.4",
|
"webpack-dev-server": "5.0.4",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
@ -1640,9 +1640,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/preset-env": {
|
"node_modules/@babel/preset-env": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz",
|
||||||
"integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==",
|
"integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1754,9 +1754,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||||
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
|
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -1840,22 +1840,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.10.2",
|
"version": "6.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.3.tgz",
|
||||||
"integrity": "sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==",
|
"integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
"@codemirror/view": "^6.27.0",
|
"@codemirror/view": "^6.27.0",
|
||||||
"@lezer/common": "^1.1.0"
|
"@lezer/common": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.12.2",
|
"version": "6.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.3.tgz",
|
||||||
"integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==",
|
"integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1868,9 +1868,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/search": {
|
"node_modules/@codemirror/search": {
|
||||||
"version": "6.6.0",
|
"version": "6.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz",
|
||||||
"integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==",
|
"integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1880,9 +1880,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/state": {
|
"node_modules/@codemirror/state": {
|
||||||
"version": "6.5.4",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.6.0.tgz",
|
||||||
"integrity": "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==",
|
"integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1890,13 +1890,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.39.17",
|
"version": "6.41.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.17.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.41.1.tgz",
|
||||||
"integrity": "sha512-Aim4lFqhbijnchl83RLfABWueSGs1oUCSv0mru91QdhpXQeNKprIdRO9LWA4cYkJvuYTKGJN7++9MXx8XW43ag==",
|
"integrity": "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.6.0",
|
||||||
"crelt": "^1.0.6",
|
"crelt": "^1.0.6",
|
||||||
"style-mod": "^4.1.0",
|
"style-mod": "^4.1.0",
|
||||||
"w3c-keyname": "^2.2.4"
|
"w3c-keyname": "^2.2.4"
|
||||||
@ -4524,9 +4524,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@xmldom/xmldom": {
|
"node_modules/@xmldom/xmldom": {
|
||||||
"version": "0.8.11",
|
"version": "0.8.13",
|
||||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
|
||||||
"integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
|
"integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
@ -5003,9 +5003,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/arrive": {
|
"node_modules/arrive": {
|
||||||
"version": "2.5.2",
|
"version": "2.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/arrive/-/arrive-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/arrive/-/arrive-2.5.3.tgz",
|
||||||
"integrity": "sha512-A9asXhuUR6pgHtwUciZw4FRZDR09ZwVsz1ckEGE6W9gXWrYM9cAkuKzHplpYN0bd/iobg0xqQ9fpRr/GHPsXUw==",
|
"integrity": "sha512-FsZjDDxS2BZ1TuGvqhTf8KbGaH0hOx+DS7HhYIvsreCkAuSUFgJ9NUhIC4f3SM3c5T/1he1KAn566GZjzqJarA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/asn1.js": {
|
"node_modules/asn1.js": {
|
||||||
@ -5089,9 +5089,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.27",
|
"version": "10.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
|
||||||
"integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==",
|
"integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5109,8 +5109,8 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.28.1",
|
"browserslist": "^4.28.2",
|
||||||
"caniuse-lite": "^1.0.30001774",
|
"caniuse-lite": "^1.0.30001787",
|
||||||
"fraction.js": "^5.3.4",
|
"fraction.js": "^5.3.4",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"postcss-value-parser": "^4.2.0"
|
"postcss-value-parser": "^4.2.0"
|
||||||
@ -5169,21 +5169,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.13.6",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
|
||||||
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
|
"integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.11",
|
"follow-redirects": "^1.15.11",
|
||||||
"form-data": "^4.0.5",
|
"form-data": "^4.0.5",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/axios/node_modules/proxy-from-env": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/babel-loader": {
|
"node_modules/babel-loader": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.1.1.tgz",
|
||||||
"integrity": "sha512-5HTUZa013O4SWEYlJDHexrqSIYkWatfA9w/ZZQa7V2nMc0dRWkfu/0pmioC7XMYm8M7Z/3+q42NWj6e+fAT0MQ==",
|
"integrity": "sha512-JwKSzk2kjIe7mgPK+/lyZ2QAaJcpahNAdM+hgR2HI8D0OJVkdj8Rl6J3kaLYki9pwF7P2iWnD8qVv80Lq1ABtg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -5283,9 +5293,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.0",
|
"version": "2.10.19",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz",
|
||||||
"integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
|
"integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -5316,9 +5326,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/basic-ftp": {
|
"node_modules/basic-ftp": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.2.tgz",
|
||||||
"integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==",
|
"integrity": "sha512-1tDrzKsdCg70WGvbFss/ulVAxupNauGnOlgpyjKzeQxzyllBLS0CGLV7tjIXTK3ZQA9/FBEm9qyFFN1bciA6pw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -5738,9 +5748,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -5855,9 +5865,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.28.1",
|
"version": "4.28.2",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||||
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
|
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -5875,11 +5885,11 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.10.12",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001782",
|
||||||
"electron-to-chromium": "^1.5.263",
|
"electron-to-chromium": "^1.5.328",
|
||||||
"node-releases": "^2.0.27",
|
"node-releases": "^2.0.36",
|
||||||
"update-browserslist-db": "^1.2.0"
|
"update-browserslist-db": "^1.2.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
@ -6087,9 +6097,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001777",
|
"version": "1.0.30001788",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz",
|
||||||
"integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==",
|
"integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -6246,26 +6256,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chromedriver": {
|
"node_modules/chromedriver": {
|
||||||
"version": "130.0.4",
|
"version": "146.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-130.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-146.0.6.tgz",
|
||||||
"integrity": "sha512-lpR+PWXszij1k4Ig3t338Zvll9HtCTiwoLM7n4pCCswALHxzmgwaaIFBh3rt9+5wRk9D07oFblrazrBxwaYYAQ==",
|
"integrity": "sha512-FIRi3hy0nRiyirK03etVXEpYTIodevFcvTBAM5ZCq+pX3w31jLm6JE8BVW1ypAVLvSp6HJDvboCcdgUroS3miw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@testim/chrome-version": "^1.1.4",
|
"@testim/chrome-version": "^1.1.4",
|
||||||
"axios": "^1.7.4",
|
"axios": "^1.13.5",
|
||||||
"compare-versions": "^6.1.0",
|
"compare-versions": "^6.1.0",
|
||||||
"extract-zip": "^2.0.1",
|
"extract-zip": "^2.0.1",
|
||||||
"proxy-agent": "^6.4.0",
|
"proxy-agent": "^6.5.0",
|
||||||
"proxy-from-env": "^1.1.0",
|
"proxy-from-env": "^2.0.0",
|
||||||
"tcp-port-used": "^1.0.2"
|
"tcp-port-used": "^1.0.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"chromedriver": "bin/chromedriver"
|
"chromedriver": "bin/chromedriver"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chromedriver/node_modules/proxy-from-env": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ci-info": {
|
"node_modules/ci-info": {
|
||||||
@ -6813,9 +6833,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/core-js": {
|
"node_modules/core-js": {
|
||||||
"version": "3.48.0",
|
"version": "3.49.0",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz",
|
||||||
"integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==",
|
"integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -7127,9 +7147,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cspell-glob/node_modules/picomatch": {
|
"node_modules/cspell-glob/node_modules/picomatch": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -8276,9 +8296,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "3.3.3",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.1.tgz",
|
||||||
"integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==",
|
"integrity": "sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==",
|
||||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@types/trusted-types": "^2.0.7"
|
"@types/trusted-types": "^2.0.7"
|
||||||
@ -8397,9 +8417,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.307",
|
"version": "1.5.339",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.339.tgz",
|
||||||
"integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==",
|
"integrity": "sha512-Is+0BBHJ4NrdpAYiperrmp53pLywG/yV/6lIMTAnhxvzj/Cmn5Q/ogSHC6AKe7X+8kPLxxFk0cs5oc/3j/fxIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@ -9128,6 +9148,16 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/exit-x": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expand-tilde": {
|
"node_modules/expand-tilde": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
|
||||||
@ -9469,9 +9499,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/filelist/node_modules/brace-expansion": {
|
"node_modules/filelist/node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -9627,16 +9657,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flatted": {
|
"node_modules/flatted": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||||
"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
|
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.11",
|
"version": "1.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -10150,9 +10180,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/grunt": {
|
"node_modules/grunt": {
|
||||||
"version": "1.6.1",
|
"version": "1.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.2.tgz",
|
||||||
"integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==",
|
"integrity": "sha512-bUzh5nA/P5L66ihXTDP6J5BGnMB/8lXJXejYWSbH4Y4TvWM9t2S39sggQDYYQlx06cYcCsmu63HMYHGCIzUVfg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -10161,14 +10191,14 @@
|
|||||||
"exit": "~0.1.2",
|
"exit": "~0.1.2",
|
||||||
"findup-sync": "~5.0.0",
|
"findup-sync": "~5.0.0",
|
||||||
"glob": "~7.1.6",
|
"glob": "~7.1.6",
|
||||||
"grunt-cli": "~1.4.3",
|
"grunt-cli": "^1.4.3",
|
||||||
"grunt-known-options": "~2.0.0",
|
"grunt-known-options": "~2.0.0",
|
||||||
"grunt-legacy-log": "~3.0.0",
|
"grunt-legacy-log": "~3.0.0",
|
||||||
"grunt-legacy-util": "~2.0.1",
|
"grunt-legacy-util": "~2.0.1",
|
||||||
"iconv-lite": "~0.6.3",
|
"iconv-lite": "~0.6.3",
|
||||||
"js-yaml": "~3.14.0",
|
"js-yaml": "~3.14.0",
|
||||||
"minimatch": "~3.0.4",
|
"minimatch": "^3.1.5",
|
||||||
"nopt": "~3.0.6"
|
"nopt": "^5.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"grunt": "bin/grunt"
|
"grunt": "bin/grunt"
|
||||||
@ -10410,30 +10440,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/grunt-legacy-log": {
|
"node_modules/grunt-legacy-log": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.1.tgz",
|
||||||
"integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==",
|
"integrity": "sha512-vytI3IUC8qUK9TcvvpHpGJzDojua/sfJV4TdLB4FtCFzospqduzBuL3+dEfpvO+tGECv7/273+33hjjMXSa92g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "~1.1.2",
|
"colors": "~1.1.2",
|
||||||
"grunt-legacy-log-utils": "~2.1.0",
|
"grunt-legacy-log-utils": "^2.1.3",
|
||||||
"hooker": "~0.2.3",
|
"hooker": "~0.2.3",
|
||||||
"lodash": "~4.17.19"
|
"lodash": "^4.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/grunt-legacy-log-utils": {
|
"node_modules/grunt-legacy-log-utils": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.3.tgz",
|
||||||
"integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==",
|
"integrity": "sha512-sgG+QvKmdb44wZyzJP+ejDsy3jYxG2wzohpol+JTMlXqMUBDoZb01JPQ5jKAedtZBFwhmABAc88T9hEBLy3U+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "~4.1.0",
|
"chalk": "^4.1.0"
|
||||||
"lodash": "~4.17.19"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
@ -10496,17 +10525,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/grunt-legacy-util": {
|
"node_modules/grunt-legacy-util": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.2.tgz",
|
||||||
"integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==",
|
"integrity": "sha512-0xoDILyR4BVJel5uJwnhjdWN9evOQ8A0uXbQUIJ0hgVthIA6kloXHSoqATQPj6BRrHrHkcQtCeGVb0ixFoHyEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~3.2.0",
|
"async": "~3.2.0",
|
||||||
"exit": "~0.1.2",
|
"exit-x": "~0.2.2",
|
||||||
"getobject": "~1.0.0",
|
"getobject": "~1.0.0",
|
||||||
"hooker": "~0.2.3",
|
"hooker": "~0.2.3",
|
||||||
"lodash": "~4.17.21",
|
"lodash": "^4.18.0",
|
||||||
"underscore.string": "~3.3.5",
|
"underscore.string": "~3.3.5",
|
||||||
"which": "~2.0.2"
|
"which": "~2.0.2"
|
||||||
},
|
},
|
||||||
@ -10585,9 +10614,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/grunt/node_modules/minimatch": {
|
"node_modules/grunt/node_modules/minimatch": {
|
||||||
"version": "3.0.8",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||||
"integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
|
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -10628,9 +10657,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/handlebars": {
|
"node_modules/handlebars": {
|
||||||
"version": "4.7.8",
|
"version": "4.7.9",
|
||||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
|
||||||
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
@ -10898,9 +10927,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/html-webpack-plugin": {
|
"node_modules/html-webpack-plugin": {
|
||||||
"version": "5.6.6",
|
"version": "5.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz",
|
||||||
"integrity": "sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==",
|
"integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -12158,11 +12187,11 @@
|
|||||||
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==",
|
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==",
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/jq-wasm": {
|
"node_modules/jq-web": {
|
||||||
"version": "1.1.0-jq-1.8.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/jq-wasm/-/jq-wasm-1.1.0-jq-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/jq-web/-/jq-web-0.5.1.tgz",
|
||||||
"integrity": "sha512-lWfu34lpDFIygOYcL5TzxhZIApDR9iR5XywcVoyUAZ6jlQrj8HKHOKeCcHgUm2dE9RVdbP3eqNAKGLuj+k4seQ==",
|
"integrity": "sha512-3Fa3E6g3U1O1j46ljy0EM10yRr4txzILga8J7bqOG8F89gZ6Lilz82WG9z6TItWpYEO0YGa4W8yFGj+NMM1xqQ==",
|
||||||
"license": "MIT"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/jquery": {
|
"node_modules/jquery": {
|
||||||
"version": "3.7.1",
|
"version": "3.7.1",
|
||||||
@ -12383,13 +12412,10 @@
|
|||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/jsrsasign": {
|
"node_modules/jsrsasign": {
|
||||||
"version": "11.1.1",
|
"version": "11.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-11.1.3.tgz",
|
||||||
"integrity": "sha512-6w95OOXH8DNeGxakqLndBEqqwQ6A70zGaky1oxfg8WVLWOnghTfJsc5Tknx+Z88MHSb1bGLcqQHImOF8Lk22XA==",
|
"integrity": "sha512-nPnK5D/4lv0Dwr7TlzrKtAd8JlLZwFTqTUUB3NQCbtdobcRcohGFxjbPySDVh74iWUudcCsapYT6OxoyhJLhhA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/kjur/jsrsasign#donations"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/jszip": {
|
"node_modules/jszip": {
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
@ -12666,9 +12692,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.23",
|
"version": "4.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
@ -13103,9 +13129,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mini-css-extract-plugin": {
|
"node_modules/mini-css-extract-plugin": {
|
||||||
"version": "2.10.1",
|
"version": "2.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz",
|
||||||
"integrity": "sha512-k7G3Y5QOegl380tXmZ68foBRRjE9Ljavx835ObdvmZjQ639izvZD8CS7BkWw1qKPPzHsGL/JDhl0uyU1zc2rJw==",
|
"integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -13204,9 +13230,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mocha/node_modules/brace-expansion": {
|
"node_modules/mocha/node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -13300,9 +13326,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/moment-timezone": {
|
"node_modules/moment-timezone": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.6.1.tgz",
|
||||||
"integrity": "sha512-ldA5lRNm3iJCWZcBCab4pnNL3HSZYXVb/3TYr75/1WCTWYuTqYUb5f/S384pncYjJ88lbO8Z4uPDvmoluHJc8Q==",
|
"integrity": "sha512-1B9lmAhB9D9/sHaPC1N7wLFEVUoFldxOpOO96lOD1PvJ43vCd0ozDPbu0FEL3++VvawOlDkq8YD373tJmP5JHw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"moment": "^2.29.4"
|
"moment": "^2.29.4"
|
||||||
@ -13768,9 +13794,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.3",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
|
||||||
"integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
|
"integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
|
||||||
"license": "(BSD-3-Clause OR GPL-2.0)",
|
"license": "(BSD-3-Clause OR GPL-2.0)",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6.13.0"
|
"node": ">= 6.13.0"
|
||||||
@ -13805,9 +13831,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nopt": {
|
"node_modules/nopt": {
|
||||||
"version": "3.0.6",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||||
"integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==",
|
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -13815,6 +13841,9 @@
|
|||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"nopt": "bin/nopt.js"
|
"nopt": "bin/nopt.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/normalize-path": {
|
"node_modules/normalize-path": {
|
||||||
@ -14608,9 +14637,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "0.1.12",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
|
||||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
"integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@ -14678,9 +14707,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -14786,9 +14815,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.8",
|
"version": "8.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
|
||||||
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
|
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -15045,9 +15074,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/protobufjs": {
|
"node_modules/protobufjs": {
|
||||||
"version": "7.5.4",
|
"version": "7.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz",
|
||||||
"integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
|
"integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -15429,9 +15458,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/readdir-glob/node_modules/brace-expansion": {
|
"node_modules/readdir-glob/node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -16623,9 +16652,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/sql-formatter": {
|
"node_modules/sql-formatter": {
|
||||||
"version": "15.7.2",
|
"version": "15.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.7.3.tgz",
|
||||||
"integrity": "sha512-b0BGoM81KFRVSpZFwPpIPU5gng4YD8DI/taLD96NXCFRf5af3FzSE4aSwjKmxcyTmf/MfPu91j75883nRrWDBw==",
|
"integrity": "sha512-5+zl9Nqg5aNjss0tb1G+StpC4dJKbjv3+g8CL/+V+00PfZop+2RKGyi53ScFl0dr+Dkx1LjmUO54Q3N7K3EtMw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1",
|
"argparse": "^2.0.1",
|
||||||
@ -17033,9 +17062,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.46.0",
|
"version": "5.46.2",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz",
|
||||||
"integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==",
|
"integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -17214,9 +17243,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -17861,9 +17890,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack": {
|
"node_modules/webpack": {
|
||||||
"version": "5.105.4",
|
"version": "5.106.2",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
|
||||||
"integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==",
|
"integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -17883,9 +17912,8 @@
|
|||||||
"events": "^3.2.0",
|
"events": "^3.2.0",
|
||||||
"glob-to-regexp": "^0.4.1",
|
"glob-to-regexp": "^0.4.1",
|
||||||
"graceful-fs": "^4.2.11",
|
"graceful-fs": "^4.2.11",
|
||||||
"json-parse-even-better-errors": "^2.3.1",
|
|
||||||
"loader-runner": "^4.3.1",
|
"loader-runner": "^4.3.1",
|
||||||
"mime-types": "^2.1.27",
|
"mime-db": "^1.54.0",
|
||||||
"neo-async": "^2.6.2",
|
"neo-async": "^2.6.2",
|
||||||
"schema-utils": "^4.3.3",
|
"schema-utils": "^4.3.3",
|
||||||
"tapable": "^2.3.0",
|
"tapable": "^2.3.0",
|
||||||
@ -18075,9 +18103,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server/node_modules/brace-expansion": {
|
"node_modules/webpack-dev-server/node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -18206,6 +18234,16 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack/node_modules/mime-db": {
|
||||||
|
"version": "1.54.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||||
|
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/websocket-driver": {
|
"node_modules/websocket-driver": {
|
||||||
"version": "0.7.4",
|
"version": "0.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||||
@ -18705,9 +18743,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.8.2",
|
"version": "2.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
58
package.json
58
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.22.1",
|
"version": "10.23.0",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
@ -42,28 +42,28 @@
|
|||||||
"@babel/eslint-parser": "^7.28.6",
|
"@babel/eslint-parser": "^7.28.6",
|
||||||
"@babel/plugin-syntax-import-assertions": "^7.28.6",
|
"@babel/plugin-syntax-import-assertions": "^7.28.6",
|
||||||
"@babel/plugin-transform-runtime": "^7.29.0",
|
"@babel/plugin-transform-runtime": "^7.29.0",
|
||||||
"@babel/preset-env": "^7.29.0",
|
"@babel/preset-env": "^7.29.2",
|
||||||
"@babel/runtime": "^7.28.6",
|
"@babel/runtime": "^7.29.2",
|
||||||
"@codemirror/commands": "^6.10.2",
|
"@codemirror/commands": "^6.10.3",
|
||||||
"@codemirror/language": "^6.12.2",
|
"@codemirror/language": "^6.12.3",
|
||||||
"@codemirror/search": "^6.6.0",
|
"@codemirror/search": "^6.7.0",
|
||||||
"@codemirror/state": "^6.5.4",
|
"@codemirror/state": "^6.5.4",
|
||||||
"@codemirror/view": "^6.39.17",
|
"@codemirror/view": "^6.41.1",
|
||||||
"autoprefixer": "^10.4.27",
|
"autoprefixer": "^10.5.0",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.1.1",
|
||||||
"base64-loader": "^1.0.0",
|
"base64-loader": "^1.0.0",
|
||||||
"chromedriver": "^130.0.4",
|
"chromedriver": "^146.0.6",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
"copy-webpack-plugin": "^13.0.1",
|
"copy-webpack-plugin": "^13.0.1",
|
||||||
"core-js": "^3.48.0",
|
"core-js": "^3.49.0",
|
||||||
"cspell": "^8.19.4",
|
"cspell": "^8.19.4",
|
||||||
"css-loader": "7.1.4",
|
"css-loader": "7.1.4",
|
||||||
"eslint": "^9.39.4",
|
"eslint": "^9.39.4",
|
||||||
"eslint-plugin-jsdoc": "^50.8.0",
|
"eslint-plugin-jsdoc": "^50.8.0",
|
||||||
"globals": "^15.15.0",
|
"globals": "^15.15.0",
|
||||||
"grunt": "^1.6.1",
|
"grunt": "^1.6.2",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^3.0.0",
|
"grunt-concurrent": "^3.0.0",
|
||||||
"grunt-contrib-clean": "~2.0.1",
|
"grunt-contrib-clean": "~2.0.1",
|
||||||
@ -74,19 +74,19 @@
|
|||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-webpack": "^6.0.0",
|
"grunt-webpack": "^6.0.0",
|
||||||
"grunt-zip": "^1.0.0",
|
"grunt-zip": "^1.0.0",
|
||||||
"html-webpack-plugin": "^5.6.6",
|
"html-webpack-plugin": "^5.6.7",
|
||||||
"imports-loader": "^5.0.0",
|
"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",
|
"modify-source-webpack-plugin": "^4.1.0",
|
||||||
"nightwatch": "^3.15.0",
|
"nightwatch": "^3.15.0",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.5.10",
|
||||||
"postcss-css-variables": "^0.19.0",
|
"postcss-css-variables": "^0.19.0",
|
||||||
"postcss-import": "^16.1.1",
|
"postcss-import": "^16.1.1",
|
||||||
"postcss-loader": "^8.2.1",
|
"postcss-loader": "^8.2.1",
|
||||||
"prompt": "^1.3.0",
|
"prompt": "^1.3.0",
|
||||||
"sitemap": "^8.0.3",
|
"sitemap": "^8.0.3",
|
||||||
"terser": "^5.46.0",
|
"terser": "^5.46.2",
|
||||||
"webpack": "^5.105.4",
|
"webpack": "^5.106.2",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-server": "5.0.4",
|
"webpack-dev-server": "5.0.4",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
@ -97,9 +97,9 @@
|
|||||||
"@astronautlabs/amf": "^0.0.6",
|
"@astronautlabs/amf": "^0.0.6",
|
||||||
"@blu3r4y/lzma": "^2.3.3",
|
"@blu3r4y/lzma": "^2.3.3",
|
||||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||||
"@xmldom/xmldom": "^0.8.11",
|
"@xmldom/xmldom": "^0.8.13",
|
||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
"arrive": "^2.5.2",
|
"arrive": "^2.5.3",
|
||||||
"assert": "^2.1.0",
|
"assert": "^2.1.0",
|
||||||
"avsc": "^5.7.9",
|
"avsc": "^5.7.9",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
@ -121,7 +121,7 @@
|
|||||||
"d3": "7.9.0",
|
"d3": "7.9.0",
|
||||||
"d3-hexbin": "^0.2.2",
|
"d3-hexbin": "^0.2.2",
|
||||||
"diff": "^5.2.2",
|
"diff": "^5.2.2",
|
||||||
"dompurify": "^3.3.3",
|
"dompurify": "^3.4.1",
|
||||||
"es6-promisify": "^7.0.0",
|
"es6-promisify": "^7.0.0",
|
||||||
"escodegen": "^2.1.0",
|
"escodegen": "^2.1.0",
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
@ -131,12 +131,12 @@
|
|||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^6.0.1",
|
"flat": "^6.0.1",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.9",
|
||||||
"hash-wasm": "^4.12.0",
|
"hash-wasm": "^4.12.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"ieee754": "^1.2.1",
|
"ieee754": "^1.2.1",
|
||||||
"jimp": "^1.6.0",
|
"jimp": "1.6.0",
|
||||||
"jq-wasm": "^1.1.0-jq-1.8.1",
|
"jq-web": "^0.5.1",
|
||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"js-sha3": "^0.9.3",
|
"js-sha3": "^0.9.3",
|
||||||
"jsesc": "^3.1.0",
|
"jsesc": "^3.1.0",
|
||||||
@ -145,20 +145,20 @@
|
|||||||
"jsonpath-plus": "^10.4.0",
|
"jsonpath-plus": "^10.4.0",
|
||||||
"jsonwebtoken": "9.0.3",
|
"jsonwebtoken": "9.0.3",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^11.1.1",
|
"jsrsasign": "^11.1.3",
|
||||||
"kbpgp": "^2.1.17",
|
"kbpgp": "^2.1.17",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.2.1",
|
"libyara-wasm": "^1.2.1",
|
||||||
"lodash": "^4.17.23",
|
"lodash": "^4.18.1",
|
||||||
"loglevel": "^1.9.2",
|
"loglevel": "^1.9.2",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"lz-string": "^1.5.0",
|
"lz-string": "^1.5.0",
|
||||||
"lz4js": "^0.2.0",
|
"lz4js": "^0.2.0",
|
||||||
"markdown-it": "^14.1.1",
|
"markdown-it": "^14.1.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.6.0",
|
"moment-timezone": "^0.6.1",
|
||||||
"ngeohash": "^0.6.3",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^1.3.3",
|
"node-forge": "^1.4.0",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
"nodom": "^2.4.0",
|
"nodom": "^2.4.0",
|
||||||
"notepack.io": "^3.0.1",
|
"notepack.io": "^3.0.1",
|
||||||
@ -168,7 +168,7 @@
|
|||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"protobufjs": "^7.5.4",
|
"protobufjs": "^7.5.5",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rison": "^0.1.1",
|
"rison": "^0.1.1",
|
||||||
@ -176,7 +176,7 @@
|
|||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
"sortablejs": "^1.15.7",
|
"sortablejs": "^1.15.7",
|
||||||
"split.js": "^1.6.5",
|
"split.js": "^1.6.5",
|
||||||
"sql-formatter": "^15.6.12",
|
"sql-formatter": "^15.7.3",
|
||||||
"ssdeep.js": "0.0.3",
|
"ssdeep.js": "0.0.3",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"tesseract.js": "^6.0.1",
|
"tesseract.js": "^6.0.1",
|
||||||
|
|||||||
@ -55,8 +55,15 @@ class Chef {
|
|||||||
progress = await recipe.execute(this.dish, progress);
|
progress = await recipe.execute(this.dish, progress);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
|
|
||||||
|
let displayStr;
|
||||||
|
if ("displayStr" in err) {
|
||||||
|
displayStr = err.displayStr;
|
||||||
|
} else {
|
||||||
|
displayStr = err.toString();
|
||||||
|
}
|
||||||
error = {
|
error = {
|
||||||
displayStr: err.displayStr,
|
displayStr: displayStr,
|
||||||
};
|
};
|
||||||
progress = err.progress;
|
progress = err.progress;
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/core/Ingredient.mjs
Executable file → Normal file
7
src/core/Ingredient.mjs
Executable file → Normal file
@ -5,7 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Utils from "./Utils.mjs";
|
import Utils from "./Utils.mjs";
|
||||||
import {fromHex} from "./lib/Hex.mjs";
|
import { fromHex } from "./lib/Hex.mjs";
|
||||||
|
import OperationError from "./errors/OperationError.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The arguments to operations.
|
* The arguments to operations.
|
||||||
@ -119,7 +120,9 @@ class Ingredient {
|
|||||||
number = parseFloat(data);
|
number = parseFloat(data);
|
||||||
if (isNaN(number)) {
|
if (isNaN(number)) {
|
||||||
const sample = Utils.truncate(data.toString(), 10);
|
const sample = Utils.truncate(data.toString(), 10);
|
||||||
throw "Invalid ingredient value. Not a number: " + sample;
|
throw new OperationError(
|
||||||
|
"Invalid ingredient value. Not a number: " + sample,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return number;
|
return number;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Dish from "./Dish.mjs";
|
import Dish from "./Dish.mjs";
|
||||||
|
import OperationError from "./errors/OperationError.mjs";
|
||||||
import Ingredient from "./Ingredient.mjs";
|
import Ingredient from "./Ingredient.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,7 +224,11 @@ class Operation {
|
|||||||
*/
|
*/
|
||||||
set ingValues(ingValues) {
|
set ingValues(ingValues) {
|
||||||
ingValues.forEach((val, i) => {
|
ingValues.forEach((val, i) => {
|
||||||
this._ingList[i].value = val;
|
try {
|
||||||
|
this._ingList[i].value = val;
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Failed to set value of ingredient '${this._ingList[i].name}': ${err}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -69,11 +69,15 @@ class Recipe {
|
|||||||
if (o instanceof Operation) {
|
if (o instanceof Operation) {
|
||||||
return o;
|
return o;
|
||||||
} else {
|
} else {
|
||||||
const op = new modules[o.module][o.name]();
|
try {
|
||||||
op.ingValues = o.ingValues;
|
const op = new modules[o.module][o.name]();
|
||||||
op.breakpoint = o.breakpoint;
|
op.ingValues = o.ingValues;
|
||||||
op.disabled = o.disabled;
|
op.breakpoint = o.breakpoint;
|
||||||
return op;
|
op.disabled = o.disabled;
|
||||||
|
return op;
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Failed to hydrate operation '${o.name}': ${err}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -249,6 +249,7 @@
|
|||||||
"DNS over HTTPS",
|
"DNS over HTTPS",
|
||||||
"Strip HTTP headers",
|
"Strip HTTP headers",
|
||||||
"Dechunk HTTP response",
|
"Dechunk HTTP response",
|
||||||
|
"Parse Ethernet frame",
|
||||||
"Parse User Agent",
|
"Parse User Agent",
|
||||||
"Parse IP range",
|
"Parse IP range",
|
||||||
"Parse IPv6 address",
|
"Parse IPv6 address",
|
||||||
@ -385,6 +386,7 @@
|
|||||||
"CSS selector",
|
"CSS selector",
|
||||||
"Extract EXIF",
|
"Extract EXIF",
|
||||||
"Extract ID3",
|
"Extract ID3",
|
||||||
|
"Extract Audio Metadata",
|
||||||
"Extract Files",
|
"Extract Files",
|
||||||
"RAKE",
|
"RAKE",
|
||||||
"Template"
|
"Template"
|
||||||
@ -514,7 +516,8 @@
|
|||||||
"View Bit Plane",
|
"View Bit Plane",
|
||||||
"Randomize Colour Palette",
|
"Randomize Colour Palette",
|
||||||
"Extract LSB",
|
"Extract LSB",
|
||||||
"ELF Info"
|
"ELF Info",
|
||||||
|
"Extract Audio Metadata"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -547,7 +550,8 @@
|
|||||||
"Hex Density chart",
|
"Hex Density chart",
|
||||||
"Scatter chart",
|
"Scatter chart",
|
||||||
"Series chart",
|
"Series chart",
|
||||||
"Heatmap chart"
|
"Heatmap chart",
|
||||||
|
"Extract Audio Metadata"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
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");
|
||||||
103
src/core/lib/AudioBytes.mjs
Normal file
103
src/core/lib/AudioBytes.mjs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Byte-reading and text-decoding utilities for audio metadata parsing.
|
||||||
|
*
|
||||||
|
* @author d0s1nt [d0s1nt@cyberchefaudio]
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @returns {string} 4-byte ASCII at offset, or "" if out of bounds. */
|
||||||
|
export function ascii4(b, off) {
|
||||||
|
if (off + 4 > b.length) return "";
|
||||||
|
return String.fromCharCode(b[off], b[off + 1], b[off + 2], b[off + 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} Byte offset of ASCII needle `s`, or -1. */
|
||||||
|
export function indexOfAscii(b, s, start, end) {
|
||||||
|
const limit = Math.max(0, Math.min(end, b.length) - s.length);
|
||||||
|
for (let i = start; i <= limit; i++) {
|
||||||
|
let ok = true;
|
||||||
|
for (let j = 0; j < s.length; j++) {
|
||||||
|
if (b[i + j] !== s.charCodeAt(j)) {
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} Unsigned 32-bit big-endian read. */
|
||||||
|
export function u32be(bytes, off) {
|
||||||
|
return ((bytes[off] << 24) >>> 0) | (bytes[off + 1] << 16) | (bytes[off + 2] << 8) | bytes[off + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} Unsigned 32-bit little-endian read. */
|
||||||
|
export function u32le(bytes, off) {
|
||||||
|
return (bytes[off] | (bytes[off + 1] << 8) | (bytes[off + 2] << 16) | (bytes[off + 3] << 24)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} Unsigned 16-bit little-endian read. */
|
||||||
|
export function u16le(bytes, off) {
|
||||||
|
return bytes[off] | (bytes[off + 1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {BigInt} Unsigned 64-bit little-endian read. */
|
||||||
|
export function u64le(bytes, off) {
|
||||||
|
return BigInt(u32le(bytes, off)) | (BigInt(u32le(bytes, off + 4)) << 32n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {number} Decoded ID3v2 synchsafe integer from four 7-bit bytes. */
|
||||||
|
export function synchsafeToInt(b0, b1, b2, b3) {
|
||||||
|
return ((b0 & 0x7f) << 21) | ((b1 & 0x7f) << 14) | ((b2 & 0x7f) << 7) | (b3 & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {string} Decoded UTF-16LE byte range, nulls stripped. */
|
||||||
|
export function decodeUtf16LE(b, off, len) {
|
||||||
|
if (len <= 0 || off + len > b.length) return "";
|
||||||
|
try {
|
||||||
|
return new TextDecoder("utf-16le").decode(b.slice(off, off + len)).replace(/\u0000/g, "").trim();
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {{valueBytes: Uint8Array, next: number}} Bytes until null terminator, UTF-16 aware. */
|
||||||
|
export function readNullTerminated(bytes, start, encoding) {
|
||||||
|
const isUtf16 = encoding === 1 || encoding === 2;
|
||||||
|
if (!isUtf16) {
|
||||||
|
let i = start;
|
||||||
|
while (i < bytes.length && bytes[i] !== 0x00) i++;
|
||||||
|
return { valueBytes: bytes.slice(start, i), next: i + 1 };
|
||||||
|
}
|
||||||
|
let i = start;
|
||||||
|
while (i + 1 < bytes.length && !(bytes[i] === 0x00 && bytes[i + 1] === 0x00)) i += 2;
|
||||||
|
return { valueBytes: bytes.slice(start, i), next: i + 2 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const ID3_ENCODINGS = ["iso-8859-1", "utf-16", "utf-16be", "utf-8"];
|
||||||
|
|
||||||
|
/** @returns {string} Text decoded using ID3v2 encoding byte (0=latin1, 1=utf16, 2=utf16be, 3=utf8). */
|
||||||
|
export function decodeText(bytes, encoding) {
|
||||||
|
if (!bytes || bytes.length === 0) return "";
|
||||||
|
try {
|
||||||
|
return new TextDecoder(ID3_ENCODINGS[encoding] || "utf-16").decode(bytes);
|
||||||
|
} catch {
|
||||||
|
return safeUtf8(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {string} UTF-8 decode with replacement (never throws). */
|
||||||
|
export function safeUtf8(bytes) {
|
||||||
|
try {
|
||||||
|
return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {string} ISO-8859-1 decode, nulls stripped, trimmed. */
|
||||||
|
export function decodeLatin1Trim(bytes) {
|
||||||
|
return decodeText(bytes, 0).replace(/\u0000/g, "").trim();
|
||||||
|
}
|
||||||
82
src/core/lib/AudioMetaSchema.mjs
Normal file
82
src/core/lib/AudioMetaSchema.mjs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Report skeleton and container detection for audio metadata extraction.
|
||||||
|
*
|
||||||
|
* @author d0s1nt [d0s1nt@cyberchefaudio]
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
|
import { ascii4, indexOfAscii } from "./AudioBytes.mjs";
|
||||||
|
|
||||||
|
/** Builds the empty report skeleton ready for a format parser to populate. */
|
||||||
|
export function makeEmptyReport(filename, byteLength, container) {
|
||||||
|
return {
|
||||||
|
schema_version: "audio-meta-1.0",
|
||||||
|
artifact: {
|
||||||
|
filename,
|
||||||
|
byte_length: byteLength,
|
||||||
|
container: { type: container.type, brand: container.brand || null, mime: container.mime || null },
|
||||||
|
},
|
||||||
|
detections: { metadata_systems: [], provenance_systems: [] },
|
||||||
|
tags: {
|
||||||
|
common: {
|
||||||
|
title: null, artist: null, album: null, date: null, track: null,
|
||||||
|
genre: null, comment: null, composer: null, copyright: null, language: null,
|
||||||
|
},
|
||||||
|
raw: {},
|
||||||
|
},
|
||||||
|
embedded: [],
|
||||||
|
provenance: {
|
||||||
|
c2pa: {
|
||||||
|
present: false,
|
||||||
|
embedding: [],
|
||||||
|
manifest_store: { active_manifest_urn: null, instance_id: null, claim_generator: null },
|
||||||
|
assertions: [],
|
||||||
|
signature: {
|
||||||
|
algorithm: null, signing_time: null,
|
||||||
|
certificate: { subject_cn: null, issuer_cn: null, serial_number: null },
|
||||||
|
},
|
||||||
|
validation: { validation_state: "Unknown", reasons: [], details_raw: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errors: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Detects the audio container format from magic bytes. */
|
||||||
|
export function sniffContainer(b) {
|
||||||
|
if (b.length >= 3 && b[0] === 0x49 && b[1] === 0x44 && b[2] === 0x33)
|
||||||
|
return { type: "mp3", mime: "audio/mpeg" };
|
||||||
|
if (b.length >= 2 && b[0] === 0xff && (b[1] & 0xe0) === 0xe0) {
|
||||||
|
if ((b[1] & 0x06) === 0x00) return { type: "aac", mime: "audio/aac" };
|
||||||
|
return { type: "mp3", mime: "audio/mpeg" };
|
||||||
|
}
|
||||||
|
if (b.length >= 8 && b[0] === 0x0b && b[1] === 0x77)
|
||||||
|
return { type: "ac3", mime: "audio/ac3" };
|
||||||
|
if (b.length >= 16 &&
|
||||||
|
b[0] === 0x30 && b[1] === 0x26 && b[2] === 0xb2 && b[3] === 0x75 &&
|
||||||
|
b[4] === 0x8e && b[5] === 0x66 && b[6] === 0xcf && b[7] === 0x11)
|
||||||
|
return { type: "wma", mime: "audio/x-ms-wma" };
|
||||||
|
if (b.length >= 12 && ascii4(b, 0) === "RIFF" && ascii4(b, 8) === "WAVE")
|
||||||
|
return { type: "wav", mime: "audio/wav" };
|
||||||
|
if (b.length >= 12 && ascii4(b, 0) === "BW64" && ascii4(b, 8) === "WAVE")
|
||||||
|
return { type: "bw64", mime: "audio/wav" };
|
||||||
|
if (b.length >= 4 && ascii4(b, 0) === "fLaC")
|
||||||
|
return { type: "flac", mime: "audio/flac" };
|
||||||
|
if (b.length >= 4 && ascii4(b, 0) === "OggS") {
|
||||||
|
const idx = indexOfAscii(b, "OpusHead", 0, Math.min(b.length, 65536));
|
||||||
|
return idx >= 0 ? { type: "opus", mime: "audio/ogg" } : { type: "ogg", mime: "audio/ogg" };
|
||||||
|
}
|
||||||
|
if (b.length >= 12 && ascii4(b, 4) === "ftyp") {
|
||||||
|
const brand = ascii4(b, 8);
|
||||||
|
const isM4A = brand === "M4A " || brand === "M4B " || brand === "M4P ";
|
||||||
|
return { type: isM4A ? "m4a" : "mp4", mime: isM4A ? "audio/mp4" : "video/mp4", brand };
|
||||||
|
}
|
||||||
|
if (b.length >= 12 && ascii4(b, 0) === "FORM") {
|
||||||
|
const formType = ascii4(b, 8);
|
||||||
|
if (formType === "AIFF" || formType === "AIFC") return { type: "aiff", mime: "audio/aiff", brand: formType };
|
||||||
|
}
|
||||||
|
return { type: "unknown", mime: null };
|
||||||
|
}
|
||||||
630
src/core/lib/AudioParsers.mjs
Normal file
630
src/core/lib/AudioParsers.mjs
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
/**
|
||||||
|
* Format-specific audio metadata parsers.
|
||||||
|
*
|
||||||
|
* @author d0s1nt [d0s1nt@cyberchefaudio]
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
|
import {
|
||||||
|
ascii4, indexOfAscii,
|
||||||
|
u32be, u32le, u16le, u64le, synchsafeToInt,
|
||||||
|
decodeUtf16LE, readNullTerminated, decodeText,
|
||||||
|
safeUtf8, decodeLatin1Trim,
|
||||||
|
} from "./AudioBytes.mjs";
|
||||||
|
|
||||||
|
/** Parses MP3 metadata: ID3v2 frames, ID3v1 footer, APEv2 tags. */
|
||||||
|
export function parseMp3(b, report) {
|
||||||
|
processId3v2(b, report);
|
||||||
|
processId3v1(b, report);
|
||||||
|
|
||||||
|
const ape = parseApeV2BestEffort(b);
|
||||||
|
if (ape) {
|
||||||
|
report.detections.metadata_systems.push("apev2");
|
||||||
|
report.tags.raw.apev2 = ape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates ID3v2 frames and populates the report. */
|
||||||
|
function processId3v2(b, report) {
|
||||||
|
report.detections.metadata_systems.push("id3v2");
|
||||||
|
|
||||||
|
const id3 = parseId3v2(b);
|
||||||
|
report.tags.raw.id3v2 = id3 ? { header: id3.header, frames: [] } : null;
|
||||||
|
|
||||||
|
if (id3) {
|
||||||
|
for (const f of id3.frames) {
|
||||||
|
const entry = { id: f.id, size: f.size, description: ID3_FRAME_DESCRIPTIONS[f.id] || null };
|
||||||
|
|
||||||
|
if (f.id[0] === "T" && f.id !== "TXXX") {
|
||||||
|
const text = f.data?.length >= 1 ?
|
||||||
|
decodeText(f.data.slice(1), f.data[0]).replace(/\u0000/g, "").trim() :
|
||||||
|
"";
|
||||||
|
entry.decoded = text;
|
||||||
|
if (f.id === "TLEN") {
|
||||||
|
const ms = normalizeTlen(text);
|
||||||
|
if (ms !== null) entry.normalized_ms = ms;
|
||||||
|
}
|
||||||
|
mapCommonId3(report, f.id, text);
|
||||||
|
} else if (f.id === "TXXX") {
|
||||||
|
const txxx = decodeTxxx(f.data);
|
||||||
|
entry.decoded = txxx;
|
||||||
|
if (!report.tags.raw.id3v2.txxx) report.tags.raw.id3v2.txxx = [];
|
||||||
|
report.tags.raw.id3v2.txxx.push(txxx);
|
||||||
|
} else if (f.id === "COMM") {
|
||||||
|
const comm = decodeCommFrame(f.data);
|
||||||
|
entry.decoded = comm;
|
||||||
|
if (comm?.text && !report.tags.common.comment) report.tags.common.comment = comm.text;
|
||||||
|
} else if (f.id === "GEOB") {
|
||||||
|
processGeobFrame(f, entry, report);
|
||||||
|
}
|
||||||
|
|
||||||
|
report.tags.raw.id3v2.frames.push(entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
report.detections.metadata_systems = report.detections.metadata_systems.filter((x) => x !== "id3v2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses GEOB frame contents, populates entry, embedded objects, and C2PA provenance. */
|
||||||
|
function processGeobFrame(f, entry, report) {
|
||||||
|
const d = f.data, enc = d[0];
|
||||||
|
let off = 1;
|
||||||
|
const mime = readNullTerminated(d, off, 0);
|
||||||
|
const mimeType = decodeLatin1Trim(mime.valueBytes);
|
||||||
|
off = mime.next;
|
||||||
|
const file = readNullTerminated(d, off, enc);
|
||||||
|
const filename = decodeText(file.valueBytes, enc).replace(/\u0000/g, "").trim();
|
||||||
|
off = file.next;
|
||||||
|
const desc = readNullTerminated(d, off, enc);
|
||||||
|
const description = decodeText(desc.valueBytes, enc).replace(/\u0000/g, "").trim();
|
||||||
|
off = desc.next;
|
||||||
|
const objLen = d.length - off;
|
||||||
|
|
||||||
|
entry.geob = { mimeType, filename, description, object_bytes: objLen };
|
||||||
|
const geobId = `geob_${report.embedded.filter((x) => x.source === "id3v2:GEOB").length}`;
|
||||||
|
report.embedded.push({
|
||||||
|
id: geobId, source: "id3v2:GEOB",
|
||||||
|
content_type: mimeType || null, byte_length: objLen,
|
||||||
|
description: description || null, filename: filename || null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mt = (mimeType || "").toLowerCase();
|
||||||
|
if (mt.includes("c2pa") || mt.includes("jumbf") || mt.includes("application/x-c2pa-manifest-store")) {
|
||||||
|
report.provenance.c2pa.present = true;
|
||||||
|
report.provenance.c2pa.embedding.push({
|
||||||
|
carrier: "id3v2:GEOB", content_type: mimeType || null, byte_length: objLen,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Processes the 128-byte ID3v1 footer tag. */
|
||||||
|
function processId3v1(b, report) {
|
||||||
|
const id3v1 = parseId3v1(b);
|
||||||
|
if (!id3v1) return;
|
||||||
|
|
||||||
|
report.detections.metadata_systems.push("id3v1");
|
||||||
|
report.tags.raw.id3v1 = id3v1;
|
||||||
|
mapCommon(report, id3v1, ID3V1_TO_COMMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses WAV/BWF/BW64 RIFF chunks: LIST/INFO, bext, iXML, axml, ds64. */
|
||||||
|
export function parseRiffWave(b, report, maxTextBytes) {
|
||||||
|
report.detections.metadata_systems.push("riff_info");
|
||||||
|
|
||||||
|
const chunks = enumerateChunks(b, 12, b.length, 50000);
|
||||||
|
const riff = { chunks: [], info: null, bext: null, ixml: null, axml: null, ds64: null };
|
||||||
|
|
||||||
|
const info = {};
|
||||||
|
for (const c of chunks) {
|
||||||
|
riff.chunks.push({ id: c.id, size: c.size, offset: c.dataOff });
|
||||||
|
processRiffChunk(b, c, riff, info, report, maxTextBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
riff.info = Object.keys(info).length ? info : null;
|
||||||
|
report.tags.raw.riff = riff;
|
||||||
|
if (riff.info) mapCommon(report, riff.info, RIFF_TO_COMMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Processes a single RIFF chunk, updating riff state and the report. */
|
||||||
|
function processRiffChunk(b, c, riff, info, report, maxTextBytes) {
|
||||||
|
if (c.id === "ds64") {
|
||||||
|
riff.ds64 = { present: true, size: c.size };
|
||||||
|
if (!report.detections.metadata_systems.includes("bw64_ds64")) report.detections.metadata_systems.push("bw64_ds64");
|
||||||
|
if (report.artifact.container.type === "wav") report.artifact.container.type = "bw64";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.id === "LIST" && ascii4(b, c.dataOff) === "INFO") {
|
||||||
|
for (const s of enumerateChunks(b, c.dataOff + 4, c.dataOff + c.size, 10000))
|
||||||
|
info[s.id] = decodeLatin1Trim(b.slice(s.dataOff, s.dataOff + s.size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.id === "bext") {
|
||||||
|
if (!report.detections.metadata_systems.includes("bwf_bext")) report.detections.metadata_systems.push("bwf_bext");
|
||||||
|
riff.bext = parseBext(b, c.dataOff, c.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.id === "iXML" || c.id === "axml") {
|
||||||
|
const key = c.id === "iXML" ? "ixml" : "axml";
|
||||||
|
if (!report.detections.metadata_systems.includes(key)) report.detections.metadata_systems.push(key);
|
||||||
|
const payload = b.slice(c.dataOff, c.dataOff + c.size);
|
||||||
|
riff[key] = { xml: safeUtf8(payload.slice(0, Math.min(payload.length, maxTextBytes))), truncated: payload.length > maxTextBytes };
|
||||||
|
report.embedded.push({
|
||||||
|
id: `${key}_0`, source: `riff:${c.id}`, content_type: "application/xml",
|
||||||
|
byte_length: payload.length, description: `${c.id} chunk`, filename: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses FLAC metablocks: STREAMINFO, Vorbis Comment, PICTURE. */
|
||||||
|
export function parseFlac(b, report, maxTextBytes) {
|
||||||
|
report.detections.metadata_systems.push("flac_metablocks");
|
||||||
|
|
||||||
|
const blocks = parseFlacMetaBlocks(b);
|
||||||
|
report.tags.raw.flac = { blocks: [] };
|
||||||
|
|
||||||
|
for (const blk of blocks) {
|
||||||
|
report.tags.raw.flac.blocks.push({ type: blk.typeName, length: blk.length });
|
||||||
|
|
||||||
|
if (blk.typeName === "VORBIS_COMMENT") {
|
||||||
|
if (!report.detections.metadata_systems.includes("vorbis_comments")) report.detections.metadata_systems.push("vorbis_comments");
|
||||||
|
const vc = parseVorbisComment(blk.data);
|
||||||
|
report.tags.raw.vorbis_comments = vc;
|
||||||
|
mapVorbisCommon(report, vc);
|
||||||
|
} else if (blk.typeName === "PICTURE") {
|
||||||
|
const pic = parseFlacPicture(blk.data, maxTextBytes);
|
||||||
|
report.embedded.push({
|
||||||
|
id: `cover_art_${report.embedded.filter((x) => x.id.startsWith("cover_art_")).length}`,
|
||||||
|
source: "flac:PICTURE", content_type: pic.mime || null,
|
||||||
|
byte_length: pic.dataLength, description: pic.description || null, filename: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses OGG/Opus Vorbis comments. */
|
||||||
|
export function parseOgg(b, report) {
|
||||||
|
if (!report.detections.metadata_systems.includes("ogg_opus_tags")) report.detections.metadata_systems.push("ogg_opus_tags");
|
||||||
|
|
||||||
|
const scanEnd = Math.min(b.length, 1024 * 1024);
|
||||||
|
let tags = null;
|
||||||
|
const opusTagsIdx = indexOfAscii(b, "OpusTags", 0, scanEnd);
|
||||||
|
if (opusTagsIdx >= 0) {
|
||||||
|
report.artifact.container.type = "opus";
|
||||||
|
tags = parseVorbisComment(b.slice(opusTagsIdx + 8, scanEnd));
|
||||||
|
} else {
|
||||||
|
const vorbisIdx = indexOfAscii(b, "\x03vorbis", 0, scanEnd);
|
||||||
|
if (vorbisIdx >= 0) tags = parseVorbisComment(b.slice(vorbisIdx + 7, scanEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
report.tags.raw.ogg = { has_opustags: opusTagsIdx >= 0, has_vorbis_comment: !!tags };
|
||||||
|
|
||||||
|
if (tags) {
|
||||||
|
if (!report.detections.metadata_systems.includes("vorbis_comments")) report.detections.metadata_systems.push("vorbis_comments");
|
||||||
|
report.tags.raw.vorbis_comments = tags;
|
||||||
|
mapVorbisCommon(report, tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Best-effort top-level atom scan for MP4/M4A. */
|
||||||
|
export function parseMp4BestEffort(b, report) {
|
||||||
|
report.detections.metadata_systems.push("mp4_atoms");
|
||||||
|
const atoms = [];
|
||||||
|
|
||||||
|
let off = 0;
|
||||||
|
while (off + 8 <= b.length && atoms.length < 2000) {
|
||||||
|
const size = u32be(b, off);
|
||||||
|
const type = ascii4(b, off + 4);
|
||||||
|
if (size < 8) break;
|
||||||
|
atoms.push({ type, size, offset: off });
|
||||||
|
off += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
report.tags.raw.mp4 = {
|
||||||
|
top_level_atoms: atoms.slice(0, 200),
|
||||||
|
hints: {
|
||||||
|
hasMoov: atoms.some((a) => a.type === "moov"),
|
||||||
|
hasUdta: atoms.some((a) => a.type === "udta"),
|
||||||
|
hasMeta: atoms.some((a) => a.type === "meta"),
|
||||||
|
hasIlst: atoms.some((a) => a.type === "ilst"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Best-effort AIFF/AIFC chunk scanning for NAME, AUTH, ANNO. */
|
||||||
|
export function parseAiffBestEffort(b, report, maxTextBytes) {
|
||||||
|
report.detections.metadata_systems.push("aiff_chunks");
|
||||||
|
let off = 12;
|
||||||
|
const chunks = [];
|
||||||
|
while (off + 8 <= b.length && chunks.length < 2000) {
|
||||||
|
const id = ascii4(b, off);
|
||||||
|
const size = u32be(b, off + 4);
|
||||||
|
const dataOff = off + 8;
|
||||||
|
chunks.push({ id, size, offset: off });
|
||||||
|
|
||||||
|
if (["NAME", "AUTH", "ANNO", "(c) "].includes(id)) {
|
||||||
|
const txt = safeUtf8(b.slice(dataOff, dataOff + Math.min(size, maxTextBytes)));
|
||||||
|
if (!report.tags.raw.aiff) report.tags.raw.aiff = { chunks: [] };
|
||||||
|
report.tags.raw.aiff.chunks.push({ id, value: txt, truncated: size > maxTextBytes });
|
||||||
|
}
|
||||||
|
|
||||||
|
off = dataOff + size + (size % 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!report.tags.raw.aiff) report.tags.raw.aiff = {};
|
||||||
|
report.tags.raw.aiff.chunk_index = chunks.slice(0, 500);
|
||||||
|
|
||||||
|
const nameChunk = report.tags.raw.aiff?.chunks?.find((ch) => ch.id === "NAME")?.value;
|
||||||
|
if (nameChunk) report.tags.common.title = report.tags.common.title || nameChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AAC_SAMPLE_RATES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
||||||
|
const AAC_PROFILES = ["Main", "LC", "SSR", "LTP"];
|
||||||
|
const AAC_CHANNELS = ["defined in AOT", "mono", "stereo", "3.0", "4.0", "5.0", "5.1", "7.1"];
|
||||||
|
|
||||||
|
/** Parses AAC ADTS frame header for audio parameters. */
|
||||||
|
export function parseAacAdts(b, report) {
|
||||||
|
report.detections.metadata_systems.push("adts_header");
|
||||||
|
if (b.length < 7) return;
|
||||||
|
|
||||||
|
const id = (b[1] >> 3) & 0x01;
|
||||||
|
const profile = (b[2] >> 6) & 0x03;
|
||||||
|
const freqIdx = (b[2] >> 2) & 0x0f;
|
||||||
|
const chanCfg = ((b[2] & 0x01) << 2) | ((b[3] >> 6) & 0x03);
|
||||||
|
|
||||||
|
report.tags.raw.aac = {
|
||||||
|
mpeg_version: id === 1 ? "MPEG-2" : "MPEG-4",
|
||||||
|
profile: AAC_PROFILES[profile] || `Profile ${profile}`,
|
||||||
|
sample_rate: AAC_SAMPLE_RATES[freqIdx] || null,
|
||||||
|
sample_rate_index: freqIdx,
|
||||||
|
channel_configuration: chanCfg,
|
||||||
|
channel_description: AAC_CHANNELS[chanCfg] || null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const AC3_SAMPLE_RATES = [48000, 44100, 32000];
|
||||||
|
const AC3_BITRATES = [32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640];
|
||||||
|
const AC3_ACMODES = [
|
||||||
|
"2.0 (Ch1+Ch2)", "1.0 (C)", "2.0 (L R)", "3.0 (L C R)",
|
||||||
|
"2.1 (L R S)", "3.1 (L C R S)", "2.2 (L R SL SR)", "3.2 (L C R SL SR)",
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Parses AC3 (Dolby Digital) bitstream info. */
|
||||||
|
export function parseAc3(b, report) {
|
||||||
|
report.detections.metadata_systems.push("ac3_bsi");
|
||||||
|
if (b.length < 8) return;
|
||||||
|
|
||||||
|
const fscod = (b[4] >> 6) & 0x03;
|
||||||
|
const frmsizecod = b[4] & 0x3f;
|
||||||
|
const bsid = (b[5] >> 3) & 0x1f;
|
||||||
|
const bsmod = b[5] & 0x07;
|
||||||
|
const acmod = (b[6] >> 5) & 0x07;
|
||||||
|
|
||||||
|
report.tags.raw.ac3 = {
|
||||||
|
sample_rate: AC3_SAMPLE_RATES[fscod] || null,
|
||||||
|
fscod,
|
||||||
|
bitrate_kbps: AC3_BITRATES[frmsizecod >> 1] || null,
|
||||||
|
frmsizecod, bsid, bsmod, acmod,
|
||||||
|
channel_layout: AC3_ACMODES[acmod] || null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses WMA files (ASF container) for content description metadata. */
|
||||||
|
export function parseWmaAsf(b, report) {
|
||||||
|
report.detections.metadata_systems.push("asf_header");
|
||||||
|
if (b.length < 30) return;
|
||||||
|
|
||||||
|
const headerSize = Number(u64le(b, 16));
|
||||||
|
const numObjects = u32le(b, 24);
|
||||||
|
const headerEnd = Math.min(b.length, headerSize);
|
||||||
|
|
||||||
|
const objects = [];
|
||||||
|
let off = 30;
|
||||||
|
|
||||||
|
for (let i = 0; i < numObjects && off + 24 <= headerEnd; i++) {
|
||||||
|
const guid4 = [b[off], b[off + 1], b[off + 2], b[off + 3]];
|
||||||
|
const objSize = Number(u64le(b, off + 16));
|
||||||
|
if (objSize < 24 || off + objSize > headerEnd) break;
|
||||||
|
|
||||||
|
const dataOff = off + 24;
|
||||||
|
const dataLen = objSize - 24;
|
||||||
|
|
||||||
|
if (guid4[0] === 0x33 && guid4[1] === 0x26 && guid4[2] === 0xb2 && guid4[3] === 0x75 && dataLen >= 10) {
|
||||||
|
const cd = parseAsfContentDescription(b, dataOff);
|
||||||
|
if (!report.detections.metadata_systems.includes("asf_content_desc"))
|
||||||
|
report.detections.metadata_systems.push("asf_content_desc");
|
||||||
|
if (!report.tags.raw.asf) report.tags.raw.asf = {};
|
||||||
|
report.tags.raw.asf.content_description = cd;
|
||||||
|
mapCommon(report, cd, ASF_CD_TO_COMMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guid4[0] === 0x40 && guid4[1] === 0xa4 && guid4[2] === 0xd0 && guid4[3] === 0xd2 && dataLen >= 2) {
|
||||||
|
const ext = parseAsfExtContentDescription(b, dataOff, dataOff + dataLen);
|
||||||
|
if (!report.detections.metadata_systems.includes("asf_ext_content_desc"))
|
||||||
|
report.detections.metadata_systems.push("asf_ext_content_desc");
|
||||||
|
if (!report.tags.raw.asf) report.tags.raw.asf = {};
|
||||||
|
report.tags.raw.asf.extended_content = ext;
|
||||||
|
|
||||||
|
const c = report.tags.common;
|
||||||
|
for (const d of ext) {
|
||||||
|
const field = WMA_TO_COMMON[(d.name || "").toUpperCase()];
|
||||||
|
if (field && d.value) c[field] = c[field] || d.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objects.push({ guid_prefix: guid4.map(x => x.toString(16).padStart(2, "0")).join(""), size: objSize });
|
||||||
|
off += objSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!report.tags.raw.asf) report.tags.raw.asf = {};
|
||||||
|
report.tags.raw.asf.header_objects = objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ID3_FRAME_DESCRIPTIONS = {
|
||||||
|
TIT2: "Title/songname/content description", TPE1: "Lead performer(s)/Soloist(s)",
|
||||||
|
TRCK: "Track number/Position in set", TALB: "Album/Movie/Show title",
|
||||||
|
TDRC: "Recording time", TYER: "Year", TCON: "Content type",
|
||||||
|
TPE2: "Band/orchestra/accompaniment", TLEN: "Length (ms)", TCOM: "Composer",
|
||||||
|
COMM: "Comments", APIC: "Attached picture", GEOB: "General encapsulated object",
|
||||||
|
TXXX: "User defined text information frame", UFID: "Unique file identifier", PRIV: "Private frame",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ID3_TO_COMMON = {
|
||||||
|
TIT2: "title", TPE1: "artist", TALB: "album", TDRC: "date", TYER: "date",
|
||||||
|
TRCK: "track", TCON: "genre", COMM: "comment", TCOM: "composer", TCOP: "copyright", TLAN: "language",
|
||||||
|
};
|
||||||
|
const VORBIS_TO_COMMON = {
|
||||||
|
TITLE: "title", ARTIST: "artist", ALBUM: "album", DATE: "date",
|
||||||
|
TRACKNUMBER: "track", GENRE: "genre", COMMENT: "comment", COMPOSER: "composer", LANGUAGE: "language",
|
||||||
|
};
|
||||||
|
const WMA_TO_COMMON = {
|
||||||
|
"WM/ALBUMTITLE": "album", "WM/GENRE": "genre", "WM/YEAR": "date",
|
||||||
|
"WM/TRACKNUMBER": "track", "WM/COMPOSER": "composer", "WM/LANGUAGE": "language",
|
||||||
|
};
|
||||||
|
const ID3V1_TO_COMMON = { title: "title", artist: "artist", album: "album", year: "date", comment: "comment", genre: "genre", track: "track" };
|
||||||
|
const RIFF_TO_COMMON = { INAM: "title", IART: "artist", ICMT: "comment", IGNR: "genre", ICRD: "date", ICOP: "copyright" };
|
||||||
|
const ASF_CD_TO_COMMON = { title: "title", author: "artist", copyright: "copyright", description: "comment" };
|
||||||
|
|
||||||
|
/** Maps source object fields to the common tags layer via a mapping table. */
|
||||||
|
function mapCommon(report, source, mapping) {
|
||||||
|
const c = report.tags.common;
|
||||||
|
for (const [sk, ck] of Object.entries(mapping))
|
||||||
|
c[ck] = c[ck] || source[sk] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Maps an ID3v2 frame value to the common tags layer. */
|
||||||
|
function mapCommonId3(report, frameId, text) {
|
||||||
|
const field = ID3_TO_COMMON[frameId];
|
||||||
|
if (field) report.tags.common[field] = report.tags.common[field] || text || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decodes an ID3v2 COMM (Comments) frame. */
|
||||||
|
function decodeCommFrame(data) {
|
||||||
|
if (!data || data.length < 5) return null;
|
||||||
|
const enc = data[0];
|
||||||
|
const language = String.fromCharCode(data[1], data[2], data[3]);
|
||||||
|
const { valueBytes: descBytes, next } = readNullTerminated(data, 4, enc);
|
||||||
|
const short_description = decodeText(descBytes, enc).replace(/\u0000/g, "").trim() || null;
|
||||||
|
const text = decodeText(data.slice(next), enc).replace(/\u0000/g, "").trim() || null;
|
||||||
|
return { language, short_description, text };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Normalizes TLEN to integer milliseconds. */
|
||||||
|
function normalizeTlen(s) {
|
||||||
|
if (!s) return null;
|
||||||
|
if (/^\s*\d+\s*$/.test(s)) return parseInt(s.trim(), 10);
|
||||||
|
const f = Number(s);
|
||||||
|
if (Number.isFinite(f) && f > 0 && f < 100000) return Math.round(f * 1000);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses the ID3v2 tag header and frames. */
|
||||||
|
function parseId3v2(mp3) {
|
||||||
|
if (mp3.length < 10 || mp3[0] !== 0x49 || mp3[1] !== 0x44 || mp3[2] !== 0x33) return null;
|
||||||
|
|
||||||
|
const major = mp3[3], minor = mp3[4], flags = mp3[5];
|
||||||
|
const tagSize = synchsafeToInt(mp3[6], mp3[7], mp3[8], mp3[9]);
|
||||||
|
let offset = 10;
|
||||||
|
const end = 10 + tagSize;
|
||||||
|
|
||||||
|
const frames = [];
|
||||||
|
while (offset + 10 <= end) {
|
||||||
|
const id = String.fromCharCode(mp3[offset], mp3[offset + 1], mp3[offset + 2], mp3[offset + 3]);
|
||||||
|
if (!/^[A-Z0-9]{4}$/.test(id)) break;
|
||||||
|
const size = major === 4 ?
|
||||||
|
synchsafeToInt(mp3[offset + 4], mp3[offset + 5], mp3[offset + 6], mp3[offset + 7]) :
|
||||||
|
u32be(mp3, offset + 4);
|
||||||
|
offset += 10;
|
||||||
|
if (size <= 0 || offset + size > mp3.length) break;
|
||||||
|
frames.push({ id, size, data: mp3.slice(offset, offset + size) });
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { header: { version: `${major}.${minor}`, flags, tag_size: tagSize }, frames };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses the 128-byte ID3v1 tag at the end of the file. */
|
||||||
|
function parseId3v1(b) {
|
||||||
|
if (b.length < 128) return null;
|
||||||
|
const off = b.length - 128;
|
||||||
|
if (b[off] !== 0x54 || b[off + 1] !== 0x41 || b[off + 2] !== 0x47) return null;
|
||||||
|
|
||||||
|
let track = null;
|
||||||
|
if (b[off + 125] === 0x00 && b[off + 126] !== 0x00) track = String(b[off + 126]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: decodeLatin1Trim(b.slice(off + 3, off + 33)),
|
||||||
|
artist: decodeLatin1Trim(b.slice(off + 33, off + 63)),
|
||||||
|
album: decodeLatin1Trim(b.slice(off + 63, off + 93)),
|
||||||
|
year: decodeLatin1Trim(b.slice(off + 93, off + 97)),
|
||||||
|
comment: decodeLatin1Trim(b.slice(off + 97, off + 127)),
|
||||||
|
track, genre: String(b[off + 127]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decodes an ID3v2 TXXX (user-defined text) frame. */
|
||||||
|
function decodeTxxx(data) {
|
||||||
|
if (!data || data.length < 2) return null;
|
||||||
|
const enc = data[0];
|
||||||
|
const { valueBytes: descBytes, next } = readNullTerminated(data, 1, enc);
|
||||||
|
const desc = decodeText(descBytes, enc).replace(/\u0000/g, "").trim();
|
||||||
|
const val = decodeText(data.slice(next), enc).replace(/\u0000/g, "").trim();
|
||||||
|
return { description: desc || null, value: val || null };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Best-effort APEv2 tag parser scanning the last 32 KB. */
|
||||||
|
function parseApeV2BestEffort(b) {
|
||||||
|
const scanStart = Math.max(0, b.length - 32768);
|
||||||
|
const idx = indexOfAscii(b, "APETAGEX", scanStart, b.length);
|
||||||
|
if (idx < 0) return null;
|
||||||
|
if (idx + 32 > b.length) return { present: true, warning: "APETAGEX found but footer truncated." };
|
||||||
|
|
||||||
|
const ver = u32le(b, idx + 8), size = u32le(b, idx + 12);
|
||||||
|
const count = u32le(b, idx + 16), flags = u32le(b, idx + 20);
|
||||||
|
|
||||||
|
const tagStart = idx + 32 - size;
|
||||||
|
if (tagStart < 0 || tagStart >= b.length)
|
||||||
|
return { present: true, version: ver, size, count, flags, warning: "APEv2 bounds invalid (non-standard placement)." };
|
||||||
|
|
||||||
|
const items = [];
|
||||||
|
let off = tagStart + 32;
|
||||||
|
const end = Math.min(b.length, idx);
|
||||||
|
while (off + 8 < end && items.length < 5000) {
|
||||||
|
const valueSize = u32le(b, off), itemFlags = u32le(b, off + 4);
|
||||||
|
off += 8;
|
||||||
|
let keyEnd = off;
|
||||||
|
while (keyEnd < end && b[keyEnd] !== 0x00) keyEnd++;
|
||||||
|
const key = decodeLatin1Trim(b.slice(off, keyEnd));
|
||||||
|
off = keyEnd + 1;
|
||||||
|
if (!key || off + valueSize > end) break;
|
||||||
|
const value = safeUtf8(b.slice(off, off + valueSize)).replace(/\u0000/g, "").trim();
|
||||||
|
off += valueSize;
|
||||||
|
items.push({ key, value, flags: itemFlags });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { present: true, version: ver, size, count, flags, items };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enumerates RIFF-style chunks (id + LE32 size) within a byte range, padding to even. */
|
||||||
|
function enumerateChunks(b, start, end, maxCount) {
|
||||||
|
const chunks = [];
|
||||||
|
let off = start;
|
||||||
|
while (off + 8 <= end && chunks.length < maxCount) {
|
||||||
|
const id = ascii4(b, off);
|
||||||
|
const size = u32le(b, off + 4);
|
||||||
|
const dataOff = off + 8;
|
||||||
|
if (dataOff + size > end) break;
|
||||||
|
chunks.push({ id, size, dataOff });
|
||||||
|
off = dataOff + size + (size % 2);
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses a BWF bext chunk. */
|
||||||
|
function parseBext(b, off, size) {
|
||||||
|
const slice = b.slice(off, off + size);
|
||||||
|
const timeRefLow = u32le(slice, 338), timeRefHigh = u32le(slice, 342);
|
||||||
|
return {
|
||||||
|
description: decodeLatin1Trim(slice.slice(0, 256)) || null,
|
||||||
|
originator: decodeLatin1Trim(slice.slice(256, 288)) || null,
|
||||||
|
originator_reference: decodeLatin1Trim(slice.slice(288, 320)) || null,
|
||||||
|
origination_date: decodeLatin1Trim(slice.slice(320, 330)) || null,
|
||||||
|
origination_time: decodeLatin1Trim(slice.slice(330, 338)) || null,
|
||||||
|
time_reference_samples: ((BigInt(timeRefHigh) << 32n) | BigInt(timeRefLow)).toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const FLAC_TYPE_NAMES = { 0: "STREAMINFO", 1: "PADDING", 2: "APPLICATION", 3: "SEEKTABLE", 4: "VORBIS_COMMENT", 5: "CUESHEET", 6: "PICTURE" };
|
||||||
|
|
||||||
|
/** Parses FLAC metadata blocks following the "fLaC" marker. */
|
||||||
|
function parseFlacMetaBlocks(b) {
|
||||||
|
const blocks = [];
|
||||||
|
let off = 4;
|
||||||
|
while (off + 4 <= b.length && blocks.length < 10000) {
|
||||||
|
const header = b[off];
|
||||||
|
const isLast = (header & 0x80) !== 0;
|
||||||
|
const type = header & 0x7f;
|
||||||
|
const len = (b[off + 1] << 16) | (b[off + 2] << 8) | b[off + 3];
|
||||||
|
off += 4;
|
||||||
|
if (off + len > b.length) break;
|
||||||
|
blocks.push({ type, typeName: FLAC_TYPE_NAMES[type] || `TYPE_${type}`, length: len, data: b.slice(off, off + len) });
|
||||||
|
off += len;
|
||||||
|
if (isLast) break;
|
||||||
|
}
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses a Vorbis Comment block (used by FLAC and OGG). */
|
||||||
|
function parseVorbisComment(buf) {
|
||||||
|
let off = 0;
|
||||||
|
const vendorLen = u32le(buf, off); off += 4;
|
||||||
|
if (off + vendorLen > buf.length) return { vendor: null, comments: [], warning: "vendor_len out of bounds" };
|
||||||
|
const vendor = safeUtf8(buf.slice(off, off + vendorLen)); off += vendorLen;
|
||||||
|
const count = u32le(buf, off); off += 4;
|
||||||
|
|
||||||
|
const comments = [];
|
||||||
|
for (let i = 0; i < count && off + 4 <= buf.length && comments.length < 20000; i++) {
|
||||||
|
const l = u32le(buf, off); off += 4;
|
||||||
|
if (off + l > buf.length) break;
|
||||||
|
const s = safeUtf8(buf.slice(off, off + l)); off += l;
|
||||||
|
const eq = s.indexOf("=");
|
||||||
|
if (eq > 0) comments.push({ key: s.slice(0, eq).toUpperCase(), value: s.slice(eq + 1) });
|
||||||
|
}
|
||||||
|
return { vendor, comments };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Maps Vorbis Comment fields to the common tags layer. */
|
||||||
|
function mapVorbisCommon(report, vc) {
|
||||||
|
const c = report.tags.common;
|
||||||
|
for (const [vk, ck] of Object.entries(VORBIS_TO_COMMON))
|
||||||
|
c[ck] = c[ck] || vc.comments?.find((x) => x.key === vk)?.value || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses a FLAC PICTURE metadata block (extracts mime, description, data length). */
|
||||||
|
function parseFlacPicture(data, maxTextBytes) {
|
||||||
|
let off = 4;
|
||||||
|
const mimeLen = u32be(data, off); off += 4;
|
||||||
|
const mime = safeUtf8(data.slice(off, off + Math.min(mimeLen, maxTextBytes))); off += mimeLen;
|
||||||
|
const descLen = u32be(data, off); off += 4;
|
||||||
|
const description = safeUtf8(data.slice(off, off + Math.min(descLen, maxTextBytes))); off += descLen + 16;
|
||||||
|
return { mime, description, dataLength: u32be(data, off) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses the ASF Content Description Object fields. */
|
||||||
|
function parseAsfContentDescription(b, off) {
|
||||||
|
const titleLen = u16le(b, off), authorLen = u16le(b, off + 2);
|
||||||
|
const copyrightLen = u16le(b, off + 4), descLen = u16le(b, off + 6), ratingLen = u16le(b, off + 8);
|
||||||
|
let pos = off + 10;
|
||||||
|
const title = decodeUtf16LE(b, pos, titleLen); pos += titleLen;
|
||||||
|
const author = decodeUtf16LE(b, pos, authorLen); pos += authorLen;
|
||||||
|
const copyright = decodeUtf16LE(b, pos, copyrightLen); pos += copyrightLen;
|
||||||
|
const description = decodeUtf16LE(b, pos, descLen); pos += descLen;
|
||||||
|
const rating = decodeUtf16LE(b, pos, ratingLen);
|
||||||
|
return { title, author, copyright, description, rating };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Parses the ASF Extended Content Description Object descriptors. */
|
||||||
|
function parseAsfExtContentDescription(b, off, end) {
|
||||||
|
const count = u16le(b, off);
|
||||||
|
let pos = off + 2;
|
||||||
|
const descriptors = [];
|
||||||
|
for (let i = 0; i < count && pos + 6 <= end && descriptors.length < 5000; i++) {
|
||||||
|
const nameLen = u16le(b, pos); pos += 2;
|
||||||
|
if (pos + nameLen > end) break;
|
||||||
|
const name = decodeUtf16LE(b, pos, nameLen); pos += nameLen;
|
||||||
|
const valueType = u16le(b, pos); pos += 2;
|
||||||
|
const valueLen = u16le(b, pos); pos += 2;
|
||||||
|
if (pos + valueLen > end) break;
|
||||||
|
let value;
|
||||||
|
if (valueType === 0) value = decodeUtf16LE(b, pos, valueLen);
|
||||||
|
else if (valueType === 3) value = u32le(b, pos);
|
||||||
|
else if (valueType === 5) value = u16le(b, pos);
|
||||||
|
else if (valueType === 2) value = u32le(b, pos) !== 0;
|
||||||
|
else value = `(${valueLen} bytes, type ${valueType})`;
|
||||||
|
pos += valueLen;
|
||||||
|
descriptors.push({ name, value_type: valueType, value });
|
||||||
|
}
|
||||||
|
return descriptors;
|
||||||
|
}
|
||||||
@ -45,6 +45,11 @@ export function search(input, searchRegex, removeRegex=null, sortBy=null, unique
|
|||||||
return results;
|
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
|
* URL regular expression
|
||||||
|
|||||||
@ -50,6 +50,7 @@ const HEX_ALPHABET_MAP = HEX_ALPHABET.split("");
|
|||||||
export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
||||||
if (!data) return "";
|
if (!data) return "";
|
||||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||||
|
if (data.length === 0) return "";
|
||||||
|
|
||||||
const regularHexString = toHex(data, "", padding, "", 0);
|
const regularHexString = toHex(data, "", padding, "", 0);
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0)
|
|||||||
export function toModhexFast(data) {
|
export function toModhexFast(data) {
|
||||||
if (!data) return "";
|
if (!data) return "";
|
||||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||||
|
if (data.length === 0) return "";
|
||||||
|
|
||||||
const output = [];
|
const output = [];
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class A1Z26CipherDecode extends Operation {
|
|||||||
const delim = Utils.charRep(args[0] || "Space");
|
const delim = Utils.charRep(args[0] || "Space");
|
||||||
|
|
||||||
if (input.length === 0) {
|
if (input.length === 0) {
|
||||||
return [];
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const bites = input.split(delim);
|
const bites = input.split(delim);
|
||||||
|
|||||||
175
src/core/operations/ExtractAudioMetadata.mjs
Normal file
175
src/core/operations/ExtractAudioMetadata.mjs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/**
|
||||||
|
* @author d0s1nt [d0s1nt@cyberchefaudio]
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import { makeEmptyReport, sniffContainer } from "../lib/AudioMetaSchema.mjs";
|
||||||
|
import {
|
||||||
|
parseMp3, parseRiffWave, parseFlac, parseOgg,
|
||||||
|
parseMp4BestEffort, parseAiffBestEffort,
|
||||||
|
parseAacAdts, parseAc3, parseWmaAsf,
|
||||||
|
} from "../lib/AudioParsers.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract Audio Metadata operation.
|
||||||
|
*/
|
||||||
|
class ExtractAudioMetadata extends Operation {
|
||||||
|
/** Creates the Extract Audio Metadata operation. */
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Extract Audio Metadata";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description =
|
||||||
|
"Extract common audio metadata across MP3 (ID3v2/ID3v1/GEOB), WAV/BWF/BW64 (INFO/bext/iXML/axml), FLAC (Vorbis Comment/Picture), OGG (Vorbis/OpusTags), AAC (ADTS), AC3 (Dolby Digital), WMA (ASF), plus best-effort MP4/M4A and AIFF scanning. Outputs normalized JSON.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Audio_file_format";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "JSON";
|
||||||
|
this.presentType = "html";
|
||||||
|
|
||||||
|
this.args = [
|
||||||
|
{ name: "Filename (optional)", type: "string", value: "" },
|
||||||
|
{ name: "Max embedded text bytes (iXML/axml/etc)", type: "number", value: 1024 * 512 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const filename = (args?.[0] || "").trim() || null;
|
||||||
|
const maxTextBytes = Number.isFinite(args?.[1]) ? Math.max(1024, args[1]) : 1024 * 512;
|
||||||
|
|
||||||
|
if (!(input instanceof ArrayBuffer) || input.byteLength === 0)
|
||||||
|
throw new OperationError("No input data. Load an audio file (drag/drop or use the open file button).");
|
||||||
|
|
||||||
|
const bytes = new Uint8Array(input);
|
||||||
|
const container = sniffContainer(bytes);
|
||||||
|
const report = makeEmptyReport(filename, bytes.length, container);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsers = {
|
||||||
|
mp3: () => parseMp3(bytes, report),
|
||||||
|
wav: () => parseRiffWave(bytes, report, maxTextBytes),
|
||||||
|
bw64: () => parseRiffWave(bytes, report, maxTextBytes),
|
||||||
|
flac: () => parseFlac(bytes, report, maxTextBytes),
|
||||||
|
ogg: () => parseOgg(bytes, report),
|
||||||
|
opus: () => parseOgg(bytes, report),
|
||||||
|
mp4: () => parseMp4BestEffort(bytes, report),
|
||||||
|
m4a: () => parseMp4BestEffort(bytes, report),
|
||||||
|
aiff: () => parseAiffBestEffort(bytes, report, maxTextBytes),
|
||||||
|
aac: () => parseAacAdts(bytes, report),
|
||||||
|
ac3: () => parseAc3(bytes, report),
|
||||||
|
wma: () => parseWmaAsf(bytes, report),
|
||||||
|
};
|
||||||
|
if (parsers[container.type]) {
|
||||||
|
parsers[container.type]();
|
||||||
|
} else {
|
||||||
|
report.errors.push({ stage: "sniff", message: "Unknown/unsupported container (best-effort scan not implemented)." });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
report.errors.push({ stage: "parse", message: String(e?.message || e) });
|
||||||
|
}
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Renders the extracted metadata as an HTML table. */
|
||||||
|
present(data) {
|
||||||
|
if (!data || typeof data !== "object") return JSON.stringify(data, null, 4);
|
||||||
|
|
||||||
|
const esc = Utils.escapeHtml;
|
||||||
|
const row = (k, v) => `<tr><td>${esc(String(k))}</td><td>${esc(String(v ?? ""))}</td></tr>\n`;
|
||||||
|
const section = (title) => `<tr><th colspan="2" style="background:#e9ecef;text-align:center">${esc(title)}</th></tr>\n`;
|
||||||
|
const objRows = (obj, filter = (v) => v !== null) => {
|
||||||
|
for (const [k, v] of Object.entries(obj)) {
|
||||||
|
if (filter(v)) html += row(k, v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const objSection = (obj, title, filter) => {
|
||||||
|
if (!obj) return;
|
||||||
|
html += section(title);
|
||||||
|
objRows(obj, filter);
|
||||||
|
};
|
||||||
|
const listSection = (arr, title, fmt) => {
|
||||||
|
if (!arr?.length) return;
|
||||||
|
html += section(title);
|
||||||
|
for (const item of arr) html += fmt(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
let html = `<table class="table table-hover table-sm table-bordered table-nonfluid">\n`;
|
||||||
|
|
||||||
|
html += section("Artifact");
|
||||||
|
html += row("Filename", data.artifact?.filename || "(none)");
|
||||||
|
html += row("Size", `${(data.artifact?.byte_length ?? 0).toLocaleString()} bytes`);
|
||||||
|
html += row("Container", data.artifact?.container?.type);
|
||||||
|
html += row("MIME", data.artifact?.container?.mime);
|
||||||
|
if (data.artifact?.container?.brand) html += row("Brand", data.artifact.container.brand);
|
||||||
|
|
||||||
|
html += section("Detections");
|
||||||
|
html += row("Metadata systems", (data.detections?.metadata_systems || []).join(", ") || "None");
|
||||||
|
html += row("Provenance systems", (data.detections?.provenance_systems || []).join(", ") || "None");
|
||||||
|
|
||||||
|
const common = data.tags?.common || {};
|
||||||
|
html += section("Common Tags");
|
||||||
|
if (Object.values(common).some((v) => v !== null)) {
|
||||||
|
for (const [key, val] of Object.entries(common)) {
|
||||||
|
if (val !== null) html += row(key.charAt(0).toUpperCase() + key.slice(1), val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html += row("(none)", "No common tags found");
|
||||||
|
}
|
||||||
|
|
||||||
|
listSection(data.tags?.raw?.id3v2?.frames, "ID3v2 Frames", (f) => {
|
||||||
|
const val = typeof f.decoded === "object" ? JSON.stringify(f.decoded) : (f.decoded ?? `(${f.size} bytes)`);
|
||||||
|
return row(f.id + (f.description ? ` \u2014 ${f.description}` : ""), val);
|
||||||
|
});
|
||||||
|
objSection(data.tags?.raw?.id3v1, "ID3v1", (v) => !!v);
|
||||||
|
listSection(data.tags?.raw?.apev2?.items, "APEv2 Tags", (i) => row(i.key, i.value));
|
||||||
|
|
||||||
|
if (data.tags?.raw?.vorbis_comments?.comments?.length) {
|
||||||
|
html += section("Vorbis Comments");
|
||||||
|
html += row("Vendor", data.tags.raw.vorbis_comments.vendor);
|
||||||
|
for (const c of data.tags.raw.vorbis_comments.comments) html += row(c.key, c.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
objSection(data.tags?.raw?.riff?.info, "RIFF INFO", () => true);
|
||||||
|
objSection(data.tags?.raw?.riff?.bext, "BWF bext");
|
||||||
|
listSection(data.tags?.raw?.riff?.chunks, "RIFF Chunks", (c) => row(c.id, `${c.size} bytes @ offset ${c.offset}`));
|
||||||
|
listSection(data.tags?.raw?.flac?.blocks, "FLAC Metadata Blocks", (b) => row(b.type, `${b.length} bytes`));
|
||||||
|
|
||||||
|
if (data.tags?.raw?.mp4?.top_level_atoms?.length) {
|
||||||
|
html += section("MP4 Top-Level Atoms");
|
||||||
|
const atoms = data.tags.raw.mp4.top_level_atoms;
|
||||||
|
for (const a of atoms.slice(0, 50)) html += row(a.type, `${a.size} bytes @ offset ${a.offset}`);
|
||||||
|
if (atoms.length > 50) html += row("...", `${atoms.length - 50} more atoms`);
|
||||||
|
}
|
||||||
|
|
||||||
|
listSection(data.tags?.raw?.aiff?.chunks, "AIFF Chunks", (c) => row(c.id, c.value));
|
||||||
|
objSection(data.tags?.raw?.aac, "AAC ADTS");
|
||||||
|
objSection(data.tags?.raw?.ac3, "AC3 (Dolby Digital)");
|
||||||
|
objSection(data.tags?.raw?.asf?.content_description, "ASF Content Description", (v) => !!v);
|
||||||
|
listSection(data.tags?.raw?.asf?.extended_content, "ASF Extended Content", (d) => row(d.name, d.value));
|
||||||
|
listSection(data.embedded, "Embedded Objects", (e) => row(e.id, `${e.content_type || "unknown"} \u2014 ${(e.byte_length ?? 0).toLocaleString()} bytes`));
|
||||||
|
|
||||||
|
if (data.provenance?.c2pa?.present) {
|
||||||
|
html += section("C2PA Provenance");
|
||||||
|
html += row("Present", "Yes");
|
||||||
|
for (const emb of (data.provenance.c2pa.embedding || []))
|
||||||
|
html += row("Carrier", `${emb.carrier} \u2014 ${(emb.byte_length ?? 0).toLocaleString()} bytes`);
|
||||||
|
}
|
||||||
|
|
||||||
|
listSection(data.errors, "Errors", (e) => row(e.stage, e.message));
|
||||||
|
|
||||||
|
html += "</table>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExtractAudioMetadata;
|
||||||
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
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";
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,8 +50,7 @@ class ExtractEmailAddresses extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [displayTotal, sort, unique] = args,
|
const [displayTotal, sort, unique] = args,
|
||||||
// email regex from: https://www.regextester.com/98066
|
regex = EMAIL_REGEX;
|
||||||
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;
|
|
||||||
|
|
||||||
const results = search(
|
const results = search(
|
||||||
input,
|
input,
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import * as jq from "jq-wasm";
|
import jq from "jq-web";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jq operation
|
* jq operation
|
||||||
@ -30,7 +30,12 @@ class Jq extends Operation {
|
|||||||
name: "Query",
|
name: "Query",
|
||||||
type: "string",
|
type: "string",
|
||||||
value: ""
|
value: ""
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: "Raw",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,15 +45,19 @@ class Jq extends Operation {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
return (async () => {
|
const [query, raw] = args;
|
||||||
const [query] = args;
|
let result;
|
||||||
try {
|
|
||||||
const result = await jq.json(input, query);
|
try {
|
||||||
return JSON.stringify(result);
|
result = jq.json(input, query);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Invalid jq expression: ${err.message}`);
|
throw new OperationError(`Invalid jq expression: ${err.message}`);
|
||||||
}
|
}
|
||||||
})();
|
if (raw && typeof result === "string") {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return JSON.stringify(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,7 +99,7 @@ class OffsetChecker extends Operation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputs.join(sampleDelim);
|
return outputs.join(Utils.escapeHtml(sampleDelim));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
112
src/core/operations/ParseEthernetFrame.mjs
Normal file
112
src/core/operations/ParseEthernetFrame.mjs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* @author tedk [tedk@ted.do]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import {fromHex, toHex} from "../lib/Hex.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Ethernet frame operation
|
||||||
|
*/
|
||||||
|
class ParseEthernetFrame extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParseEthernetFrame constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Parse Ethernet frame";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Parses an Ethernet frame and either shows the deduced values (Source and destination MAC, VLANs) or returns the packet data.<br /><br />Good for use in conjunction with the Parse IPv4, and Parse TCP/UDP recipes.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/Ethernet_frame#Frame_%E2%80%93_data_link_layer";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input type",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"Raw", "Hex"
|
||||||
|
],
|
||||||
|
defaultIndex: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Return type",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"Text output", "Packet data", "Packet data (hex)",
|
||||||
|
],
|
||||||
|
defaultIndex: 0,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const format = args[0];
|
||||||
|
const outputFormat = args[1];
|
||||||
|
|
||||||
|
if (format === "Hex") {
|
||||||
|
input = fromHex(input);
|
||||||
|
} else if (format === "Raw") {
|
||||||
|
input = new Uint8Array(Utils.strToArrayBuffer(input));
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid input format selected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const destinationMac = input.slice(0, 6);
|
||||||
|
const sourceMac = input.slice(6, 12);
|
||||||
|
|
||||||
|
let offset = 12;
|
||||||
|
const vlans = [];
|
||||||
|
|
||||||
|
while (offset < input.length) {
|
||||||
|
const ethType = Utils.byteArrayToChars(input.slice(offset, offset+2));
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
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, offset+2);
|
||||||
|
vlans.push(((vlanTag[0] & 0b00001111) << 8) | vlanTag[1]);
|
||||||
|
|
||||||
|
offset += 2;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const packetData = input.slice(offset);
|
||||||
|
|
||||||
|
if (outputFormat === "Packet data") {
|
||||||
|
return Utils.byteArrayToChars(packetData);
|
||||||
|
} else if (outputFormat === "Packet data (hex)") {
|
||||||
|
return toHex(packetData);
|
||||||
|
} else if (outputFormat === "Text output") {
|
||||||
|
let retval = `Source MAC: ${toHex(sourceMac, ":")}\nDestination MAC: ${toHex(destinationMac, ":")}\n`;
|
||||||
|
if (vlans.length > 0) {
|
||||||
|
retval += `VLAN: ${vlans.join(", ")}\n`;
|
||||||
|
}
|
||||||
|
retval += `Data:\n${toHex(packetData)}`;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParseEthernetFrame;
|
||||||
@ -33,6 +33,12 @@ class ParseIPv4Header extends Operation {
|
|||||||
"name": "Input format",
|
"name": "Input format",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["Hex", "Raw"]
|
"value": ["Hex", "Raw"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Table", "Data (hex)", "Data (raw)"],
|
||||||
|
defaultIndex: 0,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -44,6 +50,8 @@ class ParseIPv4Header extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const format = args[0];
|
const format = args[0];
|
||||||
|
const outputFormat = args[1];
|
||||||
|
|
||||||
let output;
|
let output;
|
||||||
|
|
||||||
if (format === "Hex") {
|
if (format === "Hex") {
|
||||||
@ -98,7 +106,10 @@ class ParseIPv4Header extends Operation {
|
|||||||
checksumResult = givenChecksum + " (incorrect, should be " + correctChecksum + ")";
|
checksumResult = givenChecksum + " (incorrect, should be " + correctChecksum + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
output = `<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>Field</th><th>Value</th></tr>
|
const data = input.slice(ihl * 4);
|
||||||
|
|
||||||
|
if (outputFormat === "Table") {
|
||||||
|
output = `<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>Field</th><th>Value</th></tr>
|
||||||
<tr><td>Version</td><td>${version}</td></tr>
|
<tr><td>Version</td><td>${version}</td></tr>
|
||||||
<tr><td>Internet Header Length (IHL)</td><td>${ihl} (${ihl * 4} bytes)</td></tr>
|
<tr><td>Internet Header Length (IHL)</td><td>${ihl} (${ihl * 4} bytes)</td></tr>
|
||||||
<tr><td>Differentiated Services Code Point (DSCP)</td><td>${dscp}</td></tr>
|
<tr><td>Differentiated Services Code Point (DSCP)</td><td>${dscp}</td></tr>
|
||||||
@ -116,13 +127,19 @@ class ParseIPv4Header extends Operation {
|
|||||||
<tr><td>Protocol</td><td>${protocol}, ${protocolInfo.protocol} (${protocolInfo.keyword})</td></tr>
|
<tr><td>Protocol</td><td>${protocol}, ${protocolInfo.protocol} (${protocolInfo.keyword})</td></tr>
|
||||||
<tr><td>Header checksum</td><td>${checksumResult}</td></tr>
|
<tr><td>Header checksum</td><td>${checksumResult}</td></tr>
|
||||||
<tr><td>Source IP address</td><td>${ipv4ToStr(srcIP)}</td></tr>
|
<tr><td>Source IP address</td><td>${ipv4ToStr(srcIP)}</td></tr>
|
||||||
<tr><td>Destination IP address</td><td>${ipv4ToStr(dstIP)}</td></tr>`;
|
<tr><td>Destination IP address</td><td>${ipv4ToStr(dstIP)}</td></tr>
|
||||||
|
<tr><td>Data (hex)</td><td>${toHex(data)}</td></tr>`;
|
||||||
|
|
||||||
if (ihl > 5) {
|
if (ihl > 5) {
|
||||||
output += `<tr><td>Options</td><td>${toHex(options)}</td></tr>`;
|
output += `<tr><td>Options</td><td>${toHex(options)}</td></tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output + "</table>";
|
||||||
|
} else if (outputFormat === "Data (hex)") {
|
||||||
|
return toHex(data);
|
||||||
|
} else if (outputFormat === "Data (raw)") {
|
||||||
|
return Utils.byteArrayToChars(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output + "</table>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
import XRegExp from "xregexp";
|
import XRegExp from "xregexp";
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
|
import { EMAIL_REGEX } from "../lib/Extract.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +46,7 @@ class RegularExpression extends Operation {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Email address",
|
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",
|
name: "URL",
|
||||||
|
|||||||
@ -393,7 +393,7 @@ class App {
|
|||||||
* Checks if the favourites category is expanded
|
* Checks if the favourites category is expanded
|
||||||
*/
|
*/
|
||||||
isFavouritesExpanded() {
|
isFavouritesExpanded() {
|
||||||
const catFavourites = document.getElementById("#catFavourites");
|
const catFavourites = document.getElementById("catFavourites");
|
||||||
return catFavourites ? catFavourites.classList.contains("show") : false;
|
return catFavourites ? catFavourites.classList.contains("show") : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -130,6 +130,7 @@ class Manager {
|
|||||||
// Controls
|
// Controls
|
||||||
document.getElementById("bake").addEventListener("click", this.controls.bakeClick.bind(this.controls));
|
document.getElementById("bake").addEventListener("click", this.controls.bakeClick.bind(this.controls));
|
||||||
document.getElementById("auto-bake").addEventListener("change", this.controls.autoBakeChange.bind(this.controls));
|
document.getElementById("auto-bake").addEventListener("change", this.controls.autoBakeChange.bind(this.controls));
|
||||||
|
document.getElementById("auto-bake").addEventListener("keydown", this.controls.autoBakeKeyboardHandler.bind(this.controls));
|
||||||
document.getElementById("step").addEventListener("click", this.controls.stepClick.bind(this.controls));
|
document.getElementById("step").addEventListener("click", this.controls.stepClick.bind(this.controls));
|
||||||
document.getElementById("clr-recipe").addEventListener("click", this.controls.clearRecipeClick.bind(this.controls));
|
document.getElementById("clr-recipe").addEventListener("click", this.controls.clearRecipeClick.bind(this.controls));
|
||||||
document.getElementById("save").addEventListener("click", this.controls.saveClick.bind(this.controls));
|
document.getElementById("save").addEventListener("click", this.controls.saveClick.bind(this.controls));
|
||||||
|
|||||||
@ -146,7 +146,7 @@
|
|||||||
<button type="button" aria-label="Edit Favourites" class="btn btn-warning bmd-btn-icon" id="edit-favourites" data-toggle="tooltip" title="Edit favourites">
|
<button type="button" aria-label="Edit Favourites" class="btn btn-warning bmd-btn-icon" id="edit-favourites" data-toggle="tooltip" title="Edit favourites">
|
||||||
<i class="material-icons" aria-hidden="true">star</i>
|
<i class="material-icons" aria-hidden="true">star</i>
|
||||||
</button>
|
</button>
|
||||||
<div id="content-wrapper">
|
<div tabindex="0" id="content-wrapper">
|
||||||
<div id="banner">
|
<div id="banner">
|
||||||
<div id="download-wrapper">
|
<div id="download-wrapper">
|
||||||
<a href="#" class="banner-link desktop-only" data-toggle="modal" data-target="#download-modal" data-help-title="Downloading CyberChef" data-help="<p>CyberChef can be downloaded to run locally or hosted within your own network. It has no server-side component so all that is required is that the ZIP file is uncompressed and the files are accessible.</p><p>As a user, it is worth noting that unofficial versions of CyberChef could have been modified to introduce Input and/or Recipe exfiltration. We recommend always using the official, open source, up-to-date version of CyberChef hosted at <a href='https://gchq.github.io/CyberChef'>https://gchq.github.io/CyberChef</a> if accessible.</p><p>The Network tab in your browser's Developer console (F12) can be used to inspect the network requests made by a website. This can confirm that no data is uploaded when a CyberChef recipe is baked.</p>">
|
<a href="#" class="banner-link desktop-only" data-toggle="modal" data-target="#download-modal" data-help-title="Downloading CyberChef" data-help="<p>CyberChef can be downloaded to run locally or hosted within your own network. It has no server-side component so all that is required is that the ZIP file is uncompressed and the files are accessible.</p><p>As a user, it is worth noting that unofficial versions of CyberChef could have been modified to introduce Input and/or Recipe exfiltration. We recommend always using the official, open source, up-to-date version of CyberChef hosted at <a href='https://gchq.github.io/CyberChef'>https://gchq.github.io/CyberChef</a> if accessible.</p><p>The Network tab in your browser's Developer console (F12) can be used to inspect the network requests made by a website. This can confirm that no data is uploaded when a CyberChef recipe is baked.</p>">
|
||||||
@ -646,22 +646,22 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" href="#faqs" aria-controls="profile" role="tab" data-toggle="tab">
|
<a id="tab-1" class="nav-link active" href="#faqs" aria-controls="profile" role="tab" data-toggle="tab">
|
||||||
FAQs
|
FAQs
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" href="#report-bug" aria-controls="messages" role="tab" data-toggle="tab">
|
<a id="tab-2" class="nav-link" href="#report-bug" aria-controls="messages" role="tab" data-toggle="tab">
|
||||||
Report a bug
|
Report a bug
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" href="#about" aria-controls="messages" role="tab" data-toggle="tab">
|
<a id="tab-3" class="nav-link" href="#about" aria-controls="messages" role="tab" data-toggle="tab">
|
||||||
About
|
About
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" href="#keybindings" aria-controls="messages" role="tab" data-toggle="tab">
|
<a id="tab-4" class="nav-link" href="#keybindings" aria-controls="messages" role="tab" data-toggle="tab">
|
||||||
Keybindings
|
Keybindings
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -22,6 +22,11 @@
|
|||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#banner div a:focus {
|
||||||
|
background-color: #eef3ec;
|
||||||
|
border: solid black 2px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Notice wrapper */
|
/* Notice wrapper */
|
||||||
#notice-wrapper {
|
#notice-wrapper {
|
||||||
|
|||||||
@ -78,6 +78,11 @@
|
|||||||
border-left: 2px solid var(--primary-border-colour);
|
border-left: 2px solid var(--primary-border-colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p a:focus {
|
||||||
|
color: #0a6ebd;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.checkbox label input[type=checkbox]+.checkbox-decorator .check,
|
.checkbox label input[type=checkbox]+.checkbox-decorator .check,
|
||||||
.checkbox label input[type=checkbox]+.checkbox-decorator .check::before {
|
.checkbox label input[type=checkbox]+.checkbox-decorator .check::before {
|
||||||
border-color: var(--input-border-colour);
|
border-color: var(--input-border-colour);
|
||||||
|
|||||||
@ -57,6 +57,18 @@ class ControlsWaiter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks or unchecks the Auto Bake checkbox with "Enter"
|
||||||
|
* @param {Event} ev
|
||||||
|
*/
|
||||||
|
autoBakeKeyboardHandler(ev) {
|
||||||
|
const checkBox = document.getElementById("auto-bake");
|
||||||
|
ev.preventDefault();
|
||||||
|
if (ev.key === "Enter" || ev.key === " ") {
|
||||||
|
checkBox.checked = !checkBox.checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to trigger baking.
|
* Handler to trigger baking.
|
||||||
@ -387,6 +399,18 @@ class ControlsWaiter {
|
|||||||
*/
|
*/
|
||||||
supportButtonClick(e) {
|
supportButtonClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const faqs = document.getElementById("faqs");
|
||||||
|
const faqsAElement = faqs.getElementsByTagName("a");
|
||||||
|
for (let i = 0; i < faqsAElement.length; i++) {
|
||||||
|
faqsAElement[i].setAttribute("tabindex", "0");
|
||||||
|
faqsAElement[i].addEventListener("keydown", this.navigateFAQList, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = document.querySelectorAll('[role="tab"]');
|
||||||
|
|
||||||
|
for (let i = 0; i < tabs.length; i++) {
|
||||||
|
tabs[i].addEventListener("keydown", this.changeTabs, false);
|
||||||
|
}
|
||||||
|
|
||||||
const reportBugInfo = document.getElementById("report-bug-info");
|
const reportBugInfo = document.getElementById("report-bug-info");
|
||||||
const saveLink = this.generateStateUrl(true, true, null, null, "https://gchq.github.io/CyberChef/");
|
const saveLink = this.generateStateUrl(true, true, null, null, "https://gchq.github.io/CyberChef/");
|
||||||
@ -403,6 +427,64 @@ ${navigator.userAgent}
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} ev
|
||||||
|
*/
|
||||||
|
changeTabs(ev) {
|
||||||
|
const tab = ev.target;
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
if (ev.key === "ArrowRight") {
|
||||||
|
const nextTab = tab.parentElement;
|
||||||
|
if (nextTab.nextElementSibling === null) {
|
||||||
|
tab.parentElement.parentElement.firstElementChild.firstElementChild.focus();
|
||||||
|
} else {
|
||||||
|
nextTab.nextElementSibling.firstElementChild.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ev.key === "ArrowLeft") {
|
||||||
|
const prevTab = tab.parentElement;
|
||||||
|
|
||||||
|
if (prevTab.previousElementSibling === null) {
|
||||||
|
tab.parentElement.parentElement.lastElementChild.firstElementChild.focus();
|
||||||
|
} else {
|
||||||
|
prevTab.previousElementSibling.firstElementChild.focus();
|
||||||
|
}
|
||||||
|
} else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-1")) {
|
||||||
|
document.getElementById("faqs").querySelector("[class='btn btn-primary']").focus();
|
||||||
|
} else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-2")) {
|
||||||
|
document.getElementById("report-bug").querySelector("[class='btn btn-primary']").focus();
|
||||||
|
} else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-3")) {
|
||||||
|
document.getElementById("about").querySelector("[href]").focus();
|
||||||
|
} else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-4")) {
|
||||||
|
const button = document.getElementById("support-modal").getElementsByClassName("modal-footer");
|
||||||
|
const close = button[0].firstElementChild;
|
||||||
|
close.focus();
|
||||||
|
} else if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
|
||||||
|
tab.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} ev
|
||||||
|
*/
|
||||||
|
navigateFAQList(ev) {
|
||||||
|
|
||||||
|
const el = ev.target.nextElementSibling;
|
||||||
|
if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
|
||||||
|
ev.preventDefault();
|
||||||
|
const question = el.classList;
|
||||||
|
if (question !== undefined && question.value) {
|
||||||
|
if (!question.value.includes("show")) {
|
||||||
|
question.add("show");
|
||||||
|
} else if (question.contains("show")) {
|
||||||
|
question.remove("show");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the stale indicator to show that the input or recipe has changed
|
* Shows the stale indicator to show that the input or recipe has changed
|
||||||
* since the last bake.
|
* since the last bake.
|
||||||
|
|||||||
@ -268,7 +268,7 @@ module.exports = {
|
|||||||
testOpHtml(browser, "Parse colour code", "#000", ".colorpicker-preview", "rgb(0, 0, 0)");
|
testOpHtml(browser, "Parse colour code", "#000", ".colorpicker-preview", "rgb(0, 0, 0)");
|
||||||
testOpHtml(browser, "Parse DateTime", "01/12/2000 13:00:00", "", /Date: Friday 1st December 2000/);
|
testOpHtml(browser, "Parse DateTime", "01/12/2000 13:00:00", "", /Date: Friday 1st December 2000/);
|
||||||
// testOp(browser, "Parse IP range", "test input", "test_output");
|
// testOp(browser, "Parse IP range", "test input", "test_output");
|
||||||
testOpHtml(browser, "Parse IPv4 header", "45 c0 00 c4 02 89 00 00 ff 11 1e 8c c0 a8 0c 01 c0 a8 0c 02", "tr:last-child td:last-child", "192.168.12.2");
|
testOpHtml(browser, "Parse IPv4 header", "45 c0 00 c4 02 89 00 00 ff 11 1e 8c c0 a8 0c 01 c0 a8 0c 02", "tr:nth-last-child(2) td:last-child", "192.168.12.2");
|
||||||
// testOp(browser, "Parse IPv6 address", "test input", "test_output");
|
// testOp(browser, "Parse IPv6 address", "test input", "test_output");
|
||||||
// testOp(browser, "Parse ObjectID timestamp", "test input", "test_output");
|
// testOp(browser, "Parse ObjectID timestamp", "test input", "test_output");
|
||||||
// testOp(browser, "Parse QR Code", "test input", "test_output");
|
// testOp(browser, "Parse QR Code", "test input", "test_output");
|
||||||
@ -354,6 +354,7 @@ module.exports = {
|
|||||||
// testOp(browser, "Tail", "test input", "test_output");
|
// testOp(browser, "Tail", "test input", "test_output");
|
||||||
// testOp(browser, "Take bytes", "test input", "test_output");
|
// testOp(browser, "Take bytes", "test input", "test_output");
|
||||||
testOp(browser, "Tar", "test input", /^file\.txt\x00{92}/);
|
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/);
|
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 BCD", "test input", "test_output");
|
||||||
// testOp(browser, "To Base", "test input", "test_output");
|
// testOp(browser, "To Base", "test input", "test_output");
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
|
import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
|
||||||
|
|
||||||
import TestRegister from "../lib/TestRegister.mjs";
|
import TestRegister from "../lib/TestRegister.mjs";
|
||||||
|
import "./tests/A1Z26CipherDecode.mjs";
|
||||||
import "./tests/AESKeyWrap.mjs";
|
import "./tests/AESKeyWrap.mjs";
|
||||||
import "./tests/AlternatingCaps.mjs";
|
import "./tests/AlternatingCaps.mjs";
|
||||||
import "./tests/AvroToJSON.mjs";
|
import "./tests/AvroToJSON.mjs";
|
||||||
@ -66,6 +67,7 @@ import "./tests/DropNthBytes.mjs";
|
|||||||
import "./tests/ECDSA.mjs";
|
import "./tests/ECDSA.mjs";
|
||||||
import "./tests/ELFInfo.mjs";
|
import "./tests/ELFInfo.mjs";
|
||||||
import "./tests/Enigma.mjs";
|
import "./tests/Enigma.mjs";
|
||||||
|
import "./tests/ExtractAudioMetadata.mjs";
|
||||||
import "./tests/ExtractEmailAddresses.mjs";
|
import "./tests/ExtractEmailAddresses.mjs";
|
||||||
import "./tests/ExtractHashes.mjs";
|
import "./tests/ExtractHashes.mjs";
|
||||||
import "./tests/ExtractIPAddresses.mjs";
|
import "./tests/ExtractIPAddresses.mjs";
|
||||||
@ -120,6 +122,7 @@ import "./tests/NetBIOS.mjs";
|
|||||||
import "./tests/NormaliseUnicode.mjs";
|
import "./tests/NormaliseUnicode.mjs";
|
||||||
import "./tests/NTLM.mjs";
|
import "./tests/NTLM.mjs";
|
||||||
import "./tests/OTP.mjs";
|
import "./tests/OTP.mjs";
|
||||||
|
import "./tests/ParseEthernetFrame.mjs";
|
||||||
import "./tests/ParseIPRange.mjs";
|
import "./tests/ParseIPRange.mjs";
|
||||||
import "./tests/ParseObjectIDTimestamp.mjs";
|
import "./tests/ParseObjectIDTimestamp.mjs";
|
||||||
import "./tests/ParseQRCode.mjs";
|
import "./tests/ParseQRCode.mjs";
|
||||||
@ -140,6 +143,7 @@ import "./tests/Rabbit.mjs";
|
|||||||
import "./tests/RAKE.mjs";
|
import "./tests/RAKE.mjs";
|
||||||
import "./tests/Regex.mjs";
|
import "./tests/Regex.mjs";
|
||||||
import "./tests/Register.mjs";
|
import "./tests/Register.mjs";
|
||||||
|
import "./tests/RegularExpression.mjs";
|
||||||
import "./tests/RisonEncodeDecode.mjs";
|
import "./tests/RisonEncodeDecode.mjs";
|
||||||
import "./tests/Rotate.mjs";
|
import "./tests/Rotate.mjs";
|
||||||
import "./tests/RSA.mjs";
|
import "./tests/RSA.mjs";
|
||||||
|
|||||||
33
tests/operations/tests/A1Z26CipherDecode.mjs
Normal file
33
tests/operations/tests/A1Z26CipherDecode.mjs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* A1Z26 Cipher Decode tests
|
||||||
|
*
|
||||||
|
* @author brick-pixel
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
"name": "A1Z26 Cipher Decode: basic decode",
|
||||||
|
"input": "8 5 12 12 15",
|
||||||
|
"expectedOutput": "hello",
|
||||||
|
"recipeConfig": [
|
||||||
|
{
|
||||||
|
"op": "A1Z26 Cipher Decode",
|
||||||
|
"args": ["Space"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "A1Z26 Cipher Decode: empty input returns empty string",
|
||||||
|
"input": "",
|
||||||
|
"expectedOutput": "",
|
||||||
|
"recipeConfig": [
|
||||||
|
{
|
||||||
|
"op": "A1Z26 Cipher Decode",
|
||||||
|
"args": ["Space"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
287
tests/operations/tests/ExtractAudioMetadata.mjs
Normal file
287
tests/operations/tests/ExtractAudioMetadata.mjs
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
/**
|
||||||
|
* Extract Audio Metadata operation tests.
|
||||||
|
*
|
||||||
|
* @author d0s1nt
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
import {
|
||||||
|
MP3_HEX, WAV_HEX, FLAC_HEX, AAC_HEX,
|
||||||
|
AC3_HEX, OGG_HEX, OPUS_HEX, WMA_HEX,
|
||||||
|
M4A_HEX, AIFF_HEX
|
||||||
|
} from "../../samples/Audio.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
// ---- MP3 ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: MP3 container and MIME",
|
||||||
|
input: MP3_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>mp3<\/td>.*MIME<\/td><td>audio\/mpeg<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.mp3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: MP3 common tags (title, artist)",
|
||||||
|
input: MP3_HEX,
|
||||||
|
expectedMatch: /Title<\/td><td>Galway<\/td>.*Artist<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.mp3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: MP3 ID3v2 frames (TIT2, TPE1, TSSE)",
|
||||||
|
input: MP3_HEX,
|
||||||
|
expectedMatch: /ID3v2 Frames.*TIT2.*Galway.*TPE1.*Kevin MacLeod.*TSSE.*Lavf56\.40\.101/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.mp3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: MP3 detections (id3v2)",
|
||||||
|
input: MP3_HEX,
|
||||||
|
expectedMatch: /Metadata systems<\/td><td>id3v2<\/td>/,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.mp3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- WAV ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WAV container and MIME",
|
||||||
|
input: WAV_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>wav<\/td>.*MIME<\/td><td>audio\/wav<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wav", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WAV RIFF chunks (fmt)",
|
||||||
|
input: WAV_HEX,
|
||||||
|
expectedMatch: /RIFF Chunks.*fmt .*16 bytes @ offset 20/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wav", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- FLAC ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: FLAC container and common tags",
|
||||||
|
input: FLAC_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>flac<\/td>.*Title<\/td><td>Galway<\/td>.*Artist<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.flac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: FLAC metadata blocks (STREAMINFO, VORBIS_COMMENT)",
|
||||||
|
input: FLAC_HEX,
|
||||||
|
expectedMatch: /FLAC Metadata Blocks.*STREAMINFO<\/td><td>34 bytes<\/td>.*VORBIS_COMMENT<\/td><td>86 bytes<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.flac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: FLAC Vorbis comments (vendor, tags)",
|
||||||
|
input: FLAC_HEX,
|
||||||
|
expectedMatch: /Vorbis Comments.*Vendor<\/td><td>Lavf56\.40\.101<\/td>.*TITLE<\/td><td>Galway<\/td>.*ARTIST<\/td><td>Kevin MacLeod<\/td>.*ENCODER<\/td><td>Lavf56\.40\.101<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.flac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: FLAC detections",
|
||||||
|
input: FLAC_HEX,
|
||||||
|
expectedMatch: /Metadata systems<\/td><td>flac_metablocks, vorbis_comments<\/td>/,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.flac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- AAC ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AAC container and MIME",
|
||||||
|
input: AAC_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>aac<\/td>.*MIME<\/td><td>audio\/aac<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.aac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AAC ADTS technical fields",
|
||||||
|
input: AAC_HEX,
|
||||||
|
expectedMatch: /AAC ADTS.*mpeg_version<\/td><td>MPEG-4<\/td>.*profile<\/td><td>LC<\/td>.*sample_rate<\/td><td>44100<\/td>.*channel_description<\/td><td>stereo<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.aac", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- AC3 ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AC3 container and MIME",
|
||||||
|
input: AC3_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>ac3<\/td>.*MIME<\/td><td>audio\/ac3<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.ac3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AC3 technical fields (sample rate, bitrate, channels)",
|
||||||
|
input: AC3_HEX,
|
||||||
|
expectedMatch: /AC3 \(Dolby Digital\).*sample_rate<\/td><td>44100<\/td>.*bitrate_kbps<\/td><td>192<\/td>.*channel_layout<\/td><td>2\.0 \(L R\)<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.ac3", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- OGG Vorbis ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: OGG container and common tags",
|
||||||
|
input: OGG_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>ogg<\/td>.*Title<\/td><td>Galway<\/td>.*Artist<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.ogg", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: OGG Vorbis comments (vendor, encoder)",
|
||||||
|
input: OGG_HEX,
|
||||||
|
expectedMatch: /Vorbis Comments.*Vendor<\/td><td>Lavf56\.40\.101<\/td>.*ENCODER<\/td><td>Lavc56\.60\.100 libvorbis<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.ogg", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- Opus ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: Opus container and common tags",
|
||||||
|
input: OPUS_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>opus<\/td>.*Title<\/td><td>Galway<\/td>.*Artist<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.opus", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: Opus Vorbis comments (vendor, encoder)",
|
||||||
|
input: OPUS_HEX,
|
||||||
|
expectedMatch: /Vorbis Comments.*Vendor<\/td><td>Lavf58\.19\.102<\/td>.*ENCODER<\/td><td>Lavc58\.34\.100 libopus<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.opus", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- WMA/ASF ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WMA container and MIME",
|
||||||
|
input: WMA_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>wma<\/td>.*MIME<\/td><td>audio\/x-ms-wma<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wma", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WMA common tags (title, artist)",
|
||||||
|
input: WMA_HEX,
|
||||||
|
expectedMatch: /Title<\/td><td>Galway<\/td>.*Artist<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wma", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WMA ASF Content Description",
|
||||||
|
input: WMA_HEX,
|
||||||
|
expectedMatch: /ASF Content Description.*title<\/td><td>Galway<\/td>.*author<\/td><td>Kevin MacLeod<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wma", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WMA ASF Extended Content (encoding settings)",
|
||||||
|
input: WMA_HEX,
|
||||||
|
expectedMatch: /ASF Extended Content.*WM\/EncodingSettings<\/td><td>Lavf56\.40\.101<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wma", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: WMA detections",
|
||||||
|
input: WMA_HEX,
|
||||||
|
expectedMatch: /Metadata systems<\/td><td>asf_header, asf_content_desc, asf_ext_content_desc<\/td>/,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.wma", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- M4A ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: M4A container, MIME and brand",
|
||||||
|
input: M4A_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>m4a<\/td>.*MIME<\/td><td>audio\/mp4<\/td>.*Brand<\/td><td>M4A <\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.m4a", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: M4A top-level atoms (ftyp, mdat)",
|
||||||
|
input: M4A_HEX,
|
||||||
|
expectedMatch: /MP4 Top-Level Atoms.*ftyp<\/td>.*mdat<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.m4a", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ---- AIFF ----
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AIFF container, MIME and brand",
|
||||||
|
input: AIFF_HEX,
|
||||||
|
expectedMatch: /Container<\/td><td>aiff<\/td>.*MIME<\/td><td>audio\/aiff<\/td>.*Brand<\/td><td>AIFF<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.aiff", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AIFF common tag (title from NAME chunk)",
|
||||||
|
input: AIFF_HEX,
|
||||||
|
expectedMatch: /Title<\/td><td>Galway<\/td>/,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.aiff", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Extract Audio Metadata: AIFF chunks (NAME)",
|
||||||
|
input: AIFF_HEX,
|
||||||
|
expectedMatch: /AIFF Chunks.*NAME<\/td><td>Galway<\/td>/s,
|
||||||
|
recipeConfig: [
|
||||||
|
{ op: "From Hex", args: ["None"] },
|
||||||
|
{ op: "Extract Audio Metadata", args: ["test.aiff", 524288] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]);
|
||||||
@ -11,44 +11,70 @@ TestRegister.addTests([
|
|||||||
{
|
{
|
||||||
name: "Extract email address",
|
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",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
op: "Extract email addresses",
|
||||||
"args": [false]
|
args: [false],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Extract email address - Display total",
|
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",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
op: "Extract email addresses",
|
||||||
"args": [true]
|
args: [true],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Extract email address (Internationalized)",
|
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",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
op: "Extract email addresses",
|
||||||
"args": [false]
|
args: [false],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Extract email address - Display total (Internationalized)",
|
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",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
op: "Extract email addresses",
|
||||||
"args": [true]
|
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],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
32
tests/operations/tests/Jq.mjs
Normal file
32
tests/operations/tests/Jq.mjs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Jq tests.
|
||||||
|
*
|
||||||
|
* @author rtpt-romankarwacik [roman.karwacik@redteam-pentesting.de]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Get raw JSON Property",
|
||||||
|
input: '{"data": "testString\\u0000"}',
|
||||||
|
expectedOutput: "testString\u0000",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Jq",
|
||||||
|
args: [".data", true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get JSON Property",
|
||||||
|
input: '{"data": "testString\\u0000"}',
|
||||||
|
expectedOutput: "\"testString\\u0000\"",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Jq",
|
||||||
|
args: [".data", false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
@ -147,4 +147,24 @@ dc;ii;hv;ig;hr;hf;dc;he;hj;hv;hv;ie;hg;du",
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Empty input through From Hex and To Modhex returns empty output",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Hex",
|
||||||
|
"args": [
|
||||||
|
"Auto"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "To Modhex",
|
||||||
|
"args": [
|
||||||
|
"Space",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|||||||
45
tests/operations/tests/ParseEthernetFrame.mjs
Normal file
45
tests/operations/tests/ParseEthernetFrame.mjs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Parse Ethernet frame tests.
|
||||||
|
*
|
||||||
|
* @author tedk [tedk@ted.do]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Parse plain Ethernet frame",
|
||||||
|
input: "000000000000ffffffffffff08004500",
|
||||||
|
expectedOutput: "Source MAC: ff:ff:ff:ff:ff:ff\nDestination MAC: 00:00:00:00:00:00\nData:\n45 00",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse Ethernet frame",
|
||||||
|
"args": ["Hex", "Text output"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// Example PCAP data from: https://packetlife.net/captures/protocol/vlan/
|
||||||
|
{
|
||||||
|
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: 118\nData:\naa aa",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse Ethernet frame",
|
||||||
|
"args": ["Hex", "Text output"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: 209, 20\nData:\n45 00",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse Ethernet frame",
|
||||||
|
"args": ["Hex", "Text output"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
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",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
73
tests/samples/Audio.mjs
Normal file
73
tests/samples/Audio.mjs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Audio file headers in various formats for use in tests.
|
||||||
|
*
|
||||||
|
* Each constant contains the minimal bytes needed for container
|
||||||
|
* detection and metadata extraction (trimmed from real audio files).
|
||||||
|
*
|
||||||
|
* @author d0s1nt [d0s1nt@cyberchefaudio]
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MP3 with ID3v2.4 header — title: Galway, artist: Kevin MacLeod
|
||||||
|
* 78 bytes: ID3v2 header + TIT2 + TPE1 + TSSE frames
|
||||||
|
*/
|
||||||
|
export const MP3_HEX = "4944330400000000004e544954320000000800000347616c77617900545045310000000f0000034b6576696e204d61634c656f6400545353450000000f0000034c61766635362e34302e3130310000000000000000000000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WAV (RIFF/WAVE) header — 2 channels, 16-bit, 44100 Hz
|
||||||
|
* 48 bytes: RIFF header + fmt chunk + data chunk start
|
||||||
|
*/
|
||||||
|
export const WAV_HEX = "52494646e69d2a0057415645666d7420100000000100020044ac000010b102000400100064617461489d2a0000000100";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FLAC with streaminfo + Vorbis comment block — title: Galway, artist: Kevin MacLeod
|
||||||
|
* 174 bytes: fLaC magic + STREAMINFO (34 bytes) + VORBIS_COMMENT block (86 bytes)
|
||||||
|
*/
|
||||||
|
export const FLAC_HEX = "664c6143000000221200120000052e00319f0ac442f0000aa752c925754a50e5f02e117eeb46467e7053040000560d0000004c61766635362e34302e313031030000000c0000007469746c653d47616c776179140000006172746973743d4b6576696e204d61634c656f6415000000656e636f6465723d4c61766635362e34302e313031";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AAC ADTS frame header — MPEG-4, LC profile, 44100 Hz, stereo
|
||||||
|
* 32 bytes: ADTS sync + frame header fields
|
||||||
|
*/
|
||||||
|
export const AAC_HEX = "fff150800bbffcde02004c61766335382e33342e31303000423590002000001e";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AC3 (Dolby Digital) sync frame header — 44100 Hz, 192 kbps, 2.0 stereo
|
||||||
|
* 32 bytes: AC3 sync word + BSI fields
|
||||||
|
*/
|
||||||
|
export const AC3_HEX = "0b773968544043e106f575f0d4da1c1ac159850953e549a125736e8d37359d3f";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OGG Vorbis — two OGG pages with identification + comment headers
|
||||||
|
* title: Galway, artist: Kevin MacLeod, vendor: Lavf56.40.101
|
||||||
|
* 281 bytes
|
||||||
|
*/
|
||||||
|
export const OGG_HEX = "4f6767530002000000000000000027a7032a000000002acbc833011e01766f72626973000000000244ac00000000000080b5010000000000b8014f6767530000000000000000000027a7032a010000007e1abea41168ffffffffffffffffffffffffffffff0703766f726269730d0000004c61766635362e34302e313031030000001f000000656e636f6465723d4c61766335362e36302e313030206c6962766f726269730c0000007469746c653d47616c776179140000006172746973743d4b6576696e204d61634c656f64";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opus — two OGG pages with OpusHead + OpusTags headers
|
||||||
|
* title: Galway, artist: Kevin MacLeod, vendor: Lavf58.19.102
|
||||||
|
* 233 bytes
|
||||||
|
*/
|
||||||
|
export const OPUS_HEX = "4f67675300020000000000000000919a59f200000000f6117eb601134f707573486561640102380180bb00000000004f67675300000000000000000000919a59f201000000b047e56601664f707573546167730d0000004c61766635382e31392e313032030000001d000000656e636f6465723d4c61766335382e33342e313030206c69626f7075730c0000007469746c653d47616c776179140000006172746973743d4b6576696e204d61634c656f64";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WMA/ASF — ASF header with Content Description + Extended Content
|
||||||
|
* title: Galway, author: Kevin MacLeod, encoder: Lavf56.40.101
|
||||||
|
* 700 bytes: ASF Header Object + all sub-objects
|
||||||
|
*/
|
||||||
|
export const WMA_HEX = "3026b2758e66cf11a6d900aa0062ce6c8a02000000000000060000000102a1dcab8c47a9cf118ee400c00c205365680000000000000000000000000000000000000000000000bc3504000000000000803ed5deb19d0156000000000000007040490b00000000b03a7009000000001c0c00000000000002000000800c0000800c000000f40100b503bf5f2ea9cf118ee300c00c2053652e0000000000000011d2d3abbaa9cf118ee600c00c2053650600000000003326b2758e66cf11a6d900aa0062ce6c4c000000000000000e001c00000000000000470061006c0077006100790000004b006500760069006e0020004d00610063004c0065006f006400000040a4d0d207e3d21197f000a0c95ea850b40000000000000003000c007400690074006c006500000000000e00470061006c0077006100790000000e0041007500740068006f007200000000001c004b006500760069006e0020004d00610063004c0065006f0064000000280057004d002f0045006e0063006f00640069006e006700530065007400740069006e0067007300000000001c004c00610076006600350036002e00340030002e0031003000310000009107dcb7b7a9cf118ee600c00c2053657200000000000000409e69f84d5bcf11a8fd00805f5c442b50cdc3bf8f61cf118bb200aa00b4e22000000000000000001c000000080000000100000000006101020044ac0000803e0000e70210000a000000000001000000000001e702e7020100004052d1861d31d011a3a400a0c90348f664000000000000004152d1861d31d011a3a400a0c90348f60100000002001700570069006e0064006f007700730020004d006500640069006100200041007500640069006f0020005600380000000000020061013626b2758e66cf11a6d900aa0062ce6c32330400000000000000000000000000000000000000000056000000000000000101";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* M4A (MPEG-4 Audio) — ftyp atom with brand "M4A ", plus mdat
|
||||||
|
* 512 bytes: ftyp + free + mdat start (moov not included in slice)
|
||||||
|
*/
|
||||||
|
export const M4A_HEX = "0000001c667479704d344120000002004d34412069736f6d69736f3200000008667265650003e2236d6461742111450014500146fff10a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5de98214b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4bc211a93a09c3e310803595989841e21e02814c4d2f28f925da49e5fe61d4521f0088400d65662610788780a0563ab2a671af1d0cd2fd9997d18be037ff8852d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AIFF (FORM/AIFF) header with NAME chunk = "Galway", COMM and SSND chunks
|
||||||
|
* 36 bytes: FORM header + NAME chunk + COMM chunk start
|
||||||
|
*/
|
||||||
|
export const AIFF_HEX = "464f524d002a9d84414946464e414d450000000647616c776179434f4d4d00000012000200";
|
||||||
Loading…
x
Reference in New Issue
Block a user