diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 000000000..66fca29b2 --- /dev/null +++ b/.cspell.json @@ -0,0 +1,17 @@ +{ + "version": "0.2", + "language": "en,en-gb", + "words": [], + "dictionaries": [ + "npm", + "softwareTerms", + "node", + "html", + "css", + "bash", + "en-gb", + "misc" + ], + "ignorePaths": ["package.json", "package-lock.json", "node_modules"] + } + \ No newline at end of file diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index a068ffbb3..a77f4984b 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -25,6 +25,7 @@ jobs: - name: Install run: | + export DETECT_CHROMEDRIVER_VERSION=true npm ci npm run setheapsize @@ -61,12 +62,22 @@ jobs: tags: ${{ steps.image-metadata.outputs.tags }} labels: ${{ steps.image-metadata.outputs.labels }} containerfiles: ./Dockerfile - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 oci: true + # enable build layer caching between platforms + layers: true # Webpack seems to use a lot of open files, increase the max open file limit to accomodate. extra-args: | --ulimit nofile=10000 + - name: Publish to GHCR + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.build-image.outputs.image }} + tags: ${{ steps.build-image.outputs.tags }} + registry: ${{ env.REGISTRY }} + username: ${{ env.REGISTRY_USER }} + password: ${{ env.REGISTRY_PASSWORD }} - name: Upload Release Assets id: upload-release-assets @@ -83,11 +94,3 @@ jobs: uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} - - - name: Publish to GHCR - uses: redhat-actions/push-to-registry@v2 - with: - tags: ${{ steps.build-image.outputs.tags }} - registry: ${{ env.REGISTRY }} - username: ${{ env.REGISTRY_USER }} - password: ${{ env.REGISTRY_PASSWORD }} diff --git a/Dockerfile b/Dockerfile index be4c8bada..ba605fd71 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,35 @@ -FROM node:18-alpine AS build +##################################### +# Build the app to a static website # +##################################### +# Modifier --platform=$BUILDPLATFORM limits the platform to "BUILDPLATFORM" during buildx multi-platform builds +# This is because npm "chromedriver" package is not compatiable with all platforms +# For more info see: https://docs.docker.com/build/building/multi-platform/#cross-compilation +FROM --platform=$BUILDPLATFORM node:18-alpine AS builder +WORKDIR /app + +COPY package.json . +COPY package-lock.json . + +# Install dependencies +# --ignore-scripts prevents postinstall script (which runs grunt) as it depends on files other than package.json +RUN npm ci --ignore-scripts + +# Copy files needed for postinstall and build COPY . . -RUN npm ci + +# npm postinstall runs grunt, which depends on files other than package.json +RUN npm run postinstall + +# Build the app RUN npm run build -FROM nginx:1.25-alpine3.18 AS cyberchef +######################################### +# Package static build files into nginx # +######################################### +# We are using Github Actions: redhat-actions/buildah-build@v2 which needs manual selection of arch in base image +# Remove TARGETARCH if docker buildx is supported in the CI release as --platform=$TARGETPLATFORM will be automatically set +ARG TARGETPLATFORM +FROM --platform=${TARGETPLATFORM} nginx:stable-alpine AS cyberchef -COPY --from=build ./build/prod /usr/share/nginx/html/ +COPY --from=builder /app/build/prod /usr/share/nginx/html/ diff --git a/README.md b/README.md index 5549bda2a..89f0371d5 100755 --- a/README.md +++ b/README.md @@ -20,21 +20,36 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur [A live demo can be found here][1] - have fun! -## Containers +## Running Locally with Docker -If you would like to try out CyberChef locally you can either build it yourself: +**Prerequisites** +- [Docker](hhttps://www.docker.com/products/docker-desktop/) + - Docker Desktop must be open and running on your machine + + +#### Option 1: Build the Docker Image Yourself + +1. Build the docker image ```bash docker build --tag cyberchef --ulimit nofile=10000 . +``` +2. Run the docker container +```bash docker run -it -p 8080:80 cyberchef ``` +3. Navigate to `http://localhost:8080` in your browser -Or you can use our image directly: +#### Option 2: Use the pre-built Docker Image + +If you prefer to skip the build process, you can use the pre-built image ```bash docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest ``` +Just like before, navigate to `http://localhost:8080` in your browser. + This image is built and published through our [GitHub Workflows](.github/workflows/releases.yml) ## How it works diff --git a/package-lock.json b/package-lock.json index 8f9619945..b374df4bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.0", + "dompurify": "^3.2.5", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -45,14 +46,17 @@ "file-saver": "^2.0.5", "flat": "^6.0.1", "geodesy": "1.1.3", + "handlebars": "^4.7.8", + "hash-wasm": "^4.12.0", "highlight.js": "^11.9.0", "ieee754": "^1.2.1", "jimp": "^0.22.12", + "jq-web": "^0.5.1", "jquery": "3.7.1", - "js-crc": "^0.2.0", "js-sha3": "^0.9.3", "jsesc": "^3.0.2", "json5": "^2.2.3", + "jsonata": "^2.0.3", "jsonpath-plus": "^9.0.0", "jsonwebtoken": "8.5.1", "jsqr": "^1.4.0", @@ -93,6 +97,7 @@ "ua-parser-js": "^1.0.38", "unorm": "^1.6.0", "utf8": "^3.0.0", + "uuid": "^11.1.0", "vkbeautify": "^0.99.3", "xpath": "0.0.34", "xregexp": "^5.1.1", @@ -121,6 +126,7 @@ "compression-webpack-plugin": "^11.1.0", "copy-webpack-plugin": "^12.0.2", "core-js": "^3.37.1", + "cspell": "^8.17.3", "css-loader": "7.1.2", "eslint": "^9.4.0", "eslint-plugin-jsdoc": "^48.2.9", @@ -1908,6 +1914,594 @@ "node": ">=0.1.90" } }, + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.17.3.tgz", + "integrity": "sha512-6uOF726o3JnExAUKM20OJJXZo+Qf9Jt64nkVwnVXx7Upqr5I9Pb1npYPEAIpUA03SnWYmKwUIqhAmkwrN+bLPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-ada": "^4.1.0", + "@cspell/dict-al": "^1.1.0", + "@cspell/dict-aws": "^4.0.9", + "@cspell/dict-bash": "^4.2.0", + "@cspell/dict-companies": "^3.1.13", + "@cspell/dict-cpp": "^6.0.3", + "@cspell/dict-cryptocurrencies": "^5.0.4", + "@cspell/dict-csharp": "^4.0.6", + "@cspell/dict-css": "^4.0.17", + "@cspell/dict-dart": "^2.3.0", + "@cspell/dict-data-science": "^2.0.7", + "@cspell/dict-django": "^4.1.4", + "@cspell/dict-docker": "^1.1.12", + "@cspell/dict-dotnet": "^5.0.9", + "@cspell/dict-elixir": "^4.0.7", + "@cspell/dict-en_us": "^4.3.30", + "@cspell/dict-en-common-misspellings": "^2.0.9", + "@cspell/dict-en-gb": "1.1.33", + "@cspell/dict-filetypes": "^3.0.10", + "@cspell/dict-flutter": "^1.1.0", + "@cspell/dict-fonts": "^4.0.4", + "@cspell/dict-fsharp": "^1.1.0", + "@cspell/dict-fullstack": "^3.2.3", + "@cspell/dict-gaming-terms": "^1.1.0", + "@cspell/dict-git": "^3.0.4", + "@cspell/dict-golang": "^6.0.18", + "@cspell/dict-google": "^1.0.8", + "@cspell/dict-haskell": "^4.0.5", + "@cspell/dict-html": "^4.0.11", + "@cspell/dict-html-symbol-entities": "^4.0.3", + "@cspell/dict-java": "^5.0.11", + "@cspell/dict-julia": "^1.1.0", + "@cspell/dict-k8s": "^1.0.10", + "@cspell/dict-kotlin": "^1.1.0", + "@cspell/dict-latex": "^4.0.3", + "@cspell/dict-lorem-ipsum": "^4.0.4", + "@cspell/dict-lua": "^4.0.7", + "@cspell/dict-makefile": "^1.0.4", + "@cspell/dict-markdown": "^2.0.9", + "@cspell/dict-monkeyc": "^1.0.10", + "@cspell/dict-node": "^5.0.6", + "@cspell/dict-npm": "^5.1.24", + "@cspell/dict-php": "^4.0.14", + "@cspell/dict-powershell": "^5.0.14", + "@cspell/dict-public-licenses": "^2.0.13", + "@cspell/dict-python": "^4.2.15", + "@cspell/dict-r": "^2.1.0", + "@cspell/dict-ruby": "^5.0.7", + "@cspell/dict-rust": "^4.0.11", + "@cspell/dict-scala": "^5.0.7", + "@cspell/dict-shell": "^1.1.0", + "@cspell/dict-software-terms": "^4.2.4", + "@cspell/dict-sql": "^2.2.0", + "@cspell/dict-svelte": "^1.0.6", + "@cspell/dict-swift": "^2.0.5", + "@cspell/dict-terraform": "^1.1.0", + "@cspell/dict-typescript": "^3.2.0", + "@cspell/dict-vue": "^3.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-json-reporter": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.17.3.tgz", + "integrity": "sha512-RWSfyHOin/d9CqLjz00JMvPkag3yUSsQZr6G9BnCT5cMEO/ws8wQZzA54CNj/LAOccbknTX65SSroPPAtxs56w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "8.17.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.17.3.tgz", + "integrity": "sha512-DqqSWKt9NLWPGloYxZTpzUhgdW8ObMkZmOOF6TyqpJ4IbckEct8ULgskNorTNRlmmjLniaNgvg6JSHuYO3Urxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-resolver": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.17.3.tgz", + "integrity": "sha512-yQlVaIsWiax6RRuuacZs++kl6Y9rwH9ZkVlsG9fhdeCJ5Xf3WCW+vmX1chzhhKDzRr8CF9fsvb1uagd/5/bBYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.17.3.tgz", + "integrity": "sha512-CC3nob/Kbuesz5WTW+LjAHnDFXJrA49pW5ckmbufJxNnoAk7EJez/qr7/ELMTf6Fl3A5xZ776Lhq7738Hy/fmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.17.3.tgz", + "integrity": "sha512-ozgeuSioX9z2wtlargfgdw3LKwDFAfm8gxu+xwNREvXiLsevb+lb7ZlY5/ay+MahqR5Hfs7XzYzBLTKL/ldn9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.0.tgz", + "integrity": "sha512-7SvmhmX170gyPd+uHXrfmqJBY5qLcCX8kTGURPVeGxmt8XNXT75uu9rnZO+jwrfuU2EimNoArdVy5GZRGljGNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-al": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.0.tgz", + "integrity": "sha512-PtNI1KLmYkELYltbzuoztBxfi11jcE9HXBHCpID2lou/J4VMYKJPNqe4ZjVzSI9NYbMnMnyG3gkbhIdx66VSXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-aws": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.9.tgz", + "integrity": "sha512-bDYdnnJGwSkIZ4gzrauu7qzOs/ZAY/FnU4k11LgdMI8BhwMfsbsy2EI1iS+sD/BI5ZnNT9kU5YR3WADeNOmhRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.0.tgz", + "integrity": "sha512-HOyOS+4AbCArZHs/wMxX/apRkjxg6NDWdt0jF9i9XkvJQUltMwEhyA2TWYjQ0kssBsnof+9amax2lhiZnh3kCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-shell": "1.1.0" + } + }, + "node_modules/@cspell/dict-companies": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.14.tgz", + "integrity": "sha512-iqo1Ce4L7h0l0GFSicm2wCLtfuymwkvgFGhmu9UHyuIcTbdFkDErH+m6lH3Ed+QuskJlpQ9dM7puMIGqUlVERw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cpp": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-6.0.3.tgz", + "integrity": "sha512-OFrVXdxCeGKnon36Pe3yFjBuY4kzzEwWFf3vDz+cJTodZDkjFkBifQeTtt5YfimgF8cfAJZXkBCsxjipAgmAiw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.4.tgz", + "integrity": "sha512-6iFu7Abu+4Mgqq08YhTKHfH59mpMpGTwdzDB2Y8bbgiwnGFCeoiSkVkgLn1Kel2++hYcZ8vsAW/MJS9oXxuMag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-csharp": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.6.tgz", + "integrity": "sha512-w/+YsqOknjQXmIlWDRmkW+BHBPJZ/XDrfJhZRQnp0wzpPOGml7W0q1iae65P2AFRtTdPKYmvSz7AL5ZRkCnSIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-css": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.17.tgz", + "integrity": "sha512-2EisRLHk6X/PdicybwlajLGKF5aJf4xnX2uuG5lexuYKt05xV/J/OiBADmi8q9obhxf1nesrMQbqAt+6CsHo/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dart": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.0.tgz", + "integrity": "sha512-1aY90lAicek8vYczGPDKr70pQSTQHwMFLbmWKTAI6iavmb1fisJBS1oTmMOKE4ximDf86MvVN6Ucwx3u/8HqLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-data-science": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.7.tgz", + "integrity": "sha512-XhAkK+nSW6zmrnWzusmZ1BpYLc62AWYHZc2p17u4nE2Z9XG5DleG55PCZxXQTKz90pmwlhFM9AfpkJsYaBWATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-django": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.4.tgz", + "integrity": "sha512-fX38eUoPvytZ/2GA+g4bbdUtCMGNFSLbdJJPKX2vbewIQGfgSFJKY56vvcHJKAvw7FopjvgyS/98Ta9WN1gckg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.12.tgz", + "integrity": "sha512-6d25ZPBnYZaT9D9An/x6g/4mk542R8bR3ipnby3QFCxnfdd6xaWiTcwDPsCgwN2aQZIQ1jX/fil9KmBEqIK/qA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dotnet": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.9.tgz", + "integrity": "sha512-JGD6RJW5sHtO5lfiJl11a5DpPN6eKSz5M1YBa1I76j4dDOIqgZB6rQexlDlK1DH9B06X4GdDQwdBfnpAB0r2uQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-elixir": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.7.tgz", + "integrity": "sha512-MAUqlMw73mgtSdxvbAvyRlvc3bYnrDqXQrx5K9SwW8F7fRYf9V4vWYFULh+UWwwkqkhX9w03ZqFYRTdkFku6uA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en_us": { + "version": "4.3.31", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.31.tgz", + "integrity": "sha512-MDc+1B0aFwQONS0JZ6w7ks2KFGkUcaNTFJ8kI6GHvFRmEl3zP5NJDwFEXFsoEdLDb86j2myauSWMJXR3JFuwbA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en-common-misspellings": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.9.tgz", + "integrity": "sha512-O/jAr1VNtuyCFckbTmpeEf43ZFWVD9cJFvWaA6rO2IVmLirJViHWJUyBZOuQcesSplzEIw80MAYmnK06/MDWXQ==", + "dev": true, + "license": "CC BY-SA 4.0" + }, + "node_modules/@cspell/dict-en-gb": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", + "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-filetypes": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.11.tgz", + "integrity": "sha512-bBtCHZLo7MiSRUqx5KEiPdGOmXIlDGY+L7SJEtRWZENpAKE+96rT7hj+TUUYWBbCzheqHr0OXZJFEKDgsG/uZg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-flutter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.0.tgz", + "integrity": "sha512-3zDeS7zc2p8tr9YH9tfbOEYfopKY/srNsAa+kE3rfBTtQERAZeOhe5yxrnTPoufctXLyuUtcGMUTpxr3dO0iaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fonts": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.4.tgz", + "integrity": "sha512-cHFho4hjojBcHl6qxidl9CvUb492IuSk7xIf2G2wJzcHwGaCFa2o3gRcxmIg1j62guetAeDDFELizDaJlVRIOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fsharp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.0.tgz", + "integrity": "sha512-oguWmHhGzgbgbEIBKtgKPrFSVAFtvGHaQS0oj+vacZqMObwkapcTGu7iwf4V3Bc2T3caf0QE6f6rQfIJFIAVsw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fullstack": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.4.tgz", + "integrity": "sha512-JRRvaOLBZ13BO9sP395W+06tyO1Jy/87aFlKe9xQiCWMiwpCo2kGq0xBGq0PDWe253lYLs+GKrNmLU0fSxrObg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-gaming-terms": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.0.tgz", + "integrity": "sha512-46AnDs9XkgJ2f1Sqol1WgfJ8gOqp60fojpc9Wxch7x+BA63g4JfMV5/M5x0sI0TLlLY8EBSglcr8wQF/7C80AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.0.4.tgz", + "integrity": "sha512-C44M+m56rYn6QCsLbiKiedyPTMZxlDdEYAsPwwlL5bhMDDzXZ3Ic8OCQIhMbiunhCOJJT+er4URmOmM+sllnjg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-golang": { + "version": "6.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.18.tgz", + "integrity": "sha512-Mt+7NwfodDwUk7423DdaQa0YaA+4UoV3XSxQwZioqjpFBCuxfvvv4l80MxCTAAbK6duGj0uHbGTwpv8fyKYPKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-google": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.8.tgz", + "integrity": "sha512-BnMHgcEeaLyloPmBs8phCqprI+4r2Jb8rni011A8hE+7FNk7FmLE3kiwxLFrcZnnb7eqM0agW4zUaNoB0P+z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-haskell": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.5.tgz", + "integrity": "sha512-s4BG/4tlj2pPM9Ha7IZYMhUujXDnI0Eq1+38UTTCpatYLbQqDwRFf2KNPLRqkroU+a44yTUAe0rkkKbwy4yRtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.11.tgz", + "integrity": "sha512-QR3b/PB972SRQ2xICR1Nw/M44IJ6rjypwzA4jn+GH8ydjAX9acFNfc+hLZVyNe0FqsE90Gw3evLCOIF0vy1vQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html-symbol-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.3.tgz", + "integrity": "sha512-aABXX7dMLNFdSE8aY844X4+hvfK7977sOWgZXo4MTGAmOzR8524fjbJPswIBK7GaD3+SgFZ2yP2o0CFvXDGF+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-java": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.11.tgz", + "integrity": "sha512-T4t/1JqeH33Raa/QK/eQe26FE17eUCtWu+JsYcTLkQTci2dk1DfcIKo8YVHvZXBnuM43ATns9Xs0s+AlqDeH7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-julia": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.0.tgz", + "integrity": "sha512-CPUiesiXwy3HRoBR3joUseTZ9giFPCydSKu2rkh6I2nVjXnl5vFHzOMLXpbF4HQ1tH2CNfnDbUndxD+I+7eL9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-k8s": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.10.tgz", + "integrity": "sha512-313haTrX9prep1yWO7N6Xw4D6tvUJ0Xsx+YhCP+5YrrcIKoEw5Rtlg8R4PPzLqe6zibw6aJ+Eqq+y76Vx5BZkw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-kotlin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.0.tgz", + "integrity": "sha512-vySaVw6atY7LdwvstQowSbdxjXG6jDhjkWVWSjg1XsUckyzH1JRHXe9VahZz1i7dpoFEUOWQrhIe5B9482UyJQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-latex": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-4.0.3.tgz", + "integrity": "sha512-2KXBt9fSpymYHxHfvhUpjUFyzrmN4c4P8mwIzweLyvqntBT3k0YGZJSriOdjfUjwSygrfEwiuPI1EMrvgrOMJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lorem-ipsum": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.4.tgz", + "integrity": "sha512-+4f7vtY4dp2b9N5fn0za/UR0kwFq2zDtA62JCbWHbpjvO9wukkbl4rZg4YudHbBgkl73HRnXFgCiwNhdIA1JPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lua": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.7.tgz", + "integrity": "sha512-Wbr7YSQw+cLHhTYTKV6cAljgMgcY+EUAxVIZW3ljKswEe4OLxnVJ7lPqZF5JKjlXdgCjbPSimsHqyAbC5pQN/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-makefile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.4.tgz", + "integrity": "sha512-E4hG/c0ekPqUBvlkrVvzSoAA+SsDA9bLi4xSV3AXHTVru7Y2bVVGMPtpfF+fI3zTkww/jwinprcU1LSohI3ylw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-markdown": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.9.tgz", + "integrity": "sha512-j2e6Eg18BlTb1mMP1DkyRFMM/FLS7qiZjltpURzDckB57zDZbUyskOFdl4VX7jItZZEeY0fe22bSPOycgS1Z5A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@cspell/dict-css": "^4.0.17", + "@cspell/dict-html": "^4.0.11", + "@cspell/dict-html-symbol-entities": "^4.0.3", + "@cspell/dict-typescript": "^3.2.0" + } + }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.10.tgz", + "integrity": "sha512-7RTGyKsTIIVqzbvOtAu6Z/lwwxjGRtY5RkKPlXKHEoEAgIXwfDxb5EkVwzGQwQr8hF/D3HrdYbRT8MFBfsueZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-node": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.6.tgz", + "integrity": "sha512-CEbhPCpxGvRNByGolSBTrXXW2rJA4bGqZuTx1KKO85mwR6aadeOmUE7xf/8jiCkXSy+qvr9aJeh+jlfXcsrziQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-npm": { + "version": "5.1.26", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.26.tgz", + "integrity": "sha512-JU0/9P4nLPPC3Py+sF42tUKm9J4KAvwXaJubp2a4QwhCPzFVlOJTP2tTseFlLbdZn23d61pt0hZ+Jhyy7N76Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-php": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.14.tgz", + "integrity": "sha512-7zur8pyncYZglxNmqsRycOZ6inpDoVd4yFfz1pQRe5xaRWMiK3Km4n0/X/1YMWhh3e3Sl/fQg5Axb2hlN68t1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-powershell": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.14.tgz", + "integrity": "sha512-ktjjvtkIUIYmj/SoGBYbr3/+CsRGNXGpvVANrY0wlm/IoGlGywhoTUDYN0IsGwI2b8Vktx3DZmQkfb3Wo38jBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.13.tgz", + "integrity": "sha512-1Wdp/XH1ieim7CadXYE7YLnUlW0pULEjVl9WEeziZw3EKCAw8ZI8Ih44m4bEa5VNBLnuP5TfqC4iDautAleQzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-python": { + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.15.tgz", + "integrity": "sha512-VNXhj0Eh+hdHN89MgyaoSAexBQKmYtJaMhucbMI7XmBs4pf8fuFFN3xugk51/A4TZJr8+RImdFFsGMOw+I4bDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-data-science": "^2.0.7" + } + }, + "node_modules/@cspell/dict-r": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.0.tgz", + "integrity": "sha512-k2512wgGG0lTpTYH9w5Wwco+lAMf3Vz7mhqV8+OnalIE7muA0RSuD9tWBjiqLcX8zPvEJr4LdgxVju8Gk3OKyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-ruby": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.7.tgz", + "integrity": "sha512-4/d0hcoPzi5Alk0FmcyqlzFW9lQnZh9j07MJzPcyVO62nYJJAGKaPZL2o4qHeCS/od/ctJC5AHRdoUm0ktsw6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-rust": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.11.tgz", + "integrity": "sha512-OGWDEEzm8HlkSmtD8fV3pEcO2XBpzG2XYjgMCJCRwb2gRKvR+XIm6Dlhs04N/K2kU+iH8bvrqNpM8fS/BFl0uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-scala": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.7.tgz", + "integrity": "sha512-yatpSDW/GwulzO3t7hB5peoWwzo+Y3qTc0pO24Jf6f88jsEeKmDeKkfgPbYuCgbE4jisGR4vs4+jfQZDIYmXPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-shell": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.1.0.tgz", + "integrity": "sha512-D/xHXX7T37BJxNRf5JJHsvziFDvh23IF/KvkZXNSh8VqcRdod3BAz9VGHZf6VDqcZXr1VRqIYR3mQ8DSvs3AVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-software-terms": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.2.5.tgz", + "integrity": "sha512-CaRzkWti3AgcXoxuRcMijaNG7YUk/MH1rHjB8VX34v3UdCxXXeqvRyElRKnxhFeVLB/robb2UdShqh/CpskxRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-sql": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.0.tgz", + "integrity": "sha512-MUop+d1AHSzXpBvQgQkCiok8Ejzb+nrzyG16E8TvKL2MQeDwnIvMe3bv90eukP6E1HWb+V/MA/4pnq0pcJWKqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.6.tgz", + "integrity": "sha512-8LAJHSBdwHCoKCSy72PXXzz7ulGROD0rP1CQ0StOqXOOlTUeSFaJJlxNYjlONgd2c62XBQiN2wgLhtPN+1Zv7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-swift": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.5.tgz", + "integrity": "sha512-3lGzDCwUmnrfckv3Q4eVSW3sK3cHqqHlPprFJZD4nAqt23ot7fic5ALR7J4joHpvDz36nHX34TgcbZNNZOC/JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-terraform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.0.tgz", + "integrity": "sha512-G55pcUUxeXAhejstmD35B47SkFd4uqCQimc+CMgq8Nx0dr03guL2iMsz8faRWQGkCnGimX8S91rbOhDv9p/heg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-typescript": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.0.tgz", + "integrity": "sha512-Pk3zNePLT8qg51l0M4g1ISowYAEGxTuNfZlgkU5SvHa9Cu7x/BWoyYq9Fvc3kAyoisCjRPyvWF4uRYrPitPDFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-vue": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.4.tgz", + "integrity": "sha512-0dPtI0lwHcAgSiQFx8CzvqjdoXROcH+1LyqgROCpBgppommWpVhbQ0eubnKotFEXgpUCONVkeZJ6Ql8NbTEu+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dynamic-import": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.17.3.tgz", + "integrity": "sha512-Kg6IJhGHPv+9OxpxaXUpcqgnHEOhMLRWHLyx7FADZ+CJyO4AVeWQfhpTRM6KXhzIl7dPlLG1g8JAQxaoy88KTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "import-meta-resolve": "^4.1.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@cspell/filetypes": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.17.3.tgz", + "integrity": "sha512-UFqRmJPccOSo+RYP/jZ4cr0s7ni37GrvnNAg1H/qIIxfmBYsexTAmsNzMqxp1M31NeI1Cx3LL7PspPMT0ms+7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/strong-weak-map": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.17.3.tgz", + "integrity": "sha512-l/CaFc3CITI/dC+whEBZ05Om0KXR3V2whhVOWOBPIqA5lCjWAyvWWvmFD+CxWd0Hs6Qcb/YDnMyJW14aioXN4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/url": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.17.3.tgz", + "integrity": "sha512-gcsCz8g0qY94C8RXiAlUH/89n84Q9RSptP91XrvnLOT+Xva9Aibd7ywd5k9ameuf8Nagyl0ezB1MInZ30S9SRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0" + } + }, "node_modules/@csstools/color-helpers": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", @@ -3775,6 +4369,13 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -4400,6 +5001,13 @@ "node": ">=0.10.0" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -5687,6 +6295,35 @@ "node": ">=0.10.0" } }, + "node_modules/chalk-template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.0.tgz", + "integrity": "sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -5813,6 +6450,46 @@ "node": ">= 10.0" } }, + "node_modules/clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clear-module/node_modules/parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clear-module/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -5994,6 +6671,23 @@ "node": ">= 10" } }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -6492,6 +7186,275 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, + "node_modules/cspell": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.17.3.tgz", + "integrity": "sha512-fBZg674Dir9y/FWMwm2JyixM/1eB2vnqHJjRxOgGS/ZiZ3QdQ3LkK02Aqvlni8ffWYDZnYnYY9rfWmql9bb42w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-json-reporter": "8.17.3", + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "@cspell/dynamic-import": "8.17.3", + "@cspell/url": "8.17.3", + "chalk": "^5.4.1", + "chalk-template": "^1.1.0", + "commander": "^13.1.0", + "cspell-dictionary": "8.17.3", + "cspell-gitignore": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-io": "8.17.3", + "cspell-lib": "8.17.3", + "fast-json-stable-stringify": "^2.1.0", + "file-entry-cache": "^9.1.0", + "get-stdin": "^9.0.0", + "semver": "^7.6.3", + "tinyglobby": "^0.2.10" + }, + "bin": { + "cspell": "bin.mjs", + "cspell-esm": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" + } + }, + "node_modules/cspell-config-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.17.3.tgz", + "integrity": "sha512-+N32Q6xck3D2RqZIFwq8s0TnzHYMpyh4bgNtYqW5DIP3TLDiA4/MJGjwmLKAg/s9dkre6n8/++vVli3MZAOhIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "8.17.3", + "comment-json": "^4.2.5", + "yaml": "^2.7.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-dictionary": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.17.3.tgz", + "integrity": "sha512-89I/lpQKdkX17RCFrUIJnc70Rjfpup/o+ynHZen0hUxGTfLsEJPrK6H2oGvic3Yrv5q8IOtwM1p8vqPqBkBheA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "cspell-trie-lib": "8.17.3", + "fast-equals": "^5.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-gitignore": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.17.3.tgz", + "integrity": "sha512-rQamjb8R+Nwib/Bpcgf+xv5IdsOHgbP+fe4hCgv0jjgUPkeOR2c4dGwc0WS+2UkJbc+wQohpzBGDLRYGSB/hQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-io": "8.17.3", + "find-up-simple": "^1.0.0" + }, + "bin": { + "cspell-gitignore": "bin.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-glob": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.17.3.tgz", + "integrity": "sha512-0ov9A0E6OuOO7KOxlGCxJ09LR/ubZ6xcGwWc5bu+jp/8onUowQfe+9vZdznj/o8/vcf5JkDzyhRSBsdhWKqoAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-grammar": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.17.3.tgz", + "integrity": "sha512-wfjkkvHthnKJtEaTgx3cPUPquGRXfgXSCwvMJaDyUi36KBlopXX38PejBTdmuqrvp7bINLSuHErml9wAfL5Fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3" + }, + "bin": { + "cspell-grammar": "bin.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-io": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.17.3.tgz", + "integrity": "sha512-NwEVb3Kr8loV1C8Stz9QSMgUrBkxqf2s7A9H2/RBnfvQBt9CWZS6NgoNxTPwHj3h1sUNl9reDkMQQzkKtgWGBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-service-bus": "8.17.3", + "@cspell/url": "8.17.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.17.3.tgz", + "integrity": "sha512-KpwYIj8HwFyTzCCQcyezlmomvyNfPwZQmqTh4V126sFvf9HLoMdfyq8KYDZmZ//4HzwrF/ufJOF3CpuVUiJHfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-bundled-dicts": "8.17.3", + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-resolver": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "@cspell/dynamic-import": "8.17.3", + "@cspell/filetypes": "8.17.3", + "@cspell/strong-weak-map": "8.17.3", + "@cspell/url": "8.17.3", + "clear-module": "^4.1.2", + "comment-json": "^4.2.5", + "cspell-config-lib": "8.17.3", + "cspell-dictionary": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-grammar": "8.17.3", + "cspell-io": "8.17.3", + "cspell-trie-lib": "8.17.3", + "env-paths": "^3.0.0", + "fast-equals": "^5.2.2", + "gensequence": "^7.0.0", + "import-fresh": "^3.3.0", + "resolve-from": "^5.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.0.8", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-lib/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-lib/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cspell-trie-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.17.3.tgz", + "integrity": "sha512-6LE5BeT2Rwv0bkQckpxX0K1fnFCWfeJ8zVPFtYOaix0trtqj0VNuwWzYDnxyW+OwMioCH29yRAMODa+JDFfUrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "gensequence": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cspell/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/file-entry-cache": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", + "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/flat-cache": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.3.1", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/css-loader": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", @@ -7459,6 +8422,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz", + "integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", @@ -8480,6 +9452,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -8749,6 +9731,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/findup-sync": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", @@ -9023,6 +10018,16 @@ "node": ">= 4.0.0" } }, + "node_modules/gensequence": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", + "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9096,6 +10101,19 @@ "node": ">= 0.4" } }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -9198,6 +10216,32 @@ "process": "^0.11.10" } }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -9802,6 +10846,27 @@ "dev": true, "license": "MIT" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -9838,6 +10903,16 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -9890,6 +10965,11 @@ "node": ">= 0.10" } }, + "node_modules/hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==" + }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -10369,6 +11449,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imports-loader": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-5.0.0.tgz", @@ -11246,18 +12337,18 @@ "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", "license": "BSD-3-Clause" }, + "node_modules/jq-web": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/jq-web/-/jq-web-0.5.1.tgz", + "integrity": "sha512-3Fa3E6g3U1O1j46ljy0EM10yRr4txzILga8J7bqOG8F89gZ6Lilz82WG9z6TItWpYEO0YGa4W8yFGj+NMM1xqQ==", + "license": "ISC" + }, "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", "license": "MIT" }, - "node_modules/js-crc": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/js-crc/-/js-crc-0.2.0.tgz", - "integrity": "sha512-8DdCSAOACpF8WDAjyDFBC2rj8OS4HUP9mNZBDfl8jCiPCnJG+2bkuycalxwZh6heFy6PrMvoWTp47lp6gzT65A==", - "license": "MIT" - }, "node_modules/js-sha3": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", @@ -11403,6 +12494,14 @@ "node": ">=6" } }, + "node_modules/jsonata": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-2.0.6.tgz", + "integrity": "sha512-WhQB5tXQ32qjkx2GYHFw2XbL90u+LLzjofAYwi+86g6SyZeXHz9F1Q0amy3dWRYczshOC3Haok9J4pOCgHtwyQ==", + "engines": { + "node": ">= 8" + } + }, "node_modules/jsonpath-plus": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-9.0.0.tgz", @@ -12593,7 +13692,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, "license": "MIT" }, "node_modules/netmask": { @@ -12815,6 +13913,15 @@ "node": ">=8" } }, + "node_modules/nightwatch/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/nightwatch/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -14900,6 +16007,16 @@ "node": ">=8" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -15748,6 +16865,15 @@ "node": ">=0.8.0" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", @@ -15788,7 +16914,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -16486,6 +17611,48 @@ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", + "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -16993,13 +18160,15 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "license": "MIT", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/v8flags": { @@ -17031,6 +18200,20 @@ "integrity": "sha512-2ozZEFfmVvQcHWoHLNuiKlUfDKlhh4KGsy54U0UrlLMR1SO+XKAIDqBxtBwHgNrekurlJwE8A9K6L49T78ZQ9Q==", "license": "MIT" }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", @@ -17750,6 +18933,12 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, "node_modules/worker-loader": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-3.0.8.tgz", @@ -17941,6 +19130,19 @@ } } }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xhr": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", @@ -18042,6 +19244,19 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 7c8a97de0..9191ab6f0 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "compression-webpack-plugin": "^11.1.0", "copy-webpack-plugin": "^12.0.2", "core-js": "^3.37.1", + "cspell": "^8.17.3", "css-loader": "7.1.2", "eslint": "^9.4.0", "eslint-plugin-jsdoc": "^48.2.9", @@ -122,6 +123,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.0", + "dompurify": "^3.2.5", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -130,14 +132,17 @@ "file-saver": "^2.0.5", "flat": "^6.0.1", "geodesy": "1.1.3", + "handlebars": "^4.7.8", + "hash-wasm": "^4.12.0", "highlight.js": "^11.9.0", "ieee754": "^1.2.1", "jimp": "^0.22.12", + "jq-web": "^0.5.1", "jquery": "3.7.1", - "js-crc": "^0.2.0", "js-sha3": "^0.9.3", "jsesc": "^3.0.2", "json5": "^2.2.3", + "jsonata": "^2.0.3", "jsonpath-plus": "^9.0.0", "jsonwebtoken": "8.5.1", "jsqr": "^1.4.0", @@ -178,6 +183,7 @@ "ua-parser-js": "^1.0.38", "unorm": "^1.6.0", "utf8": "^3.0.0", + "uuid": "^11.1.0", "vkbeautify": "^0.99.3", "xpath": "0.0.34", "xregexp": "^5.1.1", @@ -193,6 +199,7 @@ "testui": "npx grunt testui", "testuidev": "npx nightwatch --env=dev", "lint": "npx grunt lint", + "lint:grammar": "cspell ./src", "postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule", "newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs", "minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index de3ea8826..434c8bb61 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -72,6 +72,8 @@ "Avro to JSON", "CBOR Encode", "CBOR Decode", + "YAML to JSON", + "JSON to YAML", "Caret/M-decode", "Rison Encode", "Rison Decode", @@ -193,7 +195,9 @@ "Parse SSH Host Key", "Parse CSR", "Public Key from Certificate", - "Public Key from Private Key" + "Public Key from Private Key", + "SM2 Encrypt", + "SM2 Decrypt" ] }, { @@ -290,6 +294,7 @@ "To Upper case", "To Lower case", "Swap case", + "Alternating Caps", "To Case Insensitive Regex", "From Case Insensitive Regex", "Add line numbers", @@ -365,11 +370,13 @@ "Regular expression", "XPath expression", "JPath expression", + "Jsonata Query", "CSS selector", "Extract EXIF", "Extract ID3", "Extract Files", - "RAKE" + "RAKE", + "Template" ] }, { @@ -400,6 +407,7 @@ "name": "Hashing", "ops": [ "Analyse hash", + "Generate all checksums", "Generate all hashes", "MD2", "MD4", @@ -418,6 +426,7 @@ "Snefru", "BLAKE2b", "BLAKE2s", + "BLAKE3", "GOST Hash", "Streebog", "SSDEEP", @@ -441,10 +450,9 @@ "Fletcher-64 Checksum", "Adler-32 Checksum", "Luhn Checksum", - "CRC-8 Checksum", - "CRC-16 Checksum", - "CRC-32 Checksum", - "TCP/IP Checksum" + "CRC Checksum", + "TCP/IP Checksum", + "XOR Checksum" ] }, { @@ -465,8 +473,10 @@ "CSS Minify", "XPath expression", "JPath expression", + "Jq", "CSS selector", "PHP Deserialize", + "PHP Serialize", "Microsoft Script Decoder", "Strip HTML tags", "Diff", @@ -541,6 +551,7 @@ "Pseudo-Random Number Generator", "Generate De Bruijn Sequence", "Generate UUID", + "Analyse UUID", "Generate TOTP", "Generate HOTP", "Generate QR Code", diff --git a/src/core/lib/Base32.mjs b/src/core/lib/Base32.mjs new file mode 100644 index 000000000..92b76eca7 --- /dev/null +++ b/src/core/lib/Base32.mjs @@ -0,0 +1,23 @@ +// import Utils from "../Utils.mjs"; + +/** + * Base32 resources. + * + * @author Peter C-S [petercs@purelymail.com] + * @license Apache-2.0 + */ + +/** + * Base32 alphabets. + */ +export const ALPHABET_OPTIONS = [ + { + name: "Standard", // https://www.rfc-editor.org/rfc/rfc4648#section-6 + value: "A-Z2-7=", + }, + { + name: "Hex Extended", // https://www.rfc-editor.org/rfc/rfc4648#section-7 + value: "0-9A-V=", + }, +]; + diff --git a/src/core/lib/Extract.mjs b/src/core/lib/Extract.mjs index 18fec28cf..3de2dd6d2 100644 --- a/src/core/lib/Extract.mjs +++ b/src/core/lib/Extract.mjs @@ -62,3 +62,9 @@ export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" * Domain name regular expression */ export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig; + + +/** + * DMARC Domain name regular expression + */ +export const DMARC_DOMAIN_REGEX = /\b((?=[a-z0-9_-]{1,63}\.)(xn--)?[a-z0-9_]+(-[a-z0-9_]+)*\.)+[a-z]{2,63}\b/ig; diff --git a/src/core/lib/SM2.mjs b/src/core/lib/SM2.mjs new file mode 100644 index 000000000..e81564106 --- /dev/null +++ b/src/core/lib/SM2.mjs @@ -0,0 +1,258 @@ +/** + * Utilities and operations utilized for SM2 encryption and decryption + * @author flakjacket95 [dflack95@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; +import { fromHex } from "../lib/Hex.mjs"; +import Utils from "../Utils.mjs"; +import Sm3 from "crypto-api/src/hasher/sm3.mjs"; +import {toHex} from "crypto-api/src/encoder/hex.mjs"; +import r from "jsrsasign"; + +/** + * SM2 Class for encryption and decryption operations + */ +export class SM2 { + /** + * Constructor for SM2 class; sets up with the curve and the output format as specified in user args + * + * @param {*} curve + * @param {*} format + */ + constructor(curve, format) { + this.ecParams = null; + this.rng = new r.SecureRandom(); + /* + For any additional curve definitions utilized by SM2, add another block like the below for that curve, then add the curve name to the Curve selection dropdown + */ + r.crypto.ECParameterDB.regist( + "sm2p256v1", // name / p = 2**256 - 2**224 - 2**96 + 2**64 - 1 + 256, + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", // p + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", // a + "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", // b + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", // n + "1", // h + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", // gx + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", // gy + [] + ); // alias + this.ecParams = r.crypto.ECParameterDB.getByName(curve); + + this.format = format; + } + + /** + * Set the public key coordinates for the SM2 class + * + * @param {string} publicKeyX + * @param {string} publicKeyY + */ + setPublicKey(publicKeyX, publicKeyY) { + /* + * TODO: This needs some additional length validation; and checking for errors in the decoding process + * TODO: Can probably support other public key encoding methods here as well in the future + */ + this.publicKey = this.ecParams.curve.decodePointHex("04" + publicKeyX + publicKeyY); + + if (this.publicKey.isInfinity()) { + throw new OperationError("Invalid Public Key"); + } + } + + /** + * Set the private key value for the SM2 class + * + * @param {string} privateKey + */ + setPrivateKey(privateKeyHex) { + this.privateKey = new r.BigInteger(privateKeyHex, 16); + } + + /** + * Main encryption function; takes user input, processes encryption and returns the result in hex (with the components arranged as configured by the user args) + * + * @param {*} input + * @returns {string} + */ + encrypt(input) { + const G = this.ecParams.G; + + /* + * Compute a new, random public key along the same elliptic curve to form the starting point for our encryption process (record the resulting X and Y as hex to provide as part of the operation output) + * k: Randomly generated BigInteger + * c1: Result of dotting our curve generator point `G` with the value of `k` + */ + const k = this.generatePublicKey(); + const c1 = G.multiply(k); + const [hexC1X, hexC1Y] = this.getPointAsHex(c1); + + /* + * Compute p2 (secret) using the public key, and the chosen k value above + */ + const p2 = this.publicKey.multiply(k); + + /* + * Compute the C3 SM3 hash before we transform the array + */ + const c3 = this.c3(p2, input); + + /* + * Genreate a proper length encryption key, XOR iteratively, and convert newly encrypted data to hex + */ + const key = this.kdf(p2, input.byteLength); + for (let i = 0; i < input.byteLength; i++) { + input[i] ^= Utils.ord(key[i]); + } + const c2 = Buffer.from(input).toString("hex"); + + /* + * Check user input specs; order the output components as selected + */ + if (this.format === "C1C3C2") { + return hexC1X + hexC1Y + c3 + c2; + } else { + return hexC1X + hexC1Y + c2 + c3; + } + } + /** + * Function to decrypt an SM2 encrypted message + * + * @param {*} input + */ + decrypt(input) { + const c1X = input.slice(0, 64); + const c1Y = input.slice(64, 128); + + let c3 = ""; + let c2 = ""; + + if (this.format === "C1C3C2") { + c3 = input.slice(128, 192); + c2 = input.slice(192); + } else { + c2 = input.slice(128, -64); + c3 = input.slice(-64); + } + c2 = Uint8Array.from(fromHex(c2)); + const c1 = this.ecParams.curve.decodePointHex("04" + c1X + c1Y); + + /* + * Compute the p2 (secret) value by taking the C1 point provided in the encrypted package, and multiplying by the private k value + */ + const p2 = c1.multiply(this.privateKey); + + /* + * Similar to encryption; compute sufficient length key material and XOR the input data to recover the original message + */ + const key = this.kdf(p2, c2.byteLength); + + for (let i = 0; i < c2.byteLength; i++) { + c2[i] ^= Utils.ord(key[i]); + } + + const check = this.c3(p2, c2); + if (check === c3) { + return c2.buffer; + } else { + throw new OperationError("Decryption Error -- Computed Hashes Do Not Match"); + } + } + + + /** + * Generates a large random number + * + * @param {*} limit + * @returns + */ + getBigRandom(limit) { + return new r.BigInteger(limit.bitLength(), this.rng) + .mod(limit.subtract(r.BigInteger.ONE)) + .add(r.BigInteger.ONE); + } + + /** + * Helper function for generating a large random K number; utilized for generating our initial C1 point + * TODO: Do we need to do any sort of validation on the resulting k values? + * + * @returns {BigInteger} + */ + generatePublicKey() { + const n = this.ecParams.n; + const k = this.getBigRandom(n); + return k; + } + + /** + * SM2 Key Derivation Function (KDF); Takes P2 point, and generates a key material stream large enough to encrypt all of the input data + * + * @param {*} p2 + * @param {*} len + * @returns {string} + */ + kdf(p2, len) { + const [hX, hY] = this.getPointAsHex(p2); + + const total = Math.ceil(len / 32) + 1; + let cnt = 1; + + let keyMaterial = ""; + + while (cnt < total) { + const num = Utils.intToByteArray(cnt, 4, "big"); + const overall = fromHex(hX).concat(fromHex(hY)).concat(num); + keyMaterial += this.sm3(overall); + cnt++; + } + return keyMaterial; + } + + /** + * Calculates the C3 component of our final encrypted payload; which is the SM3 hash of the P2 point and the original, unencrypted input data + * + * @param {*} p2 + * @param {*} input + * @returns {string} + */ + c3(p2, input) { + const [hX, hY] = this.getPointAsHex(p2); + + const overall = fromHex(hX).concat(Array.from(input)).concat(fromHex(hY)); + + return toHex(this.sm3(overall)); + + } + + /** + * SM3 setup helper function; takes input data as an array, processes the hash and returns the result + * + * @param {*} data + * @returns {string} + */ + sm3(data) { + const hashData = Utils.arrayBufferToStr(Uint8Array.from(data).buffer, false); + const hasher = new Sm3(); + hasher.update(hashData); + return hasher.finalize(); + } + + /** + * Utility function, returns an elliptic curve points X and Y values as hex; + * + * @param {EcPointFp} point + * @returns {[]} + */ + getPointAsHex(point) { + const biX = point.getX().toBigInteger(); + const biY = point.getY().toBigInteger(); + + const charlen = this.ecParams.keycharlen; + const hX = ("0000000000" + biX.toString(16)).slice(- charlen); + const hY = ("0000000000" + biY.toString(16)).slice(- charlen); + return [hX, hY]; + } +} diff --git a/src/core/operations/AESDecrypt.mjs b/src/core/operations/AESDecrypt.mjs index e24a5119b..5e6cec264 100644 --- a/src/core/operations/AESDecrypt.mjs +++ b/src/core/operations/AESDecrypt.mjs @@ -112,7 +112,7 @@ class AESDecrypt extends Operation { run(input, args) { const key = Utils.convertToByteString(args[0].string, args[0].option), iv = Utils.convertToByteString(args[1].string, args[1].option), - mode = args[2].substring(0, 3), + mode = args[2].split("/")[0], noPadding = args[2].endsWith("NoPadding"), inputType = args[3], outputType = args[4], diff --git a/src/core/operations/AESEncrypt.mjs b/src/core/operations/AESEncrypt.mjs index 7b52ff039..84e1c5405 100644 --- a/src/core/operations/AESEncrypt.mjs +++ b/src/core/operations/AESEncrypt.mjs @@ -66,6 +66,14 @@ class AESEncrypt extends Operation { { name: "ECB", off: [5] + }, + { + name: "CBC/NoPadding", + off: [5] + }, + { + name: "ECB/NoPadding", + off: [5] } ] }, @@ -98,7 +106,8 @@ class AESEncrypt extends Operation { run(input, args) { const key = Utils.convertToByteString(args[0].string, args[0].option), iv = Utils.convertToByteString(args[1].string, args[1].option), - mode = args[2], + mode = args[2].split("/")[0], + noPadding = args[2].endsWith("NoPadding"), inputType = args[3], outputType = args[4], aad = Utils.convertToByteString(args[5].string, args[5].option); @@ -114,11 +123,20 @@ The following algorithms will be used based on the size of the key: input = Utils.convertToByteString(input, inputType); + // Handle NoPadding modes + if (noPadding && input.length % 16 !== 0) { + throw new OperationError("Input length must be a multiple of 16 bytes for NoPadding modes."); + } const cipher = forge.cipher.createCipher("AES-" + mode, key); cipher.start({ iv: iv, additionalData: mode === "GCM" ? aad : undefined }); + if (noPadding) { + cipher.mode.pad = function(output, options) { + return true; + }; + } cipher.update(forge.util.createBuffer(input)); cipher.finish(); diff --git a/src/core/operations/AlternatingCaps.mjs b/src/core/operations/AlternatingCaps.mjs new file mode 100644 index 000000000..2d54867c4 --- /dev/null +++ b/src/core/operations/AlternatingCaps.mjs @@ -0,0 +1,53 @@ +/** + * @author sw5678 + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Alternating caps operation + */ +class AlternatingCaps extends Operation { + + /** + * AlternatingCaps constructor + */ + constructor() { + super(); + + this.name = "Alternating Caps"; + this.module = "Default"; + this.description = "Alternating caps, also known as studly caps, sticky caps, or spongecase is a form of text notation in which the capitalization of letters varies by some pattern, or arbitrarily. An example of this would be spelling 'alternative caps' as 'aLtErNaTiNg CaPs'."; + this.infoURL = "https://en.wikipedia.org/wiki/Alternating_caps"; + this.inputType = "string"; + this.outputType = "string"; + this.args= []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + let output = ""; + let previousCaps = true; + for (let i = 0; i < input.length; i++) { + // Check if the element is a letter + if (!RegExp(/^\p{L}/, "u").test(input[i])) { + output += input[i]; + } else if (previousCaps) { + output += input[i].toLowerCase(); + previousCaps = false; + } else { + output += input[i].toUpperCase(); + previousCaps = true; + } + } + return output; + } +} + +export default AlternatingCaps; diff --git a/src/core/operations/AnalyseUUID.mjs b/src/core/operations/AnalyseUUID.mjs new file mode 100644 index 000000000..b35060179 --- /dev/null +++ b/src/core/operations/AnalyseUUID.mjs @@ -0,0 +1,48 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import * as uuid from "uuid"; + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * Analyse UUID operation + */ +class AnalyseUUID extends Operation { + + /** + * AnalyseUUID constructor + */ + constructor() { + super(); + + this.name = "Analyse UUID"; + this.module = "Crypto"; + this.description = "Tries to determine information about a given UUID and suggests which version may have been used to generate it"; + this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + try { + const uuidVersion = uuid.version(input); + return "UUID version: " + uuidVersion; + } catch (error) { + throw new OperationError("Invalid UUID"); + } + } + +} + +export default AnalyseUUID; diff --git a/src/core/operations/BLAKE3.mjs b/src/core/operations/BLAKE3.mjs new file mode 100644 index 000000000..0f686120a --- /dev/null +++ b/src/core/operations/BLAKE3.mjs @@ -0,0 +1,58 @@ +/** + * @author xumptex [xumptex@outlook.fr] + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { blake3 } from "hash-wasm"; +/** + * BLAKE3 operation + */ +class BLAKE3 extends Operation { + + /** + * BLAKE3 constructor + */ + constructor() { + super(); + + this.name = "BLAKE3"; + this.module = "Hashing"; + this.description = "Hashes the input using BLAKE3 (UTF-8 encoded), with an optional key (also UTF-8), and outputs the result in hexadecimal format."; + this.infoURL = "https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE3"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Size (bytes)", + "type": "number" + }, { + "name": "Key", + "type": "string", + "value": "" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = args[1]; + const size = args[0]; + // Check if the user want a key hash or not + if (key === "") { + return blake3(input, size*8); + } if (key.length !== 32) { + throw new OperationError("The key must be exactly 32 bytes long"); + } + return blake3(input, size*8, key); + } + +} + +export default BLAKE3; diff --git a/src/core/operations/CRC16Checksum.mjs b/src/core/operations/CRC16Checksum.mjs deleted file mode 100644 index 035ee04b3..000000000 --- a/src/core/operations/CRC16Checksum.mjs +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @author n1474335 [n1474335@gmail.com] - * @copyright Crown Copyright 2016 - * @license Apache-2.0 - */ - -import Operation from "../Operation.mjs"; -import JSCRC from "js-crc"; - -/** - * CRC-16 Checksum operation - */ -class CRC16Checksum extends Operation { - - /** - * CRC16Checksum constructor - */ - constructor() { - super(); - - this.name = "CRC-16 Checksum"; - this.module = "Crypto"; - this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.

The CRC was invented by W. Wesley Peterson in 1961."; - this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check"; - this.inputType = "ArrayBuffer"; - this.outputType = "string"; - this.args = []; - } - - /** - * @param {ArrayBuffer} input - * @param {Object[]} args - * @returns {string} - */ - run(input, args) { - return JSCRC.crc16(input); - } - -} - -export default CRC16Checksum; diff --git a/src/core/operations/CRC32Checksum.mjs b/src/core/operations/CRC32Checksum.mjs deleted file mode 100644 index cfe846438..000000000 --- a/src/core/operations/CRC32Checksum.mjs +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @author n1474335 [n1474335@gmail.com] - * @copyright Crown Copyright 2016 - * @license Apache-2.0 - */ - -import Operation from "../Operation.mjs"; -import JSCRC from "js-crc"; - -/** - * CRC-32 Checksum operation - */ -class CRC32Checksum extends Operation { - - /** - * CRC32Checksum constructor - */ - constructor() { - super(); - - this.name = "CRC-32 Checksum"; - this.module = "Crypto"; - this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.

The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975."; - this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check"; - this.inputType = "ArrayBuffer"; - this.outputType = "string"; - this.args = []; - } - - /** - * @param {ArrayBuffer} input - * @param {Object[]} args - * @returns {string} - */ - run(input, args) { - return JSCRC.crc32(input); - } - -} - -export default CRC32Checksum; diff --git a/src/core/operations/CRC8Checksum.mjs b/src/core/operations/CRC8Checksum.mjs deleted file mode 100644 index 193cadf98..000000000 --- a/src/core/operations/CRC8Checksum.mjs +++ /dev/null @@ -1,157 +0,0 @@ -/** - * @author mshwed [m@ttshwed.com] - * @copyright Crown Copyright 2019 - * @license Apache-2.0 - */ - -import Operation from "../Operation.mjs"; -import OperationError from "../errors/OperationError.mjs"; - -import { toHexFast } from "../lib/Hex.mjs"; - -/** - * CRC-8 Checksum operation - */ -class CRC8Checksum extends Operation { - - /** - * CRC8Checksum constructor - */ - constructor() { - super(); - - this.name = "CRC-8 Checksum"; - this.module = "Crypto"; - this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.

The CRC was invented by W. Wesley Peterson in 1961."; - this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check"; - this.inputType = "ArrayBuffer"; - this.outputType = "string"; - this.args = [ - { - "name": "Algorithm", - "type": "option", - "value": [ - "CRC-8", - "CRC-8/CDMA2000", - "CRC-8/DARC", - "CRC-8/DVB-S2", - "CRC-8/EBU", - "CRC-8/I-CODE", - "CRC-8/ITU", - "CRC-8/MAXIM", - "CRC-8/ROHC", - "CRC-8/WCDMA" - ] - } - ]; - } - - /** - * Generates the pre-computed lookup table for byte division - * - * @param polynomial - */ - calculateCRC8LookupTable(polynomial) { - const crc8Table = new Uint8Array(256); - - let currentByte; - for (let i = 0; i < 256; i++) { - currentByte = i; - for (let bit = 0; bit < 8; bit++) { - if ((currentByte & 0x80) !== 0) { - currentByte <<= 1; - currentByte ^= polynomial; - } else { - currentByte <<= 1; - } - } - - crc8Table[i] = currentByte; - } - - return crc8Table; - } - - /** - * Calculates the CRC-8 Checksum from an input - * - * @param {ArrayBuffer} input - * @param {number} polynomial - * @param {number} initializationValue - * @param {boolean} inputReflection - * @param {boolean} outputReflection - * @param {number} xorOut - */ - calculateCRC8(input, polynomial, initializationValue, inputReflection, outputReflection, xorOut) { - const crcSize = 8; - const crcTable = this.calculateCRC8LookupTable(polynomial); - - let crc = initializationValue !== 0 ? initializationValue : 0; - let currentByte, position; - - input = new Uint8Array(input); - for (const inputByte of input) { - currentByte = inputReflection ? this.reverseBits(inputByte, crcSize) : inputByte; - - position = (currentByte ^ crc) & 255; - crc = crcTable[position]; - } - - crc = outputReflection ? this.reverseBits(crc, crcSize) : crc; - - if (xorOut !== 0) crc = crc ^ xorOut; - - return toHexFast(new Uint8Array([crc])); - } - - /** - * Reverse the bits for a given input byte. - * - * @param {number} input - */ - reverseBits(input, hashSize) { - let reversedByte = 0; - for (let i = hashSize - 1; i >= 0; i--) { - reversedByte |= ((input & 1) << i); - input >>= 1; - } - - return reversedByte; - } - - /** - * @param {ArrayBuffer} input - * @param {Object[]} args - * @returns {string} - */ - run(input, args) { - const algorithm = args[0]; - - switch (algorithm) { - case "CRC-8": - return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x0); - case "CRC-8/CDMA2000": - return this.calculateCRC8(input, 0x9B, 0xFF, false, false, 0x0); - case "CRC-8/DARC": - return this.calculateCRC8(input, 0x39, 0x0, true, true, 0x0); - case "CRC-8/DVB-S2": - return this.calculateCRC8(input, 0xD5, 0x0, false, false, 0x0); - case "CRC-8/EBU": - return this.calculateCRC8(input, 0x1D, 0xFF, true, true, 0x0); - case "CRC-8/I-CODE": - return this.calculateCRC8(input, 0x1D, 0xFD, false, false, 0x0); - case "CRC-8/ITU": - return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x55); - case "CRC-8/MAXIM": - return this.calculateCRC8(input, 0x31, 0x0, true, true, 0x0); - case "CRC-8/ROHC": - return this.calculateCRC8(input, 0x7, 0xFF, true, true, 0x0); - case "CRC-8/WCDMA": - return this.calculateCRC8(input, 0x9B, 0x0, true, true, 0x0); - default: - throw new OperationError("Unknown checksum algorithm"); - } - } -} - -export default CRC8Checksum; diff --git a/src/core/operations/CRCChecksum.mjs b/src/core/operations/CRCChecksum.mjs new file mode 100644 index 000000000..88da2fa5a --- /dev/null +++ b/src/core/operations/CRCChecksum.mjs @@ -0,0 +1,1110 @@ +/** + * @author r4mos [2k95ljkhg@mozmail.com] + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * CRC Checksum operation + */ +class CRCChecksum extends Operation { + + /** + * CRCChecksum constructor + */ + constructor() { + super(); + + this.name = "CRC Checksum"; + this.module = "Default"; + this.description = "A Cyclic Redundancy Check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data."; + this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check"; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = [ + { + name: "Algorithm", + type: "argSelector", + value: [ + { + name: "Custom", + on: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-3/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-3/ROHC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-4/G-704", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-4/INTERLAKEN", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-4/ITU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-5/EPC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-5/EPC-C1G2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-5/G-704", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-5/ITU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-5/USB", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/CDMA2000-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/CDMA2000-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/DARC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/G-704", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-6/ITU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-7/MMC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-7/ROHC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-7/UMTS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/8H2F", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/AES", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/AUTOSAR", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/BLUETOOTH", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/CDMA2000", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/DARC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/DVB-S2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/EBU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/GSM-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/GSM-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/HITAG", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/I-432-1", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/I-CODE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/ITU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/LTE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/MAXIM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/MAXIM-DOW", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/MIFARE-MAD", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/NRSC-5", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/OPENSAFETY", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/ROHC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/SAE-J1850", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/SAE-J1850-ZERO", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/SMBUS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/TECH-3250", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-8/WCDMA", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-10/ATM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-10/CDMA2000", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-10/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-10/I-610", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-11/FLEXRAY", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-11/UMTS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-12/3GPP", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-12/CDMA2000", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-12/DECT", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-12/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-12/UMTS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-13/BBC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-14/DARC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-14/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-15/CAN", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-15/MPT1327", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ACORN", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ARC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/AUG-CCITT", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/AUTOSAR", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/BLUETOOTH", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/BUYPASS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CCITT", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CCITT-FALSE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CCITT-TRUE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CCITT-ZERO", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CDMA2000", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/CMS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/DARC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/DDS-110", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/DECT-R", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/DECT-X", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/DNP", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/EN-13757", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/EPC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/EPC-C1G2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/GENIBUS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/I-CODE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/IBM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/IBM-3740", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/IBM-SDLC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/IEC-61158-2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ISO-HDLC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ISO-IEC-14443-3-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ISO-IEC-14443-3-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/KERMIT", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/LHA", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/LJ1200", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/LTE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/M17", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/MAXIM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/MAXIM-DOW", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/MCRF4XX", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/MODBUS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/NRSC-5", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/OPENSAFETY-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/OPENSAFETY-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/PROFIBUS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/RIELLO", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/SPI-FUJITSU", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/T10-DIF", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/TELEDISK", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/TMS37157", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/UMTS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/USB", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/V-41-LSB", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/V-41-MSB", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/VERIFONE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/X-25", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/XMODEM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-16/ZMODEM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-17/CAN-FD", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-21/CAN-FD", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/BLE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/FLEXRAY-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/FLEXRAY-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/INTERLAKEN", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/LTE-A", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/LTE-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/OPENPGP", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-24/OS-9", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-30/CDMA", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-31/PHILIPS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/AAL5", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/ADCCP", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/AIXM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/AUTOSAR", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/BASE91-C", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/BASE91-D", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/BZIP2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/C", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/CASTAGNOLI", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/CD-ROM-EDC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/CKSUM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/D", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/DECT-B", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/INTERLAKEN", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/ISCSI", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/ISO-HDLC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/JAMCRC", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/MEF", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/MPEG-2", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/NVME", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/PKZIP", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/POSIX", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/Q", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/SATA", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/V-42", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/XFER", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-32/XZ", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-40/GSM", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/ECMA-182", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/GO-ECMA", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/GO-ISO", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/MS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/NVME", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/REDIS", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/WE", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-64/XZ", + off: [1, 2, 3, 4, 5, 6] + }, + { + name: "CRC-82/DARC", + off: [1, 2, 3, 4, 5, 6] + } + ] + }, + { + name: "Width (bits)", + type: "toggleString", + value: "0", + toggleValues: ["Decimal"] + }, + { + name: "Polynomial", + type: "toggleString", + value: "0", + toggleValues: ["Hex"] + }, + { + name: "Initialization", + type: "toggleString", + value: "0", + toggleValues: ["Hex"] + }, + { + name: "Reflect input", + type: "option", + value: ["True", "False"] + }, + { + name: "Reflect output", + type: "option", + value: ["True", "False"] + }, + { + name: "Xor Output", + type: "toggleString", + value: "0", + toggleValues: ["Hex"] + } + ]; + } + + /** + * Reverse the order of bits in a number + * + * @param {BigInt} data + * @param {BigInt} reflect + */ + reflectData(data, reflect) { + let value = 0n; + for (let bit = 0n; bit < reflect; bit++) { + if ((data & 1n) === 1n) { + value |= (1n << ((reflect - 1n) - bit)); + } + data >>= 1n; + } + return value; + } + + /** + * Performs the CRC Checksum calculation bit per bit without acceleration + * + * @param {BigInt} width + * @param {ArrayBuffer} input + * @param {BigInt} poly + * @param {BigInt} remainder + * @param {boolean} reflectIn + * @param {boolean} reflectOut + * @param {BigInt} xorOut + */ + calculateCrcBitPerBit(width, input, poly, remainder, reflectIn, reflectOut, xorOut) { + const TOP_BIT = 1n << (width - 1n); + const MASK = (1n << width) - 1n; + + for (let byte of input) { + byte = BigInt(byte); + if (reflectIn) { + byte = this.reflectData(byte, 8n); + } + + for (let i = 0x80n; i !== 0n; i >>= 1n) { + let bit = remainder & TOP_BIT; + + remainder = (remainder << 1n) & MASK; + + if ((byte & i) !== 0n) { + bit ^= TOP_BIT; + } + + if (bit !== 0n) { + remainder ^= poly; + } + } + } + + if (reflectOut) { + remainder = this.reflectData(remainder, width); + } + + return remainder ^ xorOut; + } + + /** + * Generates the necessary table to speed up the calculation + * + * @param {BigInt} width + * @param {BigInt} poly + * @param {BigInt} MASK + * @param {BigInt} TOP_BIT + */ + generateTable(width, poly, MASK, TOP_BIT) { + const table = new Array(256n); + for (let byte = 0n; byte < 256n; byte++) { + let value = ((byte << width - 8n) & MASK); + for (let bit = 0n; bit < 8n; bit++) { + value = (value & TOP_BIT) === 0n ? + ((value << 1n) & MASK) : + ((value << 1n) & MASK) ^ poly; + } + table[byte] = value; + } + return table; + } + + /** + * Performs the CRC Checksum calculation byte per byte using a computed table to accelerate it + * + * @param {BigInt} width + * @param {ArrayBuffer} input + * @param {BigInt} poly + * @param {BigInt} remainder + * @param {boolean} reflectIn + * @param {boolean} reflectOut + * @param {BigInt} xorOut + */ + calculateCrcBytePerByte(width, input, poly, remainder, reflectIn, reflectOut, xorOut) { + const TOP_BIT = 1n << (width - 1n); + const MASK = (1n << width) - 1n; + const TABLE = this.generateTable(width, poly, MASK, TOP_BIT); + + for (let byte of input) { + byte = BigInt(byte); + if (reflectIn) { + byte = this.reflectData(byte, 8n); + } + remainder ^= (byte << width - 8n) & MASK; + + const INDEX = remainder >> width - 8n; + remainder = (remainder << 8n) & MASK; + remainder ^= TABLE[INDEX]; + } + + if (reflectOut) { + remainder = this.reflectData(remainder, width); + } + return remainder ^ xorOut; + } + + /** + * Calculates the CRC Checksum using Bigint (https://developer.mozilla.org/en-US/docs/Glossary/BigInt) + * + * @param {BigInt} width + * @param {ArrayBuffer} input + * @param {BigInt} poly + * @param {BigInt} init + * @param {boolean} reflectIn + * @param {boolean} reflectOut + * @param {BigInt} xorOut + */ + crc(width, input, poly, init, reflectIn, reflectOut, xorOut) { + const VALUE = width < 8n ? + this.calculateCrcBitPerBit(width, input, poly, init, reflectIn, reflectOut, xorOut) : + this.calculateCrcBytePerByte(width, input, poly, init, reflectIn, reflectOut, xorOut); + + return VALUE.toString(16).padStart(Math.ceil(Number(width) / 4), "0"); + } + + /** + * Validates user input to perform a custom CRC + * + * @param {Object} widthObject + * @param {ArrayBuffer} input + * @param {Object} polyObject + * @param {Object} initObject + * @param {Object} reflectInObject + * @param {Object} reflectOutObject + * @param {Object} xorOutObject + */ + custom(widthObject, input, polyObject, initObject, reflectInObject, reflectOutObject, xorOutObject) { + try { + const width = BigInt(widthObject.string); + const poly = BigInt("0x" + polyObject.string); + const init = BigInt("0x" + initObject.string); + const reflectIn = reflectInObject === "True"; + const reflectOut = reflectOutObject === "True"; + const xorOut = BigInt("0x" + xorOutObject.string); + + return this.crc(width, input, poly, init, reflectIn, reflectOut, xorOut); + } catch (error) { + throw new OperationError("Invalid custom CRC arguments"); + } + } + + /** + * Calculation of all known CRCs. Names and constants extracted from https://reveng.sourceforge.io/crc-catalogue/all.htm + * + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const algorithm = args[0]; + input = new Uint8Array(input); + + switch (algorithm) { + case "Custom": return this.custom(args[1], input, args[2], args[3], args[4], args[5], args[6]); + case "CRC-3/GSM": return this.crc(3n, input, 0x3n, 0x0n, false, false, 0x7n); + case "CRC-3/ROHC": return this.crc(3n, input, 0x3n, 0x7n, true, true, 0x0n); + case "CRC-4/G-704": return this.crc(4n, input, 0x3n, 0x0n, true, true, 0x0n); + case "CRC-4/INTERLAKEN": return this.crc(4n, input, 0x3n, 0xFn, false, false, 0xFn); + case "CRC-4/ITU": return this.crc(4n, input, 0x3n, 0x0n, true, true, 0x0n); + case "CRC-5/EPC": return this.crc(5n, input, 0x09n, 0x09n, false, false, 0x00n); + case "CRC-5/EPC-C1G2": return this.crc(5n, input, 0x09n, 0x09n, false, false, 0x00n); + case "CRC-5/G-704": return this.crc(5n, input, 0x15n, 0x00n, true, true, 0x00n); + case "CRC-5/ITU": return this.crc(5n, input, 0x15n, 0x00n, true, true, 0x00n); + case "CRC-5/USB": return this.crc(5n, input, 0x05n, 0x1Fn, true, true, 0x1Fn); + case "CRC-6/CDMA2000-A": return this.crc(6n, input, 0x27n, 0x3Fn, false, false, 0x00n); + case "CRC-6/CDMA2000-B": return this.crc(6n, input, 0x07n, 0x3Fn, false, false, 0x00n); + case "CRC-6/DARC": return this.crc(6n, input, 0x19n, 0x00n, true, true, 0x00n); + case "CRC-6/G-704": return this.crc(6n, input, 0x03n, 0x00n, true, true, 0x00n); + case "CRC-6/GSM": return this.crc(6n, input, 0x2Fn, 0x00n, false, false, 0x3Fn); + case "CRC-6/ITU": return this.crc(6n, input, 0x03n, 0x00n, true, true, 0x00n); + case "CRC-7/MMC": return this.crc(7n, input, 0x09n, 0x00n, false, false, 0x00n); + case "CRC-7/ROHC": return this.crc(7n, input, 0x4Fn, 0x7Fn, true, true, 0x00n); + case "CRC-7/UMTS": return this.crc(7n, input, 0x45n, 0x00n, false, false, 0x00n); + case "CRC-8": return this.crc(8n, input, 0x07n, 0x00n, false, false, 0x00n); + case "CRC-8/8H2F": return this.crc(8n, input, 0x2Fn, 0xFFn, false, false, 0xFFn); + case "CRC-8/AES": return this.crc(8n, input, 0x1Dn, 0xFFn, true, true, 0x00n); + case "CRC-8/AUTOSAR": return this.crc(8n, input, 0x2Fn, 0xFFn, false, false, 0xFFn); + case "CRC-8/BLUETOOTH": return this.crc(8n, input, 0xA7n, 0x00n, true, true, 0x00n); + case "CRC-8/CDMA2000": return this.crc(8n, input, 0x9Bn, 0xFFn, false, false, 0x00n); + case "CRC-8/DARC": return this.crc(8n, input, 0x39n, 0x00n, true, true, 0x00n); + case "CRC-8/DVB-S2": return this.crc(8n, input, 0xD5n, 0x00n, false, false, 0x00n); + case "CRC-8/EBU": return this.crc(8n, input, 0x1Dn, 0xFFn, true, true, 0x00n); + case "CRC-8/GSM-A": return this.crc(8n, input, 0x1Dn, 0x00n, false, false, 0x00n); + case "CRC-8/GSM-B": return this.crc(8n, input, 0x49n, 0x00n, false, false, 0xFFn); + case "CRC-8/HITAG": return this.crc(8n, input, 0x1Dn, 0xFFn, false, false, 0x00n); + case "CRC-8/I-432-1": return this.crc(8n, input, 0x07n, 0x00n, false, false, 0x55n); + case "CRC-8/I-CODE": return this.crc(8n, input, 0x1Dn, 0xFDn, false, false, 0x00n); + case "CRC-8/ITU": return this.crc(8n, input, 0x07n, 0x00n, false, false, 0x55n); + case "CRC-8/LTE": return this.crc(8n, input, 0x9Bn, 0x00n, false, false, 0x00n); + case "CRC-8/MAXIM": return this.crc(8n, input, 0x31n, 0x00n, true, true, 0x00n); + case "CRC-8/MAXIM-DOW": return this.crc(8n, input, 0x31n, 0x00n, true, true, 0x00n); + case "CRC-8/MIFARE-MAD": return this.crc(8n, input, 0x1Dn, 0xC7n, false, false, 0x00n); + case "CRC-8/NRSC-5": return this.crc(8n, input, 0x31n, 0xFFn, false, false, 0x00n); + case "CRC-8/OPENSAFETY": return this.crc(8n, input, 0x2Fn, 0x00n, false, false, 0x00n); + case "CRC-8/ROHC": return this.crc(8n, input, 0x07n, 0xFFn, true, true, 0x00n); + case "CRC-8/SAE-J1850": return this.crc(8n, input, 0x1Dn, 0xFFn, false, false, 0xFFn); + case "CRC-8/SAE-J1850-ZERO": return this.crc(8n, input, 0x1Dn, 0x00n, false, false, 0x00n); + case "CRC-8/SMBUS": return this.crc(8n, input, 0x07n, 0x00n, false, false, 0x00n); + case "CRC-8/TECH-3250": return this.crc(8n, input, 0x1Dn, 0xFFn, true, true, 0x00n); + case "CRC-8/WCDMA": return this.crc(8n, input, 0x9Bn, 0x00n, true, true, 0x00n); + case "CRC-10/ATM": return this.crc(10n, input, 0x233n, 0x000n, false, false, 0x000n); + case "CRC-10/CDMA2000": return this.crc(10n, input, 0x3D9n, 0x3FFn, false, false, 0x000n); + case "CRC-10/GSM": return this.crc(10n, input, 0x175n, 0x000n, false, false, 0x3FFn); + case "CRC-10/I-610": return this.crc(10n, input, 0x233n, 0x000n, false, false, 0x000n); + case "CRC-11/FLEXRAY": return this.crc(11n, input, 0x385n, 0x01An, false, false, 0x000n); + case "CRC-11/UMTS": return this.crc(11n, input, 0x307n, 0x000n, false, false, 0x000n); + case "CRC-12/3GPP": return this.crc(12n, input, 0x80Fn, 0x000n, false, true, 0x000n); + case "CRC-12/CDMA2000": return this.crc(12n, input, 0xF13n, 0xFFFn, false, false, 0x000n); + case "CRC-12/DECT": return this.crc(12n, input, 0x80Fn, 0x000n, false, false, 0x000n); + case "CRC-12/GSM": return this.crc(12n, input, 0xD31n, 0x000n, false, false, 0xFFFn); + case "CRC-12/UMTS": return this.crc(12n, input, 0x80Fn, 0x000n, false, true, 0x000n); + case "CRC-13/BBC": return this.crc(13n, input, 0x1CF5n, 0x0000n, false, false, 0x0000n); + case "CRC-14/DARC": return this.crc(14n, input, 0x0805n, 0x0000n, true, true, 0x0000n); + case "CRC-14/GSM": return this.crc(14n, input, 0x202Dn, 0x0000n, false, false, 0x3FFFn); + case "CRC-15/CAN": return this.crc(15n, input, 0x4599n, 0x0000n, false, false, 0x0000n); + case "CRC-15/MPT1327": return this.crc(15n, input, 0x6815n, 0x0000n, false, false, 0x0001n); + case "CRC-16": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0x0000n); + case "CRC-16/A": return this.crc(16n, input, 0x1021n, 0xC6C6n, true, true, 0x0000n); + case "CRC-16/ACORN": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-16/ARC": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0x0000n); + case "CRC-16/AUG-CCITT": return this.crc(16n, input, 0x1021n, 0x1D0Fn, false, false, 0x0000n); + case "CRC-16/AUTOSAR": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/B": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/BLUETOOTH": return this.crc(16n, input, 0x1021n, 0x0000n, true, true, 0x0000n); + case "CRC-16/BUYPASS": return this.crc(16n, input, 0x8005n, 0x0000n, false, false, 0x0000n); + case "CRC-16/CCITT": return this.crc(16n, input, 0x1021n, 0x0000n, true, true, 0x0000n); + case "CRC-16/CCITT-FALSE": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/CCITT-TRUE": return this.crc(16n, input, 0x1021n, 0x0000n, true, true, 0x0000n); + case "CRC-16/CCITT-ZERO": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-16/CDMA2000": return this.crc(16n, input, 0xC867n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/CMS": return this.crc(16n, input, 0x8005n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/DARC": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/DDS-110": return this.crc(16n, input, 0x8005n, 0x800Dn, false, false, 0x0000n); + case "CRC-16/DECT-R": return this.crc(16n, input, 0x0589n, 0x0000n, false, false, 0x0001n); + case "CRC-16/DECT-X": return this.crc(16n, input, 0x0589n, 0x0000n, false, false, 0x0000n); + case "CRC-16/DNP": return this.crc(16n, input, 0x3D65n, 0x0000n, true, true, 0xFFFFn); + case "CRC-16/EN-13757": return this.crc(16n, input, 0x3D65n, 0x0000n, false, false, 0xFFFFn); + case "CRC-16/EPC": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/EPC-C1G2": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/GENIBUS": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/GSM": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0xFFFFn); + case "CRC-16/I-CODE": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/IBM": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0x0000n); + case "CRC-16/IBM-3740": return this.crc(16n, input, 0x1021n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/IBM-SDLC": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/IEC-61158-2": return this.crc(16n, input, 0x1DCFn, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/ISO-HDLC": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/ISO-IEC-14443-3-A": return this.crc(16n, input, 0x1021n, 0xC6C6n, true, true, 0x0000n); + case "CRC-16/ISO-IEC-14443-3-B": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/KERMIT": return this.crc(16n, input, 0x1021n, 0x0000n, true, true, 0x0000n); + case "CRC-16/LHA": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0x0000n); + case "CRC-16/LJ1200": return this.crc(16n, input, 0x6F63n, 0x0000n, false, false, 0x0000n); + case "CRC-16/LTE": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-16/M17": return this.crc(16n, input, 0x5935n, 0xFFFFn, false, false, 0x0000n); + case "CRC-16/MAXIM": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0xFFFFn); + case "CRC-16/MAXIM-DOW": return this.crc(16n, input, 0x8005n, 0x0000n, true, true, 0xFFFFn); + case "CRC-16/MCRF4XX": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0x0000n); + case "CRC-16/MODBUS": return this.crc(16n, input, 0x8005n, 0xFFFFn, true, true, 0x0000n); + case "CRC-16/NRSC-5": return this.crc(16n, input, 0x080Bn, 0xFFFFn, true, true, 0x0000n); + case "CRC-16/OPENSAFETY-A": return this.crc(16n, input, 0x5935n, 0x0000n, false, false, 0x0000n); + case "CRC-16/OPENSAFETY-B": return this.crc(16n, input, 0x755Bn, 0x0000n, false, false, 0x0000n); + case "CRC-16/PROFIBUS": return this.crc(16n, input, 0x1DCFn, 0xFFFFn, false, false, 0xFFFFn); + case "CRC-16/RIELLO": return this.crc(16n, input, 0x1021n, 0xB2AAn, true, true, 0x0000n); + case "CRC-16/SPI-FUJITSU": return this.crc(16n, input, 0x1021n, 0x1D0Fn, false, false, 0x0000n); + case "CRC-16/T10-DIF": return this.crc(16n, input, 0x8BB7n, 0x0000n, false, false, 0x0000n); + case "CRC-16/TELEDISK": return this.crc(16n, input, 0xA097n, 0x0000n, false, false, 0x0000n); + case "CRC-16/TMS37157": return this.crc(16n, input, 0x1021n, 0x89ECn, true, true, 0x0000n); + case "CRC-16/UMTS": return this.crc(16n, input, 0x8005n, 0x0000n, false, false, 0x0000n); + case "CRC-16/USB": return this.crc(16n, input, 0x8005n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/V-41-LSB": return this.crc(16n, input, 0x1021n, 0x0000n, true, true, 0x0000n); + case "CRC-16/V-41-MSB": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-16/VERIFONE": return this.crc(16n, input, 0x8005n, 0x0000n, false, false, 0x0000n); + case "CRC-16/X-25": return this.crc(16n, input, 0x1021n, 0xFFFFn, true, true, 0xFFFFn); + case "CRC-16/XMODEM": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-16/ZMODEM": return this.crc(16n, input, 0x1021n, 0x0000n, false, false, 0x0000n); + case "CRC-17/CAN-FD": return this.crc(17n, input, 0x1685Bn, 0x00000n, false, false, 0x00000n); + case "CRC-21/CAN-FD": return this.crc(21n, input, 0x102899n, 0x000000n, false, false, 0x000000n); + case "CRC-24/BLE": return this.crc(24n, input, 0x00065Bn, 0x555555n, true, true, 0x000000n); + case "CRC-24/FLEXRAY-A": return this.crc(24n, input, 0x5D6DCBn, 0xFEDCBAn, false, false, 0x000000n); + case "CRC-24/FLEXRAY-B": return this.crc(24n, input, 0x5D6DCBn, 0xABCDEFn, false, false, 0x000000n); + case "CRC-24/INTERLAKEN": return this.crc(24n, input, 0x328B63n, 0xFFFFFFn, false, false, 0xFFFFFFn); + case "CRC-24/LTE-A": return this.crc(24n, input, 0x864CFBn, 0x000000n, false, false, 0x000000n); + case "CRC-24/LTE-B": return this.crc(24n, input, 0x800063n, 0x000000n, false, false, 0x000000n); + case "CRC-24/OPENPGP": return this.crc(24n, input, 0x864CFBn, 0xB704CEn, false, false, 0x000000n); + case "CRC-24/OS-9": return this.crc(24n, input, 0x800063n, 0xFFFFFFn, false, false, 0xFFFFFFn); + case "CRC-30/CDMA": return this.crc(30n, input, 0x2030B9C7n, 0x3FFFFFFFn, false, false, 0x3FFFFFFFn); + case "CRC-31/PHILIPS": return this.crc(31n, input, 0x04C11DB7n, 0x7FFFFFFFn, false, false, 0x7FFFFFFFn); + case "CRC-32": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/AAL5": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, false, false, 0xFFFFFFFFn); + case "CRC-32/ADCCP": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/AIXM": return this.crc(32n, input, 0x814141ABn, 0x00000000n, false, false, 0x00000000n); + case "CRC-32/AUTOSAR": return this.crc(32n, input, 0xF4ACFB13n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/BASE91-C": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/BASE91-D": return this.crc(32n, input, 0xA833982Bn, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/BZIP2": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, false, false, 0xFFFFFFFFn); + case "CRC-32/C": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/CASTAGNOLI": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/CD-ROM-EDC": return this.crc(32n, input, 0x8001801Bn, 0x00000000n, true, true, 0x00000000n); + case "CRC-32/CKSUM": return this.crc(32n, input, 0x04C11DB7n, 0x00000000n, false, false, 0xFFFFFFFFn); + case "CRC-32/D": return this.crc(32n, input, 0xA833982Bn, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/DECT-B": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, false, false, 0xFFFFFFFFn); + case "CRC-32/INTERLAKEN": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/ISCSI": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/ISO-HDLC": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/JAMCRC": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0x00000000n); + case "CRC-32/MEF": return this.crc(32n, input, 0x741B8CD7n, 0xFFFFFFFFn, true, true, 0x00000000n); + case "CRC-32/MPEG-2": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, false, false, 0x00000000n); + case "CRC-32/NVME": return this.crc(32n, input, 0x1EDC6F41n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/PKZIP": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/POSIX": return this.crc(32n, input, 0x04C11DB7n, 0x00000000n, false, false, 0xFFFFFFFFn); + case "CRC-32/Q": return this.crc(32n, input, 0x814141ABn, 0x00000000n, false, false, 0x00000000n); + case "CRC-32/SATA": return this.crc(32n, input, 0x04C11DB7n, 0x52325032n, false, false, 0x00000000n); + case "CRC-32/V-42": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-32/XFER": return this.crc(32n, input, 0x000000AFn, 0x00000000n, false, false, 0x00000000n); + case "CRC-32/XZ": return this.crc(32n, input, 0x04C11DB7n, 0xFFFFFFFFn, true, true, 0xFFFFFFFFn); + case "CRC-40/GSM": return this.crc(40n, input, 0x0004820009n, 0x0000000000n, false, false, 0xFFFFFFFFFFn); + case "CRC-64/ECMA-182": return this.crc(64n, input, 0x42F0E1EBA9EA3693n, 0x0000000000000000n, false, false, 0x0000000000000000n); + case "CRC-64/GO-ECMA": return this.crc(64n, input, 0x42F0E1EBA9EA3693n, 0xFFFFFFFFFFFFFFFFn, true, true, 0xFFFFFFFFFFFFFFFFn); + case "CRC-64/GO-ISO": return this.crc(64n, input, 0x000000000000001Bn, 0xFFFFFFFFFFFFFFFFn, true, true, 0xFFFFFFFFFFFFFFFFn); + case "CRC-64/MS": return this.crc(64n, input, 0x259C84CBA6426349n, 0xFFFFFFFFFFFFFFFFn, true, true, 0x0000000000000000n); + case "CRC-64/NVME": return this.crc(64n, input, 0xAD93D23594C93659n, 0xFFFFFFFFFFFFFFFFn, true, true, 0xFFFFFFFFFFFFFFFFn); + case "CRC-64/REDIS": return this.crc(64n, input, 0xAD93D23594C935A9n, 0x0000000000000000n, true, true, 0x0000000000000000n); + case "CRC-64/WE": return this.crc(64n, input, 0x42F0E1EBA9EA3693n, 0xFFFFFFFFFFFFFFFFn, false, false, 0xFFFFFFFFFFFFFFFFn); + case "CRC-64/XZ": return this.crc(64n, input, 0x42F0E1EBA9EA3693n, 0xFFFFFFFFFFFFFFFFn, true, true, 0xFFFFFFFFFFFFFFFFn); + case "CRC-82/DARC": return this.crc(82n, input, 0x0308C0111011401440411n, 0x000000000000000000000n, true, true, 0x000000000000000000000n); + default: throw new OperationError("Unknown checksum algorithm"); + } + } + +} + +export default CRCChecksum; diff --git a/src/core/operations/ConvertLeetSpeak.mjs b/src/core/operations/ConvertLeetSpeak.mjs index 54fa62f6e..1a7cb2fcd 100644 --- a/src/core/operations/ConvertLeetSpeak.mjs +++ b/src/core/operations/ConvertLeetSpeak.mjs @@ -18,7 +18,7 @@ class ConvertLeetSpeak extends Operation { this.name = "Convert Leet Speak"; this.module = "Default"; - this.description = "Converts to and from Leet Speak"; + this.description = "Converts to and from Leet Speak."; this.infoURL = "https://wikipedia.org/wiki/Leet"; this.inputType = "string"; this.outputType = "string"; @@ -39,13 +39,16 @@ class ConvertLeetSpeak extends Operation { */ run(input, args) { const direction = args[0]; + if (direction === "To Leet Speak") { - return input.replace(/[abcdefghijklmnopqrstuvwxyz]/gi, char => { - return toLeetMap[char.toLowerCase()] || char; + return input.replace(/[a-z]/gi, char => { + const leetChar = toLeetMap[char.toLowerCase()] || char; + return char === char.toUpperCase() ? leetChar.toUpperCase() : leetChar; }); } else if (direction === "From Leet Speak") { - return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/g, char => { - return fromLeetMap[char] || char; + return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/gi, char => { + const normalChar = fromLeetMap[char] || char; + return normalChar; }); } } diff --git a/src/core/operations/ECDSAVerify.mjs b/src/core/operations/ECDSAVerify.mjs index 7e46e867d..1f8a53ea6 100644 --- a/src/core/operations/ECDSAVerify.mjs +++ b/src/core/operations/ECDSAVerify.mjs @@ -9,6 +9,7 @@ import OperationError from "../errors/OperationError.mjs"; import { fromBase64 } from "../lib/Base64.mjs"; import { toHexFast } from "../lib/Hex.mjs"; import r from "jsrsasign"; +import Utils from "../Utils.mjs"; /** * ECDSA Verify operation @@ -59,6 +60,11 @@ class ECDSAVerify extends Operation { name: "Message", type: "text", value: "" + }, + { + name: "Message format", + type: "option", + value: ["Raw", "Hex", "Base64"] } ]; } @@ -70,7 +76,7 @@ class ECDSAVerify extends Operation { */ run(input, args) { let inputFormat = args[0]; - const [, mdAlgo, keyPem, msg] = args; + const [, mdAlgo, keyPem, msg, msgFormat] = args; if (keyPem.replace("-----BEGIN PUBLIC KEY-----", "").length === 0) { throw new OperationError("Please enter a public key."); @@ -145,7 +151,8 @@ class ECDSAVerify extends Operation { throw new OperationError("Provided key is not a public key."); } sig.init(key); - sig.updateString(msg); + const messageStr = Utils.convertToByteString(msg, msgFormat); + sig.updateString(messageStr); const result = sig.verify(signatureASN1Hex); return result ? "Verified OK" : "Verification Failure"; } diff --git a/src/core/operations/ExtractDomains.mjs b/src/core/operations/ExtractDomains.mjs index c28efbb5b..9e78bf3a2 100644 --- a/src/core/operations/ExtractDomains.mjs +++ b/src/core/operations/ExtractDomains.mjs @@ -5,7 +5,7 @@ */ import Operation from "../Operation.mjs"; -import { search, DOMAIN_REGEX } from "../lib/Extract.mjs"; +import { search, DOMAIN_REGEX, DMARC_DOMAIN_REGEX } from "../lib/Extract.mjs"; import { caseInsensitiveSort } from "../lib/Sort.mjs"; /** @@ -39,6 +39,11 @@ class ExtractDomains extends Operation { name: "Unique", type: "boolean", value: false + }, + { + name: "Underscore (DMARC, DKIM, etc)", + type: "boolean", + value: false } ]; } @@ -49,11 +54,11 @@ class ExtractDomains extends Operation { * @returns {string} */ run(input, args) { - const [displayTotal, sort, unique] = args; + const [displayTotal, sort, unique, dmarc] = args; const results = search( input, - DOMAIN_REGEX, + dmarc ? DMARC_DOMAIN_REGEX : DOMAIN_REGEX, null, sort ? caseInsensitiveSort : null, unique diff --git a/src/core/operations/ExtractEmailAddresses.mjs b/src/core/operations/ExtractEmailAddresses.mjs index f50e1aaf5..34b838ab3 100644 --- a/src/core/operations/ExtractEmailAddresses.mjs +++ b/src/core/operations/ExtractEmailAddresses.mjs @@ -51,7 +51,7 @@ class ExtractEmailAddresses extends Operation { run(input, args) { const [displayTotal, sort, unique] = args, // email regex from: https://www.regextester.com/98066 - regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig; + 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( input, diff --git a/src/core/operations/ExtractIPAddresses.mjs b/src/core/operations/ExtractIPAddresses.mjs index 97b52478d..b74ec8fe2 100644 --- a/src/core/operations/ExtractIPAddresses.mjs +++ b/src/core/operations/ExtractIPAddresses.mjs @@ -21,7 +21,7 @@ class ExtractIPAddresses extends Operation { this.name = "Extract IP addresses"; this.module = "Regex"; - this.description = "Extracts all IPv4 and IPv6 addresses.

Warning: Given a string 710.65.0.456, this will match 10.65.0.45 so always check the original input!"; + this.description = "Extracts all IPv4 and IPv6 addresses.

Warning: Given a string 1.2.3.4.5.6.7.8, this will match 1.2.3.4 and 5.6.7.8 so always check the original input!"; this.inputType = "string"; this.outputType = "string"; this.args = [ @@ -65,7 +65,21 @@ class ExtractIPAddresses extends Operation { */ run(input, args) { const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args, - ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?", + + // IPv4 decimal groups can have values 0 to 255. To construct a regex the following sub-regex is reused: + ipv4DecimalByte = "(?:25[0-5]|2[0-4]\\d|1?[0-9]\\d|\\d)", + ipv4OctalByte = "(?:0[1-3]?[0-7]{1,2})", + + // Look behind and ahead will be used to exclude matches with additional decimal digits left and right of IP address + lookBehind = "(? { + const checksumLength = checksum.name.match(new RegExp("-(\\d{1,2})(\\/|$)"))[1]; + if (length === "All" || length === checksumLength) { + const value = checksum.algo.run(new Uint8Array(input), checksum.params || []); + output += includeNames ? + `${checksum.name}:${" ".repeat(25-checksum.name.length)}${value}\n`: + `${value}\n`; + } + }); + return output; + } +} + +export default GenerateAllChecksums; diff --git a/src/core/operations/GenerateAllHashes.mjs b/src/core/operations/GenerateAllHashes.mjs index d9af80658..df09aa858 100644 --- a/src/core/operations/GenerateAllHashes.mjs +++ b/src/core/operations/GenerateAllHashes.mjs @@ -22,14 +22,6 @@ import HAS160 from "./HAS160.mjs"; import Whirlpool from "./Whirlpool.mjs"; import SSDEEP from "./SSDEEP.mjs"; import CTPH from "./CTPH.mjs"; -import Fletcher8Checksum from "./Fletcher8Checksum.mjs"; -import Fletcher16Checksum from "./Fletcher16Checksum.mjs"; -import Fletcher32Checksum from "./Fletcher32Checksum.mjs"; -import Fletcher64Checksum from "./Fletcher64Checksum.mjs"; -import Adler32Checksum from "./Adler32Checksum.mjs"; -import CRC8Checksum from "./CRC8Checksum.mjs"; -import CRC16Checksum from "./CRC16Checksum.mjs"; -import CRC32Checksum from "./CRC32Checksum.mjs"; import BLAKE2b from "./BLAKE2b.mjs"; import BLAKE2s from "./BLAKE2s.mjs"; import Streebog from "./Streebog.mjs"; @@ -114,16 +106,6 @@ class GenerateAllHashes extends Operation { {name: "SSDEEP", algo: (new SSDEEP()), inputType: "str"}, {name: "CTPH", algo: (new CTPH()), inputType: "str"} ]; - this.checksums = [ - {name: "Fletcher-8", algo: (new Fletcher8Checksum), inputType: "byteArray", params: []}, - {name: "Fletcher-16", algo: (new Fletcher16Checksum), inputType: "byteArray", params: []}, - {name: "Fletcher-32", algo: (new Fletcher32Checksum), inputType: "byteArray", params: []}, - {name: "Fletcher-64", algo: (new Fletcher64Checksum), inputType: "byteArray", params: []}, - {name: "Adler-32", algo: (new Adler32Checksum), inputType: "byteArray", params: []}, - {name: "CRC-8", algo: (new CRC8Checksum), inputType: "arrayBuffer", params: ["CRC-8"]}, - {name: "CRC-16", algo: (new CRC16Checksum), inputType: "arrayBuffer", params: []}, - {name: "CRC-32", algo: (new CRC32Checksum), inputType: "arrayBuffer", params: []} - ]; } /** @@ -144,14 +126,6 @@ class GenerateAllHashes extends Operation { output += this.formatDigest(digest, length, includeNames, hash.name); }); - if (length === "All") { - output += "\nChecksums:\n"; - this.checksums.forEach(checksum => { - digest = this.executeAlgo(checksum.algo, checksum.inputType, checksum.params || []); - output += this.formatDigest(digest, length, includeNames, checksum.name); - }); - } - return output; } diff --git a/src/core/operations/GenerateUUID.mjs b/src/core/operations/GenerateUUID.mjs index 1ee0faba6..21d063e3e 100644 --- a/src/core/operations/GenerateUUID.mjs +++ b/src/core/operations/GenerateUUID.mjs @@ -5,8 +5,8 @@ */ import Operation from "../Operation.mjs"; -import crypto from "crypto"; - +import * as uuid from "uuid"; +import OperationError from "../errors/OperationError.mjs"; /** * Generate UUID operation */ @@ -20,11 +20,38 @@ class GenerateUUID extends Operation { this.name = "Generate UUID"; this.module = "Crypto"; - this.description = "Generates an RFC 4122 version 4 compliant Universally Unique Identifier (UUID), also known as a Globally Unique Identifier (GUID).

A version 4 UUID relies on random numbers, in this case generated using window.crypto if available and falling back to Math.random if not."; + this.description = + "Generates an RFC 9562 (formerly RFC 4122) compliant Universally Unique Identifier (UUID), " + + "also known as a Globally Unique Identifier (GUID).
" + + "
" + + "We currently support generating the following UUID versions:
" + + "" + + "UUIDs are generated using the uuid package.
"; this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier"; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + name: "Version", + hint: "UUID version", + type: "option", + value: ["v1", "v3", "v4", "v5", "v6", "v7"], + defaultIndex: 2, + }, + { + name: "Namespace", + hint: "UUID namespace (UUID; valid for v3 and v5)", + type: "string", + value: "1b671a64-40d5-491e-99b0-da01ff1f3341" + } + ]; } /** @@ -33,16 +60,17 @@ class GenerateUUID extends Operation { * @returns {string} */ run(input, args) { - const buf = new Uint32Array(4).map(() => { - return crypto.randomBytes(4).readUInt32BE(0, true); - }); - let i = 0; - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - const r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf, - v = c === "x" ? r : (r & 0x3 | 0x8); - i++; - return v.toString(16); - }); + const [version, namespace] = args; + const hasDesiredVersion = typeof uuid[version] === "function"; + if (!hasDesiredVersion) throw new OperationError("Invalid UUID version"); + + const requiresNamespace = ["v3", "v5"].includes(version); + if (!requiresNamespace) return uuid[version](); + + const hasValidNamespace = typeof namespace === "string" && uuid.validate(namespace); + if (!hasValidNamespace) throw new OperationError("Invalid UUID namespace"); + + return uuid[version](input, namespace); } } diff --git a/src/core/operations/JSONtoYAML.mjs b/src/core/operations/JSONtoYAML.mjs new file mode 100644 index 000000000..0d4cc626b --- /dev/null +++ b/src/core/operations/JSONtoYAML.mjs @@ -0,0 +1,46 @@ +/** + * @author ccarpo [ccarpo@gmx.net] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import YAML from "yaml"; + +/** + * JSON to YAML operation + */ +class JSONtoYAML extends Operation { + + /** + * JSONtoYAML constructor + */ + constructor() { + super(); + + this.name = "JSON to YAML"; + this.module = "Default"; + this.description = "Format a JSON object into YAML"; + this.infoURL = "https://en.wikipedia.org/wiki/YAML"; + this.inputType = "JSON"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + try { + return YAML.stringify(input); + } catch (err) { + throw new OperationError("Test"); + } + } + +} + +export default JSONtoYAML; diff --git a/src/core/operations/Jq.mjs b/src/core/operations/Jq.mjs new file mode 100644 index 000000000..c1e02b34b --- /dev/null +++ b/src/core/operations/Jq.mjs @@ -0,0 +1,57 @@ +/** + * @author zhzy0077 [zhzy0077@hotmail.com] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import jq from "jq-web"; + +/** + * jq operation + */ +class Jq extends Operation { + + /** + * Jq constructor + */ + constructor() { + super(); + + this.name = "Jq"; + this.module = "Jq"; + this.description = "jq is a lightweight and flexible command-line JSON processor."; + this.infoURL = "https://github.com/jqlang/jq"; + this.inputType = "JSON"; + this.outputType = "string"; + this.args = [ + { + name: "Query", + type: "string", + value: "" + } + ]; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [query] = args; + let result; + + try { + result = jq.json(input, query); + } catch (err) { + throw new OperationError(`Invalid jq expression: ${err.message}`); + } + + return JSON.stringify(result); + } + +} + +export default Jq; diff --git a/src/core/operations/Jsonata.mjs b/src/core/operations/Jsonata.mjs new file mode 100644 index 000000000..82cc4d397 --- /dev/null +++ b/src/core/operations/Jsonata.mjs @@ -0,0 +1,65 @@ +/** + * @author Jon K (jon@ajarsoftware.com) + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import jsonata from "jsonata"; +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * Jsonata Query operation + */ +class JsonataQuery extends Operation { + /** + * JsonataQuery constructor + */ + constructor() { + super(); + + this.name = "Jsonata Query"; + this.module = "Code"; + this.description = + "Query and transform JSON data with a jsonata query."; + this.infoURL = "https://docs.jsonata.org/overview.html"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Query", + type: "text", + value: "string", + }, + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + async run(input, args) { + const [query] = args; + let result, jsonObj; + + try { + jsonObj = JSON.parse(input); + } catch (err) { + throw new OperationError(`Invalid input JSON: ${err.message}`); + } + + try { + const expression = jsonata(query); + result = await expression.evaluate(jsonObj); + } catch (err) { + throw new OperationError( + `Invalid Jsonata Expression: ${err.message}` + ); + } + + return JSON.stringify(result === undefined ? "" : result); + } +} + +export default JsonataQuery; diff --git a/src/core/operations/PHPSerialize.mjs b/src/core/operations/PHPSerialize.mjs new file mode 100644 index 000000000..00fb1380b --- /dev/null +++ b/src/core/operations/PHPSerialize.mjs @@ -0,0 +1,126 @@ +/** + * @author brun0ne [brunonblok@gmail.com] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * PHP Serialize operation + */ +class PHPSerialize extends Operation { + + /** + * PHPSerialize constructor + */ + constructor() { + super(); + + this.name = "PHP Serialize"; + this.module = "Default"; + this.description = "Performs PHP serialization on JSON data.

This function does not support object tags.

Since PHP doesn't distinguish dicts and arrays, this operation is not always symmetric to PHP Deserialize.

Example:
[5,"abc",true]
becomes
a:3:{i:0;i:5;i:1;s:3:"abc";i:2;b:1;}"; + this.infoURL = "https://www.phpinternalsbook.com/php5/classes_objects/serialization.html"; + this.inputType = "JSON"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + /** + * Determines if a number is an integer + * @param {number} value + * @returns {boolean} + */ + function isInteger(value) { + return typeof value === "number" && parseInt(value.toString(), 10) === value; + } + + /** + * Serialize basic types + * @param {string | number | boolean} content + * @returns {string} + */ + function serializeBasicTypes(content) { + const basicTypes = { + "string": "s", + "integer": "i", + "float": "d", + "boolean": "b" + }; + /** + * Booleans + * cast to 0 or 1 + */ + if (typeof content === "boolean") { + return `${basicTypes.boolean}:${content ? 1 : 0}`; + } + /* Numbers */ + if (typeof content === "number") { + if (isInteger(content)) { + return `${basicTypes.integer}:${content.toString()}`; + } else { + return `${basicTypes.float}:${content.toString()}`; + } + } + /* Strings */ + if (typeof content === "string") + return `${basicTypes.string}:${content.length}:"${content}"`; + + /** This should be unreachable */ + throw new OperationError(`Encountered a non-implemented type: ${typeof content}`); + } + + /** + * Recursively serialize + * @param {*} object + * @returns {string} + */ + function serialize(object) { + /* Null */ + if (object == null) { + return `N;`; + } + + if (typeof object !== "object") { + /* Basic types */ + return `${serializeBasicTypes(object)};`; + } else if (object instanceof Array) { + /* Arrays */ + const serializedElements = []; + + for (let i = 0; i < object.length; i++) { + serializedElements.push(`${serialize(i)}${serialize(object[i])}`); + } + + return `a:${object.length}:{${serializedElements.join("")}}`; + } else if (object instanceof Object) { + /** + * Objects + * Note: the output cannot be guaranteed to be in the same order as the input + */ + const serializedElements = []; + const keys = Object.keys(object); + + for (const key of keys) { + serializedElements.push(`${serialize(key)}${serialize(object[key])}`); + } + + return `a:${keys.length}:{${serializedElements.join("")}}`; + } + + /** This should be unreachable */ + throw new OperationError(`Encountered a non-implemented type: ${typeof object}`); + } + + return serialize(input); + } +} + +export default PHPSerialize; diff --git a/src/core/operations/ParseX509Certificate.mjs b/src/core/operations/ParseX509Certificate.mjs index 11e63424d..cdd1e9c7c 100644 --- a/src/core/operations/ParseX509Certificate.mjs +++ b/src/core/operations/ParseX509Certificate.mjs @@ -6,7 +6,8 @@ import r from "jsrsasign"; import { fromBase64 } from "../lib/Base64.mjs"; -import { toHex } from "../lib/Hex.mjs"; +import { runHash } from "../lib/Hash.mjs"; +import { fromHex, toHex } from "../lib/Hex.mjs"; import { formatByteStr, formatDnObj } from "../lib/PublicKey.mjs"; import Operation from "../Operation.mjs"; import Utils from "../Utils.mjs"; @@ -81,7 +82,8 @@ class ParseX509Certificate extends Operation { } if (undefinedInputFormat) throw "Undefined input format"; - const sn = cert.getSerialNumberHex(), + const hex = Utils.strToArrayBuffer(Utils.byteArrayToChars(fromHex(cert.hex))), + sn = cert.getSerialNumberHex(), issuer = cert.getIssuer(), subject = cert.getSubject(), pk = cert.getPublicKey(), @@ -191,6 +193,10 @@ Issuer ${issuerStr} Subject ${subjectStr} +Fingerprints + MD5: ${runHash("md5", hex)} + SHA1: ${runHash("sha1", hex)} + SHA256: ${runHash("sha256", hex)} Public Key ${pkStr.slice(0, -1)} Certificate Signature diff --git a/src/core/operations/RailFenceCipherDecode.mjs b/src/core/operations/RailFenceCipherDecode.mjs index be54ee124..39795f215 100644 --- a/src/core/operations/RailFenceCipherDecode.mjs +++ b/src/core/operations/RailFenceCipherDecode.mjs @@ -72,7 +72,7 @@ class RailFenceCipherDecode extends Operation { } } - return plaintext.join("").trim(); + return plaintext.join(""); } } diff --git a/src/core/operations/RailFenceCipherEncode.mjs b/src/core/operations/RailFenceCipherEncode.mjs index 03651f857..89eddde75 100644 --- a/src/core/operations/RailFenceCipherEncode.mjs +++ b/src/core/operations/RailFenceCipherEncode.mjs @@ -66,7 +66,7 @@ class RailFenceCipherEncode extends Operation { rows[rowIdx] += plaintext[pos]; } - return rows.join("").trim(); + return rows.join(""); } } diff --git a/src/core/operations/SM2Decrypt.mjs b/src/core/operations/SM2Decrypt.mjs new file mode 100644 index 000000000..396571105 --- /dev/null +++ b/src/core/operations/SM2Decrypt.mjs @@ -0,0 +1,71 @@ +/** + * @author flakjacket95 [dflack95@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; +import Operation from "../Operation.mjs"; + +import { SM2 } from "../lib/SM2.mjs"; + +/** + * SM2Decrypt operation + */ +class SM2Decrypt extends Operation { + + /** + * SM2Decrypt constructor + */ + constructor() { + super(); + + this.name = "SM2 Decrypt"; + this.module = "Crypto"; + this.description = "Decrypts a message utilizing the SM2 standard"; + this.infoURL = ""; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc) + this.inputType = "string"; + this.outputType = "ArrayBuffer"; + this.args = [ + { + name: "Private Key", + type: "string", + value: "DEADBEEF" + }, + { + "name": "Input Format", + "type": "option", + "value": ["C1C3C2", "C1C2C3"], + "defaultIndex": 0 + }, + { + name: "Curve", + type: "option", + "value": ["sm2p256v1"], + "defaultIndex": 0 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {ArrayBuffer} + */ + run(input, args) { + const [privateKey, inputFormat, curveName] = args; + + if (privateKey.length !== 64) { + throw new OperationError("Input private key must be in hex; and should be 32 bytes"); + } + + const sm2 = new SM2(curveName, inputFormat); + sm2.setPrivateKey(privateKey); + + const result = sm2.decrypt(input); + return result; + } + +} + +export default SM2Decrypt; diff --git a/src/core/operations/SM2Encrypt.mjs b/src/core/operations/SM2Encrypt.mjs new file mode 100644 index 000000000..b1e5f9018 --- /dev/null +++ b/src/core/operations/SM2Encrypt.mjs @@ -0,0 +1,77 @@ +/** + * @author flakjacket95 [dflack95@gmail.com] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; +import Operation from "../Operation.mjs"; + +import { SM2 } from "../lib/SM2.mjs"; + +/** + * SM2 Encrypt operation + */ +class SM2Encrypt extends Operation { + + /** + * SM2Encrypt constructor + */ + constructor() { + super(); + + this.name = "SM2 Encrypt"; + this.module = "Crypto"; + this.description = "Encrypts a message utilizing the SM2 standard"; + this.infoURL = ""; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc) + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + + this.args = [ + { + name: "Public Key X", + type: "string", + value: "DEADBEEF" + }, + { + name: "Public Key Y", + type: "string", + value: "DEADBEEF" + }, + { + "name": "Output Format", + "type": "option", + "value": ["C1C3C2", "C1C2C3"], + "defaultIndex": 0 + }, + { + name: "Curve", + type: "option", + "value": ["sm2p256v1"], + "defaultIndex": 0 + } + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + const [publicKeyX, publicKeyY, outputFormat, curveName] = args; + this.outputFormat = outputFormat; + + if (publicKeyX.length !== 64 || publicKeyY.length !== 64) { + throw new OperationError("Invalid Public Key - Ensure each component is 32 bytes in size and in hex"); + } + + const sm2 = new SM2(curveName, outputFormat); + sm2.setPublicKey(publicKeyX, publicKeyY); + + const result = sm2.encrypt(new Uint8Array(input)); + return result; + } +} + +export default SM2Encrypt; diff --git a/src/core/operations/ShowOnMap.mjs b/src/core/operations/ShowOnMap.mjs index c2ac1c6e3..d75c2aa6a 100644 --- a/src/core/operations/ShowOnMap.mjs +++ b/src/core/operations/ShowOnMap.mjs @@ -1,6 +1,7 @@ /** * @author j433866 [j433866@gmail.com] - * @copyright Crown Copyright 2019 + * @author 0xff1ce [github.com/0xff1ce] + * @copyright Crown Copyright 2024 * @license Apache-2.0 */ @@ -22,7 +23,7 @@ class ShowOnMap extends Operation { this.name = "Show on map"; this.module = "Hashing"; this.description = "Displays co-ordinates on a slippy map.

Co-ordinates will be converted to decimal degrees before being shown on the map.

Supported formats:
  • Degrees Minutes Seconds (DMS)
  • Degrees Decimal Minutes (DDM)
  • Decimal Degrees (DD)
  • Geohash
  • Military Grid Reference System (MGRS)
  • Ordnance Survey National Grid (OSNG)
  • Universal Transverse Mercator (UTM)

This operation will not work offline."; - this.infoURL = "https://foundation.wikimedia.org/wiki/Maps_Terms_of_Use"; + this.infoURL = "https://osmfoundation.org/wiki/Terms_of_Use"; this.inputType = "string"; this.outputType = "string"; this.presentType = "html"; @@ -85,10 +86,10 @@ class ShowOnMap extends Operation { data = "0, 0"; } const zoomLevel = args[0]; - const tileUrl = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png", - tileAttribution = "
Wikimedia maps | © OpenStreetMap contributors", - leafletUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.js", - leafletCssUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.css"; + const tileUrl = "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + tileAttribution = "© OpenStreetMap contributors", + leafletUrl = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js", + leafletCssUrl = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"; return `