diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 6ad3adb7..fb895a15 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -523,7 +523,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: [], + }, + ], + }, +]);