From 5b2a6178bd1435a7a2ef019af57a1456e7d35d7f Mon Sep 17 00:00:00 2001 From: RomaRoma? Date: Tue, 21 Jul 2026 17:49:58 +0200 Subject: [PATCH] feat: add From JS6Chars operation Adds a new operation to decode JavaScript obfuscated using only 6 characters ([ ] ( ) ! +), commonly known as an esoteric JS encoding style. - Added src/core/operations/FromJS6Chars.mjs - Added operation to Code tidy category in Categories.json - Added tests in tests/operations/tests/FromJS6Chars.mjs fix: correct invalid input test to check error message output --- src/core/config/Categories.json | 3 +- src/core/operations/FromJS6Chars.mjs | 52 +++++++++++++++++++++++ tests/operations/tests/FromJS6Chars.mjs | 56 +++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/FromJS6Chars.mjs create mode 100644 tests/operations/tests/FromJS6Chars.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index bf2c3118..2539f14a 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -521,7 +521,8 @@ "BSON deserialise", "To MessagePack", "From MessagePack", - "Render Markdown" + "Render Markdown", + "From JS6Chars" ] }, { diff --git a/src/core/operations/FromJS6Chars.mjs b/src/core/operations/FromJS6Chars.mjs new file mode 100644 index 00000000..eba0dca6 --- /dev/null +++ b/src/core/operations/FromJS6Chars.mjs @@ -0,0 +1,52 @@ +/** + * @author Roma476 [friciu.robert09@gmail.com] + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * From JS6Chars operation + */ +class FromJS6Chars extends Operation { + + /** + * FromJS6Chars constructor + */ + constructor() { + super(); + + this.name = "From JS6Chars"; + this.module = "Default"; + this.description = "Decodes JavaScript that has been obfuscated using only 6 characters: [, ], (, ), ! and +. This technique exploits JavaScript's type coercion rules to construct executable code from a minimal character set.

e.g. [][(![]+[])[+[]]+...] becomes alert(1)"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + // Input Validation + for (let i = 0; i < input.length; i++) { + const char = input[i]; + if (!["[", "]", "(", ")", "!", "+"].includes(char)) { + throw new OperationError(`Invalid character at position ${i}: ${char}`); + } + } + + try { + return String(Function("\"use strict\"; return (" + input + ")")()); + } catch (err) { + throw new OperationError("Unable to decode: " + err.message); + } + } + +} + +export default FromJS6Chars; diff --git a/tests/operations/tests/FromJS6Chars.mjs b/tests/operations/tests/FromJS6Chars.mjs new file mode 100644 index 00000000..0ee918ca --- /dev/null +++ b/tests/operations/tests/FromJS6Chars.mjs @@ -0,0 +1,56 @@ +/** + * FromJS6Chars tests. + * + * @author Roma476 [friciu.robert09@gmail.com] + * + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "From JS6Chars: a", + input: "(![]+[])[+!+[]]", + expectedOutput: "a", + recipeConfig: [ + { + op: "From JS6Chars", + args: [], + }, + ], + }, + { + name: "From JS6Chars: Hello", + input: "[][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]]+![]+(![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])()[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])+[])[+!+[]]+[+!+[]]+[+!+[]]+[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]])()", + expectedOutput: "Hello", + recipeConfig: [ + { + op: "From JS6Chars", + args: [], + }, + ], + }, + { + name: "From JS6Chars: 123", + input: "[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]]", + expectedOutput: "123", + recipeConfig: [ + { + op: "From JS6Chars", + args: [], + }, + ], + }, + { + name: "From JS6Chars: invalid input", + input: "alert(1)", + expectedOutput: "Invalid character at position 0: a", + recipeConfig: [ + { + op: "From JS6Chars", + args: [], + }, + ], + }, +]);