mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-20 06:55:08 -04:00
Merge branch 'master' into feature/docker-multiplatform-build
This commit is contained in:
commit
b2981d3cc7
27 changed files with 2454 additions and 74 deletions
17
.cspell.json
Normal file
17
.cspell.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"version": "0.2",
|
||||
"language": "en,en-gb",
|
||||
"words": [],
|
||||
"dictionaries": [
|
||||
"npm",
|
||||
"softwareTerms",
|
||||
"node",
|
||||
"html",
|
||||
"css",
|
||||
"bash",
|
||||
"en-gb",
|
||||
"misc"
|
||||
],
|
||||
"ignorePaths": ["package.json", "package-lock.json", "node_modules"]
|
||||
}
|
||||
|
1136
package-lock.json
generated
1136
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -61,6 +61,7 @@
|
|||
"compression-webpack-plugin": "^11.1.0",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"core-js": "^3.37.1",
|
||||
"cspell": "^8.17.3",
|
||||
"css-loader": "7.1.2",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-plugin-jsdoc": "^48.2.9",
|
||||
|
@ -193,6 +194,7 @@
|
|||
"testui": "npx grunt testui",
|
||||
"testuidev": "npx nightwatch --env=dev",
|
||||
"lint": "npx grunt lint",
|
||||
"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",
|
||||
|
|
|
@ -74,7 +74,10 @@
|
|||
"CBOR Decode",
|
||||
"Caret/M-decode",
|
||||
"Rison Encode",
|
||||
"Rison Decode"
|
||||
"Rison Decode",
|
||||
"To Modhex",
|
||||
"From Modhex",
|
||||
"MIME Decoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -62,3 +62,9 @@ export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:"
|
|||
* Domain name regular expression
|
||||
*/
|
||||
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
|
||||
/**
|
||||
* DMARC Domain name regular expression
|
||||
*/
|
||||
export const DMARC_DOMAIN_REGEX = /\b((?=[a-z0-9_-]{1,63}\.)(xn--)?[a-z0-9_]+(-[a-z0-9_]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
|
165
src/core/lib/Modhex.mjs
Normal file
165
src/core/lib/Modhex.mjs
Normal file
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { fromHex, toHex } from "./Hex.mjs";
|
||||
|
||||
/**
|
||||
* Modhex alphabet.
|
||||
*/
|
||||
const MODHEX_ALPHABET = "cbdefghijklnrtuv";
|
||||
|
||||
|
||||
/**
|
||||
* Modhex alphabet map.
|
||||
*/
|
||||
const MODHEX_ALPHABET_MAP = MODHEX_ALPHABET.split("");
|
||||
|
||||
|
||||
/**
|
||||
* Hex alphabet to substitute Modhex.
|
||||
*/
|
||||
const HEX_ALPHABET = "0123456789abcdef";
|
||||
|
||||
|
||||
/**
|
||||
* Hex alphabet map to substitute Modhex.
|
||||
*/
|
||||
const HEX_ALPHABET_MAP = HEX_ALPHABET.split("");
|
||||
|
||||
|
||||
/**
|
||||
* Convert a byte array into a modhex string.
|
||||
*
|
||||
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||
* @param {string} [delim=" "]
|
||||
* @param {number} [padding=2]
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* // returns "cl bf bu"
|
||||
* toModhex([10,20,30]);
|
||||
*
|
||||
* // returns "cl:bf:bu"
|
||||
* toModhex([10,20,30], ":");
|
||||
*/
|
||||
export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
||||
if (!data) return "";
|
||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||
|
||||
const regularHexString = toHex(data, "", padding, "", 0);
|
||||
|
||||
let modhexString = "";
|
||||
for (const letter of regularHexString.split("")) {
|
||||
modhexString += MODHEX_ALPHABET_MAP[HEX_ALPHABET_MAP.indexOf(letter)];
|
||||
}
|
||||
|
||||
let output = "";
|
||||
const groupingRegexp = new RegExp(`.{1,${padding}}`, "g");
|
||||
const groupedModhex = modhexString.match(groupingRegexp);
|
||||
|
||||
for (let i = 0; i < groupedModhex.length; i++) {
|
||||
const group = groupedModhex[i];
|
||||
output += group + delim;
|
||||
|
||||
if (extraDelim) {
|
||||
output += extraDelim;
|
||||
}
|
||||
// Add LF after each lineSize amount of bytes but not at the end
|
||||
if ((i !== groupedModhex.length - 1) && ((i + 1) % lineSize === 0)) {
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the extraDelim at the end (if there is one)
|
||||
// and remove the delim at the end, but if it's prepended there's nothing to remove
|
||||
const rTruncLen = extraDelim.length + delim.length;
|
||||
if (rTruncLen) {
|
||||
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
|
||||
return output.slice(0, -rTruncLen);
|
||||
} else {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a byte array into a modhex string as efficiently as possible with no options.
|
||||
*
|
||||
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* // returns "clbfbu"
|
||||
* toModhexFast([10,20,30]);
|
||||
*/
|
||||
export function toModhexFast(data) {
|
||||
if (!data) return "";
|
||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||
|
||||
const output = [];
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
output.push(MODHEX_ALPHABET_MAP[(data[i] >> 4) & 0xf]);
|
||||
output.push(MODHEX_ALPHABET_MAP[data[i] & 0xf]);
|
||||
}
|
||||
return output.join("");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a modhex string into a byte array.
|
||||
*
|
||||
* @param {string} data
|
||||
* @param {string} [delim]
|
||||
* @param {number} [byteLen=2]
|
||||
* @returns {byteArray}
|
||||
*
|
||||
* @example
|
||||
* // returns [10,20,30]
|
||||
* fromModhex("cl bf bu");
|
||||
*
|
||||
* // returns [10,20,30]
|
||||
* fromModhex("cl:bf:bu", "Colon");
|
||||
*/
|
||||
export function fromModhex(data, delim="Auto", byteLen=2) {
|
||||
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
|
||||
throw new OperationError("Byte length must be a positive integer");
|
||||
|
||||
// The `.replace(/\s/g, "")` an interesting workaround: Hex "multiline" tests aren't actually
|
||||
// multiline. Tests for Modhex fixes that, thus exposing the issue.
|
||||
data = data.toLowerCase().replace(/\s/g, "");
|
||||
|
||||
if (delim !== "None") {
|
||||
const delimRegex = delim === "Auto" ? /[^cbdefghijklnrtuv]/gi : Utils.regexRep(delim);
|
||||
data = data.split(delimRegex);
|
||||
} else {
|
||||
data = [data];
|
||||
}
|
||||
|
||||
let regularHexString = "";
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
for (const letter of data[i].split("")) {
|
||||
regularHexString += HEX_ALPHABET_MAP[MODHEX_ALPHABET_MAP.indexOf(letter)];
|
||||
}
|
||||
}
|
||||
|
||||
const output = fromHex(regularHexString, "None", byteLen);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* To Modhex delimiters.
|
||||
*/
|
||||
export const TO_MODHEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"];
|
||||
|
||||
|
||||
/**
|
||||
* From Modhex delimiters.
|
||||
*/
|
||||
export const FROM_MODHEX_DELIM_OPTIONS = ["Auto"].concat(TO_MODHEX_DELIM_OPTIONS);
|
|
@ -18,7 +18,7 @@ class ConvertLeetSpeak extends Operation {
|
|||
|
||||
this.name = "Convert Leet Speak";
|
||||
this.module = "Default";
|
||||
this.description = "Converts to and from Leet Speak";
|
||||
this.description = "Converts to and from Leet Speak.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Leet";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -39,13 +39,16 @@ class ConvertLeetSpeak extends Operation {
|
|||
*/
|
||||
run(input, args) {
|
||||
const direction = args[0];
|
||||
|
||||
if (direction === "To Leet Speak") {
|
||||
return input.replace(/[abcdefghijklmnopqrstuvwxyz]/gi, char => {
|
||||
return toLeetMap[char.toLowerCase()] || char;
|
||||
return input.replace(/[a-z]/gi, char => {
|
||||
const leetChar = toLeetMap[char.toLowerCase()] || char;
|
||||
return char === char.toUpperCase() ? leetChar.toUpperCase() : leetChar;
|
||||
});
|
||||
} else if (direction === "From Leet Speak") {
|
||||
return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/g, char => {
|
||||
return fromLeetMap[char] || char;
|
||||
return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/gi, char => {
|
||||
const normalChar = fromLeetMap[char] || char;
|
||||
return normalChar;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class DESDecrypt extends Operation {
|
|||
|
||||
this.name = "DES Decrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -72,8 +72,7 @@ class DESDecrypt extends Operation {
|
|||
if (key.length !== 8) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
DES uses a key length of 8 bytes (64 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
|
|
@ -22,7 +22,7 @@ class DESEncrypt extends Operation {
|
|||
|
||||
this.name = "DES Encrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -70,8 +70,7 @@ class DESEncrypt extends Operation {
|
|||
if (key.length !== 8) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
DES uses a key length of 8 bytes (64 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
||||
import { search, DOMAIN_REGEX, DMARC_DOMAIN_REGEX } from "../lib/Extract.mjs";
|
||||
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||
|
||||
/**
|
||||
|
@ -39,6 +39,11 @@ class ExtractDomains extends Operation {
|
|||
name: "Unique",
|
||||
type: "boolean",
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Underscore (DMARC, DKIM, etc)",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -49,11 +54,11 @@ class ExtractDomains extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [displayTotal, sort, unique] = args;
|
||||
const [displayTotal, sort, unique, dmarc] = args;
|
||||
|
||||
const results = search(
|
||||
input,
|
||||
DOMAIN_REGEX,
|
||||
dmarc ? DMARC_DOMAIN_REGEX : DOMAIN_REGEX,
|
||||
null,
|
||||
sort ? caseInsensitiveSort : null,
|
||||
unique
|
||||
|
|
84
src/core/operations/FromModhex.mjs
Normal file
84
src/core/operations/FromModhex.mjs
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { FROM_MODHEX_DELIM_OPTIONS, fromModhex } from "../lib/Modhex.mjs";
|
||||
|
||||
/**
|
||||
* From Modhex operation
|
||||
*/
|
||||
class FromModhex extends Operation {
|
||||
|
||||
/**
|
||||
* FromModhex constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Modhex";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a modhex byte string back into its raw value.";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "option",
|
||||
value: FROM_MODHEX_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^(?:[cbdefghijklnrtuv]{2})+$",
|
||||
flags: "i",
|
||||
args: ["None"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?: [cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?:,[cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?:;[cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?::[cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?:\\n[cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
pattern: "^[cbdefghijklnrtuv]{2}(?:\\r\\n[cbdefghijklnrtuv]{2})*$",
|
||||
flags: "i",
|
||||
args: ["CRLF"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = args[0] || "Auto";
|
||||
return fromModhex(input, delim, 2);
|
||||
}
|
||||
}
|
||||
|
||||
export default FromModhex;
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @author k3ach [k3ach@proton.me]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
@ -20,39 +21,46 @@ class LuhnChecksum extends Operation {
|
|||
|
||||
this.name = "Luhn Checksum";
|
||||
this.module = "Default";
|
||||
this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
|
||||
this.description = "The Luhn mod N algorithm using the english alphabet. The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2.";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.args = [
|
||||
{
|
||||
"name": "Radix",
|
||||
"type": "number",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Luhn Checksum from the input.
|
||||
* Generates the Luhn checksum from the input.
|
||||
*
|
||||
* @param {string} inputStr
|
||||
* @returns {number}
|
||||
*/
|
||||
checksum(inputStr) {
|
||||
checksum(inputStr, radix = 10) {
|
||||
let even = false;
|
||||
return inputStr.split("").reverse().reduce((acc, elem) => {
|
||||
// Convert element to integer.
|
||||
let temp = parseInt(elem, 10);
|
||||
// Convert element to an integer based on the provided radix.
|
||||
let temp = parseInt(elem, radix);
|
||||
|
||||
// If element is not an integer.
|
||||
if (isNaN(temp))
|
||||
throw new OperationError("Character: " + elem + " is not a digit.");
|
||||
// If element is not a valid number in the given radix.
|
||||
if (isNaN(temp)) {
|
||||
throw new Error("Character: " + elem + " is not valid in radix " + radix + ".");
|
||||
}
|
||||
|
||||
// If element is in an even position
|
||||
if (even) {
|
||||
// Double the element and add the quotient and remainder together.
|
||||
temp = 2 * elem;
|
||||
temp = Math.floor(temp/10) + (temp % 10);
|
||||
// Double the element and sum the quotient and remainder.
|
||||
temp = 2 * temp;
|
||||
temp = Math.floor(temp / radix) + (temp % radix);
|
||||
}
|
||||
|
||||
even = !even;
|
||||
return acc + temp;
|
||||
}, 0) % 10;
|
||||
}, 0) % radix; // Use radix as the modulus base
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,9 +71,20 @@ class LuhnChecksum extends Operation {
|
|||
run(input, args) {
|
||||
if (!input) return "";
|
||||
|
||||
const checkSum = this.checksum(input);
|
||||
let checkDigit = this.checksum(input + "0");
|
||||
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
|
||||
const radix = args[0];
|
||||
|
||||
if (radix < 2 || radix > 36) {
|
||||
throw new OperationError("Error: Radix argument must be between 2 and 36");
|
||||
}
|
||||
|
||||
if (radix % 2 !== 0) {
|
||||
throw new OperationError("Error: Radix argument must be divisible by 2");
|
||||
}
|
||||
|
||||
const checkSum = this.checksum(input, radix).toString(radix);
|
||||
let checkDigit = this.checksum(input + "0", radix);
|
||||
checkDigit = checkDigit === 0 ? 0 : (radix - checkDigit);
|
||||
checkDigit = checkDigit.toString(radix);
|
||||
|
||||
return `Checksum: ${checkSum}
|
||||
Checkdigit: ${checkDigit}
|
||||
|
|
171
src/core/operations/MIMEDecoding.mjs
Normal file
171
src/core/operations/MIMEDecoding.mjs
Normal file
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { fromHex } from "../lib/Hex.mjs";
|
||||
import { fromBase64 } from "../lib/Base64.mjs";
|
||||
import cptable from "codepage";
|
||||
|
||||
/**
|
||||
* MIME Decoding operation
|
||||
*/
|
||||
class MIMEDecoding extends Operation {
|
||||
|
||||
/**
|
||||
* MIMEDecoding constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "MIME Decoding";
|
||||
this.module = "Default";
|
||||
this.description = "Enables the decoding of MIME message header extensions for non-ASCII text";
|
||||
this.infoURL = "https://tools.ietf.org/html/rfc2047";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const mimeEncodedText = Utils.byteArrayToUtf8(input);
|
||||
const encodedHeaders = mimeEncodedText.replace(/\r\n/g, "\n");
|
||||
|
||||
const decodedHeader = this.decodeHeaders(encodedHeaders);
|
||||
|
||||
return decodedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode MIME header strings
|
||||
*
|
||||
* @param headerString
|
||||
*/
|
||||
decodeHeaders(headerString) {
|
||||
// No encoded words detected
|
||||
let i = headerString.indexOf("=?");
|
||||
if (i === -1) return headerString;
|
||||
|
||||
let decodedHeaders = headerString.slice(0, i);
|
||||
let header = headerString.slice(i);
|
||||
|
||||
let isBetweenWords = false;
|
||||
let start, cur, charset, encoding, j, end, text;
|
||||
while (header.length > -1) {
|
||||
start = header.indexOf("=?");
|
||||
if (start === -1) break;
|
||||
cur = start + "=?".length;
|
||||
|
||||
i = header.slice(cur).indexOf("?");
|
||||
if (i === -1) break;
|
||||
|
||||
charset = header.slice(cur, cur + i);
|
||||
cur += i + "?".length;
|
||||
|
||||
if (header.length < cur + "Q??=".length) break;
|
||||
|
||||
encoding = header[cur];
|
||||
cur += 1;
|
||||
|
||||
if (header[cur] !== "?") break;
|
||||
|
||||
cur += 1;
|
||||
|
||||
j = header.slice(cur).indexOf("?=");
|
||||
if (j === -1) break;
|
||||
|
||||
text = header.slice(cur, cur + j);
|
||||
end = cur + j + "?=".length;
|
||||
|
||||
if (encoding.toLowerCase() === "b") {
|
||||
text = fromBase64(text);
|
||||
} else if (encoding.toLowerCase() === "q") {
|
||||
text = this.parseQEncodedWord(text);
|
||||
} else {
|
||||
isBetweenWords = false;
|
||||
decodedHeaders += header.slice(0, start + 2);
|
||||
header = header.slice(start + 2);
|
||||
}
|
||||
|
||||
if (start > 0 && (!isBetweenWords || header.slice(0, start).search(/\S/g) > -1)) {
|
||||
decodedHeaders += header.slice(0, start);
|
||||
}
|
||||
|
||||
decodedHeaders += this.convertFromCharset(charset, text);
|
||||
|
||||
header = header.slice(end);
|
||||
isBetweenWords = true;
|
||||
}
|
||||
|
||||
if (header.length > 0) {
|
||||
decodedHeaders += header;
|
||||
}
|
||||
|
||||
return decodedHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts decoded text for supported charsets.
|
||||
* Supports UTF-8, US-ASCII, ISO-8859-*
|
||||
*
|
||||
* @param encodedWord
|
||||
*/
|
||||
convertFromCharset(charset, encodedText) {
|
||||
charset = charset.toLowerCase();
|
||||
const parsedCharset = charset.split("-");
|
||||
|
||||
if (parsedCharset.length === 2 && parsedCharset[0] === "utf" && charset === "utf-8") {
|
||||
return cptable.utils.decode(65001, encodedText);
|
||||
} else if (parsedCharset.length === 2 && charset === "us-ascii") {
|
||||
return cptable.utils.decode(20127, encodedText);
|
||||
} else if (parsedCharset.length === 3 && parsedCharset[0] === "iso" && parsedCharset[1] === "8859") {
|
||||
const isoCharset = parseInt(parsedCharset[2], 10);
|
||||
if (isoCharset >= 1 && isoCharset <= 16) {
|
||||
return cptable.utils.decode(28590 + isoCharset, encodedText);
|
||||
}
|
||||
}
|
||||
|
||||
throw new OperationError("Unhandled Charset");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Q encoded word
|
||||
*
|
||||
* @param encodedWord
|
||||
*/
|
||||
parseQEncodedWord(encodedWord) {
|
||||
let decodedWord = "";
|
||||
for (let i = 0; i < encodedWord.length; i++) {
|
||||
if (encodedWord[i] === "_") {
|
||||
decodedWord += " ";
|
||||
// Parse hex encoding
|
||||
} else if (encodedWord[i] === "=") {
|
||||
if ((i + 2) >= encodedWord.length) throw new OperationError("Incorrectly Encoded Word");
|
||||
const decodedHex = Utils.byteArrayToChars(fromHex(encodedWord.substring(i + 1, i + 3)));
|
||||
decodedWord += decodedHex;
|
||||
i += 2;
|
||||
} else if (
|
||||
(encodedWord[i].charCodeAt(0) >= " ".charCodeAt(0) && encodedWord[i].charCodeAt(0) <= "~".charCodeAt(0)) ||
|
||||
encodedWord[i] === "\n" ||
|
||||
encodedWord[i] === "\r" ||
|
||||
encodedWord[i] === "\t") {
|
||||
decodedWord += encodedWord[i];
|
||||
} else {
|
||||
throw new OperationError("Incorrectly Encoded Word");
|
||||
}
|
||||
}
|
||||
|
||||
return decodedWord;
|
||||
}
|
||||
}
|
||||
|
||||
export default MIMEDecoding;
|
|
@ -59,15 +59,16 @@ class ROT13 extends Operation {
|
|||
rot13Upperacse = args[1],
|
||||
rotNumbers = args[2];
|
||||
let amount = args[3],
|
||||
chr;
|
||||
amountNumbers = args[3];
|
||||
|
||||
if (amount) {
|
||||
if (amount < 0) {
|
||||
amount = 26 - (Math.abs(amount) % 26);
|
||||
amountNumbers = 10 - (Math.abs(amountNumbers) % 10);
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
chr = input[i];
|
||||
let chr = input[i];
|
||||
if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
|
||||
chr = (chr - 65 + amount) % 26;
|
||||
output[i] = chr + 65;
|
||||
|
@ -75,7 +76,7 @@ class ROT13 extends Operation {
|
|||
chr = (chr - 97 + amount) % 26;
|
||||
output[i] = chr + 97;
|
||||
} else if (rotNumbers && chr >= 48 && chr <= 57) { // Numbers
|
||||
chr = (chr - 48 + amount) % 10;
|
||||
chr = (chr - 48 + amountNumbers) % 10;
|
||||
output[i] = chr + 48;
|
||||
}
|
||||
}
|
||||
|
|
55
src/core/operations/ToModhex.mjs
Normal file
55
src/core/operations/ToModhex.mjs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { TO_MODHEX_DELIM_OPTIONS, toModhex } from "../lib/Modhex.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* To Modhex operation
|
||||
*/
|
||||
class ToModhex extends Operation {
|
||||
|
||||
/**
|
||||
* ToModhex constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Modhex";
|
||||
this.module = "Default";
|
||||
this.description = "Converts the input string to modhex bytes separated by the specified delimiter.";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "option",
|
||||
value: TO_MODHEX_DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
name: "Bytes per line",
|
||||
type: "number",
|
||||
value: 0
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0]);
|
||||
const lineSize = args[1];
|
||||
|
||||
return toModhex(new Uint8Array(input), delim, 2, "", lineSize);
|
||||
}
|
||||
}
|
||||
|
||||
export default ToModhex;
|
|
@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation {
|
|||
|
||||
this.name = "Triple DES Decrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -73,8 +73,7 @@ class TripleDESDecrypt extends Operation {
|
|||
if (key.length !== 24 && key.length !== 16) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
Triple DES uses a key length of 24 bytes (192 bits).
|
||||
DES uses a key length of 8 bytes (64 bits).`);
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
|
|
@ -22,7 +22,7 @@ class TripleDESEncrypt extends Operation {
|
|||
|
||||
this.name = "Triple DES Encrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -72,8 +72,7 @@ class TripleDESEncrypt extends Operation {
|
|||
if (key.length !== 24 && key.length !== 16) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
Triple DES uses a key length of 24 bytes (192 bits).
|
||||
DES uses a key length of 8 bytes (64 bits).`);
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
|
3
src/web/App.mjs
Executable file → Normal file
3
src/web/App.mjs
Executable file → Normal file
|
@ -60,6 +60,7 @@ class App {
|
|||
|
||||
this.initialiseSplitter();
|
||||
this.loadLocalStorage();
|
||||
this.manager.options.applyPreferredColorScheme();
|
||||
this.populateOperationsList();
|
||||
this.manager.setup();
|
||||
this.manager.output.saveBombe();
|
||||
|
@ -536,6 +537,8 @@ class App {
|
|||
// Read in theme from URI params
|
||||
if (this.uriParams.theme) {
|
||||
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
||||
} else {
|
||||
this.manager.options.applyPreferredColorScheme();
|
||||
}
|
||||
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
|
|
8
src/web/waiters/OptionsWaiter.mjs
Executable file → Normal file
8
src/web/waiters/OptionsWaiter.mjs
Executable file → Normal file
|
@ -163,6 +163,14 @@ class OptionsWaiter {
|
|||
themeSelect.selectedIndex = themeSelect.querySelector(`option[value="${theme}"`).index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the user's preferred color scheme using the `prefers-color-scheme` media query.
|
||||
*/
|
||||
applyPreferredColorScheme() {
|
||||
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
const theme = prefersDarkScheme ? "dark" : "classic";
|
||||
this.changeTheme(theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the console logging level.
|
||||
|
|
|
@ -119,7 +119,7 @@ TestRegister.addApiTests([
|
|||
assert.strictEqual(result[0].module, "Ciphers");
|
||||
assert.strictEqual(result[0].inputType, "string");
|
||||
assert.strictEqual(result[0].outputType, "string");
|
||||
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
|
||||
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
|
||||
assert.strictEqual(result[0].args.length, 5);
|
||||
}),
|
||||
|
||||
|
|
|
@ -104,6 +104,8 @@ import "./tests/LZNT1Decompress.mjs";
|
|||
import "./tests/LZString.mjs";
|
||||
import "./tests/Magic.mjs";
|
||||
import "./tests/Media.mjs";
|
||||
import "./tests/MIMEDecoding.mjs";
|
||||
import "./tests/Modhex.mjs";
|
||||
import "./tests/MorseCode.mjs";
|
||||
import "./tests/MS.mjs";
|
||||
import "./tests/MultipleBombe.mjs";
|
||||
|
|
|
@ -28,6 +28,28 @@ TestRegister.addTests([
|
|||
args: ["From Leet Speak"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Convert to Leet Speak: basic text, keep case",
|
||||
input: "HELLO",
|
||||
expectedOutput: "H3LL0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Convert Leet Speak",
|
||||
args: ["To Leet Speak"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Convert from Leet Speak: basic leet, keep case",
|
||||
input: "H3LL0",
|
||||
expectedOutput: "HeLLo",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Convert Leet Speak",
|
||||
args: ["From Leet Speak"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
|
@ -580,8 +580,7 @@ Tag: a8f04c4d93bbef82bef61a103371aef9`,
|
|||
input: "",
|
||||
expectedOutput: `Invalid key length: 0 bytes
|
||||
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||
DES uses a key length of 8 bytes (64 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "DES Encrypt",
|
||||
|
@ -674,8 +673,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`,
|
|||
input: "",
|
||||
expectedOutput: `Invalid key length: 0 bytes
|
||||
|
||||
Triple DES uses a key length of 24 bytes (192 bits).
|
||||
DES uses a key length of 8 bytes (64 bits).`,
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Triple DES Encrypt",
|
||||
|
@ -1300,8 +1298,7 @@ The following algorithms will be used based on the size of the key:
|
|||
input: "",
|
||||
expectedOutput: `Invalid key length: 0 bytes
|
||||
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||
DES uses a key length of 8 bytes (64 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "DES Decrypt",
|
||||
|
@ -1394,8 +1391,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`,
|
|||
input: "",
|
||||
expectedOutput: `Invalid key length: 0 bytes
|
||||
|
||||
Triple DES uses a key length of 24 bytes (192 bits).
|
||||
DES uses a key length of 8 bytes (64 bits).`,
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Triple DES Decrypt",
|
||||
|
|
|
@ -2,11 +2,392 @@
|
|||
* From Decimal tests
|
||||
*
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @author k3ach [k3ach@proton.me]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @licence Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
radix: 2,
|
||||
input: "01",
|
||||
checksum: "1",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 2,
|
||||
input: "001111",
|
||||
checksum: "0",
|
||||
checkdigit: "0",
|
||||
}, {
|
||||
radix: 2,
|
||||
input: "00011101",
|
||||
checksum: "0",
|
||||
checkdigit: "0",
|
||||
}, {
|
||||
radix: 2,
|
||||
input: "0100101101",
|
||||
checksum: "1",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 4,
|
||||
input: "0123",
|
||||
checksum: "1",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 4,
|
||||
input: "130100",
|
||||
checksum: "2",
|
||||
checkdigit: "2",
|
||||
}, {
|
||||
radix: 4,
|
||||
input: "32020313",
|
||||
checksum: "3",
|
||||
checkdigit: "0",
|
||||
}, {
|
||||
radix: 4,
|
||||
input: "302233210112",
|
||||
checksum: "3",
|
||||
checkdigit: "0",
|
||||
}, {
|
||||
radix: 6,
|
||||
input: "012345",
|
||||
checksum: "4",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 6,
|
||||
input: "134255",
|
||||
checksum: "2",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 6,
|
||||
input: "15021453",
|
||||
checksum: "5",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 6,
|
||||
input: "211450230513",
|
||||
checksum: "3",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 8,
|
||||
input: "01234567",
|
||||
checksum: "2",
|
||||
checkdigit: "2",
|
||||
}, {
|
||||
radix: 8,
|
||||
input: "340624",
|
||||
checksum: "0",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 8,
|
||||
input: "07260247",
|
||||
checksum: "3",
|
||||
checkdigit: "3",
|
||||
}, {
|
||||
radix: 8,
|
||||
input: "026742114675",
|
||||
checksum: "7",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 10,
|
||||
input: "0123456789",
|
||||
checksum: "7",
|
||||
checkdigit: "7",
|
||||
}, {
|
||||
radix: 10,
|
||||
input: "468543",
|
||||
checksum: "7",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 10,
|
||||
input: "59377601",
|
||||
checksum: "5",
|
||||
checkdigit: "6",
|
||||
}, {
|
||||
radix: 10,
|
||||
input: "013909981254",
|
||||
checksum: "1",
|
||||
checkdigit: "3",
|
||||
}, {
|
||||
radix: 12,
|
||||
input: "0123456789ab",
|
||||
checksum: "3",
|
||||
checkdigit: "3",
|
||||
}, {
|
||||
radix: 12,
|
||||
input: "284685",
|
||||
checksum: "0",
|
||||
checkdigit: "6",
|
||||
}, {
|
||||
radix: 12,
|
||||
input: "951a2661",
|
||||
checksum: "0",
|
||||
checkdigit: "8",
|
||||
}, {
|
||||
radix: 12,
|
||||
input: "898202676387",
|
||||
checksum: "b",
|
||||
checkdigit: "9",
|
||||
}, {
|
||||
radix: 14,
|
||||
input: "0123456789abcd",
|
||||
checksum: "a",
|
||||
checkdigit: "a",
|
||||
}, {
|
||||
radix: 14,
|
||||
input: "33db25",
|
||||
checksum: "0",
|
||||
checkdigit: "d",
|
||||
}, {
|
||||
radix: 14,
|
||||
input: "0b4ac128",
|
||||
checksum: "b",
|
||||
checkdigit: "3",
|
||||
}, {
|
||||
radix: 14,
|
||||
input: "3d1c6d16160d",
|
||||
checksum: "3",
|
||||
checkdigit: "c",
|
||||
}, {
|
||||
radix: 16,
|
||||
input: "0123456789abcdef",
|
||||
checksum: "4",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 16,
|
||||
input: "e1fe64",
|
||||
checksum: "b",
|
||||
checkdigit: "6",
|
||||
}, {
|
||||
radix: 16,
|
||||
input: "241a5dcd",
|
||||
checksum: "1",
|
||||
checkdigit: "9",
|
||||
}, {
|
||||
radix: 16,
|
||||
input: "1fea740e0e1f",
|
||||
checksum: "7",
|
||||
checkdigit: "4",
|
||||
}, {
|
||||
radix: 18,
|
||||
input: "0123456789abcdefgh",
|
||||
checksum: "d",
|
||||
checkdigit: "d",
|
||||
}, {
|
||||
radix: 18,
|
||||
input: "995dgf",
|
||||
checksum: "9",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 18,
|
||||
input: "9f80h32h",
|
||||
checksum: "1",
|
||||
checkdigit: "0",
|
||||
}, {
|
||||
radix: 18,
|
||||
input: "5f9428e493g4",
|
||||
checksum: "8",
|
||||
checkdigit: "c",
|
||||
}, {
|
||||
radix: 20,
|
||||
input: "0123456789abcdefghij",
|
||||
checksum: "5",
|
||||
checkdigit: "5",
|
||||
}, {
|
||||
radix: 20,
|
||||
input: "918jci",
|
||||
checksum: "h",
|
||||
checkdigit: "d",
|
||||
}, {
|
||||
radix: 20,
|
||||
input: "jab7j50d",
|
||||
checksum: "g",
|
||||
checkdigit: "j",
|
||||
}, {
|
||||
radix: 20,
|
||||
input: "c56fe85eb6gg",
|
||||
checksum: "g",
|
||||
checkdigit: "5",
|
||||
}, {
|
||||
radix: 22,
|
||||
input: "0123456789abcdefghijkl",
|
||||
checksum: "g",
|
||||
checkdigit: "g",
|
||||
}, {
|
||||
radix: 22,
|
||||
input: "de57le",
|
||||
checksum: "5",
|
||||
checkdigit: "l",
|
||||
}, {
|
||||
radix: 22,
|
||||
input: "e3fg6dfc",
|
||||
checksum: "f",
|
||||
checkdigit: "d",
|
||||
}, {
|
||||
radix: 22,
|
||||
input: "1f8l80ai4kbg",
|
||||
checksum: "l",
|
||||
checkdigit: "f",
|
||||
}, {
|
||||
radix: 24,
|
||||
input: "0123456789abcdefghijklmn",
|
||||
checksum: "6",
|
||||
checkdigit: "6",
|
||||
}, {
|
||||
radix: 24,
|
||||
input: "agne7d",
|
||||
checksum: "4",
|
||||
checkdigit: "f",
|
||||
}, {
|
||||
radix: 24,
|
||||
input: "1l4d9cf4",
|
||||
checksum: "d",
|
||||
checkdigit: "c",
|
||||
}, {
|
||||
radix: 24,
|
||||
input: "blc1j09i3296",
|
||||
checksum: "8",
|
||||
checkdigit: "7",
|
||||
}, {
|
||||
radix: 26,
|
||||
input: "0123456789abcdefghijklmnop",
|
||||
checksum: "j",
|
||||
checkdigit: "j",
|
||||
}, {
|
||||
radix: 26,
|
||||
input: "82n9op",
|
||||
checksum: "i",
|
||||
checkdigit: "2",
|
||||
}, {
|
||||
radix: 26,
|
||||
input: "e9cddn70",
|
||||
checksum: "9",
|
||||
checkdigit: "i",
|
||||
}, {
|
||||
radix: 26,
|
||||
input: "ck0ep419knom",
|
||||
checksum: "p",
|
||||
checkdigit: "g",
|
||||
}, {
|
||||
radix: 28,
|
||||
input: "0123456789abcdefghijklmnopqr",
|
||||
checksum: "7",
|
||||
checkdigit: "7",
|
||||
}, {
|
||||
radix: 28,
|
||||
input: "a6hnoo",
|
||||
checksum: "h",
|
||||
checkdigit: "9",
|
||||
}, {
|
||||
radix: 28,
|
||||
input: "lblc7kh0",
|
||||
checksum: "a",
|
||||
checkdigit: "f",
|
||||
}, {
|
||||
radix: 28,
|
||||
input: "64k5piod3lmf",
|
||||
checksum: "0",
|
||||
checkdigit: "p",
|
||||
}, {
|
||||
radix: 30,
|
||||
input: "0123456789abcdefghijklmnopqrst",
|
||||
checksum: "m",
|
||||
checkdigit: "m",
|
||||
}, {
|
||||
radix: 30,
|
||||
input: "t69j7d",
|
||||
checksum: "9",
|
||||
checkdigit: "s",
|
||||
}, {
|
||||
radix: 30,
|
||||
input: "p54o9ig3",
|
||||
checksum: "a",
|
||||
checkdigit: "o",
|
||||
}, {
|
||||
radix: 30,
|
||||
input: "gc1njrt55030",
|
||||
checksum: "6",
|
||||
checkdigit: "1",
|
||||
}, {
|
||||
radix: 32,
|
||||
input: "0123456789abcdefghijklmnopqrstuv",
|
||||
checksum: "8",
|
||||
checkdigit: "8",
|
||||
}, {
|
||||
radix: 32,
|
||||
input: "rdou19",
|
||||
checksum: "u",
|
||||
checkdigit: "3",
|
||||
}, {
|
||||
radix: 32,
|
||||
input: "ighj0pc7",
|
||||
checksum: "3",
|
||||
checkdigit: "8",
|
||||
}, {
|
||||
radix: 32,
|
||||
input: "op4nn5fvjsrs",
|
||||
checksum: "g",
|
||||
checkdigit: "j",
|
||||
}, {
|
||||
radix: 34,
|
||||
input: "0123456789abcdefghijklmnopqrstuvwx",
|
||||
checksum: "p",
|
||||
checkdigit: "p",
|
||||
}, {
|
||||
radix: 34,
|
||||
input: "nvftj5",
|
||||
checksum: "b",
|
||||
checkdigit: "f",
|
||||
}, {
|
||||
radix: 34,
|
||||
input: "u9v9g162",
|
||||
checksum: "j",
|
||||
checkdigit: "b",
|
||||
}, {
|
||||
radix: 34,
|
||||
input: "o5gqg5d7gjh9",
|
||||
checksum: "5",
|
||||
checkdigit: "q",
|
||||
}, {
|
||||
radix: 36,
|
||||
input: "0123456789abcdefghijklmnopqrstuvwxyz",
|
||||
checksum: "9",
|
||||
checkdigit: "9",
|
||||
}, {
|
||||
radix: 36,
|
||||
input: "29zehu",
|
||||
checksum: "i",
|
||||
checkdigit: "j",
|
||||
}, {
|
||||
radix: 36,
|
||||
input: "1snmikbu",
|
||||
checksum: "s",
|
||||
checkdigit: "v",
|
||||
}, {
|
||||
radix: 36,
|
||||
input: "jpkar545q7gb",
|
||||
checksum: "3",
|
||||
checkdigit: "d",
|
||||
},
|
||||
];
|
||||
|
||||
testCases.forEach(element => {
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Luhn Checksum Mod " + element.radix + " on " + element.input,
|
||||
input: element.input,
|
||||
expectedOutput: "Checksum: " + element.checksum + "\nCheckdigit: " + element.checkdigit + "\nLuhn Validated String: " + element.input + element.checkdigit,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: [element.radix]
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Luhn Checksum on standard data",
|
||||
|
@ -15,7 +396,7 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: []
|
||||
args: [10]
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -26,7 +407,7 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: []
|
||||
args: [10]
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -37,18 +418,7 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Luhn Checksum on invalid data",
|
||||
input: "35641709b012469",
|
||||
expectedOutput: "Character: b is not a digit.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: []
|
||||
args: [10]
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -59,8 +429,8 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Luhn Checksum",
|
||||
args: []
|
||||
args: [10]
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
|
89
tests/operations/tests/MIMEDecoding.mjs
Normal file
89
tests/operations/tests/MIMEDecoding.mjs
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* MIME Header Decoding tests
|
||||
*
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Encoded comments",
|
||||
input: "(=?ISO-8859-1?Q?a?=)",
|
||||
expectedOutput: "(a)",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Encoded adjacent comments whitespace",
|
||||
input: "(=?ISO-8859-1?Q?a?= b)",
|
||||
expectedOutput: "(a b)",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Encoded adjacent single whitespace ignored",
|
||||
input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)",
|
||||
expectedOutput: "(ab)",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Encoded adjacent double whitespace ignored",
|
||||
input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)",
|
||||
expectedOutput: "(ab)",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Encoded adjacent CRLF whitespace ignored",
|
||||
input: "(=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?=)",
|
||||
expectedOutput: "(ab)",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "UTF-8 Encodings Multiple Headers",
|
||||
input: "=?utf-8?q?=C3=89ric?= <eric@example.org>, =?utf-8?q?Ana=C3=AFs?= <anais@example.org>",
|
||||
expectedOutput: "Éric <eric@example.org>, Anaïs <anais@example.org>",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "ISO Decoding",
|
||||
input: "From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>\nTo: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>\nCC: =?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>\nSubject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=",
|
||||
expectedOutput: "From: Keith Moore <moore@cs.utk.edu>\nTo: Keld Jørn Simonsen <keld@dkuug.dk>\nCC: André Pirard <PIRARD@vm1.ulg.ac.be>\nSubject: If you can read this you understand the example.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "MIME Decoding",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
150
tests/operations/tests/Modhex.mjs
Normal file
150
tests/operations/tests/Modhex.mjs
Normal file
|
@ -0,0 +1,150 @@
|
|||
/**
|
||||
* Modhex operation tests.
|
||||
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "ASCII to Modhex stream",
|
||||
input: "aberystwyth",
|
||||
expectedOutput: "hbhdhgidikieifiiikifhj",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "To Modhex",
|
||||
"args": [
|
||||
"None",
|
||||
0
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "ASCII to Modhex with colon deliminator",
|
||||
input: "aberystwyth",
|
||||
expectedOutput: "hb:hd:hg:id:ik:ie:if:ii:ik:if:hj",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "To Modhex",
|
||||
"args": [
|
||||
"Colon",
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Modhex stream to UTF-8",
|
||||
input: "uhkgkbuhkgkbugltlkugltkc",
|
||||
expectedOutput: "救救孩子",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Modhex",
|
||||
"args": [
|
||||
"Auto"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
name: "Mixed case Modhex stream to UTF-8",
|
||||
input: "uhKGkbUHkgkBUGltlkugltkc",
|
||||
expectedOutput: "救救孩子",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Modhex",
|
||||
"args": [
|
||||
"Auto"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
name: "Mutiline Modhex with comma to ASCII (Auto Mode)",
|
||||
input: "fk,dc,ie,hb,ii,dc,ht,ik,ie,hg,hr,hh,dc,ie,hk,\n\
|
||||
if,if,hk,hu,hi,dc,hk,hu,dc,if,hj,hg,dc,he,id,\n\
|
||||
hv,if,he,hj,dc,hv,hh,dc,if,hj,hg,dc,if,hj,hk,\n\
|
||||
ie,dc,hh,hk,hi,dc,if,id,hg,hg,dr,dc,ie,if,hb,\n\
|
||||
id,ih,hk,hu,hi,dc,if,hv,dc,hf,hg,hb,if,hj,dr,\n\
|
||||
dc,hl,ig,ie,if,dc,hd,hg,he,hb,ig,ie,hg,dc,fk,\n\
|
||||
dc,he,hv,ig,hr,hf,hu,di,if,dc,ht,hb,hn,hg,dc,\n\
|
||||
ig,ic,dc,ht,ik,dc,ht,hk,hu,hf,dc,ii,hj,hk,he,\n\
|
||||
hj,dc,hv,hh,dc,if,hj,hg,dc,hh,hk,hi,ie,dc,fk,\n\
|
||||
dc,ii,hv,ig,hr,hf,dc,he,hj,hv,hv,ie,hg,du",
|
||||
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Modhex",
|
||||
"args": [
|
||||
"Auto"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
name: "Mutiline Modhex with percent to ASCII (Percent Mode)",
|
||||
input: "fk%dc%ie%hb%ii%dc%ht%ik%ie%hg%hr%hh%dc%ie%hk%\n\
|
||||
if%if%hk%hu%hi%dc%hk%hu%dc%if%hj%hg%dc%he%id%\n\
|
||||
hv%if%he%hj%dc%hv%hh%dc%if%hj%hg%dc%if%hj%hk%\n\
|
||||
ie%dc%hh%hk%hi%dc%if%id%hg%hg%dr%dc%ie%if%hb%\n\
|
||||
id%ih%hk%hu%hi%dc%if%hv%dc%hf%hg%hb%if%hj%dr%\n\
|
||||
dc%hl%ig%ie%if%dc%hd%hg%he%hb%ig%ie%hg%dc%fk%\n\
|
||||
dc%he%hv%ig%hr%hf%hu%di%if%dc%ht%hb%hn%hg%dc%\n\
|
||||
ig%ic%dc%ht%ik%dc%ht%hk%hu%hf%dc%ii%hj%hk%he%\n\
|
||||
hj%dc%hv%hh%dc%if%hj%hg%dc%hh%hk%hi%ie%dc%fk%\n\
|
||||
dc%ii%hv%ig%hr%hf%dc%he%hj%hv%hv%ie%hg%du",
|
||||
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Modhex",
|
||||
"args": [
|
||||
"Percent"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
name: "Mutiline Modhex with semicolon to ASCII (Semi-colon Mode)",
|
||||
input: "fk;dc;ie;hb;ii;dc;ht;ik;ie;hg;hr;hh;dc;ie;hk;\n\
|
||||
if;if;hk;hu;hi;dc;hk;hu;dc;if;hj;hg;dc;he;id;\n\
|
||||
hv;if;he;hj;dc;hv;hh;dc;if;hj;hg;dc;if;hj;hk;\n\
|
||||
ie;dc;hh;hk;hi;dc;if;id;hg;hg;dr;dc;ie;if;hb;\n\
|
||||
id;ih;hk;hu;hi;dc;if;hv;dc;hf;hg;hb;if;hj;dr;\n\
|
||||
dc;hl;ig;ie;if;dc;hd;hg;he;hb;ig;ie;hg;dc;fk;\n\
|
||||
dc;he;hv;ig;hr;hf;hu;di;if;dc;ht;hb;hn;hg;dc;\n\
|
||||
ig;ic;dc;ht;ik;dc;ht;hk;hu;hf;dc;ii;hj;hk;he;\n\
|
||||
hj;dc;hv;hh;dc;if;hj;hg;dc;hh;hk;hi;ie;dc;fk;\n\
|
||||
dc;ii;hv;ig;hr;hf;dc;he;hj;hv;hv;ie;hg;du",
|
||||
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Modhex",
|
||||
"args": [
|
||||
"Semi-colon"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
name: "ASCII to Modhex with comma and line breaks",
|
||||
input: "aberystwyth",
|
||||
expectedOutput: "hb,hd,hg,id,\nik,ie,if,ii,\nik,if,hj",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "To Modhex",
|
||||
"args": [
|
||||
"Comma",
|
||||
4
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
|
@ -135,10 +135,21 @@ TestRegister.addTests([
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: no shift amount",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [true, true, true, 0]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: normal",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt.",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 3456789012",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
|
@ -146,10 +157,21 @@ TestRegister.addTests([
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: negative shift amount",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 7890123456",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [true, true, true, -13]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: full loop",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 6789012345",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
|
@ -157,10 +179,21 @@ TestRegister.addTests([
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: full loop (negative shift amount)",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 4567890123",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [true, true, true, -26]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: lowercase only",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt.",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt. 0123456789",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
|
@ -170,8 +203,8 @@ TestRegister.addTests([
|
|||
},
|
||||
{
|
||||
name: "ROT13: uppercase only",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog.",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog. 0123456789",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
|
@ -179,6 +212,50 @@ TestRegister.addTests([
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: numbers only",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [false, false, true, 5]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: numbers only (negative shift amount)",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [false, false, true, 5]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: numbers only loop",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [false, false, true, 10]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT13: numbers only loop (negative shift amount)",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT13",
|
||||
args: [false, false, true, -10]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT47: nothing",
|
||||
input: "",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue