diff --git a/.github/actions/setup-chrome/action.yml b/.github/actions/setup-chrome/action.yml new file mode 100644 index 0000000000..6bb5663f97 --- /dev/null +++ b/.github/actions/setup-chrome/action.yml @@ -0,0 +1,24 @@ +name: 'Setup Chrome' +description: 'Installs a pinned version of Chrome and links it for chromedriver' + +inputs: + chrome-version: + description: 'Chrome version to install' + required: false + default: '152' + +runs: + using: 'composite' + steps: + - name: Setup Chrome + shell: bash + run: | + rm -rf chrome/ + rm -rf node_modules/chromedriver/lib/chromedriver/chrome + npx @puppeteer/browsers install chrome@${{ inputs.chrome-version }} + chromepath=$(find "$(pwd)"/chrome/* -name chrome -print -quit) + if [ -z "$chromepath" ]; then + echo "Chrome binary not found after install under $(pwd)/chrome" >&2 + exit 1 + fi + ln -s "$chromepath" node_modules/chromedriver/lib/chromedriver/chrome \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 75f1e43b7a..23dd223078 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -53,14 +53,11 @@ jobs: - name: Setup Chrome id: setup-chrome if: success() - run: | - npx @puppeteer/browsers install chrome@148 - echo chromedir=$(dirname $(find `pwd`/chrome/* -name chrome -print -quit)) >> $GITHUB_OUTPUT + uses: ./.github/actions/setup-chrome - name: UI Tests if: success() run: | - export PATH=${{ steps.setup-chrome.outputs.chromedir }}:$PATH sudo apt-get install xvfb xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index ff8b715b13..09b381e685 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -54,14 +54,11 @@ jobs: - name: Setup Chrome id: setup-chrome if: success() - run: | - npx @puppeteer/browsers install chrome@148 - echo chromedir=$(dirname $(find `pwd`/chrome/* -name chrome -print -quit)) >> $GITHUB_OUTPUT + uses: ./.github/actions/setup-chrome - name: UI Tests if: success() run: | - export PATH=${{ steps.setup-chrome.outputs.chromedir }}:$PATH sudo apt-get install xvfb xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index f11aa476de..74ffe9d0f8 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -49,14 +49,11 @@ jobs: - name: Setup Chrome id: setup-chrome if: success() - run: | - npx @puppeteer/browsers install chrome@148 - echo chromedir=$(dirname $(find `pwd`/chrome/* -name chrome -print -quit)) >> $GITHUB_OUTPUT + uses: ./.github/actions/setup-chrome - name: UI Tests if: success() run: | - export PATH=${{ steps.setup-chrome.outputs.chromedir }}:$PATH sudo apt-get install xvfb xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui diff --git a/nightwatch.json b/nightwatch.json index 95359f4413..bc1b0575e6 100644 --- a/nightwatch.json +++ b/nightwatch.json @@ -14,7 +14,10 @@ "log_path": "tests/browser/output" }, "desiredCapabilities": { - "browserName": "chrome" + "browserName": "chrome", + "chromeOptions": { + "args" : ["--no-sandbox"] + } }, "enable_fail_fast": true }, diff --git a/package-lock.json b/package-lock.json index b584497d65..a48c038642 100644 --- a/package-lock.json +++ b/package-lock.json @@ -126,7 +126,7 @@ "babel-loader": "^10.1.1", "babel-plugin-polyfill-corejs3": "^1.0.0", "base64-loader": "^1.0.0", - "chromedriver": "^150.0.4", + "chromedriver": "152.0.2", "cli-progress": "^3.12.0", "colors": "^1.4.0", "compression-webpack-plugin": "^12.0.0", @@ -5283,13 +5283,13 @@ } }, "node_modules/adm-zip": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.18.tgz", - "integrity": "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/agent-base": { @@ -5876,14 +5876,14 @@ } }, "node_modules/axios": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz", - "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", + "form-data": "^4.0.6", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } @@ -6902,16 +6902,16 @@ } }, "node_modules/chromedriver": { - "version": "150.0.4", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-150.0.4.tgz", - "integrity": "sha512-Yg2oXBONi1mqAMOG2ybwUneSvxIn04NF4qNAJ+yGO2H7WwX1WYLGQRHVHsbySEjIuqIyDmS1ZfAw6p0wtl43zQ==", + "version": "152.0.2", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-152.0.2.tgz", + "integrity": "sha512-w/trjzSjQC8vHHwl4e+WXBGPRN3XnrsY14q/FdxCY8GtTUIlB+wH1gn/Kz3CHpdmbsouUEGal6E8bjEEz72pZg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@testim/chrome-version": "^1.1.4", - "adm-zip": "^0.5.18", - "axios": "^1.18.1", + "adm-zip": "^0.6.0", + "axios": "^1.19.0", "compare-versions": "^6.1.1", "proxy-agent": "^8.0.2", "proxy-from-env": "^2.1.0", diff --git a/package.json b/package.json index f3b4c09ff2..22601f871b 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "babel-loader": "^10.1.1", "babel-plugin-polyfill-corejs3": "^1.0.0", "base64-loader": "^1.0.0", - "chromedriver": "^150.0.4", + "chromedriver": "152.0.2", "cli-progress": "^3.12.0", "colors": "^1.4.0", "compression-webpack-plugin": "^12.0.0", @@ -198,7 +198,7 @@ }, "allowScripts": { "@nightwatch/nightwatch-inspector@1.0.1": true, - "chromedriver@150.0.4": true, + "chromedriver@152.0.2": true, "core-js": false, "core-js-pure": false, "fsevents": false, diff --git a/src/core/operations/RandomPrime.mjs b/src/core/operations/RandomPrime.mjs deleted file mode 100644 index 3509045f00..0000000000 --- a/src/core/operations/RandomPrime.mjs +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @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.

" + - "Primality guarantee:
" + - "For numbers . 3,317, the result is guaranteed prime (deterministic test).
" + - "For larger numbers, uses probabilistic testing:
" + - "- Standard (7 rounds): Probability of composite approx 1 in 16,000)

" + - "- Crypto grade (40 rounds): Probability of composite(approx 1 in 10^24)
" + - "Crypto grade is recommended for cryptographic applications (RSA, Diffie-Hellman, etc.).

" ; - 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;