Merge branch 'master' into jwt-decode-verify
This commit is contained in:
commit
cadbd8e11e
2
.github/workflows/cla-close-stale.yml
vendored
2
.github/workflows/cla-close-stale.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close stale unsigned-CLA PRs
|
||||
uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 #v10.3.0
|
||||
uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 #v10.4.0
|
||||
with:
|
||||
# ---- Guards: only act on PRs carrying the CLA label ----
|
||||
only-labels: 'awaiting cla'
|
||||
|
||||
6
.github/workflows/pull_requests.yml
vendored
6
.github/workflows/pull_requests.yml
vendored
@ -61,14 +61,14 @@ jobs:
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: success()
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
|
||||
|
||||
- name: Production Image Build
|
||||
if: success()
|
||||
id: build-image
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
|
||||
10
.github/workflows/releases.yml
vendored
10
.github/workflows/releases.yml
vendored
@ -61,14 +61,14 @@ jobs:
|
||||
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
|
||||
|
||||
- name: Image Metadata
|
||||
id: image-metadata
|
||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@ -77,14 +77,14 @@ jobs:
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.REGISTRY_USER }}
|
||||
password: ${{ env.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Publish to GHCR
|
||||
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ build
|
||||
src/core/config/modules/*
|
||||
src/core/config/OperationConfig.json
|
||||
src/core/operations/index.mjs
|
||||
src/core/lib/HTMLEntities.mjs
|
||||
src/node/config/OperationConfig.json
|
||||
src/node/index.mjs
|
||||
tests/operations/index.mjs
|
||||
|
||||
@ -367,6 +367,7 @@ module.exports = function (grunt) {
|
||||
command: chainCommands([
|
||||
"echo '\n--- Regenerating config files. ---'",
|
||||
"echo [] > src/core/config/OperationConfig.json",
|
||||
`node ${nodeFlags} src/core/config/scripts/generateHTMLEntities.mjs`,
|
||||
`node ${nodeFlags} src/core/config/scripts/generateOpsIndex.mjs`,
|
||||
`node ${nodeFlags} src/core/config/scripts/generateConfig.mjs`,
|
||||
"echo '--- Config scripts finished. ---\n'"
|
||||
|
||||
264
package-lock.json
generated
264
package-lock.json
generated
@ -21,7 +21,7 @@
|
||||
"assert": "^2.1.0",
|
||||
"avsc": "^5.7.9",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"bignumber.js": "^11.1.4",
|
||||
"bignumber.js": "^11.1.5",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@ -72,7 +72,7 @@
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
"lz4js": "^0.2.0",
|
||||
"markdown-it": "^14.2.0",
|
||||
"markdown-it": "^14.3.0",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.6.2",
|
||||
"ngeohash": "^0.6.3",
|
||||
@ -86,7 +86,7 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^8.6.5",
|
||||
"protobufjs": "^8.7.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
@ -118,13 +118,13 @@
|
||||
"@codemirror/commands": "^6.10.4",
|
||||
"@codemirror/language": "^6.12.4",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.5.4",
|
||||
"@codemirror/view": "^6.43.4",
|
||||
"@codemirror/state": "^6.7.1",
|
||||
"@codemirror/view": "^6.43.6",
|
||||
"@puppeteer/browsers": "3.0.6",
|
||||
"autoprefixer": "^10.5.2",
|
||||
"babel-loader": "^10.1.1",
|
||||
"base64-loader": "^1.0.0",
|
||||
"chromedriver": "^148.0.4",
|
||||
"chromedriver": "^150.0.3",
|
||||
"cli-progress": "^3.12.0",
|
||||
"colors": "^1.4.0",
|
||||
"compression-webpack-plugin": "^12.0.0",
|
||||
@ -157,10 +157,10 @@
|
||||
"postcss-loader": "^8.2.1",
|
||||
"prompt": "^1.3.0",
|
||||
"sitemap": "^9.0.1",
|
||||
"terser": "^5.48.0",
|
||||
"webpack": "^5.108.3",
|
||||
"terser": "^5.49.0",
|
||||
"webpack": "^5.108.4",
|
||||
"webpack-bundle-analyzer": "^5.3.0",
|
||||
"webpack-dev-server": "^5.2.5",
|
||||
"webpack-dev-server": "^5.2.6",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@ -1889,9 +1889,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/state": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.0.tgz",
|
||||
"integrity": "sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==",
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz",
|
||||
"integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1899,9 +1899,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.43.4",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.4.tgz",
|
||||
"integrity": "sha512-YImu23iyKfncJzT7sRy+rEqEhSc8RhOHqDxwy4WzXRKJwYm6iwf/9OJk5ctCAdZ6yi2ZqaGEvmf55fSVqMDrgg==",
|
||||
"version": "6.43.6",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.6.tgz",
|
||||
"integrity": "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -5129,9 +5129,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.5.17",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz",
|
||||
"integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==",
|
||||
"version": "0.5.18",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz",
|
||||
"integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -5700,17 +5700,45 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
|
||||
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz",
|
||||
"integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.1.1.tgz",
|
||||
@ -5883,9 +5911,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "11.1.4",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-11.1.4.tgz",
|
||||
"integrity": "sha512-AJ9dSeaUGj2xu7tEwmdqb51dqdb633xo4njI9K8ZFfcLrNr0XN8/EPkkZUNaF9fkCblGt2zVwZymesUdGynEkQ==",
|
||||
"version": "11.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-11.1.5.tgz",
|
||||
"integrity": "sha512-6WmzCNtUnfKpbozq+hOgWaZMMzORmYBwF1xZScyoIX3QRYWeKTtxxwDOW5tIz7C9BdjkIYHGTcelCLkXg0mndw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
@ -6705,20 +6733,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chromedriver": {
|
||||
"version": "148.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-148.0.4.tgz",
|
||||
"integrity": "sha512-3UyptFDG4YF1Pyv3fzn95s1CN4K3zCpHSmE6g+6J4f2u9KxxOYzrwN2GApVyM2z02hlbSqzo9Ajn2hMi7LnvCw==",
|
||||
"version": "150.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-150.0.3.tgz",
|
||||
"integrity": "sha512-i2L979d6YDTVVUDUPWXz75HGKKVhjNXo74gLiy/f8Adb5zHLU+h3ABdg8RRoiegtjJB0m9vUEiPTdecD0ifa3w==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@testim/chrome-version": "^1.1.4",
|
||||
"adm-zip": "^0.5.17",
|
||||
"axios": "^1.16.0",
|
||||
"compare-versions": "^6.1.0",
|
||||
"proxy-agent": "^8.0.1",
|
||||
"proxy-from-env": "^2.0.0",
|
||||
"tcp-port-used": "^1.0.2"
|
||||
"adm-zip": "^0.5.18",
|
||||
"axios": "^1.18.1",
|
||||
"compare-versions": "^6.1.1",
|
||||
"proxy-agent": "^8.0.2",
|
||||
"proxy-from-env": "^2.1.0",
|
||||
"tcp-port-used": "^1.0.3"
|
||||
},
|
||||
"bin": {
|
||||
"chromedriver": "bin/chromedriver"
|
||||
@ -10177,13 +10205,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-uri": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-8.0.0.tgz",
|
||||
"integrity": "sha512-CqtZlMKvfJeY0Zxv8wazDwXmSKmnMnsmNy8j8+wudi8EyG/pMUB1NqHc+Tv1QaNtpYsK9nOYjb7r7Ufu32RPSw==",
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-8.0.1.tgz",
|
||||
"integrity": "sha512-/5N/P4Lrh0p/mDwlDRi7Y1+P2o/OyzZI3l6Iz1Ov6XXwwm1y3RlZLuo3gVgML99djrEDtV980bBxSuOeHLk8ww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"basic-ftp": "^5.2.0",
|
||||
"basic-ftp": "^5.3.1",
|
||||
"data-uri-to-buffer": "8.0.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
@ -11589,13 +11617,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ip-regex": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
|
||||
"integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
"integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
@ -12207,15 +12235,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is2": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz",
|
||||
"integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz",
|
||||
"integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deep-is": "^0.1.3",
|
||||
"ip-regex": "^4.1.0",
|
||||
"is-url": "^1.2.4"
|
||||
"ip-regex": "^2.1.0",
|
||||
"is-url": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=v0.10.0"
|
||||
@ -12777,9 +12805,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
|
||||
"integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz",
|
||||
"integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -13106,9 +13134,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
|
||||
"integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
|
||||
"version": "14.3.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz",
|
||||
"integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -13122,8 +13150,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.1",
|
||||
"entities": "^4.5.0",
|
||||
"linkify-it": "^5.0.2",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
@ -14454,20 +14482,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pac-proxy-agent": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-9.0.1.tgz",
|
||||
"integrity": "sha512-3ZOSpLboOlpW4yp8Cuv21KlTULRqyJ5Uuad3wXpSKFrxdNgcHEyoa22GRaZ2UlgCVuR6z+5BiavtYVvbajL/Yw==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-9.1.0.tgz",
|
||||
"integrity": "sha512-1aU+1mpj3DrQPfo3gh+3Gap3G5x+axnMx1P/y0ZF2ch7kb2meyOCAH8K2k9d27ROsTE7TnAerzxqF9aon2jqnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"get-uri": "8.0.0",
|
||||
"http-proxy-agent": "9.0.0",
|
||||
"https-proxy-agent": "9.0.0",
|
||||
"get-uri": "8.0.1",
|
||||
"http-proxy-agent": "9.1.0",
|
||||
"https-proxy-agent": "9.1.0",
|
||||
"pac-resolver": "9.0.1",
|
||||
"quickjs-wasi": "^2.2.0",
|
||||
"socks-proxy-agent": "10.0.0"
|
||||
"socks-proxy-agent": "10.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
@ -14484,28 +14512,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pac-proxy-agent/node_modules/http-proxy-agent": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.0.0.tgz",
|
||||
"integrity": "sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz",
|
||||
"integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4"
|
||||
"debug": "^4.3.4",
|
||||
"proxy-agent-negotiate": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/pac-proxy-agent/node_modules/https-proxy-agent": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.0.0.tgz",
|
||||
"integrity": "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz",
|
||||
"integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4"
|
||||
"debug": "^4.3.4",
|
||||
"proxy-agent-negotiate": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
@ -15263,9 +15293,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "8.6.5",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.6.5.tgz",
|
||||
"integrity": "sha512-zeE5LPpencAGXvsxyOYmEgJhxzHY8IsmPAFzstZVhDSVT8QH03q6gMZwZRaQGApevZbAL6u28ugs4CC+YKB2jQ==",
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.7.0.tgz",
|
||||
"integrity": "sha512-uu52JNxLh3vsL7tXU/h0gDaywufvuUCTbGSi0NKQKBZ2ZopkmrWQJSQO/EFqzu/5YhiwgVM8rq/a/iVpx4eZ0g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"long": "^5.3.2"
|
||||
@ -15299,25 +15329,43 @@
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-8.0.1.tgz",
|
||||
"integrity": "sha512-kccqGBqHZXR8onQhY/ganJjoO8QIKKRiFBhPOzbTZK16attzSZ/0XSmp9H7jrRxPKHjhGyx1q32lMPrJ3uLFgA==",
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-8.0.2.tgz",
|
||||
"integrity": "sha512-idLLRewuemWd7GH/BDJzGiB0dWGfT2SQs3jy6NtZtGWU9uPTTSdeC1/cdbqLwgzhfv027daGFuXX426e2Eg20A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"http-proxy-agent": "9.0.0",
|
||||
"https-proxy-agent": "9.0.0",
|
||||
"http-proxy-agent": "9.1.0",
|
||||
"https-proxy-agent": "9.1.0",
|
||||
"lru-cache": "^7.14.1",
|
||||
"pac-proxy-agent": "9.0.1",
|
||||
"pac-proxy-agent": "9.1.0",
|
||||
"proxy-from-env": "^2.0.0",
|
||||
"socks-proxy-agent": "10.0.0"
|
||||
"socks-proxy-agent": "10.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent-negotiate": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz",
|
||||
"integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"kerberos": "^2.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent/node_modules/agent-base": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz",
|
||||
@ -15329,28 +15377,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent/node_modules/http-proxy-agent": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.0.0.tgz",
|
||||
"integrity": "sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz",
|
||||
"integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4"
|
||||
"debug": "^4.3.4",
|
||||
"proxy-agent-negotiate": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent/node_modules/https-proxy-agent": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.0.0.tgz",
|
||||
"integrity": "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz",
|
||||
"integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "9.0.0",
|
||||
"debug": "^4.3.4"
|
||||
"debug": "^4.3.4",
|
||||
"proxy-agent-negotiate": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
@ -16795,9 +16845,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/socks-proxy-agent": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.0.0.tgz",
|
||||
"integrity": "sha512-pyp2YR3mNxAMu0mGLtzs4g7O3uT4/9sQOLAKcViAkaS9fJWkud7nmaf6ZREFqQEi24IPkBcjfHjXhPTUWjo3uA==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.1.0.tgz",
|
||||
"integrity": "sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -17235,14 +17285,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tcp-port-used": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz",
|
||||
"integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.3.tgz",
|
||||
"integrity": "sha512-4CEQ3qRJYo+mtEbJ+OoQu3dF4TDkwaO3RDVC4UzP5cpAOIUWwuwPjD7sdxDFFqsMUjsXVVYBMlg/boAaloThMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4.3.1",
|
||||
"is2": "^2.0.6"
|
||||
"is2": "2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tcp-port-used/node_modules/debug": {
|
||||
@ -17271,9 +17321,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.48.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz",
|
||||
"integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==",
|
||||
"version": "5.49.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz",
|
||||
"integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
@ -18099,9 +18149,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.108.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.3.tgz",
|
||||
"integrity": "sha512-hOpaCHmQVVY66IVTjofnH14IgSdmod2aquSGHGuYig/OIdWge01Hk2Wt988DZcwXumFUT4+FvJY5N+ikl8o/ww==",
|
||||
"version": "5.108.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.4.tgz",
|
||||
"integrity": "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -18226,9 +18276,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server": {
|
||||
"version": "5.2.5",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.5.tgz",
|
||||
"integrity": "sha512-4wZtCquSuv9CKX8oybo+mqxtxZqWz47uM1Ch94lxowBztOhWCbhqvRbfC/mODOwxgV2brY+JGZpHq58/SuVFYg==",
|
||||
"version": "5.2.6",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.6.tgz",
|
||||
"integrity": "sha512-HNLRmamRvVavZQ+avceZifmv8hmdUjg43t6MI4SqJDwFdW7RPQwH5vzGhDRZSX59SgfbeHhLnq3g+uooWo7pVw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -18250,7 +18300,7 @@
|
||||
"graceful-fs": "^4.2.6",
|
||||
"http-proxy-middleware": "^2.0.9",
|
||||
"ipaddr.js": "^2.1.0",
|
||||
"launch-editor": "^2.6.1",
|
||||
"launch-editor": "^2.14.1",
|
||||
"open": "^10.0.3",
|
||||
"p-retry": "^6.2.0",
|
||||
"schema-utils": "^4.2.0",
|
||||
@ -18384,9 +18434,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/websocket-driver": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz",
|
||||
"integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
|
||||
18
package.json
18
package.json
@ -47,13 +47,13 @@
|
||||
"@codemirror/commands": "^6.10.4",
|
||||
"@codemirror/language": "^6.12.4",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.5.4",
|
||||
"@codemirror/view": "^6.43.4",
|
||||
"@codemirror/state": "^6.7.1",
|
||||
"@codemirror/view": "^6.43.6",
|
||||
"@puppeteer/browsers": "3.0.6",
|
||||
"autoprefixer": "^10.5.2",
|
||||
"babel-loader": "^10.1.1",
|
||||
"base64-loader": "^1.0.0",
|
||||
"chromedriver": "^148.0.4",
|
||||
"chromedriver": "^150.0.3",
|
||||
"cli-progress": "^3.12.0",
|
||||
"colors": "^1.4.0",
|
||||
"compression-webpack-plugin": "^12.0.0",
|
||||
@ -86,10 +86,10 @@
|
||||
"postcss-loader": "^8.2.1",
|
||||
"prompt": "^1.3.0",
|
||||
"sitemap": "^9.0.1",
|
||||
"terser": "^5.48.0",
|
||||
"webpack": "^5.108.3",
|
||||
"terser": "^5.49.0",
|
||||
"webpack": "^5.108.4",
|
||||
"webpack-bundle-analyzer": "^5.3.0",
|
||||
"webpack-dev-server": "^5.2.5",
|
||||
"webpack-dev-server": "^5.2.6",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@ -105,7 +105,7 @@
|
||||
"assert": "^2.1.0",
|
||||
"avsc": "^5.7.9",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"bignumber.js": "^11.1.4",
|
||||
"bignumber.js": "^11.1.5",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@ -156,7 +156,7 @@
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
"lz4js": "^0.2.0",
|
||||
"markdown-it": "^14.2.0",
|
||||
"markdown-it": "^14.3.0",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.6.2",
|
||||
"ngeohash": "^0.6.3",
|
||||
@ -170,7 +170,7 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^8.6.5",
|
||||
"protobufjs": "^8.7.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
|
||||
@ -83,7 +83,9 @@
|
||||
"Rison Decode",
|
||||
"To Modhex",
|
||||
"From Modhex",
|
||||
"MIME Decoding"
|
||||
"MIME Decoding",
|
||||
"To COBS",
|
||||
"From COBS"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -174,6 +176,7 @@
|
||||
"AES Key Wrap",
|
||||
"AES Key Unwrap",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Pseudo-Random Prime Generator",
|
||||
"Enigma",
|
||||
"Bombe",
|
||||
"Multiple Bombe",
|
||||
@ -242,9 +245,8 @@
|
||||
"Subtract",
|
||||
"Multiply",
|
||||
"Divide",
|
||||
"Modular Exponentiation",
|
||||
"Modular Inverse",
|
||||
"Extended GCD",
|
||||
"Modular Inverse",
|
||||
"Mean",
|
||||
"Median",
|
||||
"Standard Deviation",
|
||||
|
||||
139
src/core/config/scripts/generateHTMLEntities.mjs
Normal file
139
src/core/config/scripts/generateHTMLEntities.mjs
Normal file
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* This script automatically generates src/core/lib/HTMLEntities.mjs, the shared
|
||||
* HTML entity lookup tables used by the "To HTML Entity" and "From HTML Entity"
|
||||
* operations.
|
||||
*
|
||||
* The data is derived from the vendored WHATWG named character reference set
|
||||
* (src/core/vendor/htmlEntities/entity.json, from
|
||||
* https://html.spec.whatwg.org/entities.json) so the
|
||||
* two operations cannot drift apart and every entity is spec-conformant:
|
||||
*
|
||||
* - HTML_ENTITY_REVERSE_LOOKUP (decode) is every single-code-point spec name.
|
||||
* - HTML_ENTITY_LOOKUP (encode) picks one canonical name per code point via a
|
||||
* deterministic tiebreak, overridden by htmlEntityOverrides.mjs where a
|
||||
* specific historical name is preferred.
|
||||
*
|
||||
* @author roberson-io [michaelroberson@gmail.com]
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint no-console: ["off"] */
|
||||
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import process from "process";
|
||||
import { fileURLToPath } from "url";
|
||||
import { HTML_ENTITY_CANONICAL_OVERRIDES } from "./htmlEntityOverrides.mjs";
|
||||
|
||||
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
if (!fs.existsSync(path.join(process.cwd(), "src/core/lib"))) {
|
||||
console.log("\nCWD: " + process.cwd());
|
||||
console.log("Error: generateHTMLEntities.mjs should be run from the project root");
|
||||
console.log("Example> node src/core/config/scripts/generateHTMLEntities.mjs");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const SPEC = JSON.parse(fs.readFileSync(
|
||||
path.join(scriptDir, "..", "..", "vendor", "htmlEntities", "entity.json"), "utf8"));
|
||||
|
||||
// Build code point -> [spec names] for single-code-point, semicolon-terminated
|
||||
// references (the representable subset; multi-code-point entities are skipped).
|
||||
const codePointNames = {};
|
||||
for (const [key, val] of Object.entries(SPEC)) {
|
||||
if (!key.endsWith(";") || val.codepoints.length !== 1) continue;
|
||||
const name = key.slice(1, -1); // strip leading "&" and trailing ";"
|
||||
(codePointNames[val.codepoints[0]] ??= []).push(name);
|
||||
}
|
||||
|
||||
// Deterministic canonical-name tiebreak: prefer a lower-case name, then the
|
||||
// shortest, then alphabetical. Overridden per code point where a specific
|
||||
// historical name is preferred.
|
||||
const isAllUpper = s => s === s.toUpperCase() && s !== s.toLowerCase();
|
||||
|
||||
/**
|
||||
* Choose the single canonical entity name for a code point.
|
||||
*
|
||||
* @param {number} codePoint - the Unicode code point being encoded
|
||||
* @param {string[]} names - all valid WHATWG names for that code point
|
||||
* @returns {string} the canonical name to emit when encoding
|
||||
*/
|
||||
function canonicalName(codePoint, names) {
|
||||
const override = HTML_ENTITY_CANONICAL_OVERRIDES[codePoint];
|
||||
if (override !== undefined) {
|
||||
if (!names.includes(override))
|
||||
throw new Error(`Override &${override}; is not a spec name for code point ${codePoint} (spec: ${names})`);
|
||||
return override;
|
||||
}
|
||||
return [...names].sort((a, b) =>
|
||||
(isAllUpper(a) - isAllUpper(b)) ||
|
||||
(a.length - b.length) ||
|
||||
(a < b ? -1 : a > b ? 1 : 0)
|
||||
)[0];
|
||||
}
|
||||
|
||||
const forward = {}; // code point -> canonical name (encode)
|
||||
const reverse = {}; // name -> code point (decode, every spec name)
|
||||
for (const [cpStr, names] of Object.entries(codePointNames)) {
|
||||
const cp = Number(cpStr);
|
||||
forward[cp] = canonicalName(cp, names);
|
||||
for (const name of names) reverse[name] = cp;
|
||||
}
|
||||
|
||||
// Decode-only aliases = spec names that are not the canonical encode name.
|
||||
const aliases = {};
|
||||
for (const [name, cp] of Object.entries(reverse)) {
|
||||
if (forward[cp] !== name) aliases[name] = cp;
|
||||
}
|
||||
|
||||
// --- emit -----------------------------------------------------------------
|
||||
const fwdEntries = Object.keys(forward).map(Number).sort((a, b) => a - b)
|
||||
.map(cp => ` ${cp}: "${forward[cp]}",`).join("\n").replace(/,$/, "");
|
||||
const aliasEntries = Object.keys(aliases).sort()
|
||||
.map(n => ` ${JSON.stringify(n)}: ${aliases[n]},`).join("\n").replace(/,$/, "");
|
||||
|
||||
const code = `/**
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateHTMLEntities.mjs
|
||||
*
|
||||
* HTML entity lookup tables shared by the "To HTML Entity" and "From HTML Entity"
|
||||
* operations, derived from the WHATWG named character reference set
|
||||
* (https://html.spec.whatwg.org/entities.json). Do not edit by hand — change the
|
||||
* vendored src/core/vendor/htmlEntities/entity.json or htmlEntityOverrides.mjs
|
||||
* and regenerate.
|
||||
*
|
||||
* @author roberson-io [michaelroberson@gmail.com]
|
||||
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Canonical lookup: Unicode code point -> entity name (without "&" and ";"),
|
||||
* used for ENCODING. One canonical name per code point.
|
||||
*/
|
||||
export const HTML_ENTITY_LOOKUP = {
|
||||
${fwdEntries}
|
||||
};
|
||||
|
||||
/**
|
||||
* Legacy / alias names that only DECODE (spelling variants, deprecated names,
|
||||
* box-drawing aliases, etc.); not used for encoding.
|
||||
*/
|
||||
export const HTML_ENTITY_DECODE_ALIASES = {
|
||||
${aliasEntries}
|
||||
};
|
||||
|
||||
/**
|
||||
* Derived reverse lookup: entity name -> code point, used for DECODING. Built
|
||||
* from the canonical lookup plus the legacy aliases.
|
||||
*/
|
||||
export const HTML_ENTITY_REVERSE_LOOKUP = {...HTML_ENTITY_DECODE_ALIASES};
|
||||
for (const codePoint in HTML_ENTITY_LOOKUP) {
|
||||
HTML_ENTITY_REVERSE_LOOKUP[HTML_ENTITY_LOOKUP[codePoint]] = Number(codePoint);
|
||||
}
|
||||
`;
|
||||
|
||||
fs.writeFileSync(path.join(process.cwd(), "src/core/lib/HTMLEntities.mjs"), code);
|
||||
console.log(`generateHTMLEntities: ${Object.keys(forward).length} encode names, ` +
|
||||
`${Object.keys(reverse).length} decode names, ${Object.keys(aliases).length} aliases, ` +
|
||||
`${Object.keys(HTML_ENTITY_CANONICAL_OVERRIDES).length} overrides applied.`);
|
||||
86
src/core/config/scripts/htmlEntityOverrides.mjs
Normal file
86
src/core/config/scripts/htmlEntityOverrides.mjs
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Canonical entity-name overrides for generateHTMLEntities.mjs.
|
||||
*
|
||||
* The WHATWG named character reference set assigns MANY names to some code
|
||||
* points (e.g. U+2211 is both ∑ and ∑), but does not designate a
|
||||
* canonical one. The generator therefore needs a rule to pick a single name per
|
||||
* code point for ENCODING. It uses a deterministic tiebreak (prefer a
|
||||
* lower-case name, then the shortest, then alphabetical), which reproduces the
|
||||
* historically-emitted name for ~1355 of the ~1414 encodable code points.
|
||||
*
|
||||
* This file pins the canonical name for the code points where the tiebreak
|
||||
* would otherwise change the emitted entity. Every value here is still a valid
|
||||
* WHATWG name for that code point (the generator asserts this) — these are
|
||||
* editorial choices, not correctness fixes, kept so "To HTML Entity" output
|
||||
* stays stable. Trim an entry to let the tiebreak decide instead.
|
||||
*
|
||||
* @author roberson-io [michaelroberson@gmail.com]
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @type {Object.<number, string>}
|
||||
*/
|
||||
export const HTML_ENTITY_CANONICAL_OVERRIDES = {
|
||||
124: "verbar",
|
||||
168: "uml",
|
||||
177: "plusmn",
|
||||
189: "frac12",
|
||||
247: "divide",
|
||||
711: "caron",
|
||||
728: "breve",
|
||||
937: "Omega",
|
||||
949: "epsilon",
|
||||
965: "upsilon",
|
||||
977: "thetasym",
|
||||
978: "upsih",
|
||||
981: "straightphi",
|
||||
8208: "hyphen",
|
||||
8214: "Verbar",
|
||||
8230: "hellip",
|
||||
8289: "ApplyFunction",
|
||||
8290: "InvisibleTimes",
|
||||
8291: "InvisibleComma",
|
||||
8459: "hamilt",
|
||||
8461: "quaternions",
|
||||
8463: "planck",
|
||||
8465: "image",
|
||||
8472: "weierp",
|
||||
8474: "rationals",
|
||||
8476: "real",
|
||||
8477: "reals",
|
||||
8484: "integers",
|
||||
8492: "bernou",
|
||||
8499: "phmmat",
|
||||
8500: "order",
|
||||
8501: "alefsym",
|
||||
8518: "DifferentialD",
|
||||
8519: "ExponentialE",
|
||||
8520: "ImaginaryI",
|
||||
8612: "LeftTeeArrow",
|
||||
8613: "UpTeeArrow",
|
||||
8615: "DownTeeArrow",
|
||||
8624: "lsh",
|
||||
8625: "rsh",
|
||||
8660: "hArr",
|
||||
8704: "forall",
|
||||
8711: "nabla",
|
||||
8712: "isin",
|
||||
8721: "sum",
|
||||
8723: "mnplus",
|
||||
8730: "radic",
|
||||
8750: "conint",
|
||||
8768: "wreath",
|
||||
8776: "asymp",
|
||||
8781: "asympeq",
|
||||
8784: "esdot",
|
||||
8788: "colone",
|
||||
8869: "perp",
|
||||
8896: "xwedge",
|
||||
8897: "xvee",
|
||||
8902: "sstarf",
|
||||
10536: "nesear",
|
||||
10537: "seswar"
|
||||
};
|
||||
@ -70,4 +70,3 @@ export function modPow(base, exponent, modulus) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
86
src/core/lib/COBS.mjs
Normal file
86
src/core/lib/COBS.mjs
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @author Imantas Lukenskas [imantas@lukenskas.dev]
|
||||
* @copyright Imantas Lukenskas 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* COBS-encode a byte array
|
||||
* @param {Uint8Array} data
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
export function toCobs(data) {
|
||||
if (!data || data.length === 0) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
|
||||
const output = [];
|
||||
data = [0, ...data];
|
||||
|
||||
while (data.length > 0) {
|
||||
const endIndex = data.findIndex((value, index) => value === 0 && index > 0);
|
||||
|
||||
if ((endIndex < 0 || endIndex > 254) && data.length > 254) {
|
||||
output.push(255);
|
||||
output.push(...data.slice(1, 255));
|
||||
data = data.slice(255);
|
||||
if (data.length !== 0) {
|
||||
data = [0, ...data];
|
||||
}
|
||||
} else if (endIndex < 0) {
|
||||
output.push(data.length);
|
||||
output.push(...data.slice(1));
|
||||
data = [];
|
||||
} else {
|
||||
output.push(endIndex);
|
||||
output.push(...data.slice(1, endIndex));
|
||||
data = data.slice(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* COBS-decode a byte array
|
||||
* @param {Uint8Array} data
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
export function fromCobs(data) {
|
||||
if (!data || data.length === 0) {
|
||||
return new Uint8Array();
|
||||
}
|
||||
|
||||
if (data.findIndex((value) => value === 0) >= 0) {
|
||||
throw new OperationError("Could not decode from COBS: payload must not contain a 0x00 byte");
|
||||
}
|
||||
|
||||
const output = [];
|
||||
|
||||
while (data.length > 0) {
|
||||
if (data[0] === 0xFF) {
|
||||
output.push(...data.slice(1, 255));
|
||||
data = data.slice(255);
|
||||
} else {
|
||||
const nextZeroIndex = data[0];
|
||||
output.push(...data.slice(1, nextZeroIndex));
|
||||
data = data.slice(nextZeroIndex);
|
||||
|
||||
let blockSize = data[0];
|
||||
while (data.length > 0) {
|
||||
output.push(0, ...data.slice(1, blockSize));
|
||||
data = data.slice(blockSize);
|
||||
|
||||
if (blockSize === 0xFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
blockSize = data[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
101
src/core/operations/ExtendedGCD.mjs
Normal file
101
src/core/operations/ExtendedGCD.mjs
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { parseBigInt, egcd } from "../lib/BigIntUtils.mjs";
|
||||
|
||||
/* ---------- operation class ---------- */
|
||||
|
||||
/**
|
||||
* Extended GCD operation
|
||||
*/
|
||||
class ExtendedGCD extends Operation {
|
||||
/**
|
||||
* ExtendedGCD constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extended GCD";
|
||||
this.module = "Crypto";
|
||||
this.description =
|
||||
"Computes the Extended Euclidean Algorithm for integers <i>a</i> and <i>b</i>.<br><br>" +
|
||||
"Finds integers <i>x</i> and <i>y</i> (Bezout coefficients) such that:<br>" +
|
||||
"a*x + b*y = gcd(a, b)<br><br>" +
|
||||
"This is fundamental to many number theory algorithms including modular inverse, " +
|
||||
"solving linear Diophantine equations, and cryptographic operations.<br><br>" +
|
||||
"<b>Input handling:</b> If either <i>a</i> or <i>b</i> is left blank, " +
|
||||
"its value is taken from the Input field.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Extended_Euclidean_algorithm";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Value a",
|
||||
type: "string",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
name: "Value b",
|
||||
type: "string",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [aStr, bStr] = args;
|
||||
|
||||
// Trim everything so "" and " " count as empty
|
||||
const aParam = aStr?.trim();
|
||||
const bParam = bStr?.trim();
|
||||
const inputVal = input?.trim();
|
||||
|
||||
let a, b;
|
||||
|
||||
if (aParam && bParam) {
|
||||
// Case 1: both values given as parameters
|
||||
a = aParam;
|
||||
b = bParam;
|
||||
} else if (!aParam && bParam) {
|
||||
// Case 2: a missing - take from input
|
||||
a = inputVal;
|
||||
b = bParam;
|
||||
if (!a) throw new OperationError("Value a must be defined");
|
||||
} else if (aParam && !bParam) {
|
||||
// Case 3: b missing - take from input
|
||||
a = aParam;
|
||||
b = inputVal;
|
||||
if (!b) throw new OperationError("Value b must be defined");
|
||||
} else if (!aParam && !bParam) {
|
||||
// Case 4: both values missing
|
||||
throw new OperationError("Values a and b must be defined");
|
||||
}
|
||||
|
||||
const aBI = parseBigInt(a, "Value a");
|
||||
const bBI = parseBigInt(b, "Value b");
|
||||
|
||||
const [g, x, y] = egcd(aBI, bBI);
|
||||
const gcd = g < 0n ? -g : g;
|
||||
|
||||
// Format output string bearing in mind that crypto-grade numbers
|
||||
// may greatly exceed the line length.
|
||||
let output = "gcd: " + gcd.toString() + "\n\n";
|
||||
output += "Bezout coefficients:\n";
|
||||
output += "x = " + x.toString() + "\n";
|
||||
output += "y = " + y.toString() + "\n\n";
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export default ExtendedGCD;
|
||||
38
src/core/operations/FromCOBS.mjs
Normal file
38
src/core/operations/FromCOBS.mjs
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @author Imantas Lukenskas [imantas@lukenskas.dev]
|
||||
* @copyright Imantas Lukenskas 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {fromCobs} from "../lib/COBS.mjs";
|
||||
|
||||
/**
|
||||
* From COBS operation
|
||||
*/
|
||||
class FromCOBS extends Operation {
|
||||
/**
|
||||
* FromCOBS constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From COBS";
|
||||
this.module = "Default";
|
||||
this.description = "Decodes COBS encoded bytes";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
return fromCobs(input);
|
||||
}
|
||||
}
|
||||
|
||||
export default FromCOBS;
|
||||
File diff suppressed because it is too large
Load Diff
154
src/core/operations/GeneratePrime.mjs
Normal file
154
src/core/operations/GeneratePrime.mjs
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { modPow } from "../lib/BigIntUtils.mjs";
|
||||
|
||||
/* ---------- helper functions ---------- */
|
||||
|
||||
/**
|
||||
* Generate random BigInt with specified bit length
|
||||
*/
|
||||
function randBigInt(bits) {
|
||||
const bytes = Math.ceil(bits / 8);
|
||||
const a = new Uint8Array(bytes);
|
||||
crypto.getRandomValues(a);
|
||||
|
||||
// Set high bit to ensure correct bit length
|
||||
a[0] |= 1 << (7 - ((8 * bytes - bits)));
|
||||
// Set low bit to ensure odd (primes > 2 are odd)
|
||||
a[bytes - 1] |= 1;
|
||||
|
||||
let h = "";
|
||||
for (const b of a) h += b.toString(16).padStart(2, "0");
|
||||
return BigInt("0x" + h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Miller-Rabin primality test
|
||||
*/
|
||||
function isProbablePrime(n, rounds) {
|
||||
if (n < 2n) return false;
|
||||
if (n === 2n || n === 3n) return true;
|
||||
if (n % 2n === 0n) return false;
|
||||
|
||||
// Write n-1 as 2^r * d
|
||||
let d = n - 1n;
|
||||
let r = 0n;
|
||||
while (d % 2n === 0n) {
|
||||
d /= 2n;
|
||||
r++;
|
||||
}
|
||||
|
||||
// Witness loop
|
||||
for (let i = 0; i < rounds; i++) {
|
||||
const a = randBigInt(n.toString(2).length - 1) % (n - 3n) + 2n;
|
||||
let x = modPow(a, d, n);
|
||||
|
||||
if (x === 1n || x === n - 1n) continue;
|
||||
|
||||
let composite = true;
|
||||
for (let j = 0n; j < r - 1n; j++) {
|
||||
x = modPow(x, 2n, n);
|
||||
if (x === n - 1n) {
|
||||
composite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (composite) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---------- operation class ---------- */
|
||||
|
||||
/**
|
||||
* Generate Prime Number operation
|
||||
*/
|
||||
class GeneratePrime extends Operation {
|
||||
/**
|
||||
* GeneratePrime constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Pseudo-Random Prime Generator";
|
||||
this.module = "Crypto";
|
||||
this.description =
|
||||
"Generates a random probable prime number of specified bit length using the Miller-Rabin primality test.<br><br>" +
|
||||
"<b>Primality guarantee:</b><br>" +
|
||||
"For numbers . 3,317, the result is guaranteed prime (deterministic test).<br>" +
|
||||
"For larger numbers, uses probabilistic testing:<br>" +
|
||||
"- <b>Standard (7 rounds):</b> Probability of composite approx 1 in 16,000)<br><br>" +
|
||||
"- <b>Crypto grade (40 rounds):</b> Probability of composite(approx 1 in 10^24)<br>" +
|
||||
"Crypto grade is recommended for cryptographic applications (RSA, Diffie-Hellman, etc.).<br><br>" ;
|
||||
this.infoURL = "https://wikipedia.org/wiki/Miller-Rabin_primality_test";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Bit length",
|
||||
type: "number",
|
||||
value: 512,
|
||||
min: 2
|
||||
},
|
||||
{
|
||||
name: "Crypto grade",
|
||||
type: "boolean",
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Output format",
|
||||
type: "option",
|
||||
value: ["Decimal", "Hexadecimal"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [bits, cryptoGrade, outputFormat] = args;
|
||||
|
||||
if (bits < 2) {
|
||||
throw new OperationError("Bit length must be at least 2");
|
||||
}
|
||||
|
||||
if (bits > 4096) {
|
||||
throw new OperationError("Bit length limited to 4096 bits for performance reasons");
|
||||
}
|
||||
|
||||
const rounds = cryptoGrade ? 40 : 7;
|
||||
let attempts = 0;
|
||||
const maxAttempts = 10000;
|
||||
|
||||
let n = randBigInt(bits);
|
||||
|
||||
while (!isProbablePrime(n, rounds)) {
|
||||
n = randBigInt(bits);
|
||||
attempts++;
|
||||
|
||||
if (attempts > maxAttempts) {
|
||||
throw new OperationError(`Failed to generate prime after ${maxAttempts} attempts. Try a different bit length.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Return only the prime for pipeability
|
||||
if (outputFormat === "Hexadecimal") {
|
||||
return "0x" + n.toString(16);
|
||||
} else {
|
||||
return n.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GeneratePrime;
|
||||
107
src/core/operations/ModularInverse.mjs
Normal file
107
src/core/operations/ModularInverse.mjs
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { parseBigInt, egcd } from "../lib/BigIntUtils.mjs";
|
||||
|
||||
|
||||
/* ---------- operation class ---------- */
|
||||
|
||||
/**
|
||||
* Modular Inverse operation
|
||||
*/
|
||||
class ModularInverse extends Operation {
|
||||
|
||||
/**
|
||||
* ModularInverse constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Modular Inverse";
|
||||
this.module = "Crypto";
|
||||
this.description =
|
||||
"Computes the modular multiplicative inverse of <i>a</i> modulo <i>m</i>.<br><br>" +
|
||||
"Finds <i>x</i> such that a*x = 1 (mod m).<br><br>" +
|
||||
"<b>Input handling:</b> If either <i>a</i> or <i>m</i> is left blank, " +
|
||||
"its value is taken from the Input field.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Modular_multiplicative_inverse";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Value (a)",
|
||||
type: "string",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
name: "Modulus (m)",
|
||||
type: "string",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [aStr, mStr] = args;
|
||||
|
||||
// Trim everything so "" and " " count as empty
|
||||
const aParam = aStr?.trim();
|
||||
const mParam = mStr?.trim();
|
||||
const inputVal = input?.trim();
|
||||
|
||||
let a, m;
|
||||
|
||||
if (aParam && mParam) {
|
||||
// Case 1: value and modulus both given as parameters
|
||||
a = aParam;
|
||||
m = mParam;
|
||||
} else if (!aParam && mParam) {
|
||||
// Case 2: value missing - take from input
|
||||
a = inputVal;
|
||||
m = mParam;
|
||||
if (!a) throw new OperationError("Value (a) must be defined");
|
||||
} else if (aParam && !mParam) {
|
||||
// Case 3: modulus missing - take from input
|
||||
a = aParam;
|
||||
m = inputVal;
|
||||
if (!m) throw new OperationError("Modulus (m) must be defined");
|
||||
} else if (!aParam && !mParam) {
|
||||
// Case 4: value and modulus both missing
|
||||
throw new OperationError("Value (a) and Modulus (m) must be defined");
|
||||
}
|
||||
|
||||
const aBI = parseBigInt(a, "Value (a)");
|
||||
const mBI = parseBigInt(m, "Modulus (m)");
|
||||
|
||||
if (mBI <= 0n) {
|
||||
throw new OperationError("Modulus must be greater than zero");
|
||||
}
|
||||
|
||||
const aNorm = ((aBI % mBI) + mBI) % mBI;
|
||||
const [g, x] = egcd(aNorm, mBI);
|
||||
|
||||
if (g !== 1n && g !== -1n) {
|
||||
throw new OperationError("Inverse does not exist because gcd(a, m) ≠ 1");
|
||||
}
|
||||
|
||||
let inv = x;
|
||||
if (g === -1n) inv = -inv;
|
||||
|
||||
inv = ((inv % mBI) + mBI) % mBI;
|
||||
|
||||
|
||||
return inv.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export default ModularInverse;
|
||||
154
src/core/operations/RandomPrime.mjs
Normal file
154
src/core/operations/RandomPrime.mjs
Normal file
@ -0,0 +1,154 @@
|
||||
/**
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { modPow } from "../lib/BigIntUtils.mjs";
|
||||
|
||||
/* ---------- helper functions ---------- */
|
||||
|
||||
/**
|
||||
* Generate random BigInt with specified bit length
|
||||
*/
|
||||
function randBigInt(bits) {
|
||||
const bytes = Math.ceil(bits / 8);
|
||||
const a = new Uint8Array(bytes);
|
||||
crypto.getRandomValues(a);
|
||||
|
||||
// Set high bit to ensure correct bit length
|
||||
a[0] |= 1 << (7 - ((8 * bytes - bits)));
|
||||
// Set low bit to ensure odd (primes > 2 are odd)
|
||||
a[bytes - 1] |= 1;
|
||||
|
||||
let h = "";
|
||||
for (const b of a) h += b.toString(16).padStart(2, "0");
|
||||
return BigInt("0x" + h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Miller-Rabin primality test
|
||||
*/
|
||||
function isProbablePrime(n, rounds) {
|
||||
if (n < 2n) return false;
|
||||
if (n === 2n || n === 3n) return true;
|
||||
if (n % 2n === 0n) return false;
|
||||
|
||||
// Write n-1 as 2^r * d
|
||||
let d = n - 1n;
|
||||
let r = 0n;
|
||||
while (d % 2n === 0n) {
|
||||
d /= 2n;
|
||||
r++;
|
||||
}
|
||||
|
||||
// Witness loop
|
||||
for (let i = 0; i < rounds; i++) {
|
||||
const a = randBigInt(n.toString(2).length - 1) % (n - 3n) + 2n;
|
||||
let x = modPow(a, d, n);
|
||||
|
||||
if (x === 1n || x === n - 1n) continue;
|
||||
|
||||
let composite = true;
|
||||
for (let j = 0n; j < r - 1n; j++) {
|
||||
x = modPow(x, 2n, n);
|
||||
if (x === n - 1n) {
|
||||
composite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (composite) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---------- operation class ---------- */
|
||||
|
||||
/**
|
||||
* Generate Prime Number operation
|
||||
*/
|
||||
class GeneratePrime extends Operation {
|
||||
/**
|
||||
* GeneratePrime constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Pseudo-Random Prime Generator";
|
||||
this.module = "Crypto";
|
||||
this.description =
|
||||
"Generates a random probable prime number of specified bit length using the Miller-Rabin primality test.<br><br>" +
|
||||
"<b>Primality guarantee:</b><br>" +
|
||||
"For numbers . 3,317, the result is guaranteed prime (deterministic test).<br>" +
|
||||
"For larger numbers, uses probabilistic testing:<br>" +
|
||||
"- <b>Standard (7 rounds):</b> Probability of composite approx 1 in 16,000)<br><br>" +
|
||||
"- <b>Crypto grade (40 rounds):</b> Probability of composite(approx 1 in 10^24)<br>" +
|
||||
"Crypto grade is recommended for cryptographic applications (RSA, Diffie-Hellman, etc.).<br><br>" ;
|
||||
this.infoURL = "https://wikipedia.org/wiki/Miller-Rabin_primality_test";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Bit length",
|
||||
type: "number",
|
||||
value: 512,
|
||||
min: 2
|
||||
},
|
||||
{
|
||||
name: "Crypto grade",
|
||||
type: "boolean",
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Output format",
|
||||
type: "option",
|
||||
value: ["Decimal", "Hexadecimal"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [bits, cryptoGrade, outputFormat] = args;
|
||||
|
||||
if (bits < 2) {
|
||||
throw new OperationError("Bit length must be at least 2");
|
||||
}
|
||||
|
||||
if (bits > 4096) {
|
||||
throw new OperationError("Bit length limited to 4096 bits for performance reasons");
|
||||
}
|
||||
|
||||
const rounds = cryptoGrade ? 40 : 7;
|
||||
let attempts = 0;
|
||||
const maxAttempts = 10000;
|
||||
|
||||
let n = randBigInt(bits);
|
||||
|
||||
while (!isProbablePrime(n, rounds)) {
|
||||
n = randBigInt(bits);
|
||||
attempts++;
|
||||
|
||||
if (attempts > maxAttempts) {
|
||||
throw new OperationError(`Failed to generate prime after ${maxAttempts} attempts. Try a different bit length.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Return only the prime for pipeability
|
||||
if (outputFormat === "Hexadecimal") {
|
||||
return "0x" + n.toString(16);
|
||||
} else {
|
||||
return n.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GeneratePrime;
|
||||
38
src/core/operations/ToCOBS.mjs
Normal file
38
src/core/operations/ToCOBS.mjs
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @author Imantas Lukenskas [imantas@lukenskas.dev]
|
||||
* @copyright Imantas Lukenskas 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {toCobs} from "../lib/COBS.mjs";
|
||||
|
||||
/**
|
||||
* To COBS operation
|
||||
*/
|
||||
class ToCOBS extends Operation {
|
||||
/**
|
||||
* ToCOBS constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To COBS";
|
||||
this.module = "Default";
|
||||
this.description = "Encodes bytes in COBS format";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
return toCobs(input);
|
||||
}
|
||||
}
|
||||
|
||||
export default ToCOBS;
|
||||
File diff suppressed because it is too large
Load Diff
2233
src/core/vendor/htmlEntities/entity.json
vendored
Normal file
2233
src/core/vendor/htmlEntities/entity.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14
src/core/vendor/htmlEntities/entity.txt
vendored
Normal file
14
src/core/vendor/htmlEntities/entity.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
entity.json is the WHATWG named character reference set, retrieved verbatim from:
|
||||
|
||||
https://html.spec.whatwg.org/entities.json
|
||||
|
||||
It is used by src/core/config/scripts/generateHTMLEntities.mjs to generate the
|
||||
shared HTML entity lookup tables (src/core/lib/HTMLEntities.mjs) consumed by the
|
||||
"To HTML Entity" and "From HTML Entity" operations.
|
||||
|
||||
Source: HTML Standard — 13.5 Named character references
|
||||
https://html.spec.whatwg.org/multipage/named-characters.html
|
||||
|
||||
Copyright and licence
|
||||
---------------------
|
||||
Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). This work is licensed under a Creative Commons Attribution 4.0 International License. To the extent portions of it are incorporated into source code, such portions in the source code are licensed under the BSD 3-Clause License instead.
|
||||
@ -24,6 +24,7 @@ import "./tests/Dish.mjs";
|
||||
import "./tests/NodeDish.mjs";
|
||||
import "./tests/Utils.mjs";
|
||||
import "./tests/Categories.mjs";
|
||||
import "./tests/ToHTMLEntity.mjs";
|
||||
import "./tests/lib/BigIntUtils.mjs";
|
||||
import "./tests/lib/ChartsProtocolPrototypePollution.mjs";
|
||||
|
||||
|
||||
82
tests/node/tests/ToHTMLEntity.mjs
Normal file
82
tests/node/tests/ToHTMLEntity.mjs
Normal file
@ -0,0 +1,82 @@
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
import ToHTMLEntity from "../../../src/core/operations/ToHTMLEntity.mjs";
|
||||
import FromHTMLEntity from "../../../src/core/operations/FromHTMLEntity.mjs";
|
||||
import { HTML_ENTITY_LOOKUP, HTML_ENTITY_REVERSE_LOOKUP } from "../../../src/core/lib/HTMLEntities.mjs";
|
||||
import it from "../assertionHandler.mjs";
|
||||
import assert from "assert";
|
||||
import { readFileSync } from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import path from "path";
|
||||
|
||||
// Vendored WHATWG named character reference set (https://html.spec.whatwg.org/entities.json).
|
||||
const SPEC = JSON.parse(readFileSync(path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"../../../src/core/vendor/htmlEntities/entity.json"), "utf8"));
|
||||
const specByName = {};
|
||||
for (const [key, val] of Object.entries(SPEC))
|
||||
if (key.endsWith(";")) specByName[key.slice(1, -1)] = val.codepoints;
|
||||
|
||||
TestRegister.addApiTests([
|
||||
it("To HTML Entity: every named entity in the table is well-formed", () => {
|
||||
// "Convert all characters" emits an entity for every code point, so a
|
||||
// correct table yields an unbroken stream of entity tokens. A malformed
|
||||
// value such as "≱;" or "ε," leaves stray characters between
|
||||
// tokens, which the walk below flags and reports with surrounding context.
|
||||
let input = "";
|
||||
for (let cp = 0; cp <= 0xFFFF; cp++) {
|
||||
if (cp >= 0xD800 && cp <= 0xDFFF) continue; // skip surrogate range
|
||||
input += String.fromCodePoint(cp);
|
||||
}
|
||||
const output = new ToHTMLEntity().run(input, [true, "Named entities"]);
|
||||
|
||||
const tokenRe = /&#[0-9]+;|&#x[0-9a-fA-F]+;|&[A-Za-z][A-Za-z0-9]*;/y;
|
||||
const malformed = [];
|
||||
let pos = 0;
|
||||
while (pos < output.length) {
|
||||
tokenRe.lastIndex = pos;
|
||||
if (tokenRe.exec(output)) {
|
||||
pos = tokenRe.lastIndex;
|
||||
} else {
|
||||
malformed.push(output.slice(Math.max(0, pos - 12), pos + 12));
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
assert.deepStrictEqual(malformed, [], `Malformed entity value(s) near: ${JSON.stringify(malformed)}`);
|
||||
}),
|
||||
|
||||
it("HTML Entity: named encoding round-trips through From HTML Entity", () => {
|
||||
// Because both operations share one lookup table, encoding a character to
|
||||
// a named entity and decoding it must return the original character for
|
||||
// every BMP code point: FromHTMLEntity(ToHTMLEntity(x)) === x.
|
||||
const toOp = new ToHTMLEntity(),
|
||||
fromOp = new FromHTMLEntity();
|
||||
const mismatches = [];
|
||||
for (let cp = 0; cp <= 0xFFFF; cp++) {
|
||||
if (cp >= 0xD800 && cp <= 0xDFFF) continue; // skip surrogate range
|
||||
const char = String.fromCodePoint(cp);
|
||||
const encoded = toOp.run(char, [true, "Named entities"]);
|
||||
const decoded = fromOp.run(encoded, []);
|
||||
if (decoded !== char)
|
||||
mismatches.push(`U+${cp.toString(16).toUpperCase().padStart(4, "0")} -> ${encoded} -> U+${decoded.codePointAt(0).toString(16).toUpperCase()}`);
|
||||
}
|
||||
assert.deepStrictEqual(mismatches, [], `Round-trip failed for: ${JSON.stringify(mismatches.slice(0, 20))}`);
|
||||
}),
|
||||
|
||||
it("HTML Entity: every table entry is conformant with the WHATWG spec", () => {
|
||||
// Both lookup tables must agree with entities.json: every encode name is a
|
||||
// real spec name mapping to exactly that code point, and every decode name
|
||||
// maps to the spec code point.
|
||||
const violations = [];
|
||||
for (const [cp, name] of Object.entries(HTML_ENTITY_LOOKUP)) {
|
||||
const spec = specByName[name];
|
||||
if (!spec || spec.length !== 1 || spec[0] !== Number(cp))
|
||||
violations.push(`encode ${cp} -> &${name}; (spec: ${spec ? JSON.stringify(spec) : "none"})`);
|
||||
}
|
||||
for (const [name, cp] of Object.entries(HTML_ENTITY_REVERSE_LOOKUP)) {
|
||||
const spec = specByName[name];
|
||||
if (!spec || spec.length !== 1 || spec[0] !== cp)
|
||||
violations.push(`decode &${name}; -> ${cp} (spec: ${spec ? JSON.stringify(spec) : "none"})`);
|
||||
}
|
||||
assert.deepStrictEqual(violations, [], `Spec violations: ${JSON.stringify(violations.slice(0, 20))}`);
|
||||
}),
|
||||
]);
|
||||
476
tests/operations/tests/COBS.mjs
Normal file
476
tests/operations/tests/COBS.mjs
Normal file
@ -0,0 +1,476 @@
|
||||
/**
|
||||
* @author Imantas Lukenskas [imantas@lukenskas.dev]
|
||||
* @copyright Imantas Lukenskas 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
// values in "COBS" testcases are taken from here:
|
||||
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "To COBS Example #1",
|
||||
"input": "00",
|
||||
"expectedOutput": "01 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #2",
|
||||
"input": "00 00",
|
||||
"expectedOutput": "01 01 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #3",
|
||||
"input": "00 11 00",
|
||||
"expectedOutput": "01 02 11 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #4",
|
||||
"input": "11 22 00 33",
|
||||
"expectedOutput": "03 11 22 02 33",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #5",
|
||||
"input": "11 22 33 44",
|
||||
"expectedOutput": "05 11 22 33 44",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #6",
|
||||
"input": "11 00 00 00",
|
||||
"expectedOutput": "02 11 01 01 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #7",
|
||||
"input": "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"expectedOutput": "ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #8",
|
||||
"input": "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"expectedOutput": "01 ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #9",
|
||||
"input": "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
|
||||
"expectedOutput": "ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe 02 ff",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #10",
|
||||
"input": "02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00",
|
||||
"expectedOutput": "ff 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 01 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "To COBS Example #11",
|
||||
"input": "03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01",
|
||||
"expectedOutput": "fe 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 02 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "To COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #1",
|
||||
"input": "01 01",
|
||||
"expectedOutput": "00",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #2",
|
||||
"input": "01 01 01",
|
||||
"expectedOutput": "00 00",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #3",
|
||||
"input": "01 02 11 01",
|
||||
"expectedOutput": "00 11 00",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #4",
|
||||
"input": "03 11 22 02 33",
|
||||
"expectedOutput": "11 22 00 33",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #5",
|
||||
"input": "05 11 22 33 44",
|
||||
"expectedOutput": "11 22 33 44",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #6",
|
||||
"input": "02 11 01 01 01",
|
||||
"expectedOutput": "11 00 00 00",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #7",
|
||||
"input": "ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"expectedOutput": "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #8",
|
||||
"input": "01 ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"expectedOutput": "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #9",
|
||||
"input": "ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe 02 ff",
|
||||
"expectedOutput": "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #10",
|
||||
"input": "ff 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 01 01",
|
||||
"expectedOutput": "02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Example #11",
|
||||
"input": "fe 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 02 01",
|
||||
"expectedOutput": "03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 01",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "From COBS Invalid input #1",
|
||||
"input": "00 48 45 4C 4C 4F",
|
||||
"expectedOutput": "Could not decode from COBS: payload must not contain a 0x00 byte",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "From COBS Invalid input #2",
|
||||
"input": "48 45 00 4C 4C 4F",
|
||||
"expectedOutput": "Could not decode from COBS: payload must not contain a 0x00 byte",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "From COBS Invalid input #3",
|
||||
"input": "48 45 4C 4C 4F 00",
|
||||
"expectedOutput": "Could not decode from COBS: payload must not contain a 0x00 byte",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "From COBS",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
78
tests/operations/tests/ExtendedGCD.mjs
Normal file
78
tests/operations/tests/ExtendedGCD.mjs
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Extended GCD tests.
|
||||
*
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
*
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Extended GCD: coprime numbers (3, 11)",
|
||||
input: "",
|
||||
expectedOutput: "gcd: 1\n\nBezout coefficients:\nx = 4\ny = -1\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["3", "11"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extended GCD: non-coprime numbers (240, 46)",
|
||||
input: "",
|
||||
expectedOutput: "gcd: 2\n\nBezout coefficients:\nx = -9\ny = 47\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["240", "46"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extended GCD: with zero (17, 0)",
|
||||
input: "",
|
||||
expectedOutput: "gcd: 17\n\nBezout coefficients:\nx = 1\ny = 0\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["17", "0"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extended GCD: hexadecimal input (0xFF, 0x11)",
|
||||
input: "",
|
||||
expectedOutput: "gcd: 17\n\nBezout coefficients:\nx = 0\ny = 1\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["0xFF", "0x11"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extended GCD: using input field for value a",
|
||||
input: "42",
|
||||
expectedOutput: "gcd: 7\n\nBezout coefficients:\nx = 1\ny = -1\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["", "35"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extended GCD: large numbers",
|
||||
input: "",
|
||||
expectedOutput: "gcd: 2\n\nBezout coefficients:\nx = 12703973750415151\ny = -1577756566311408967124629843\n\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Extended GCD",
|
||||
args: ["123456789012345678901234567890", "994064509324197316"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
126
tests/operations/tests/HTMLEntity.mjs
Normal file
126
tests/operations/tests/HTMLEntity.mjs
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* To/From HTML Entity tests.
|
||||
*
|
||||
* @author roberson-io [michaelroberson@gmail.com]
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "To HTML Entity: named",
|
||||
input: "<a href='#'>\"&\"</a>",
|
||||
expectedOutput: "<a href='#'>"&"</a>",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [false, "Named entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Regression: this value was "⇌;" (stray trailing semicolon) in the
|
||||
// original byteToEntity table. See issue #2645.
|
||||
name: "To HTML Entity: malformed value fixed (U+21CC)",
|
||||
input: "⇌",
|
||||
expectedOutput: "⇌",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [false, "Named entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Regression: U+03F5 emitted "ε," before; the spec name is ϵ
|
||||
// (ε is U+03B5). See issue #2645.
|
||||
name: "To HTML Entity: spec-conformant name (U+03F5)",
|
||||
input: "ϵ",
|
||||
expectedOutput: "ϵ",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [false, "Named entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Regression: the OHM SIGN previously emitted the non-conformant Ω
|
||||
// (spec Ω is U+03A9). It now encodes numerically.
|
||||
name: "To HTML Entity: non-conformant name dropped (U+2126 ohm sign)",
|
||||
input: "Ω",
|
||||
expectedOutput: "Ω",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [false, "Named entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// The FULL BLOCK previously decoded to █ but never encoded to it.
|
||||
// Generating both tables from the spec fixes this asymmetry.
|
||||
name: "To HTML Entity: encode/decode symmetry (U+2588 block)",
|
||||
input: "█",
|
||||
expectedOutput: "█",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [false, "Named entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To HTML Entity: numeric, convert all",
|
||||
input: "A<",
|
||||
expectedOutput: "A<",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [true, "Numeric entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To HTML Entity: hex, convert all",
|
||||
input: "A<",
|
||||
expectedOutput: "A<",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [true, "Hex entities"] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From HTML Entity: named",
|
||||
input: "<a href='#'>"&"</a>",
|
||||
expectedOutput: "<a href='#'>\"&\"</a>",
|
||||
recipeConfig: [
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Legacy/alias names still decode, now to the spec code point.
|
||||
name: "From HTML Entity: alias to spec code point (Ω)",
|
||||
input: "Ω",
|
||||
expectedOutput: "Ω",
|
||||
recipeConfig: [
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From HTML Entity: decimal numeric entity",
|
||||
input: "A",
|
||||
expectedOutput: "A",
|
||||
recipeConfig: [
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From HTML Entity: hex numeric entity",
|
||||
input: "A",
|
||||
expectedOutput: "A",
|
||||
recipeConfig: [
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Unknown entities are passed through unchanged.
|
||||
name: "From HTML Entity: invalid entity passed through",
|
||||
input: "a ¬real; b",
|
||||
expectedOutput: "a ¬real; b",
|
||||
recipeConfig: [
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "HTML Entity: round-trips through both operations",
|
||||
input: "Hello <World> & \"friends\" — ⇌ █",
|
||||
expectedOutput: "Hello <World> & \"friends\" — ⇌ █",
|
||||
recipeConfig: [
|
||||
{ op: "To HTML Entity", args: [true, "Named entities"] },
|
||||
{ op: "From HTML Entity", args: [] },
|
||||
],
|
||||
},
|
||||
]);
|
||||
78
tests/operations/tests/ModularInverse.mjs
Normal file
78
tests/operations/tests/ModularInverse.mjs
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Modular Inverse tests.
|
||||
*
|
||||
* @author p-leriche [philip.leriche@cantab.net]
|
||||
*
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Modular Inverse: basic example (3 mod 11)",
|
||||
input: "",
|
||||
expectedOutput: "4",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["3", "11"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Modular Inverse: another coprime pair (7 mod 26)",
|
||||
input: "",
|
||||
expectedOutput: "15",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["7", "26"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Modular Inverse: hexadecimal input (0x10 mod 0x11)",
|
||||
input: "",
|
||||
expectedOutput: "16",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["0x10", "0x11"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Modular Inverse: using input field for value",
|
||||
input: "5",
|
||||
expectedOutput: "21",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["", "26"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Modular Inverse: using input field for modulus",
|
||||
input: "17",
|
||||
expectedOutput: "7",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["5", ""],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Modular Inverse: large number (RSA-like)",
|
||||
input: "",
|
||||
expectedOutput: "934281398294",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Modular Inverse",
|
||||
args: ["65537", "9999999999999"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user