From eeb39a0b2b616c070bb9bd20d32f39fa35795f32 Mon Sep 17 00:00:00 2001 From: GCHQ Developer 85297 <95289555+C85297@users.noreply.github.com> Date: Fri, 6 Feb 2026 08:38:36 +0000 Subject: [PATCH] Bump v10.21.0 (#2179) --- CHANGELOG.md | 46 ++++ package-lock.json | 4 +- package.json | 5 +- src/core/config/scripts/newMinorVersion.mjs | 289 ++++++++++++-------- 4 files changed, 225 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 535a11a3..b301eb60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,25 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [10.21.0] - 2026-02-05 +- Fix import operations with special chars in them [@d98762625] [@jg42526] | [#1040] +- Remove custom CodeQL workflow [@C85297] | [#2176] +- Fix code scanning warnings in workflows [@GCHQDeveloper581] | [#2177] +- Use NPM trusted publishing [@C85297] [@GCHQDeveloper581] | [#2174] +- Fix: Correctly parse xxd odd byte hexdumps [@ThomasNotTom] [@GCHQDeveloper581] | [#2058] +- Update Sitemap URLs to Use Valid Paths in sitemap.mjs [@rbpi] [@C85297] | [#1861] +- Use recommended GitHub Actions to build image [@AlexGustafsson] [@C85297] | [#2055] +- Remove version 10 message from banner [@C85297] | [#2169] +- Bump form-data from 4.0.1 to 4.0.5 | [#2175] +- Bump node-forge from 1.3.1 to 1.3.3 | [#2173] +- Update crypto browserify [@C85297] | [#2172] +- Update kbpgp package (resolves #2135) [@GCHQDeveloper581] | [#2136] +- Fix the processing of ALPNs for JA4 to align with new specification update [@tuliperis] | [#2165] +- Add Bech32 and Bech32m encoding/decoding operations [@thomasxm] | [#2159] +- Exclude Delete character from hex dump output [@mikecat] [@C85297] | [#2086] +- Tiny typo fix in "To Base85" operation [@twostraws] | [#2118] +- Bump jsonpath-plus [@C85297] | [#2166] + ### [10.20.0] - 2026-01-28 - Fixed Optical Character Recognition and added tests [@n1474335] | [ab37c1e] - Fixed JA4 version fallback value [@n1474335] | [7a5225c] @@ -509,6 +528,7 @@ All major and minor version changes will be documented in this file. Details of ## [4.0.0] - 2016-11-28 - Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306) +[10.21.0]: https://github.com/gchq/CyberChef/releases/tag/v10.21.0 [10.20.0]: https://github.com/gchq/CyberChef/releases/tag/v10.20.0 [10.19.0]: https://github.com/gchq/CyberChef/releases/tag/v10.19.0 [10.18.0]: https://github.com/gchq/CyberChef/releases/tag/v10.18.0 @@ -754,6 +774,14 @@ All major and minor version changes will be documented in this file. Details of [@remingtr]: https://github.com/remingtr [@0xff1ce]: https://github.com/0xff1ce [@starplanet]: https://github.com/starplanet +[@C85297]: https://github.com/C85297 +[@GCHQDeveloper581]: https://github.com/GCHQDeveloper581 +[@ThomasNotTom]: https://github.com/ThomasNotTom +[@rbpi]: https://github.com/rbpi +[@AlexGustafsson]: https://github.com/AlexGustafsson +[@tuliperis]: https://github.com/tuliperis +[@thomasxm]: https://github.com/thomasxm +[@twostraws]: https://github.com/twostraws [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 @@ -942,3 +970,21 @@ All major and minor version changes will be documented in this file. Details of [#512]: https://github.com/gchq/CyberChef/issues/512 [#1732]: https://github.com/gchq/CyberChef/issues/1732 [#1789]: https://github.com/gchq/CyberChef/issues/1789 +[#1040]: https://github.com/gchq/CyberChef/pull/1040 +[#2176]: https://github.com/gchq/CyberChef/pull/2176 +[#2177]: https://github.com/gchq/CyberChef/pull/2177 +[#2174]: https://github.com/gchq/CyberChef/pull/2174 +[#2058]: https://github.com/gchq/CyberChef/pull/2058 +[#1861]: https://github.com/gchq/CyberChef/pull/1861 +[#2055]: https://github.com/gchq/CyberChef/pull/2055 +[#2169]: https://github.com/gchq/CyberChef/pull/2169 +[#2175]: https://github.com/gchq/CyberChef/pull/2175 +[#2173]: https://github.com/gchq/CyberChef/pull/2173 +[#2172]: https://github.com/gchq/CyberChef/pull/2172 +[#2136]: https://github.com/gchq/CyberChef/pull/2136 +[#2165]: https://github.com/gchq/CyberChef/pull/2165 +[#2159]: https://github.com/gchq/CyberChef/pull/2159 +[#2086]: https://github.com/gchq/CyberChef/pull/2086 +[#2118]: https://github.com/gchq/CyberChef/pull/2118 +[#2166]: https://github.com/gchq/CyberChef/pull/2166 + diff --git a/package-lock.json b/package-lock.json index 0b7bce14..6f7c2439 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "10.20.0", + "version": "10.21.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "10.20.0", + "version": "10.21.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index fe50083c..ce8dc2e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "10.20.0", + "version": "10.21.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", @@ -202,7 +202,8 @@ "lint:grammar": "cspell ./src", "postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule", "newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs", - "minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs", + "minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs && npm version minor --git-tag-version=false && echo \"Updated to version v$(npm pkg get version | xargs), please create a pull request and once merged use 'npm run tag'\"", + "tag": "git tag -s \"v$(npm pkg get version | xargs)\" -m \"$(npm pkg get version | xargs)\" && echo \"Created v$(npm pkg get version | xargs), now check and push the tag\"", "getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'", "setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048" } diff --git a/src/core/config/scripts/newMinorVersion.mjs b/src/core/config/scripts/newMinorVersion.mjs index 67754890..d22ef43b 100644 --- a/src/core/config/scripts/newMinorVersion.mjs +++ b/src/core/config/scripts/newMinorVersion.mjs @@ -7,138 +7,197 @@ */ /* eslint no-console: ["off"] */ +/* eslint jsdoc/require-jsdoc: ["off"] */ -import prompt from "prompt"; -import colors from "colors"; import path from "path"; -import fs from "fs"; +import fs from "fs"; import process from "process"; +import { execSync } from "child_process"; -const dir = path.join(process.cwd() + "/src/core/config/"); -if (!fs.existsSync(dir)) { - console.log("\nCWD: " + process.cwd()); - console.log("Error: newMinorVersion.mjs should be run from the project root"); - console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs"); - process.exit(1); -} +const ignoredAuthors = ["github-advanced-security[bot]", "dependabot[bot]"]; -let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8"); -const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/); -const newVersion = [ - parseInt(lastVersion[1], 10), - parseInt(lastVersion[2], 10) + 1, - 0 -]; +async function main() { + const dir = path.join(process.cwd() + "/src/core/config/"); + if (!fs.existsSync(dir)) { + console.log("\nCWD: " + process.cwd()); + console.log( + "Error: newMinorVersion.mjs should be run from the project root", + ); + console.log( + "Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs", + ); + process.exit(1); + } -let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm); -knownContributors = knownContributors.map(c => c.slice(2, -1)); + let changelogData = fs.readFileSync( + path.join(process.cwd(), "CHANGELOG.md"), + "utf8", + ); + const lastVersion = changelogData.match( + /## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/, + ); + const newVersion = [ + parseInt(lastVersion[1], 10), + parseInt(lastVersion[2], 10) + 1, + 0, + ]; -const date = (new Date()).toISOString().split("T")[0]; + let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm); + knownContributors = knownContributors.map((c) => c.slice(2, -1)); -const schema = { - properties: { - message: { - description: "A short but descriptive summary of a feature in this version", - example: "Added 'Op name' operation", - prompt: "Feature description", - type: "string", - required: true, + const date = new Date().toISOString().split("T")[0]; + + const lastVersionSha = execSync( + `git rev-list -n 1 v${lastVersion[1]}.${lastVersion[2]}.${lastVersion[3]}`, + { + encoding: "utf8", }, - author: { - description: "The author of the feature (only one supported, edit manually to add more)", - example: "n1474335", - prompt: "Author", - type: "string", - default: "n1474335" - }, - id: { - description: "The PR number or full commit hash for this feature.", - example: "1200", - prompt: "Pull request or commit ID", - type: "string" - }, - another: { - description: "y/n", - example: "y", - prompt: "Add another feature?", - type: "string", - pattern: /^[yn]$/, + ).trim(); + if (lastVersionSha.length !== 40) { + throw new Error( + `Unexpected output from git rev-list: ${lastVersionSha}`, + ); + } + + const features = []; + + const commits = await ( + await fetch(`https://api.github.com/repos/gchq/cyberchef/commits`) + ).json(); + let foundLast = false; + for (const commit of commits) { + if (commit.sha === lastVersionSha) { + foundLast = true; + break; + } else { + const feature = { + message: "", + authors: [], + id: "", + }; + + const msgparts = commit.commit.message.split("\n\n"); + feature.message = msgparts[0]; + const prIdMatch = feature.message.match(/\(#(\d+)\)$/); + if (prIdMatch !== null) { + feature.message = feature.message + .replace(prIdMatch[0], "") + .trim(); + feature.id = prIdMatch[1]; + } + + if (!ignoredAuthors.includes(commit.author.login)) { + feature.authors.push(commit.author.login); + } + + if (msgparts.length > 1) { + msgparts[1] + .split("\n") + .filter((line) => line.startsWith("Co-authored-by: ")) + .forEach((line) => { + let coAuthor = line.slice("Co-authored-by: ".length); + if (coAuthor.indexOf(">") !== -1) { + const email = coAuthor.slice( + coAuthor.indexOf("<") + 1, + coAuthor.indexOf(">"), + ); + if (email.endsWith("@users.noreply.github.com")) { + coAuthor = email.slice( + email.indexOf("+") + 1, + -"@users.noreply.github.com".length, + ); + } else { + throw new Error( + "Could not get ID of co-author: " + + coAuthor, + ); + } + } else { + throw new Error( + "Could not get email of co-author: " + coAuthor, + ); + } + if (!ignoredAuthors.includes(coAuthor)) { + feature.authors.push(coAuthor); + } + }); + } + + features.push(feature); } } -}; + if (!foundLast) { + throw new Error( + `Could not find last version commit: ${lastVersionSha} - need to add paging functionality`, + ); + } -// Build schema -for (const prop in schema.properties) { - const p = schema.properties[prop]; - p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt); -} + let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`; -prompt.message = ""; -prompt.delimiter = ":".green; + const authors = []; + const prIDs = []; + const commitIDs = []; -const features = []; -const authors = []; -const prIDs = []; -const commitIDs = []; + features.forEach((feature) => { + const id = + feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id; + message += `- ${feature.message} ${feature.authors.map((a) => `[@${a}]`).join(" ")} | [${id}]\n`; -prompt.start(); + feature.authors.forEach((author) => { + if (!knownContributors.includes(author)) { + knownContributors.push(author); + authors.push(`[@${author}]: https://github.com/${author}`); + } + }); -const getFeature = function() { - prompt.get(schema, (err, result) => { - if (err) { - console.log("\nExiting script."); - process.exit(0); - } - - features.push(result); - - if (result.another === "y") { - getFeature(); + if (feature.id.length > 10) { + commitIDs.push( + `[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`, + ); } else { - let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`; - - features.forEach(feature => { - const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id; - message += `- ${feature.message} [@${feature.author}] | [${id}]\n`; - - if (!knownContributors.includes(feature.author)) { - authors.push(`[@${feature.author}]: https://github.com/${feature.author}`); - } - - if (feature.id.length > 10) { - commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`); - } else { - prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`); - } - }); - - // Message - changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n"); - - // Tag - const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`; - changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1"); - - // Author - authors.forEach(author => { - changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n"); - }); - - // Commit IDs - commitIDs.forEach(commitID => { - changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n"); - }); - - // PR IDs - prIDs.forEach(prID => { - changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n"); - }); - - fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData); - - console.log("Written CHANGELOG.md\nCommit changes and then run `npm version minor`."); + prIDs.push( + `[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`, + ); } }); -}; -getFeature(); + // Message + changelogData = changelogData.replace( + /## Details\n\n/, + "## Details\n\n" + message + "\n", + ); + + // Tag + const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`; + changelogData = changelogData.replace( + /\n\n(\[\d+\.\d+\.\d+\]: https)/, + "\n\n" + newTag + "$1", + ); + + // Author + authors.forEach((author) => { + changelogData = changelogData.replace( + /(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, + "$1" + author + "\n\n", + ); + }); + + // Commit IDs + commitIDs.forEach((commitID) => { + changelogData = changelogData.replace( + /(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, + "$1" + commitID + "\n\n", + ); + }); + + // PR IDs + prIDs.forEach((prID) => { + changelogData = changelogData.replace( + /(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/(?:pull|issues)\/[^\n]+\n)\n*$/, + "$1" + prID + "\n\n", + ); + }); + + fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData); +} +main().catch(console.error);