Compare commits

...
25 Commits
Author SHA1 Message Date
n1474335 eb34ab4f6a 9.7.14 2019-10-16 17:23:59 +01:00
n1474335 08e4232166 Merge branch 'wh0-backslash' 2019-10-16 17:23:47 +01:00
n1474335 adf9772928 Added tests for Utils.parseEscapedChars 2019-10-16 17:22:48 +01:00
n1474335 562171ec86 Merge branch 'backslash' of https://github.com/wh0/CyberChef into wh0-backslash 2019-10-16 16:47:01 +01:00
n1474335 e9e162319f Merge branch 'BjoernAkAManf-master' 2019-10-16 16:32:20 +01:00
n1474335 17c9ffe107 Tidied up chainCommands function in Gruntfile 2019-10-16 16:32:06 +01:00
n1474335 1831c84a29 Merge branch 'master' of https://github.com/BjoernAkAManf/CyberChef into BjoernAkAManf-master 2019-10-16 16:23:09 +01:00
n1474335 7e27449204 Fixed search box appaerance in Firefox 2019-10-16 16:12:22 +01:00
n1474335 282476d530 Merge branch 'Xenonym-chore/remove-duplicate-issue-template' 2019-10-16 16:04:49 +01:00
n1474335 fce0728d5d Updated bug report template 2019-10-16 16:04:36 +01:00
n1474335 0e9ac90607 Merge branch 'chore/remove-duplicate-issue-template' of https://github.com/Xenonym/CyberChef into Xenonym-chore/remove-duplicate-issue-template 2019-10-16 15:59:59 +01:00
n1474335 5383f56b26 9.7.13 2019-10-16 15:51:06 +01:00
n1474335 a02484c6cd Merge branch 'Storms-Engineering-IV-length-Error' 2019-10-16 15:50:51 +01:00
n1474335 be365f66ef Added length check to Triple DES IVs 2019-10-16 15:50:37 +01:00
n1474335 011dc09d5e Merge branch 'IV-length-Error' of https://github.com/Storms-Engineering/CyberChef into Storms-Engineering-IV-length-Error 2019-10-16 15:43:47 +01:00
n1474335 fc4d6d2d2e 9.7.12 2019-10-16 15:39:56 +01:00
n1474335 9d73127cae Fixed some typos 2019-10-16 15:38:20 +01:00
n1474335 223743e3b5 Removed Clippy 2019-10-16 15:37:18 +01:00
n1474335 44ed372f21 9.7.11 2019-10-16 15:10:16 +01:00
n1474335 4d1f970105 Added test to ensure all operations are in a category. Added various operations to categories. 2019-10-16 15:10:03 +01:00
Storms-Engineering 3e93580aa4 DES Encrypt/Decrypt - checks length of IV string
Checks the length of IV string when encrypting.  DES encrypt/decrypt test swas updated to use utf8 instead of HEX.
2019-10-12 09:42:13 -08:00
Tan Zhen Yong 3c021919dd Rename feature request issue template
- to remain consistent with other issue templates using a `-` instead of `_`
2019-10-12 16:17:40 +08:00
Tan Zhen Yong 2106e8ddb0 Remove duplicate bug report issue template
The bug report issue template is duplicated (`bug-report.md` and
`bug_report.md`, note the `-`/`_` difference).

Thus, GitHub was unable to use the bug report issue template, and it
does not show up when a new issue is being created.

Let's remove the duplicate template `bug_report.md`.
2019-10-12 16:13:40 +08:00
wh0 d60d595254 Utils: don't consume three backslashes at a time 2019-10-06 17:07:58 -07:00
Björn Heinrichs c28999ec6f Fixed building on Windows
On Windows OperationConfig was not generated.
See #360 #645 for more Information.
2019-10-03 02:23:18 +02:00
56 changed files with 199 additions and 501 deletions

No files matched your search

+1 -2
View File
@@ -1,2 +1 @@
src/core/vendor/**
src/web/static/clippy_assets/**
src/core/vendor/**
+2 -2
View File
@@ -26,8 +26,8 @@ If applicable, add screenshots to help explain your problem.
**Desktop (if relevant, please complete the following information):**
- OS: [e.g. Windows]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- Browser: [e.g. chrome 72, firefox 60]
- CyberChef version: [e.g. 9.7.14]
**Additional context**
Add any other context about the problem here.
-34
View File
@@ -1,34 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: 'Bug report: <Insert title here>'
labels: bug
assignees: ''
---
<!-- Prefix the title above with 'Bug report:' -->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior or a link to the recipe / input used to cause the bug:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (if relevant, please complete the following information):**
- OS: [e.g. Windows]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+37 -18
View File
@@ -14,7 +14,6 @@ const path = require("path");
* @license Apache-2.0
*/
module.exports = function (grunt) {
grunt.file.defaultEncoding = "utf8";
grunt.file.preserveBOM = false;
@@ -102,6 +101,26 @@ module.exports = function (grunt) {
return entryModules;
}
/**
* Detects the correct delimiter to use to chain shell commands together
* based on the current OS.
*
* @param {string[]} cmds
* @returns {string}
*/
function chainCommands(cmds) {
const win = process.platform === "win32";
if (!win) {
return cmds.join(";");
}
return cmds
// && means that subsequent commands will not be executed if the
// previous one fails. & would coninue on a fail
.join("&&")
// Windows does not support \n properly
.replace("\n", "\\n");
}
grunt.initConfig({
clean: {
dev: ["build/dev/*"],
@@ -316,10 +335,10 @@ module.exports = function (grunt) {
},
exec: {
repoSize: {
command: [
command: chainCommands([
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
].join(";"),
]),
stderr: false
},
cleanGit: {
@@ -329,20 +348,20 @@ module.exports = function (grunt) {
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
},
generateConfig: {
command: [
command: chainCommands([
"echo '\n--- Regenerating config files. ---'",
"echo [] > src/core/config/OperationConfig.json",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
"echo '--- Config scripts finished. ---\n'"
].join(";")
])
},
generateNodeIndex: {
command: [
command: chainCommands([
"echo '\n--- Regenerating node index ---'",
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
"echo '--- Node index generated. ---\n'"
].join(";"),
]),
},
opTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
@@ -354,40 +373,40 @@ module.exports = function (grunt) {
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
},
setupNodeConsumers: {
command: [
"echo '\n--- Testing node conumers ---'",
command: chainCommands([
"echo '\n--- Testing node consumers ---'",
"npm link",
`mkdir ${nodeConsumerTestPath}`,
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
`cd ${nodeConsumerTestPath}`,
"npm link cyberchef"
].join(";"),
]),
},
teardownNodeConsumers: {
command: [
command: chainCommands([
`rm -rf ${nodeConsumerTestPath}`,
"echo '\n--- Node consumer tests complete ---'"
].join(";"),
]),
},
testCJSNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings cjs-consumer.js",
].join(";"),
]),
stdout: false,
},
testESMNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-consumer.mjs",
].join(";"),
]),
stdout: false,
},
testESMDeepImportNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
].join(";"),
]),
stdout: false,
},
},
+31 -20
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.7.10",
"version": "9.7.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3190,14 +3190,6 @@
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true
},
"clippyjs": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/clippyjs/-/clippyjs-0.0.3.tgz",
"integrity": "sha512-i4sPaKbCA6PfXiwxNK35E1io6AXN7VGwEGZR9sE8RqOgXPNtRWKbFubmx87JwSuwIrdClO/rkTMjhl2ZyOHjug==",
"requires": {
"jquery": "^3.2.1"
}
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
@@ -6026,7 +6018,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@@ -6047,12 +6040,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -6067,17 +6062,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6194,7 +6192,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -6206,6 +6205,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6220,6 +6220,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -6227,12 +6228,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -6251,6 +6254,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6331,7 +6335,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -6343,6 +6348,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -6428,7 +6434,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6464,6 +6471,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6483,6 +6491,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6526,12 +6535,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
+1 -2
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.7.10",
"version": "9.7.14",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -95,7 +95,6 @@
"bootstrap-material-design": "^4.1.2",
"bson": "^4.0.2",
"chi-squared": "^1.1.0",
"clippyjs": "0.0.3",
"core-js": "^3.2.1",
"crypto-api": "^0.8.5",
"crypto-js": "^3.1.9-1",
+2 -2
View File
@@ -129,7 +129,7 @@ class Dish {
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {* | Promise} - (Broswer) A promise | (Node) value of dish in given type
* @returns {* | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
get(type, notUTF8=false) {
if (typeof type === "string") {
@@ -191,7 +191,7 @@ class Dish {
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {Dish | Promise} - (Broswer) A promise | (Node) value of dish in given type
* @returns {Dish | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
presentAs(type, notUTF8=false) {
const clone = this.clone();
+7 -8
View File
@@ -201,9 +201,8 @@ class Utils {
* Utils.parseEscapedChars("\\n");
*/
static parseEscapedChars(str) {
return str.replace(/(\\)?\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a, b) {
if (a === "\\") return "\\"+b;
switch (b[0]) {
return str.replace(/\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
switch (a[0]) {
case "\\":
return "\\";
case "0":
@@ -214,7 +213,7 @@ class Utils {
case "5":
case "6":
case "7":
return String.fromCharCode(parseInt(b, 8));
return String.fromCharCode(parseInt(a, 8));
case "b":
return "\b";
case "t":
@@ -232,12 +231,12 @@ class Utils {
case "'":
return "'";
case "x":
return String.fromCharCode(parseInt(b.substr(1), 16));
return String.fromCharCode(parseInt(a.substr(1), 16));
case "u":
if (b[1] === "{")
return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
if (a[1] === "{")
return String.fromCodePoint(parseInt(a.slice(2, -1), 16));
else
return String.fromCharCode(parseInt(b.substr(1), 16));
return String.fromCharCode(parseInt(a.substr(1), 16));
}
});
}
+4
View File
@@ -123,6 +123,7 @@
"Generate PGP Key Pair",
"PGP Encrypt",
"PGP Decrypt",
"PGP Verify",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify",
"Parse SSH Host Key"
@@ -284,6 +285,7 @@
"Zip",
"Unzip",
"Bzip2 Decompress",
"Bzip2 Compress",
"Tar",
"Untar"
]
@@ -370,6 +372,7 @@
"Detect File Type",
"Scan for Embedded Files",
"Extract Files",
"YARA Rules",
"Remove EXIF",
"Extract EXIF",
"Extract RGBA",
@@ -401,6 +404,7 @@
"Cover Image",
"Image Hue/Saturation/Lightness",
"Sharpen Image",
"Normalise Image",
"Convert Image Format",
"Add Text To Image",
"Hex Density chart",
+1 -1
View File
@@ -22,7 +22,7 @@ export const ENCODING_SCHEME = [
/**
* Lookup table for the binary value of each digit representation.
*
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programmatically,
* but unfortunately it's much easier (if less elegant) to use lookup tables
* when supporting multiple encoding schemes.
*
+1 -1
View File
@@ -32,7 +32,7 @@ export const WORD_DELIM_OPTIONS = ["Line feed", "CRLF", "Forward slash", "Backsl
export const INPUT_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"];
/**
* Armithmetic sequence delimiters
* Arithmetic sequence delimiters
*/
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
+1 -1
View File
@@ -2463,7 +2463,7 @@ export function extractMZPE(bytes, offset) {
const numSections = stream.readInt(2, "le");
// Read Optional Header Magic to determine the state of the image file
// 0x10b = normal exeuctable, 0x107 = ROM image, 0x20b = PE32+ executable
// 0x10b = normal executable, 0x107 = ROM image, 0x20b = PE32+ executable
stream.moveForwardsBy(16);
const optionalMagic = stream.readInt(2, "le");
const pe32Plus = optionalMagic === 0x20b;
+1 -1
View File
@@ -178,7 +178,7 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
* @param {Uint8Array} buf - The buffer to search
* @param {Object} sig - A single signature object (Not an array of signatures)
* @param {number} offset - Where to start search from
* @returs {number} The position of the match or -1 if one cannot be found.
* @returns {number} The position of the match or -1 if one cannot be found.
*/
function locatePotentialSig(buf, sig, offset) {
// Find values for first key and value in sig
+1 -1
View File
@@ -37,7 +37,7 @@ export async function parseQrCode(input, normalise) {
image = await jimp.read(image);
}
} catch (err) {
throw new OperationError(`Error normalising iamge. (${err})`);
throw new OperationError(`Error normalising image. (${err})`);
}
const qrData = jsQR(image.bitmap.data, image.getWidth(), image.getHeight());
+1 -1
View File
@@ -50,7 +50,7 @@ class BLAKE2b extends Operation {
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string} The input having been hashed with BLAKE2b in the encoding format speicifed.
* @returns {string} The input having been hashed with BLAKE2b in the encoding format specified.
*/
run(input, args) {
const [outSize, outFormat] = args;
+1 -1
View File
@@ -51,7 +51,7 @@ class BLAKE2s extends Operation {
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string} The input having been hashed with BLAKE2s in the encoding format speicifed.
* @returns {string} The input having been hashed with BLAKE2s in the encoding format specified.
*/
run(input, args) {
const [outSize, outFormat] = args;
+6
View File
@@ -73,6 +73,12 @@ class DESDecrypt extends Operation {
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) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);
+6
View File
@@ -73,6 +73,12 @@ class DESEncrypt extends Operation {
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) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);
+1 -1
View File
@@ -57,7 +57,7 @@ class HammingDistance extends Operation {
samples = input.split(delim);
if (samples.length !== 2) {
throw new OperationError("Error: You can only calculae the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
throw new OperationError("Error: You can only calculate the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
}
if (samples[0].length !== samples[1].length) {
+1 -1
View File
@@ -77,7 +77,7 @@ class RawInflate extends Operation {
}),
result = new Uint8Array(inflate.decompress());
// Raw Inflate somethimes messes up and returns nonsense like this:
// Raw Inflate sometimes messes up and returns nonsense like this:
// ]....]....]....]....]....]....]....]....]....]....]....]....]....]...
// e.g. Input data of [8b, 1d, dc, 44]
// Look for the first two square brackets:
+2 -2
View File
@@ -64,7 +64,7 @@ class RemoveWhitespace extends Operation {
run(input, args) {
const [
removeSpaces,
removeCariageReturns,
removeCarriageReturns,
removeLineFeeds,
removeTabs,
removeFormFeeds,
@@ -73,7 +73,7 @@ class RemoveWhitespace extends Operation {
let data = input;
if (removeSpaces) data = data.replace(/ /g, "");
if (removeCariageReturns) data = data.replace(/\r/g, "");
if (removeCarriageReturns) data = data.replace(/\r/g, "");
if (removeLineFeeds) data = data.replace(/\n/g, "");
if (removeTabs) data = data.replace(/\t/g, "");
if (removeFormFeeds) data = data.replace(/\f/g, "");
+1 -1
View File
@@ -108,7 +108,7 @@ class ToQuotedPrintable extends Operation {
* @private
* @param {number} nr
* @param {byteArray[]} ranges
* @returns {bolean}
* @returns {boolean}
*/
_checkRanges(nr, ranges) {
for (let i = ranges.length - 1; i >= 0; i--) {
+6
View File
@@ -75,6 +75,12 @@ class TripleDESDecrypt extends Operation {
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) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
Triple DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);
+6
View File
@@ -75,6 +75,12 @@ class TripleDESEncrypt extends Operation {
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) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
Triple DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);
+1 -1
View File
@@ -23,7 +23,7 @@ class Typex extends Operation {
this.name = "Typex";
this.module = "Default";
this.description = "Encipher/decipher with the WW2 Typex machine.<br><br>Typex was originally built by the British Royal Air Force prior to WW2, and is based on the Enigma machine with some improvements made, including using five rotors with more stepping points and interchangeable wiring cores. It was used across the British and Commonewealth militaries. A number of later variants were produced; here we simulate a WW2 era Mark 22 Typex with plugboards for the reflector and input. Typex rotors were changed regularly and none are public: a random example set are provided.<br><br>To configure the reflector plugboard, enter a string of connected pairs of letters in the reflector box, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F (you'll need to connect every letter). There is also an input plugboard: unlike Enigma's plugboard, it's not restricted to pairs, so it's entered like a rotor (without stepping). To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code>&lt;</code> then a list of stepping points.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.description = "Encipher/decipher with the WW2 Typex machine.<br><br>Typex was originally built by the British Royal Air Force prior to WW2, and is based on the Enigma machine with some improvements made, including using five rotors with more stepping points and interchangeable wiring cores. It was used across the British and Commonwealth militaries. A number of later variants were produced; here we simulate a WW2 era Mark 22 Typex with plugboards for the reflector and input. Typex rotors were changed regularly and none are public: a random example set are provided.<br><br>To configure the reflector plugboard, enter a string of connected pairs of letters in the reflector box, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F (you'll need to connect every letter). There is also an input plugboard: unlike Enigma's plugboard, it's not restricted to pairs, so it's entered like a rotor (without stepping). To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code>&lt;</code> then a list of stepping points.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Typex";
this.inputType = "string";
this.outputType = "string";
@@ -56,7 +56,7 @@ class UNIXTimestampToWindowsFiletime extends Operation {
} else if (units === "Milliseconds (ms)") {
input = input.multipliedBy(new BigNumber("10000"));
} else if (units === "Microseconds (μs)") {
input = input.multiplyiedBy(new BigNumber("10"));
input = input.multipliedBy(new BigNumber("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.dividedBy(new BigNumber("100"));
} else {
+1 -1
View File
@@ -49,7 +49,7 @@ class URLEncode extends Operation {
* @returns {string}
*/
encodeAllChars (str) {
// TODO Do this programatically
// TODO Do this programmatically
return encodeURIComponent(str)
.replace(/!/g, "%21")
.replace(/#/g, "%23")
+1 -1
View File
@@ -55,7 +55,7 @@ class VigenèreDecode extends Operation {
keyIndex = alphabet.indexOf(chr);
msgIndex = alphabet.indexOf(input[i]);
// Subtract indexes from each other, add 26 just in case the value is negative,
// modulo to remove if neccessary
// modulo to remove if necessary
output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
chr = key[(i - fail) % key.length].toLowerCase();
+1 -1
View File
@@ -20,7 +20,7 @@ class Whirlpool extends Operation {
this.name = "Whirlpool";
this.module = "Crypto";
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Whirlpool is the latest revision, released in 2003, fixing a flaw in the difusion matrix.</li></ul>";
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Whirlpool is the latest revision, released in 2003, fixing a flaw in the diffusion matrix.</li></ul>";
this.infoURL = "https://wikipedia.org/wiki/Whirlpool_(cryptography)";
this.inputType = "ArrayBuffer";
this.outputType = "string";
+3 -3
View File
@@ -12,7 +12,7 @@ import NodeDish from "./NodeDish.mjs";
import NodeRecipe from "./NodeRecipe.mjs";
import OperationConfig from "../core/config/OperationConfig.json";
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
import ExludedOperationError from "../core/errors/ExcludedOperationError.mjs";
import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";
/**
@@ -320,12 +320,12 @@ export function bake() {
* Explain that the given operation is not included in the Node.js version.
* @param {String} name - name of operation
*/
export function _explainExludedFunction(name) {
export function _explainExcludedFunction(name) {
/**
* Throw new error type with useful message.
*/
const func = () => {
throw new ExludedOperationError(`Sorry, the ${name} operation is not available in the Node.js version of CyberChef.`);
throw new ExcludedOperationError(`Sorry, the ${name} operation is not available in the Node.js version of CyberChef.`);
};
// Add opName prop so NodeRecipe can handle it, just like wrap does.
func.opName = name;
+1 -1
View File
@@ -71,7 +71,7 @@ export function sanitise(str) {
/**
* sonething like this => somethingLikeThis
* something like this => somethingLikeThis
* ABC a sentence => ABCASentence
*/
export function sentenceToCamelCase(str) {
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Operations to exlude from the Node API
* Operations to exclude from the Node API
*
* @author d98762656 [d98762625@gmail.com]
* @copyright Crown Copyright 2018
@@ -39,7 +39,7 @@ let code = `/**
import NodeDish from "./NodeDish.mjs";
import { _wrap, help, bake, _explainExludedFunction } from "./api.mjs";
import { _wrap, help, bake, _explainExcludedFunction } from "./api.mjs";
import File from "./File.mjs";
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index";
import {
@@ -70,7 +70,7 @@ includedOperations.forEach((op) => {
});
excludedOperations.forEach((op) => {
code += ` "${decapitalise(op)}": _explainExludedFunction("${op}"),\n`;
code += ` "${decapitalise(op)}": _explainExcludedFunction("${op}"),\n`;
});
code += ` };
@@ -1 +0,0 @@
clippy.ready('Clippy', {"overlayCount": 1, "sounds": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], "framesize": [124, 93], "animations": {"Congratulate": {"frames": [{"duration": 100, "images": [[0, 0]], "sound": "15"}, {"duration": 10, "images": [[124, 0]]}, {"duration": 10, "images": [[248, 0]]}, {"duration": 10, "images": [[372, 0]], "sound": "14"}, {"duration": 10, "images": [[496, 0]]}, {"duration": 10, "images": [[620, 0]]}, {"duration": 10, "images": [[744, 0]]}, {"duration": 10, "images": [[868, 0]]}, {"duration": 10, "images": [[992, 0]], "sound": "1"}, {"duration": 100, "images": [[1116, 0]]}, {"duration": 100, "images": [[1240, 0]]}, {"duration": 100, "images": [[1364, 0]]}, {"duration": 1200, "images": [[1488, 0]]}, {"duration": 100, "images": [[1612, 0]], "sound": "10"}, {"duration": 100, "images": [[1736, 0]]}, {"duration": 1200, "images": [[1488, 0]]}, {"duration": 100, "images": [[1860, 0]]}, {"duration": 100, "images": [[1984, 0]]}, {"duration": 100, "images": [[2108, 0]]}, {"duration": 100, "images": [[2232, 0]]}, {"duration": 100, "images": [[2356, 0]], "exitBranch": 21}, {"duration": 100, "images": [[0, 0]]}]}, "LookRight": {"frames": [{"duration": 100, "images": [[0, 0]], "exitBranch": 6}, {"duration": 100, "images": [[620, 651]], "exitBranch": 5}, {"duration": 100, "images": [[744, 651]], "exitBranch": 4}, {"duration": 1200, "images": [[868, 651]]}, {"duration": 100, "images": [[992, 651]]}, {"duration": 100, "images": [[1116, 651]]}, {"duration": 100, "images": [[0, 0]]}]}, "SendMail": {"frames": [{"duration": 100, "images": [[0, 0]], "sound": "15"}, {"duration": 100, "images": [[1240, 1209]]}, {"duration": 100, "images": [[1364, 1209]]}, {"duration": 100, "images": [[1488, 1209]]}, {"duration": 100, "images": [[1612, 1209]]}, {"duration": 100, "images": [[1736, 1209]]}, {"duration": 100, "images": [[1860, 1209]]}, {"duration": 100, "images": [[1984, 1209]]}, {"duration": 100, "images": [[2108, 1209]]}, {"duration": 100, "images": [[2232, 1209]]}, {"duration": 100, "images": [[2356, 1209]]}, {"duration": 100, "images": [[2480, 1209]]}, {"duration": 100, "images": [[2604, 1209]]}, {"duration": 100, "images": [[2728, 1209]]}, {"duration": 100, "images": [[2852, 1209]]}, {"duration": 100, "images": [[2976, 1209]]}, {"duration": 100, "images": [[3100, 1209]]}, {"duration": 100, "images": [[3224, 1209]]}, {"duration": 100, "images": [[0, 1302]]}, {"duration": 100, "images": [[124, 1302]]}, {"duration": 100, "images": [[248, 1302]]}, {"duration": 100, "images": [[372, 1302]], "sound": "14"}, {"duration": 100, "images": [[496, 1302]], "exitBranch": 24}, {"duration": 100, "images": [[620, 1302]]}, {"duration": 100, "images": [[744, 1302]], "exitBranch": 26}, {"duration": 100, "images": [[868, 1302]]}, {"duration": 100, "images": [[992, 1302]], "exitBranch": 27}, {"duration": 100, "images": [[1116, 1302]], "exitBranch": 28}, {"duration": 100, "images": [[1240, 1302]], "exitBranch": 29}, {"duration": 100, "images": [[1364, 1302]], "exitBranch": 30}, {"duration": 100, "images": [[1488, 1302]], "exitBranch": 31}, {"duration": 100, "images": [[1612, 1302]], "exitBranch": 32}, {"duration": 100, "images": [[1736, 1302]]}, {"duration": 100, "images": [[1860, 1302]]}, {"duration": 100, "images": [[1984, 1302]]}, {"duration": 100, "images": [[2108, 1302]]}, {"duration": 100, "images": [[2232, 1302]]}, {"duration": 100, "images": [[2356, 1302]]}, {"duration": 100, "images": [[2480, 1302]]}, {"duration": 100, "images": [[2604, 1302]]}, {"duration": 100, "images": [[2728, 1302]]}, {"duration": 100, "images": [[2852, 1302]]}, {"duration": 100, "images": [[2976, 1302]]}, {"duration": 100, "images": [[3100, 1302]]}, {"duration": 100, "images": [[3224, 1302]]}, {"duration": 100, "images": [[0, 1395]]}, {"duration": 100, "images": [[124, 1395]]}, {"duration": 100, "images": [[248, 1395]], "exitBranch": 48}, {"duration": 100, "images": [[372, 1395]], "exitBranch": 49}, {"duration": 100, "images": [[496, 1395]]}, {"duration": 100, "images": [[620, 1395]], "sound": "4"}, {"duration": 100, "images": [[744, 1395]]}, {"duration": 100, "images": [[868, 1395]]}, {"duration": 600}, {"duration": 100, "images": [[992, 1395]]}, {"duration": 100, "images": [[1116, 1395]]}, {"duration": 100, "images": [[1240, 1395]]}, {"duration": 100, "images": [[1364, 1395]]}, {"duration": 100, "images": [[1488, 1395]]}, {"duration": 100, "images": [[1612, 1395]]}, {"duration": 100, "images": [[1736, 1395]]}, {"duration": 100, "images": [[1860, 1395]]}, {"duration": 100, "images": [[0, 0]]}]}, "Thinking": {"frames": [{"duration": 100, "images": [[0, 0]], "sound": "15"}, {"duration": 100, "images": [[124, 93]]}, {"duration": 100, "images": [[248, 93]]}, {"duration": 100, "images": [[372, 93]]}, {"duration": 100, "images": [[496, 93]], "sound": "14"}, {"duration": 100, "images": [[620, 93]]}, {"duration": 100, "images": [[744, 93]]}, {"duration": 100, "images": [[868, 93]]}, {"duration": 100, "images": Line truncated
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

-62
View File
@@ -1,62 +0,0 @@
.clippy, .clippy-balloon {
position: fixed;
z-index: 1000;
cursor: pointer;
}
.clippy-balloon {
background: #FFC;
color: black;
padding: 8px;
border: 1px solid black;
border-radius: 5px;
}
.clippy-content {
max-width: 200px;
min-width: 120px;
font-family: "Microsoft Sans", sans-serif;
font-size: 10pt;
}
.clippy-tip {
width: 10px;
height: 16px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAgCAMAAAAlvKiEAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAlQTFRF///MAAAA////52QwgAAAAAN0Uk5T//8A18oNQQAAAGxJREFUeNqs0kEOwCAIRFHn3//QTUU6xMyyxii+jQosrTPkyPEM6IN3FtzIRk1U4dFeKWQiH6pRRowMVKEmvronEynkwj0uZJgR22+YLopPSo9P34wJSamLSU7lSIWLJU7NkNomNlhqxUeAAQC+TQLZyEuJBwAAAABJRU5ErkJggg==) no-repeat;
position: absolute;
}
.clippy-top-left .clippy-tip {
top: 100%;
margin-top: 0px;
left: 100%;
margin-left: -50px;
}
.clippy-top-right .clippy-tip {
top: 100%;
margin-top: 0px;
left: 0;
margin-left: 50px;
background-position: -10px 0;
}
.clippy-bottom-right .clippy-tip {
top: 0;
margin-top: -16px;
left: 0;
margin-left: 50px;
background-position: -10px -16px;
}
.clippy-bottom-left .clippy-tip {
top: 0;
margin-top: -16px;
left: 100%;
margin-left: -50px;
background-position: 0px -16px;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

-1
View File
@@ -8,7 +8,6 @@
/* Libraries */
import "highlight.js/styles/vs.css";
import "../static/clippy_assets/clippy.css";
/* Frameworks */
import "./vendors/bootstrap.scss";
-8
View File
@@ -82,14 +82,6 @@ a:focus {
border-color: var(--btn-success-hover-border-colour);
}
input[type="search"] {
appearance: searchfield;
}
input[type="search"]::-webkit-search-cancel-button {
appearance: searchfield-cancel-button;
}
select.form-control:not([size]):not([multiple]), select.custom-file-control:not([size]):not([multiple]) {
height: unset !important;
}
+1 -1
View File
@@ -25,7 +25,7 @@ class ControlsWaiter {
/**
* Initialise Bootstrap componenets
* Initialise Bootstrap components
*/
initComponents() {
$("body").bootstrapMaterialDesign();
+1 -1
View File
@@ -172,7 +172,7 @@ class OperationsWaiter {
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
.popover({trigger: "manual"})
.on("mouseenter", function(e) {
if (e.buttons > 0) return; // Mouse button held down - likely dragging an opertion
if (e.buttons > 0) return; // Mouse button held down - likely dragging an operation
const _this = this;
$(this).popover("show");
$(".popover").on("mouseleave", function () {
+1 -1
View File
@@ -58,7 +58,7 @@ class OptionsWaiter {
/**
* Handler for options click events.
* Dispays the options pane.
* Displays the options pane.
*
* @param {event} e
*/
+1 -1
View File
@@ -174,7 +174,7 @@ class OutputWaiter {
}
/**
* Updates the stored bake ID for the output in the ouptut array
* Updates the stored bake ID for the output in the output array
*
* @param {number} bakeId
* @param {number} inputNum
+1 -294
View File
@@ -4,17 +4,13 @@
* @license Apache-2.0
*/
import clippy from "clippyjs";
import "../static/clippy_assets/agents/Clippy/agent.js";
import clippyMap from "../static/clippy_assets/agents/Clippy/map.png";
/**
* Waiter to handle seasonal events and easter eggs.
*/
class SeasonalWaiter {
/**
* SeasonalWaiter contructor.
* SeasonalWaiter constructor.
*
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
@@ -22,8 +18,6 @@ class SeasonalWaiter {
constructor(app, manager) {
this.app = app;
this.manager = manager;
this.clippyAgent = null;
}
@@ -34,14 +28,6 @@ class SeasonalWaiter {
// Konami code
this.kkeys = [];
window.addEventListener("keydown", this.konamiCodeListener.bind(this));
// Clippy
const now = new Date();
if (now.getMonth() === 3 && now.getDate() === 1) {
this.addClippyOption();
this.manager.addDynamicListener(".option-item #clippy", "change", this.setupClippy, this);
this.setupClippy();
}
}
@@ -65,285 +51,6 @@ class SeasonalWaiter {
}
}
/**
* Creates an option in the Options menu for turning Clippy on or off
*/
addClippyOption() {
const optionsBody = document.getElementById("options-body"),
optionItem = document.createElement("span");
optionItem.className = "bmd-form-group is-filled";
optionItem.innerHTML = `<div class="checkbox option-item">
<label for="clippy">
<input type="checkbox" option="clippy" id="clippy" checked="">
Use the Clippy helper
</label>
</div>`;
optionsBody.appendChild(optionItem);
if (!("clippy" in this.app.options)) {
this.app.options.clippy = true;
}
this.manager.options.load();
}
/**
* Sets up Clippy for April Fools Day
*/
setupClippy() {
// Destroy any previous agents
if (this.clippyAgent) {
this.clippyAgent.closeBalloonImmediately();
this.clippyAgent.hide();
}
if (!this.app.options.clippy) {
if (this.clippyTimeouts) this.clippyTimeouts.forEach(t => clearTimeout(t));
return;
}
// Set base path to # to prevent external network requests
const clippyAssets = "#";
// Shim the library to prevent external network requests
shimClippy(clippy);
const self = this;
clippy.load("Clippy", (agent) => {
shimClippyAgent(agent);
self.clippyAgent = agent;
agent.show();
agent.speak("Hello, I'm Clippy, your personal cyber assistant!");
}, undefined, clippyAssets);
// Watch for the Auto Magic button appearing
const magic = document.getElementById("magic");
const observer = new MutationObserver((mutationsList, observer) => {
// Read in message and recipe
let msg, recipe;
for (const mutation of mutationsList) {
if (mutation.attributeName === "data-original-title") {
msg = magic.getAttribute("data-original-title");
}
if (mutation.attributeName === "data-recipe") {
recipe = magic.getAttribute("data-recipe");
}
}
// Close balloon if it is currently showing a magic hint
const balloon = self.clippyAgent._balloon._balloon;
if (balloon.is(":visible") && balloon.text().indexOf("That looks like encoded data") >= 0) {
self.clippyAgent._balloon.hide(true);
this.clippyAgent._balloon._hidden = true;
}
// If a recipe was found, get Clippy to tell the user
if (recipe) {
recipe = this.manager.controls.generateStateUrl(true, true, JSON.parse(recipe));
msg = `That looks like encoded data!<br><br>${msg}<br><br>Click <a class="clippyMagicRecipe" href="${recipe}">here</a> to load this recipe.`;
// Stop current balloon activity immediately and trigger speak again
this.clippyAgent.closeBalloonImmediately();
self.clippyAgent.speak(msg, true);
// self.clippyAgent._queue.next();
}
});
observer.observe(document.getElementById("magic"), {attributes: true});
// Play animations for various things
this.manager.addListeners("#search", "click", () => {
this.clippyAgent.play("Searching");
}, this);
this.manager.addListeners("#save,#save-to-file", "click", () => {
this.clippyAgent.play("Save");
}, this);
this.manager.addListeners("#clr-recipe,#clr-io", "click", () => {
this.clippyAgent.play("EmptyTrash");
}, this);
this.manager.addListeners("#bake", "click", e => {
if (e.target.closest("button").textContent.toLowerCase().indexOf("bake") >= 0) {
this.clippyAgent.play("Thinking");
} else {
this.clippyAgent.play("EmptyTrash");
}
this.clippyAgent._queue.clear();
}, this);
this.manager.addListeners("#input-text", "keydown", () => {
this.clippyAgent.play("Writing");
this.clippyAgent._queue.clear();
}, this);
this.manager.addDynamicListener("a.clippyMagicRecipe", "click", (e) => {
this.clippyAgent.play("Congratulate");
}, this);
this.clippyTimeouts = [];
// Show challenge after timeout
this.clippyTimeouts.push(setTimeout(() => {
const hex = "1f 8b 08 00 ae a1 9b 5c 00 ff 05 40 a1 12 00 10 0c fd 26 61 5b 76 aa 9d 26 a8 02 02 37 84 f7 fb bb c5 a4 5f 22 c6 09 e5 6e c5 4c 2d 3f e9 30 a6 ea 41 a2 f2 ac 1c 00 00 00";
self.clippyAgent.speak(`How about a fun challenge?<br><br>Try decoding this (click to load):<br><a href="#recipe=[]&input=${encodeURIComponent(btoa(hex))}">${hex}</a>`, true);
self.clippyAgent.play("GetAttention");
}, 1 * 60 * 1000));
this.clippyTimeouts.push(setTimeout(() => {
self.clippyAgent.speak("<i>Did you know?</i><br><br>You can load files into CyberChef up to around 500MB using drag and drop or the load file button.", 15000);
self.clippyAgent.play("Wave");
}, 2 * 60 * 1000));
this.clippyTimeouts.push(setTimeout(() => {
self.clippyAgent.speak("<i>Did you know?</i><br><br>You can use the 'Fork' operation to split up your input and run the recipe over each branch separately.<br><br><a class='clippyMagicRecipe' href=\"#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&amp;input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA\">Here's an example</a>.", 15000);
self.clippyAgent.play("Print");
}, 3 * 60 * 1000));
this.clippyTimeouts.push(setTimeout(() => {
self.clippyAgent.speak("<i>Did you know?</i><br><br>The 'Magic' operation uses a number of methods to detect encoded data and the operations which can be used to make sense of it. A technical description of these methods can be found <a href=\"https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic\">here</a>.", 15000);
self.clippyAgent.play("Alert");
}, 4 * 60 * 1000));
this.clippyTimeouts.push(setTimeout(() => {
self.clippyAgent.speak("<i>Did you know?</i><br><br>You can use parts of the input as arguments to operations.<br><br><a class='clippyMagicRecipe' href=\"#recipe=Register('key%3D(%5B%5C%5Cda-f%5D*)',true,false)Find_/_Replace(%7B'option':'Regex','string':'.*data%3D(.*)'%7D,'$1',true,false,true)RC4(%7B'option':'Hex','string':'$R0'%7D,'Hex','Latin1')&amp;input=aHR0cDovL21hbHdhcmV6LmJpei9iZWFjb24ucGhwP2tleT0wZTkzMmE1YyZkYXRhPThkYjdkNWViZTM4NjYzYTU0ZWNiYjMzNGUzZGIxMQ\">Click here for an example</a>.", 15000);
self.clippyAgent.play("CheckingSomething");
}, 5 * 60 * 1000));
}
}
/**
* Shims various ClippyJS functions to modify behaviour.
*
* @param {Clippy} clippy - The Clippy library
*/
function shimClippy(clippy) {
// Shim _loadSounds so that it doesn't actually try to load any sounds
clippy.load._loadSounds = function _loadSounds (name, path) {
let dfd = clippy.load._sounds[name];
if (dfd) return dfd;
// set dfd if not defined
dfd = clippy.load._sounds[name] = $.Deferred();
// Resolve immediately without loading
dfd.resolve({});
return dfd.promise();
};
// Shim _loadMap so that it uses the local copy
clippy.load._loadMap = function _loadMap (path) {
let dfd = clippy.load._maps[path];
if (dfd) return dfd;
// set dfd if not defined
dfd = clippy.load._maps[path] = $.Deferred();
const src = clippyMap;
const img = new Image();
img.onload = dfd.resolve;
img.onerror = dfd.reject;
// start loading the map;
img.setAttribute("src", src);
return dfd.promise();
};
// Make sure we don't request the remote map
clippy.Animator.prototype._setupElement = function _setupElement (el) {
const frameSize = this._data.framesize;
el.css("display", "none");
el.css({ width: frameSize[0], height: frameSize[1] });
el.css("background", "url('" + clippyMap + "') no-repeat");
return el;
};
}
/**
* Shims various ClippyJS Agent functions to modify behaviour.
*
* @param {Agent} agent - The Clippy Agent
*/
function shimClippyAgent(agent) {
// Turn off all sounds
agent._animator._playSound = () => {};
// Improve speak function to support HTML markup
const self = agent._balloon;
agent._balloon.speak = (complete, text, hold) => {
self._hidden = false;
self.show();
const c = self._content;
// set height to auto
c.height("auto");
c.width("auto");
// add the text
c.html(text);
// set height
c.height(c.height());
c.width(c.width());
c.text("");
self.reposition();
self._complete = complete;
self._sayWords(text, hold, complete);
if (hold) agent._queue.next();
};
// Improve the _sayWords function to allow HTML and support timeouts
agent._balloon.WORD_SPEAK_TIME = 60;
agent._balloon._sayWords = (text, hold, complete) => {
self._active = true;
self._hold = hold;
const words = text.split(/[^\S-]/);
const time = self.WORD_SPEAK_TIME;
const el = self._content;
let idx = 1;
clearTimeout(self.holdTimeout);
self._addWord = $.proxy(function () {
if (!self._active) return;
if (idx > words.length) {
delete self._addWord;
self._active = false;
if (!self._hold) {
complete();
self.hide();
} else if (typeof hold === "number") {
self.holdTimeout = setTimeout(() => {
self._hold = false;
complete();
self.hide();
}, hold);
}
} else {
el.html(words.slice(0, idx).join(" "));
idx++;
self._loop = window.setTimeout($.proxy(self._addWord, self), time);
}
}, self);
self._addWord();
};
// Add break-word to balloon CSS
agent._balloon._balloon.css("word-break", "break-word");
// Close the balloon on click (unless it was a link)
agent._balloon._balloon.click(e => {
if (e.target.nodeName !== "A") {
agent._balloon.hide(true);
agent._balloon._hidden = true;
}
});
// Add function to immediately close the balloon even if it is currently doing something
agent.closeBalloonImmediately = () => {
agent._queue.clear();
agent._balloon.hide(true);
agent._balloon._hidden = true;
agent._queue.next();
};
}
export default SeasonalWaiter;
+1 -1
View File
@@ -33,7 +33,7 @@ class WindowWaiter {
/**
* Handler for window blur events.
* Saves the current time so that we can calculate how long the window was unfocussed for when
* Saves the current time so that we can calculate how long the window was unfocused for when
* focus is returned.
*/
windowBlur() {
+1 -1
View File
@@ -353,7 +353,7 @@ class WorkerWaiter {
* @param {object} workerObj - Object containing the worker information
* @param {ChefWorker} workerObj.worker - The actual worker object
* @param {number} workerObj.inputNum - The inputNum of the input being baked by the worker
* @param {boolean} workerObj.active - If true, the worker is currrently baking an input
* @param {boolean} workerObj.active - If true, the worker is currently baking an input
*/
workerFinished(workerObj) {
const workerIdx = this.chefWorkers.indexOf(workerObj);
+1 -1
View File
@@ -945,7 +945,7 @@ self.updateMaxTabs = function(maxTabs, activeTab) {
* @param {boolean} searchData.showLoading - If true, include loading inputs in the results
* @param {boolean} searchData.showLoaded - If true, include loaded inputs in the results
* @param {string} searchData.filter - A regular expression to match the inputs on
* @param {string} searchData.filterType - Either "CONTENT" or "FILENAME". Detemines what should be matched with filter
* @param {string} searchData.filterType - Either "CONTENT" or "FILENAME". Determines what should be matched with filter
* @param {number} searchData.numResults - The maximum number of results to be returned
*/
self.filterTabs = function(searchData) {
+8 -5
View File
@@ -13,13 +13,16 @@
import {
setLongTestFailure,
logTestReport,
} from "../lib/utils";
} from "../lib/utils.mjs";
import TestRegister from "../lib/TestRegister.mjs";
import "./tests/nodeApi";
import "./tests/operations";
import "./tests/File";
import "./tests/NodeDish";
import "./tests/nodeApi.mjs";
import "./tests/operations.mjs";
import "./tests/File.mjs";
import "./tests/Dish.mjs";
import "./tests/NodeDish.mjs";
import "./tests/Utils.mjs";
import "./tests/Categories.mjs";
const testStatus = {
allTestsPassing: true,
+19
View File
@@ -0,0 +1,19 @@
import TestRegister from "../../lib/TestRegister.mjs";
import Categories from "../../../src/core/config/Categories.json";
import OperationConfig from "../../../src/core/config/OperationConfig.json";
import it from "../assertionHandler.mjs";
import assert from "assert";
TestRegister.addApiTests([
it("Categories: operations should be in a category", () => {
const catOps = [];
Categories.forEach(cat => {
catOps.push(...cat.ops);
});
for (const op in OperationConfig) {
assert(catOps.includes(op), `'${op}' operation is not present in any category`);
}
}),
]);
@@ -1,6 +1,6 @@
import TestRegister from "../../lib/TestRegister.mjs";
import Dish from "../../src/core/Dish.mjs";
import it from "../node/assertionHandler.mjs";
import Dish from "../../../src/core/Dish.mjs";
import it from "../../node/assertionHandler.mjs";
import assert from "assert";
TestRegister.addApiTests([
+23
View File
@@ -0,0 +1,23 @@
import TestRegister from "../../lib/TestRegister.mjs";
import Utils from "../../../src/core/Utils.mjs";
import it from "../assertionHandler.mjs";
import assert from "assert";
TestRegister.addApiTests([
it("Utils: should parse six backslashes correctly", () => {
assert.equal(Utils.parseEscapedChars("\\\\\\\\\\\\"), "\\\\\\");
}),
it("Utils: should parse escaped quotes correctly", () => {
assert.equal(Utils.parseEscapedChars("\\'"), "'");
}),
it("Utils: should parse escaped quotes and backslashes correctly", () => {
assert.equal(Utils.parseEscapedChars("\\\\'"), "\\'");
}),
it("Utils: should parse escaped quotes and escaped backslashes correctly", () => {
assert.equal(Utils.parseEscapedChars("\\\\\\'"), "\\'");
}),
]);
+5 -5
View File
@@ -400,7 +400,7 @@ color: white;
},
iv: {
string: "threetwo",
option: "Hex",
option: "utf8",
},
mode: "ECB",
});
@@ -415,7 +415,7 @@ color: white;
},
iv: {
string: "threetwo",
option: "Hex",
option: "utf8",
},
mode: "ECB",
});
@@ -943,10 +943,10 @@ smothering ampersand abreast
chef.tripleDESDecrypt(
chef.tripleDESEncrypt("Destroy Money", {
key: {string: "30 31 2f 30 34 2f 31 39 39 39 20 32 32 3a 33 33 3a 30 3130 31 2f 30 34", option: "Hex"},
iv: {string: "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00", option: "Hex"}}),
iv: {string: "00 00 00 00 00 00 00 00", option: "Hex"}}),
{
key: {string: "30 31 2f 30 34 2f 31 39 39 39 20 32 32 3a 33 33 3a 30 3130 31 2f 30 34", option: "Hex"},
iv: {string: "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00", option: "Hex"}
iv: {string: "00 00 00 00 00 00 00 00", option: "Hex"}
}).toString(),
"Destroy Money");
}),
@@ -1028,7 +1028,7 @@ ExifImageHeight: 57`);
const zipped = chef.zip("some file content", {
filename: "sample.zip",
comment: "added",
operaringSystem: "Unix",
operatingSystem: "Unix",
});
assert.strictEqual(zipped.type, 7);
-3
View File
@@ -95,9 +95,6 @@ import "./tests/ParseUDP.mjs";
// Cannot test operations that use the File type yet
// import "./tests/SplitColourChannels.mjs";
// import "./tests/nodeApi/nodeApi.mjs";
// import "./tests/nodeApi/ops.mjs";
const testStatus = {
allTestsPassing: true,
counts: {
+1 -1
View File
@@ -69,7 +69,7 @@ TestRegister.addTests([
],
},
{
name: "Generate Base64 Windows Powershell",
name: "Generate Base64 Windows PowerShell",
input: "ZABpAHIAIAAiAGMAOgBcAHAAcgBvAGcAcgBhAG0AIABmAGkAbABlAHMAIgAgAA==",
expectedOutput: "dir \"c:\\program files\" ",
recipeConfig: [