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;