From be2080259ec9ae7d64945fc5640188ec4b773ba6 Mon Sep 17 00:00:00 2001 From: Kyle Parrish Date: Wed, 2 Oct 2019 09:57:50 -0400 Subject: [PATCH 001/216] Add Fang URL to categories --- src/core/config/Categories.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 94f7fd309f..18fc19ffc8 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -183,6 +183,7 @@ "Encode NetBIOS Name", "Decode NetBIOS Name", "Defang URL", + "Fang URL", "Defang IP Addresses" ] }, From cd15a8c406726bf06d55b879d271ac3f79b3ba99 Mon Sep 17 00:00:00 2001 From: Kyle Parrish Date: Wed, 2 Oct 2019 09:58:28 -0400 Subject: [PATCH 002/216] Create FangURL.mjs --- src/core/operations/FangURL.mjs | 77 +++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/core/operations/FangURL.mjs diff --git a/src/core/operations/FangURL.mjs b/src/core/operations/FangURL.mjs new file mode 100644 index 0000000000..5badaae75b --- /dev/null +++ b/src/core/operations/FangURL.mjs @@ -0,0 +1,77 @@ +/** + * @author arnydo [github@arnydo.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * FangURL operation + */ +class FangURL extends Operation { + + /** + * FangURL constructor + */ + constructor() { + super(); + + this.name = "Fang URL"; + this.module = "Default"; + this.description = "Takes a 'Defanged' Universal Resource Locator (URL) and 'Fangs' it. Meaning, it removes the alterations (defanged) that render it useless so that it can be used again."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Escape [.]", + type: "boolean", + value: true + }, + { + name: "Escape hxxp", + type: "boolean", + value: true + }, + { + name: "Escape ://", + type: "boolean", + value: true + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [dots, http, slashes] = args; + + input = fangURL(input, dots, http, slashes); + + return input; + } + +} + + +/** + * Defangs a given URL + * + * @param {string} url + * @param {boolean} dots + * @param {boolean} http + * @param {boolean} slashes + * @returns {string} + */ +function fangURL(url, dots, http, slashes) { + if (dots) url = url.replace(/\[\.\]/g, "."); + if (http) url = url.replace(/hxxp/g, "http"); + if (slashes) url = url.replace(/\[\:\/\/\]/g, "://"); + + return url; +} + +export default FangURL; From 3546ee30a22611f6af16c00532a31eb08fdd2501 Mon Sep 17 00:00:00 2001 From: Kyle Parrish Date: Mon, 7 Oct 2019 16:09:22 -0400 Subject: [PATCH 003/216] Update escaped chars --- src/core/operations/FangURL.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/FangURL.mjs b/src/core/operations/FangURL.mjs index 5badaae75b..7390c1a9ce 100644 --- a/src/core/operations/FangURL.mjs +++ b/src/core/operations/FangURL.mjs @@ -69,7 +69,7 @@ class FangURL extends Operation { function fangURL(url, dots, http, slashes) { if (dots) url = url.replace(/\[\.\]/g, "."); if (http) url = url.replace(/hxxp/g, "http"); - if (slashes) url = url.replace(/\[\:\/\/\]/g, "://"); + if (slashes) url = url.replace(/[://]/g, "://"); return url; } From 012b54d44fa1a14208aa96f3ddc7c645493397a7 Mon Sep 17 00:00:00 2001 From: Dave York Date: Sat, 19 Jun 2021 22:28:02 -0400 Subject: [PATCH 004/216] adding a dockerfile --- Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..ce17e0b88e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM node:dubnium-buster-slim +RUN apt-get update && apt-get install -y build-essential && rm -rf /var/lib/apt/lists/* + +COPY . / +ENV NODE_OPTIONS="--max_old_space_size=2048" +RUN npm install node-sass +RUN npm install -g grunt-cli +RUN npm i +CMD grunt dev From 0668a9d4cff5e4983595c7a8dd43b2d6cc2d3ff6 Mon Sep 17 00:00:00 2001 From: Dave York Date: Sat, 19 Jun 2021 22:33:14 -0400 Subject: [PATCH 005/216] update readme with docker instructions --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index ac9b8174e4..38d0bfd105 100755 --- a/README.md +++ b/README.md @@ -22,6 +22,16 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur [A live demo can be found here][1] - have fun! +## Running in Docker + +If you would like to run the app locally in docker please follow the steps below: + +``` +git clone https://github.com/gchq/CyberChef.git +cd CyberChef +docker build --tag cyberchef . +docker run --rm --name cyberchef -it -p 8080:8080 cyberchef +``` ## How it works From f3abb053429fc0c49342a2f447c19c1720e23045 Mon Sep 17 00:00:00 2001 From: Dave York Date: Thu, 1 Jul 2021 09:32:02 -0400 Subject: [PATCH 006/216] update readme per suggestion --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 38d0bfd105..6e80684568 100755 --- a/README.md +++ b/README.md @@ -22,17 +22,6 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur [A live demo can be found here][1] - have fun! -## Running in Docker - -If you would like to run the app locally in docker please follow the steps below: - -``` -git clone https://github.com/gchq/CyberChef.git -cd CyberChef -docker build --tag cyberchef . -docker run --rm --name cyberchef -it -p 8080:8080 cyberchef -``` - ## How it works There are four main areas in CyberChef: @@ -114,6 +103,17 @@ An installation walkthrough, how-to guides for adding new operations and themes, - Submit a pull request. If you are doing this for the first time, you will be prompted to sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) via the CLA assistant on the pull request. This will also ask whether you are happy for GCHQ to contact you about a token of thanks for your contribution, or about job opportunities at GCHQ. +## Running in Docker + +If you would like to run the app locally in docker please follow the steps below: + +``` +git clone https://github.com/gchq/CyberChef.git +cd CyberChef +docker build --tag cyberchef . +docker run --rm --name cyberchef -it -p 8080:8080 cyberchef +``` + ## Licencing CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/). From daef66372713bd08096799679a0e326b466ac5aa Mon Sep 17 00:00:00 2001 From: Erik Hansson Date: Sat, 11 Feb 2023 17:27:47 +0100 Subject: [PATCH 007/216] Add X.509 output formats --- src/core/operations/ParseX509Certificate.mjs | 238 +++++++++++-------- 1 file changed, 142 insertions(+), 96 deletions(-) diff --git a/src/core/operations/ParseX509Certificate.mjs b/src/core/operations/ParseX509Certificate.mjs index 88678de942..e0aa38b712 100644 --- a/src/core/operations/ParseX509Certificate.mjs +++ b/src/core/operations/ParseX509Certificate.mjs @@ -5,8 +5,8 @@ */ import r from "jsrsasign"; -import { fromBase64 } from "../lib/Base64.mjs"; -import { toHex } from "../lib/Hex.mjs"; +import { fromBase64, toBase64 } from "../lib/Base64.mjs"; +import { fromHex, toHex } from "../lib/Hex.mjs"; import { formatByteStr, formatDnObj } from "../lib/PublicKey.mjs"; import Operation from "../Operation.mjs"; import Utils from "../Utils.mjs"; @@ -33,6 +33,11 @@ class ParseX509Certificate extends Operation { "name": "Input format", "type": "option", "value": ["PEM", "DER Hex", "Base64", "Raw"] + }, + { + "name": "Output format", + "type": "option", + "value": ["Text", "JSON", "PEM", "DER Hex", "Base64", "Raw"] } ]; this.checks = [ @@ -55,9 +60,13 @@ class ParseX509Certificate extends Operation { } const cert = new r.X509(), - inputFormat = args[0]; + inputFormat = args[0], + outputFormat = args[1]; + + let undefinedInputFormat = false, + undefinedOuputFormat = false, + output = ""; - let undefinedInputFormat = false; try { switch (inputFormat) { case "DER Hex": @@ -81,107 +90,146 @@ class ParseX509Certificate extends Operation { } if (undefinedInputFormat) throw "Undefined input format"; - const sn = cert.getSerialNumberHex(), - issuer = cert.getIssuer(), - subject = cert.getSubject(), - pk = cert.getPublicKey(), - pkFields = [], - sig = cert.getSignatureValueHex(); + try { + switch (outputFormat) { + case "Text": + output = formatText(cert); + break; + case "JSON": + output = JSON.stringify(cert.getParam()); + break; + case "DER Hex": + output = cert.hex; + break; + case "PEM": + output = r.hextopem(cert.hex, "CERTIFICATE"); + break; + case "Base64": + output = toBase64(fromHex(cert.hex)); + break; + case "Raw": + output = Utils.byteArrayToChars(fromHex(cert.hex)); + break; + default: + undefinedOuputFormat = true; + } + } catch (e) { + throw "Certificate encoding error (what even hapened?)"; + } + if (undefinedOuputFormat) throw "Undefined output format"; + + return output; + } - let pkStr = "", - sigStr = "", - extensions = ""; +} +/** + * Format X.509 certificate. + * + * @param {r.X509} cert + * @returns {string} + */ +function formatText(cert) { + const sn = cert.getSerialNumberHex(), + issuer = cert.getIssuer(), + subject = cert.getSubject(), + pk = cert.getPublicKey(), + pkFields = [], + sig = cert.getSignatureValueHex(); + + let pkStr = "", + sigStr = "", + extensions = ""; + + // Public Key fields + pkFields.push({ + key: "Algorithm", + value: pk.type + }); - // Public Key fields + if (pk.type === "EC") { // ECDSA pkFields.push({ - key: "Algorithm", - value: pk.type + key: "Curve Name", + value: pk.curveName }); + pkFields.push({ + key: "Length", + value: (((new r.BigInteger(pk.pubKeyHex, 16)).bitLength() - 3) / 2) + " bits" + }); + pkFields.push({ + key: "pub", + value: formatByteStr(pk.pubKeyHex, 16, 18) + }); + } else if (pk.type === "DSA") { // DSA + pkFields.push({ + key: "pub", + value: formatByteStr(pk.y.toString(16), 16, 18) + }); + pkFields.push({ + key: "P", + value: formatByteStr(pk.p.toString(16), 16, 18) + }); + pkFields.push({ + key: "Q", + value: formatByteStr(pk.q.toString(16), 16, 18) + }); + pkFields.push({ + key: "G", + value: formatByteStr(pk.g.toString(16), 16, 18) + }); + } else if (pk.e) { // RSA + pkFields.push({ + key: "Length", + value: pk.n.bitLength() + " bits" + }); + pkFields.push({ + key: "Modulus", + value: formatByteStr(pk.n.toString(16), 16, 18) + }); + pkFields.push({ + key: "Exponent", + value: pk.e + " (0x" + pk.e.toString(16) + ")" + }); + } else { + pkFields.push({ + key: "Error", + value: "Unknown Public Key type" + }); + } - if (pk.type === "EC") { // ECDSA - pkFields.push({ - key: "Curve Name", - value: pk.curveName - }); - pkFields.push({ - key: "Length", - value: (((new r.BigInteger(pk.pubKeyHex, 16)).bitLength()-3) /2) + " bits" - }); - pkFields.push({ - key: "pub", - value: formatByteStr(pk.pubKeyHex, 16, 18) - }); - } else if (pk.type === "DSA") { // DSA - pkFields.push({ - key: "pub", - value: formatByteStr(pk.y.toString(16), 16, 18) - }); - pkFields.push({ - key: "P", - value: formatByteStr(pk.p.toString(16), 16, 18) - }); - pkFields.push({ - key: "Q", - value: formatByteStr(pk.q.toString(16), 16, 18) - }); - pkFields.push({ - key: "G", - value: formatByteStr(pk.g.toString(16), 16, 18) - }); - } else if (pk.e) { // RSA - pkFields.push({ - key: "Length", - value: pk.n.bitLength() + " bits" - }); - pkFields.push({ - key: "Modulus", - value: formatByteStr(pk.n.toString(16), 16, 18) - }); - pkFields.push({ - key: "Exponent", - value: pk.e + " (0x" + pk.e.toString(16) + ")" - }); - } else { - pkFields.push({ - key: "Error", - value: "Unknown Public Key type" - }); - } - - // Format Public Key fields - for (let i = 0; i < pkFields.length; i++) { - pkStr += ` ${pkFields[i].key}:${(pkFields[i].value + "\n").padStart( - 18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1, - " " - )}`; - } + // Format Public Key fields + for (let i = 0; i < pkFields.length; i++) { + pkStr += ` ${pkFields[i].key}:${(pkFields[i].value + "\n").padStart( + 18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1, + " " + )}`; + } - // Signature fields - let breakoutSig = false; - try { - breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0; - } catch (err) { - // Error processing signature, output without further breakout - } + // Signature fields + let breakoutSig = false; + try { + breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0; + } catch (err) { + // Error processing signature, output without further breakout + } - if (breakoutSig) { // DSA or ECDSA - sigStr = ` r: ${formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18)} + if (breakoutSig) { // DSA or ECDSA + sigStr = ` r: ${formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18)} s: ${formatByteStr(r.ASN1HEX.getV(sig, 48), 16, 18)}`; - } else { // RSA or unknown - sigStr = ` Signature: ${formatByteStr(sig, 16, 18)}`; - } + } else { // RSA or unknown + sigStr = ` Signature: ${formatByteStr(sig, 16, 18)}`; + } - // Extensions - try { - extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0]; - } catch (err) {} + // Extensions + try { + extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0]; + } catch (err) { } - const issuerStr = formatDnObj(issuer, 2), - nbDate = formatDate(cert.getNotBefore()), - naDate = formatDate(cert.getNotAfter()), - subjectStr = formatDnObj(subject, 2); + const issuerStr = formatDnObj(issuer, 2), + nbDate = formatDate(cert.getNotBefore()), + naDate = formatDate(cert.getNotAfter()), + subjectStr = formatDnObj(subject, 2); - return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)}) + return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)}) Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn}) Algorithm ID: ${cert.getSignatureAlgorithmField()} Validity @@ -199,8 +247,6 @@ ${sigStr} Extensions ${extensions}`; - } - } /** From 3e8c5d945cd65e920930ddd6dfb012123cd6a0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 27 Feb 2023 06:09:30 +0000 Subject: [PATCH 008/216] Add "XOR Checksum" operation --- src/core/config/Categories.json | 3 +- src/core/operations/XORChecksum.mjs | 59 +++++++++++++++++++ tests/operations/tests/Checksum.mjs | 90 ++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/core/operations/XORChecksum.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 075e8d6662..97b20bd76c 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -390,7 +390,8 @@ "CRC-8 Checksum", "CRC-16 Checksum", "CRC-32 Checksum", - "TCP/IP Checksum" + "TCP/IP Checksum", + "XOR Checksum" ] }, { diff --git a/src/core/operations/XORChecksum.mjs b/src/core/operations/XORChecksum.mjs new file mode 100644 index 0000000000..1603a26518 --- /dev/null +++ b/src/core/operations/XORChecksum.mjs @@ -0,0 +1,59 @@ +/** + * @author Thomas Weißschuh [thomas@t-8ch.de] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; +import { toHex } from "../lib/Hex.mjs"; + +/** + * XOR Checksum operation + */ +class XORChecksum extends Operation { + + /** + * XORChecksum constructor + */ + constructor() { + super(); + + this.name = "XOR Checksum"; + this.module = "Crypto"; + this.description = "XOR Checksum splits the input into blocks of a configurable size and performs the XOR operation on these blocks."; + this.infoURL = "https://wikipedia.org/wiki/XOR"; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = [ + { + name: "Blocksize", + type: "number", + value: 4 + }, + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const blocksize = args[0]; + input = new Uint8Array(input); + + const res = Array(blocksize); + res.fill(0); + + for (const chunk of Utils.chunked(input, blocksize)) { + for (let i = 0; i < blocksize; i++) { + res[i] ^= chunk[i]; + } + } + + return toHex(res, ""); + } +} + +export default XORChecksum; diff --git a/tests/operations/tests/Checksum.mjs b/tests/operations/tests/Checksum.mjs index 142ee26787..5266ab9929 100644 --- a/tests/operations/tests/Checksum.mjs +++ b/tests/operations/tests/Checksum.mjs @@ -237,5 +237,93 @@ TestRegister.addTests([ "args": [] } ] - } + }, + { + name: "XOR Checksum (1): nothing", + input: "", + expectedOutput: "00", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [1] + } + ] + }, + { + name: "XOR Checksum (1): basic string", + input: BASIC_STRING, + expectedOutput: "08", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [1] + } + ] + }, + { + name: "XOR Checksum (1): UTF-8", + input: UTF8_STR, + expectedOutput: "df", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [1] + } + ] + }, + { + name: "XOR Checksum (1): all bytes", + input: ALL_BYTES, + expectedOutput: "00", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [1] + } + ] + }, + { + name: "XOR Checksum (4): nothing", + input: "", + expectedOutput: "00000000", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [4] + } + ] + }, + { + name: "XOR Checksum (4): basic string", + input: BASIC_STRING, + expectedOutput: "4918421b", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [4] + } + ] + }, + { + name: "XOR Checksum (4): UTF-8", + input: UTF8_STR, + expectedOutput: "83a424dc", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [4] + } + ] + }, + { + name: "XOR Checksum (4): all bytes", + input: ALL_BYTES, + expectedOutput: "00000000", + recipeConfig: [ + { + "op": "XOR Checksum", + "args": [4] + } + ] + }, ]); From 5f0f037c46c551d8af7106654ab5b0f8c4660aca Mon Sep 17 00:00:00 2001 From: sg5506844 <130462468+sg5506844@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:37:16 +0530 Subject: [PATCH 009/216] Feature: Add Base92 operations --- src/core/config/Categories.json | 2 + src/core/lib/Base92.mjs | 44 +++++++++++++++ src/core/operations/FromBase92.mjs | 55 ++++++++++++++++++ src/core/operations/ToBase92.mjs | 67 ++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/Base92.mjs | 89 ++++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+) create mode 100644 src/core/lib/Base92.mjs create mode 100644 src/core/operations/FromBase92.mjs create mode 100644 src/core/operations/ToBase92.mjs create mode 100644 tests/operations/tests/Base92.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index ce2f01f5ec..277951ea88 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -29,6 +29,8 @@ "To Base64", "From Base64", "Show Base64 offsets", + "To Base92", + "From Base92", "To Base85", "From Base85", "To Base", diff --git a/src/core/lib/Base92.mjs b/src/core/lib/Base92.mjs new file mode 100644 index 0000000000..902c3e7de4 --- /dev/null +++ b/src/core/lib/Base92.mjs @@ -0,0 +1,44 @@ +/** + * Base92 resources. + * + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; + +/** + * Base92 alphabet char + * + * @param {number} val + * @returns {number} + */ +export function base92Chr(val) { + if (val < 0 || val >= 91) { + throw new OperationError("Invalid value"); + } + if (val === 0) + return "!".charCodeAt(0); + else if (val <= 61) + return "#".charCodeAt(0) + val - 1; + else + return "a".charCodeAt(0) + val - 62; +} + +/** + * Base92 alphabet ord + * + * @param {string} val + * @returns {number} + */ +export function base92Ord(val) { + if (val === "!") + return 0; + else if ("#" <= val && val <= "_") + return val.charCodeAt(0) - "#".charCodeAt(0) + 1; + else if ("a" <= val && val <= "}") + return val.charCodeAt(0) - "a".charCodeAt(0) + 62; + throw new OperationError(`${val} is not a base92 character`); +} + diff --git a/src/core/operations/FromBase92.mjs b/src/core/operations/FromBase92.mjs new file mode 100644 index 0000000000..8315a51cf0 --- /dev/null +++ b/src/core/operations/FromBase92.mjs @@ -0,0 +1,55 @@ +/** + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import { base92Ord } from "../lib/Base92.mjs"; +import Operation from "../Operation.mjs"; + +/** + * From Base92 operation + */ +class FromBase92 extends Operation { + /** + * FromBase92 constructor + */ + constructor() { + super(); + + this.name = "From Base92"; + this.module = "Default"; + this.description = "Base92 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers."; + this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems"; + this.inputType = "string"; + this.outputType = "byteArray"; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + const res = []; + let bitString = ""; + + for (let i = 0; i < input.length; i += 2) { + if (i + 1 !== input.length) { + const x = base92Ord(input[i]) * 91 + base92Ord(input[i + 1]); + bitString += x.toString(2).padStart(13, "0"); + } else { + const x = base92Ord(input[i]); + bitString += x.toString(2).padStart(6, "0"); + } + while (bitString.length >= 8) { + res.push(parseInt(bitString.slice(0, 8), 2)); + bitString = bitString.slice(8); + } + } + + return res; + } +} + +export default FromBase92; diff --git a/src/core/operations/ToBase92.mjs b/src/core/operations/ToBase92.mjs new file mode 100644 index 0000000000..bca8e8722d --- /dev/null +++ b/src/core/operations/ToBase92.mjs @@ -0,0 +1,67 @@ +/** + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import { base92Chr } from "../lib/Base92.mjs"; +import Operation from "../Operation.mjs"; + +/** + * To Base92 operation + */ +class ToBase92 extends Operation { + /** + * ToBase92 constructor + */ + constructor() { + super(); + + this.name = "To Base92"; + this.module = "Default"; + this.description = "Base92 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers."; + this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems"; + this.inputType = "string"; + this.outputType = "byteArray"; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + const res = []; + let bitString = ""; + + while (input.length > 0) { + while (bitString.length < 13 && input.length > 0) { + bitString += input[0].charCodeAt(0).toString(2).padStart(8, "0"); + input = input.slice(1); + } + if (bitString.length < 13) + break; + const i = parseInt(bitString.slice(0, 13), 2); + res.push(base92Chr(Math.floor(i / 91))); + res.push(base92Chr(i % 91)); + bitString = bitString.slice(13); + } + + if (bitString.length > 0) { + if (bitString.length < 7) { + bitString = bitString.padEnd(6, "0"); + res.push(base92Chr(parseInt(bitString, 2))); + } else { + bitString = bitString.padEnd(13, "0"); + const i = parseInt(bitString.slice(0, 13), 2); + res.push(base92Chr(Math.floor(i / 91))); + res.push(base92Chr(i % 91)); + } + } + + return res; + + } +} + +export default ToBase92; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 56f432e090..8d433954e9 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -25,6 +25,7 @@ import "./tests/Base58.mjs"; import "./tests/Base64.mjs"; import "./tests/Base62.mjs"; import "./tests/Base85.mjs"; +import "./tests/Base92.mjs"; import "./tests/BitwiseOp.mjs"; import "./tests/ByteRepr.mjs"; import "./tests/CartesianProduct.mjs"; diff --git a/tests/operations/tests/Base92.mjs b/tests/operations/tests/Base92.mjs new file mode 100644 index 0000000000..2811182d4a --- /dev/null +++ b/tests/operations/tests/Base92.mjs @@ -0,0 +1,89 @@ +/** + * Base92 tests. + * + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "To Base92: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + op: "To Base92", + args: [], + }, + ], + }, + { + name: "To Base92: Spec encoding example 1", + input: "AB", + expectedOutput: "8y2", + recipeConfig: [ + { + op: "To Base92", + args: [], + }, + ], + }, + { + name: "To Base92: Spec encoding example 2", + input: "Hello!!", + expectedOutput: ";K_$aOTo&", + recipeConfig: [ + { + op: "To Base92", + args: [], + }, + ], + }, + { + name: "To Base92: Spec encoding example 3", + input: "base-92", + expectedOutput: "DX2?V Date: Sun, 16 Apr 2023 21:47:43 +1200 Subject: [PATCH 010/216] [181] 'fix' dev to get started --- .gitignore | 1 + src/core/Recipe.mjs | 4 +++- src/core/lib/Magic.mjs | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3b7449c40c..616ca224e3 100755 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ src/node/index.mjs **/*.DS_Store tests/browser/output/* .node-version +.idea diff --git a/src/core/Recipe.mjs b/src/core/Recipe.mjs index 3ce40aa4d6..86265b65b7 100755 --- a/src/core/Recipe.mjs +++ b/src/core/Recipe.mjs @@ -4,7 +4,9 @@ * @license Apache-2.0 */ -import OperationConfig from "./config/OperationConfig.json" assert {type: "json"}; +// @TODO: NTS return this to original? ( it breaks dev though ) +// import OperationConfig from "./config/OperationConfig.json" assert {type: "json"}; +import OperationConfig from "./config/OperationConfig.json"; import OperationError from "./errors/OperationError.mjs"; import Operation from "./Operation.mjs"; import DishError from "./errors/DishError.mjs"; diff --git a/src/core/lib/Magic.mjs b/src/core/lib/Magic.mjs index 921fc3f6f3..8a57969acc 100644 --- a/src/core/lib/Magic.mjs +++ b/src/core/lib/Magic.mjs @@ -1,4 +1,6 @@ -import OperationConfig from "../config/OperationConfig.json" assert {type: "json"}; +// @TODO: NTS return this to original? ( it breaks dev though ) +// import OperationConfig from "../config/OperationConfig.json" assert {type: "json"}; +import OperationConfig from "../config/OperationConfig.json"; import Utils, { isWorkerEnvironment } from "../Utils.mjs"; import Recipe from "../Recipe.mjs"; import Dish from "../Dish.mjs"; From 3102adc73d3cb3b85d2ef321ef0d1575fb8d2b0a Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:06:26 +1200 Subject: [PATCH 011/216] [#181] update pane-controls display --- src/web/stylesheets/components/_pane.css | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/web/stylesheets/components/_pane.css b/src/web/stylesheets/components/_pane.css index 54e67b3bd6..b3fa81b632 100755 --- a/src/web/stylesheets/components/_pane.css +++ b/src/web/stylesheets/components/_pane.css @@ -12,9 +12,7 @@ } .title { - padding: 8px; - padding-left: 12px; - padding-right: 12px; + padding: 8px 12px; height: var(--title-height); border-bottom: 1px solid var(--primary-border-colour); font-weight: var(--title-weight); @@ -25,11 +23,9 @@ } .pane-controls { - position: absolute; right: 8px; top: 8px; - display: flex; - flex-direction: row; + display: inline-flex; } .pane-controls .btn { @@ -49,3 +45,4 @@ #files .card-header .float-right a:hover { text-decoration: none; } + From daf2c684a9c8e05b44542b150ac82741c433dd7c Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:07:26 +1200 Subject: [PATCH 012/216] [#181] add justify-content: space-between to the banner --- src/web/stylesheets/layout/_banner.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/web/stylesheets/layout/_banner.css b/src/web/stylesheets/layout/_banner.css index 5985695858..6849b87bdc 100755 --- a/src/web/stylesheets/layout/_banner.css +++ b/src/web/stylesheets/layout/_banner.css @@ -15,6 +15,9 @@ color: var(--banner-font-colour); background-color: var(--banner-bg-colour); margin: 0; + + /*///////// dolphin additions //////*/ + justify-content: space-between; } #banner i { From 32d8ce7069b404febee22f57d0e71be619f2cd5b Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:09:01 +1200 Subject: [PATCH 013/216] [#181] update some css to shorthand --- src/web/stylesheets/layout/_io.css | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/web/stylesheets/layout/_io.css b/src/web/stylesheets/layout/_io.css index 0146bf27f7..344efe3c25 100755 --- a/src/web/stylesheets/layout/_io.css +++ b/src/web/stylesheets/layout/_io.css @@ -131,10 +131,7 @@ .output-tab-content { width: 100%; max-width: 100%; - padding-left: 5px; - padding-right: 5px; - padding-top: 10px; - padding-bottom: 10px; + padding: 10px 5px; height: var(--tab-height); vertical-align: middle; overflow: hidden; @@ -319,8 +316,7 @@ #output-num-results-container { width: 20%; float: right; - margin: 0; - margin-left: 10%; + margin: 0 0 0 10%; } #input-find-options-checkboxes, @@ -355,10 +351,7 @@ #input-search-results li, #output-search-results li { - padding-left: 5px; - padding-right: 5px; - padding-top: 10px; - padding-bottom: 10px; + padding: 10px 5px; text-align: center; width: 100%; color: var(--op-list-operation-font-colour); From e998324194ccd7bade5e4b5dc0ac871830334169 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:13:26 +1200 Subject: [PATCH 014/216] [#181] comment out edit-favourites for now --- src/web/stylesheets/layout/_operations.css | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/web/stylesheets/layout/_operations.css b/src/web/stylesheets/layout/_operations.css index b73dfa84a3..1766f6dc14 100755 --- a/src/web/stylesheets/layout/_operations.css +++ b/src/web/stylesheets/layout/_operations.css @@ -20,10 +20,10 @@ linear-gradient(to top, var(--primary-border-colour) 1px, rgba(0, 0, 0, 0) 1px); } -#edit-favourites { - float: right; - margin-top: -7px; -} +/*#edit-favourites {*/ +/* float: right;*/ +/* margin-top: -7px;*/ +/*}*/ .favourites-hover { color: var(--rec-list-operation-font-colour); @@ -41,3 +41,4 @@ .op-list .operation:hover { filter: brightness(98%); } + From 3608d4ac127cb4b238d8ff6ba0d6d0666964cab6 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:14:46 +1200 Subject: [PATCH 015/216] [#181] set up mobile UI, unsorted CSS blocks ( will move them to appropriate places when the UI is solid ) --- src/web/stylesheets/layout/_structure.css | 95 +++++++++++++---------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/src/web/stylesheets/layout/_structure.css b/src/web/stylesheets/layout/_structure.css index 4f262029c2..a23b0d50d6 100755 --- a/src/web/stylesheets/layout/_structure.css +++ b/src/web/stylesheets/layout/_structure.css @@ -10,62 +10,79 @@ body { overflow: hidden; } -#content-wrapper { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; +.gutter { + background-color: var(--secondary-border-colour); + background-repeat: no-repeat; + background-position: 50%; +} + +.gutter.gutter-horizontal { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAeCAYAAAAGos/EAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+EFBhEwBDmIiYYAAAAjSURBVBjTYzxz5sx/BgYGBiYGKGB89+4dA4oIy71790aGGgCn+DBbOcAB0wAAAABJRU5ErkJggg=='); + cursor: ew-resize; +} + +.gutter.gutter-vertical { + background-image: url('data:image/png;base64,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'); + cursor: ns-resize; } +/*//////// dolphins mobile ui below ///////////*/ + #workspace-wrapper { - position: absolute; - top: 30px; - bottom: 0; - width: 100%; + margin-top: 30px; } -div#operations, -div#recipe { - width: 50%; - height: 100%; +#content-wrapper, +#workspace-wrapper, +#operations, +#recipe, +#input, +#output, +#search { + width: 100vw; } -div#input, -div#output { - width: 100%; - height: 50%; +#recipe { + height: 15vh; + overflow-y: scroll; } -.split { - box-sizing: border-box; - /* overflow: auto; */ - /* Removed to enable Background Magic button pulse to overflow. - Replace this rule if it seems to be causing problems. */ - position: relative; +#input .cm-scroller, +#output .cm-scroller { + height: 20vh; + overflow-y: scroll; } -#operations.split { - overflow: auto; +#recipe .title, +#input .title, +#output .title { + display: flex; + justify-content: space-between; } -.split.split-horizontal, .gutter.gutter-horizontal { - height: 100%; - float: left; +#content-wrapper { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; } -.gutter { - background-color: var(--secondary-border-colour); - background-repeat: no-repeat; - background-position: 50%; +/*@TODO: move elsewhere*/ +.desktop-only { + display: none; } -.gutter.gutter-horizontal { - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAeCAYAAAAGos/EAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB+EFBhEwBDmIiYYAAAAjSURBVBjTYzxz5sx/BgYGBiYGKGB89+4dA4oIy71790aGGgCn+DBbOcAB0wAAAABJRU5ErkJggg=='); - cursor: ew-resize; +@media only screen and ( min-width: 1024px ) { + .desktop-only { + display: inline-block; + } } -.gutter.gutter-vertical { - background-image: url('data:image/png;base64,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'); - cursor: ns-resize; +/*@TODO: rename*/ +/* reverse the pane controls and magic/stale indicator in order +to prevent weird empty spaces to the right on mobile*/ +.foo { + display: flex; + flex-direction: row-reverse; } From 8ca5cfaf488fa18e12bc2651d99bab22370be4c9 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:15:41 +1200 Subject: [PATCH 016/216] [#181] add generic default as per the norm --- src/web/stylesheets/utils/_overrides.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/stylesheets/utils/_overrides.css b/src/web/stylesheets/utils/_overrides.css index a2f8b02929..f03acc34e7 100755 --- a/src/web/stylesheets/utils/_overrides.css +++ b/src/web/stylesheets/utils/_overrides.css @@ -17,7 +17,7 @@ } .material-icons { - font-family: 'Material Icons'; + font-family: 'Material Icons', sans-serif; font-weight: normal; font-style: normal; font-size: 24px; From 683c323fd500ef96900c73fa1457997129c8666a Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:19:18 +1200 Subject: [PATCH 017/216] [#181] add this.breakpoint and move some user layout choices into an if statement checking the breakpoint --- src/web/App.mjs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/web/App.mjs b/src/web/App.mjs index cce91b1e76..7b98e109ea 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -46,6 +46,8 @@ class App { this.appLoaded = false; this.workerLoaded = false; this.waitersLoaded = false; + + this.breakpoint = 1024; } @@ -57,15 +59,17 @@ class App { setup() { document.dispatchEvent(this.manager.appstart); - this.initialiseSplitter(); + if ( window.innerWidth >= this.breakpoint ) { + this.initialiseSplitter(); + this.setCompileMessage(); + this.adjustComponentSizes(); + } + this.loadLocalStorage(); this.populateOperationsList(); this.manager.setup(); this.manager.output.saveBombe(); - this.adjustComponentSizes(); - this.setCompileMessage(); this.uriParams = this.getURIParams(); - log.debug("App loaded"); this.appLoaded = true; this.loaded(); From a1d89464ad5c7ffb4ea775ff3df2ce062566f45b Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:19:42 +1200 Subject: [PATCH 018/216] [#181] update breakpoint to 768, add a TODO --- src/web/App.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/web/App.mjs b/src/web/App.mjs index 7b98e109ea..5db558b7c6 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -47,7 +47,7 @@ class App { this.workerLoaded = false; this.waitersLoaded = false; - this.breakpoint = 1024; + this.breakpoint = 768; } @@ -59,6 +59,7 @@ class App { setup() { document.dispatchEvent(this.manager.appstart); + // @TODO: add a window resize listener if ( window.innerWidth >= this.breakpoint ) { this.initialiseSplitter(); this.setCompileMessage(); From ab996c32519a84a0540ea122fb7d8535bc8e15b6 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:20:38 +1200 Subject: [PATCH 019/216] [#181] update breakpoint for .desktop-only --- src/web/stylesheets/layout/_structure.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/stylesheets/layout/_structure.css b/src/web/stylesheets/layout/_structure.css index a23b0d50d6..6b36cd2dea 100755 --- a/src/web/stylesheets/layout/_structure.css +++ b/src/web/stylesheets/layout/_structure.css @@ -73,7 +73,7 @@ body { display: none; } -@media only screen and ( min-width: 1024px ) { +@media only screen and ( min-width: 768px ) { .desktop-only { display: inline-block; } From 3e76bc563c0f65afc12bbd49331f4b8ccec0f996 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Apr 2023 10:21:58 +1200 Subject: [PATCH 020/216] [#181] update template for mobile UI. I will incorporate / probably revert some things once the mobile UI is solid, then patch up desktop view to its original state --- src/web/html/index.html | 135 ++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 52 deletions(-) diff --git a/src/web/html/index.html b/src/web/html/index.html index c602c275f0..d70ca3e0c8 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -31,6 +31,7 @@ + + -
-
-
-
-
+ + + + + - +
+