mirror of
https://github.com/gchq/CyberChef
synced 2025-12-20 10:13:42 +00:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac3c220789 | ||
|
|
add65e121a | ||
|
|
de2e757691 | ||
|
|
eb34ab4f6a | ||
|
|
08e4232166 | ||
|
|
adf9772928 | ||
|
|
562171ec86 | ||
|
|
e9e162319f | ||
|
|
17c9ffe107 | ||
|
|
1831c84a29 | ||
|
|
7e27449204 | ||
|
|
282476d530 | ||
|
|
fce0728d5d | ||
|
|
0e9ac90607 | ||
|
|
5383f56b26 | ||
|
|
a02484c6cd | ||
|
|
be365f66ef | ||
|
|
011dc09d5e | ||
|
|
fc4d6d2d2e | ||
|
|
9d73127cae | ||
|
|
223743e3b5 | ||
|
|
44ed372f21 | ||
|
|
4d1f970105 | ||
|
|
b28a891a40 | ||
|
|
834ff95702 | ||
|
|
3e93580aa4 | ||
|
|
7a3ca027bb | ||
|
|
3c021919dd | ||
|
|
2106e8ddb0 | ||
|
|
3472484601 | ||
|
|
826a8c8a74 | ||
|
|
c66703f0ca | ||
|
|
874e7d8d54 | ||
|
|
4e2b85b8c8 | ||
|
|
5314a456cb | ||
|
|
ba2a5b195c | ||
|
|
f8115671ee | ||
|
|
494279edd8 | ||
|
|
bd6673afed | ||
|
|
210daf7324 | ||
|
|
d60d595254 | ||
|
|
c28999ec6f | ||
|
|
014e70a7b1 | ||
|
|
5148b16246 |
@@ -1,2 +1 @@
|
|||||||
src/core/vendor/**
|
src/core/vendor/**
|
||||||
src/web/static/clippy_assets/**
|
|
||||||
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -26,8 +26,8 @@ If applicable, add screenshots to help explain your problem.
|
|||||||
|
|
||||||
**Desktop (if relevant, please complete the following information):**
|
**Desktop (if relevant, please complete the following information):**
|
||||||
- OS: [e.g. Windows]
|
- OS: [e.g. Windows]
|
||||||
- Browser [e.g. chrome, safari]
|
- Browser: [e.g. chrome 72, firefox 60]
|
||||||
- Version [e.g. 22]
|
- CyberChef version: [e.g. 9.7.14]
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
|||||||
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -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.
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,7 +4,6 @@ travis.log
|
|||||||
build
|
build
|
||||||
.vscode
|
.vscode
|
||||||
.*.swp
|
.*.swp
|
||||||
.DS_Store
|
|
||||||
src/core/config/modules/*
|
src/core/config/modules/*
|
||||||
src/core/config/OperationConfig.json
|
src/core/config/OperationConfig.json
|
||||||
src/core/operations/index.mjs
|
src/core/operations/index.mjs
|
||||||
|
|||||||
55
Gruntfile.js
55
Gruntfile.js
@@ -14,7 +14,6 @@ const path = require("path");
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
module.exports = function (grunt) {
|
module.exports = function (grunt) {
|
||||||
grunt.file.defaultEncoding = "utf8";
|
grunt.file.defaultEncoding = "utf8";
|
||||||
grunt.file.preserveBOM = false;
|
grunt.file.preserveBOM = false;
|
||||||
@@ -102,6 +101,26 @@ module.exports = function (grunt) {
|
|||||||
return entryModules;
|
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({
|
grunt.initConfig({
|
||||||
clean: {
|
clean: {
|
||||||
dev: ["build/dev/*"],
|
dev: ["build/dev/*"],
|
||||||
@@ -316,10 +335,10 @@ module.exports = function (grunt) {
|
|||||||
},
|
},
|
||||||
exec: {
|
exec: {
|
||||||
repoSize: {
|
repoSize: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
|
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
|
||||||
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
|
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
|
||||||
].join(";"),
|
]),
|
||||||
stderr: false
|
stderr: false
|
||||||
},
|
},
|
||||||
cleanGit: {
|
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"
|
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
|
||||||
},
|
},
|
||||||
generateConfig: {
|
generateConfig: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
"echo '\n--- Regenerating config files. ---'",
|
"echo '\n--- Regenerating config files. ---'",
|
||||||
"echo [] > src/core/config/OperationConfig.json",
|
"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/generateOpsIndex.mjs",
|
||||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
|
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
|
||||||
"echo '--- Config scripts finished. ---\n'"
|
"echo '--- Config scripts finished. ---\n'"
|
||||||
].join(";")
|
])
|
||||||
},
|
},
|
||||||
generateNodeIndex: {
|
generateNodeIndex: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
"echo '\n--- Regenerating node index ---'",
|
"echo '\n--- Regenerating node index ---'",
|
||||||
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
||||||
"echo '--- Node index generated. ---\n'"
|
"echo '--- Node index generated. ---\n'"
|
||||||
].join(";"),
|
]),
|
||||||
},
|
},
|
||||||
opTests: {
|
opTests: {
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
|
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"
|
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
|
||||||
},
|
},
|
||||||
setupNodeConsumers: {
|
setupNodeConsumers: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
"echo '\n--- Testing node conumers ---'",
|
"echo '\n--- Testing node consumers ---'",
|
||||||
"npm link",
|
"npm link",
|
||||||
`mkdir ${nodeConsumerTestPath}`,
|
`mkdir ${nodeConsumerTestPath}`,
|
||||||
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
|
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"npm link cyberchef"
|
"npm link cyberchef"
|
||||||
].join(";"),
|
]),
|
||||||
},
|
},
|
||||||
teardownNodeConsumers: {
|
teardownNodeConsumers: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
`rm -rf ${nodeConsumerTestPath}`,
|
`rm -rf ${nodeConsumerTestPath}`,
|
||||||
"echo '\n--- Node consumer tests complete ---'"
|
"echo '\n--- Node consumer tests complete ---'"
|
||||||
].join(";"),
|
]),
|
||||||
},
|
},
|
||||||
testCJSNodeConsumer: {
|
testCJSNodeConsumer: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"node --no-warnings cjs-consumer.js",
|
"node --no-warnings cjs-consumer.js",
|
||||||
].join(";"),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
testESMNodeConsumer: {
|
testESMNodeConsumer: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"node --no-warnings --experimental-modules esm-consumer.mjs",
|
"node --no-warnings --experimental-modules esm-consumer.mjs",
|
||||||
].join(";"),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
testESMDeepImportNodeConsumer: {
|
testESMDeepImportNodeConsumer: {
|
||||||
command: [
|
command: chainCommands([
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
|
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
|
||||||
].join(";"),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "9.7.7",
|
"version": "9.7.15",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3190,14 +3190,6 @@
|
|||||||
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
|
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
|
||||||
"dev": true
|
"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": {
|
"cliui": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "9.7.7",
|
"version": "9.7.15",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
@@ -95,7 +95,6 @@
|
|||||||
"bootstrap-material-design": "^4.1.2",
|
"bootstrap-material-design": "^4.1.2",
|
||||||
"bson": "^4.0.2",
|
"bson": "^4.0.2",
|
||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"clippyjs": "0.0.3",
|
|
||||||
"core-js": "^3.2.1",
|
"core-js": "^3.2.1",
|
||||||
"crypto-api": "^0.8.5",
|
"crypto-api": "^0.8.5",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class Dish {
|
|||||||
*
|
*
|
||||||
* @param {number} type - The data type of value, see Dish enums.
|
* @param {number} type - The data type of value, see Dish enums.
|
||||||
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
|
* @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) {
|
get(type, notUTF8=false) {
|
||||||
if (typeof type === "string") {
|
if (typeof type === "string") {
|
||||||
@@ -191,7 +191,7 @@ class Dish {
|
|||||||
*
|
*
|
||||||
* @param {number} type - The data type of value, see Dish enums.
|
* @param {number} type - The data type of value, see Dish enums.
|
||||||
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
|
* @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) {
|
presentAs(type, notUTF8=false) {
|
||||||
const clone = this.clone();
|
const clone = this.clone();
|
||||||
|
|||||||
@@ -201,9 +201,8 @@ class Utils {
|
|||||||
* Utils.parseEscapedChars("\\n");
|
* Utils.parseEscapedChars("\\n");
|
||||||
*/
|
*/
|
||||||
static parseEscapedChars(str) {
|
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) {
|
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) {
|
||||||
if (a === "\\") return "\\"+b;
|
switch (a[0]) {
|
||||||
switch (b[0]) {
|
|
||||||
case "\\":
|
case "\\":
|
||||||
return "\\";
|
return "\\";
|
||||||
case "0":
|
case "0":
|
||||||
@@ -214,7 +213,7 @@ class Utils {
|
|||||||
case "5":
|
case "5":
|
||||||
case "6":
|
case "6":
|
||||||
case "7":
|
case "7":
|
||||||
return String.fromCharCode(parseInt(b, 8));
|
return String.fromCharCode(parseInt(a, 8));
|
||||||
case "b":
|
case "b":
|
||||||
return "\b";
|
return "\b";
|
||||||
case "t":
|
case "t":
|
||||||
@@ -232,12 +231,12 @@ class Utils {
|
|||||||
case "'":
|
case "'":
|
||||||
return "'";
|
return "'";
|
||||||
case "x":
|
case "x":
|
||||||
return String.fromCharCode(parseInt(b.substr(1), 16));
|
return String.fromCharCode(parseInt(a.substr(1), 16));
|
||||||
case "u":
|
case "u":
|
||||||
if (b[1] === "{")
|
if (a[1] === "{")
|
||||||
return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
|
return String.fromCodePoint(parseInt(a.slice(2, -1), 16));
|
||||||
else
|
else
|
||||||
return String.fromCharCode(parseInt(b.substr(1), 16));
|
return String.fromCharCode(parseInt(a.substr(1), 16));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
"Generate PGP Key Pair",
|
"Generate PGP Key Pair",
|
||||||
"PGP Encrypt",
|
"PGP Encrypt",
|
||||||
"PGP Decrypt",
|
"PGP Decrypt",
|
||||||
|
"PGP Verify",
|
||||||
"PGP Encrypt and Sign",
|
"PGP Encrypt and Sign",
|
||||||
"PGP Decrypt and Verify",
|
"PGP Decrypt and Verify",
|
||||||
"Parse SSH Host Key"
|
"Parse SSH Host Key"
|
||||||
@@ -284,6 +285,7 @@
|
|||||||
"Zip",
|
"Zip",
|
||||||
"Unzip",
|
"Unzip",
|
||||||
"Bzip2 Decompress",
|
"Bzip2 Decompress",
|
||||||
|
"Bzip2 Compress",
|
||||||
"Tar",
|
"Tar",
|
||||||
"Untar"
|
"Untar"
|
||||||
]
|
]
|
||||||
@@ -370,6 +372,7 @@
|
|||||||
"Detect File Type",
|
"Detect File Type",
|
||||||
"Scan for Embedded Files",
|
"Scan for Embedded Files",
|
||||||
"Extract Files",
|
"Extract Files",
|
||||||
|
"YARA Rules",
|
||||||
"Remove EXIF",
|
"Remove EXIF",
|
||||||
"Extract EXIF",
|
"Extract EXIF",
|
||||||
"Extract RGBA",
|
"Extract RGBA",
|
||||||
@@ -401,6 +404,7 @@
|
|||||||
"Cover Image",
|
"Cover Image",
|
||||||
"Image Hue/Saturation/Lightness",
|
"Image Hue/Saturation/Lightness",
|
||||||
"Sharpen Image",
|
"Sharpen Image",
|
||||||
|
"Normalise Image",
|
||||||
"Convert Image Format",
|
"Convert Image Format",
|
||||||
"Add Text To Image",
|
"Add Text To Image",
|
||||||
"Hex Density chart",
|
"Hex Density chart",
|
||||||
|
|||||||
9
src/core/errors/index.mjs
Normal file
9
src/core/errors/index.mjs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import OperationError from "./OperationError.mjs";
|
||||||
|
import DishError from "./DishError.mjs";
|
||||||
|
import ExcludedOperationError from "./ExcludedOperationError";
|
||||||
|
|
||||||
|
export {
|
||||||
|
OperationError,
|
||||||
|
DishError,
|
||||||
|
ExcludedOperationError,
|
||||||
|
};
|
||||||
@@ -22,7 +22,7 @@ export const ENCODING_SCHEME = [
|
|||||||
/**
|
/**
|
||||||
* Lookup table for the binary value of each digit representation.
|
* 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
|
* but unfortunately it's much easier (if less elegant) to use lookup tables
|
||||||
* when supporting multiple encoding schemes.
|
* when supporting multiple encoding schemes.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base64's the input byte array using the given alphabet, returning a string.
|
* Base64's the input byte array using the given alphabet, returning a string.
|
||||||
@@ -33,6 +33,9 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||||
|
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
||||||
|
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
|
||||||
|
}
|
||||||
|
|
||||||
let output = "",
|
let output = "",
|
||||||
chr1, chr2, chr3,
|
chr1, chr2, chr3,
|
||||||
@@ -86,6 +89,9 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
|
|||||||
|
|
||||||
alphabet = alphabet || "A-Za-z0-9+/=";
|
alphabet = alphabet || "A-Za-z0-9+/=";
|
||||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||||
|
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
||||||
|
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
|
||||||
|
}
|
||||||
|
|
||||||
const output = [];
|
const output = [];
|
||||||
let chr1, chr2, chr3,
|
let chr1, chr2, chr3,
|
||||||
|
|||||||
@@ -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)"];
|
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"];
|
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
|
||||||
|
|
||||||
|
|||||||
@@ -2451,7 +2451,7 @@ export function extractJPEG(bytes, offset) {
|
|||||||
export function extractMZPE(bytes, offset) {
|
export function extractMZPE(bytes, offset) {
|
||||||
const stream = new Stream(bytes.slice(offset));
|
const stream = new Stream(bytes.slice(offset));
|
||||||
|
|
||||||
// Move to PE header pointer
|
// Read pointer to PE header
|
||||||
stream.moveTo(0x3c);
|
stream.moveTo(0x3c);
|
||||||
const peAddress = stream.readInt(4, "le");
|
const peAddress = stream.readInt(4, "le");
|
||||||
|
|
||||||
@@ -2462,12 +2462,36 @@ export function extractMZPE(bytes, offset) {
|
|||||||
stream.moveForwardsBy(6);
|
stream.moveForwardsBy(6);
|
||||||
const numSections = stream.readInt(2, "le");
|
const numSections = stream.readInt(2, "le");
|
||||||
|
|
||||||
// Get optional header size
|
// Read Optional Header Magic to determine the state of the image file
|
||||||
stream.moveForwardsBy(12);
|
// 0x10b = normal executable, 0x107 = ROM image, 0x20b = PE32+ executable
|
||||||
const optionalHeaderSize = stream.readInt(2, "le");
|
stream.moveForwardsBy(16);
|
||||||
|
const optionalMagic = stream.readInt(2, "le");
|
||||||
|
const pe32Plus = optionalMagic === 0x20b;
|
||||||
|
|
||||||
// Move past optional header to section header
|
// Move to Data Directory
|
||||||
stream.moveForwardsBy(2 + optionalHeaderSize);
|
const dataDirectoryOffset = pe32Plus ? 112 : 96;
|
||||||
|
stream.moveForwardsBy(dataDirectoryOffset - 2);
|
||||||
|
|
||||||
|
// Read Certificate Table address and size (IMAGE_DIRECTORY_ENTRY_SECURITY)
|
||||||
|
stream.moveForwardsBy(32);
|
||||||
|
const certTableAddress = stream.readInt(4, "le");
|
||||||
|
const certTableSize = stream.readInt(4, "le");
|
||||||
|
|
||||||
|
// PE files can contain extra data appended to the end of the file called an "overlay".
|
||||||
|
// This data is not covered by the PE header and could be any arbitrary format, so its
|
||||||
|
// length cannot be determined without contextual information.
|
||||||
|
// However, the Attribute Certificate Table is stored in the overlay - usually right at
|
||||||
|
// the end. Therefore, if this table is defined, we can use its offset and size to carve
|
||||||
|
// out the entire PE file, including the overlay.
|
||||||
|
// If the Certificate Table is not defined, we continue to parse the PE file as best we
|
||||||
|
// can up to the end of the final section, not including any appended data in the overlay.
|
||||||
|
if (certTableAddress > 0) {
|
||||||
|
stream.moveTo(certTableAddress + certTableSize);
|
||||||
|
return stream.carve();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move past Optional Header to Section Header
|
||||||
|
stream.moveForwardsBy(88);
|
||||||
|
|
||||||
// Move to final section header
|
// Move to final section header
|
||||||
stream.moveForwardsBy((numSections - 1) * 0x28);
|
stream.moveForwardsBy((numSections - 1) * 0x28);
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
|
|||||||
* @param {Uint8Array} buf - The buffer to search
|
* @param {Uint8Array} buf - The buffer to search
|
||||||
* @param {Object} sig - A single signature object (Not an array of signatures)
|
* @param {Object} sig - A single signature object (Not an array of signatures)
|
||||||
* @param {number} offset - Where to start search from
|
* @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) {
|
function locatePotentialSig(buf, sig, offset) {
|
||||||
// Find values for first key and value in sig
|
// Find values for first key and value in sig
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export async function parseQrCode(input, normalise) {
|
|||||||
image = await jimp.read(image);
|
image = await jimp.read(image);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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());
|
const qrData = jsQR(image.bitmap.data, image.getWidth(), image.getHeight());
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class BLAKE2b extends Operation {
|
|||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer} input
|
* @param {ArrayBuffer} input
|
||||||
* @param {Object[]} args
|
* @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) {
|
run(input, args) {
|
||||||
const [outSize, outFormat] = args;
|
const [outSize, outFormat] = args;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class BLAKE2s extends Operation {
|
|||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer} input
|
* @param {ArrayBuffer} input
|
||||||
* @param {Object[]} args
|
* @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) {
|
run(input, args) {
|
||||||
const [outSize, outFormat] = args;
|
const [outSize, outFormat] = args;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Bzip2Decompress extends Operation {
|
|||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
async run(input, args) {
|
||||||
const [small] = args;
|
const [small] = args;
|
||||||
if (input.byteLength <= 0) {
|
if (input.byteLength <= 0) {
|
||||||
throw new OperationError("Please provide an input.");
|
throw new OperationError("Please provide an input.");
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ class DESDecrypt extends Operation {
|
|||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).
|
||||||
Triple DES uses a key length of 24 bytes (192 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);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ class DESEncrypt extends Operation {
|
|||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).
|
||||||
Triple DES uses a key length of 24 bytes (192 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);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class GeneratePGPKeyPair extends Operation {
|
|||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
async run(input, args) {
|
||||||
const [keyType, keySize] = args[0].split("-"),
|
const [keyType, keySize] = args[0].split("-"),
|
||||||
password = args[1],
|
password = args[1],
|
||||||
name = args[2],
|
name = args[2],
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class HammingDistance extends Operation {
|
|||||||
samples = input.split(delim);
|
samples = input.split(delim);
|
||||||
|
|
||||||
if (samples.length !== 2) {
|
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) {
|
if (samples[0].length !== samples[1].length) {
|
||||||
|
|||||||
@@ -128,8 +128,7 @@ class PHPDeserialize extends Operation {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "n":
|
case "n":
|
||||||
expect(";");
|
expect(";");
|
||||||
return "";
|
return "null";
|
||||||
|
|
||||||
case "i":
|
case "i":
|
||||||
case "d":
|
case "d":
|
||||||
case "b": {
|
case "b": {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class RawInflate extends Operation {
|
|||||||
}),
|
}),
|
||||||
result = new Uint8Array(inflate.decompress());
|
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]
|
// e.g. Input data of [8b, 1d, dc, 44]
|
||||||
// Look for the first two square brackets:
|
// Look for the first two square brackets:
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class RemoveWhitespace extends Operation {
|
|||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [
|
const [
|
||||||
removeSpaces,
|
removeSpaces,
|
||||||
removeCariageReturns,
|
removeCarriageReturns,
|
||||||
removeLineFeeds,
|
removeLineFeeds,
|
||||||
removeTabs,
|
removeTabs,
|
||||||
removeFormFeeds,
|
removeFormFeeds,
|
||||||
@@ -73,7 +73,7 @@ class RemoveWhitespace extends Operation {
|
|||||||
let data = input;
|
let data = input;
|
||||||
|
|
||||||
if (removeSpaces) data = data.replace(/ /g, "");
|
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 (removeLineFeeds) data = data.replace(/\n/g, "");
|
||||||
if (removeTabs) data = data.replace(/\t/g, "");
|
if (removeTabs) data = data.replace(/\t/g, "");
|
||||||
if (removeFormFeeds) data = data.replace(/\f/g, "");
|
if (removeFormFeeds) data = data.replace(/\f/g, "");
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class ToQuotedPrintable extends Operation {
|
|||||||
* @private
|
* @private
|
||||||
* @param {number} nr
|
* @param {number} nr
|
||||||
* @param {byteArray[]} ranges
|
* @param {byteArray[]} ranges
|
||||||
* @returns {bolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
_checkRanges(nr, ranges) {
|
_checkRanges(nr, ranges) {
|
||||||
for (let i = ranges.length - 1; i >= 0; i--) {
|
for (let i = ranges.length - 1; i >= 0; i--) {
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ class TripleDESDecrypt extends Operation {
|
|||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).
|
||||||
DES uses a key length of 8 bytes (64 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);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ class TripleDESEncrypt extends Operation {
|
|||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).
|
||||||
DES uses a key length of 8 bytes (64 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);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Typex extends Operation {
|
|||||||
|
|
||||||
this.name = "Typex";
|
this.name = "Typex";
|
||||||
this.module = "Default";
|
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><</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><</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.infoURL = "https://wikipedia.org/wiki/Typex";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class UNIXTimestampToWindowsFiletime extends Operation {
|
|||||||
} else if (units === "Milliseconds (ms)") {
|
} else if (units === "Milliseconds (ms)") {
|
||||||
input = input.multipliedBy(new BigNumber("10000"));
|
input = input.multipliedBy(new BigNumber("10000"));
|
||||||
} else if (units === "Microseconds (μs)") {
|
} else if (units === "Microseconds (μs)") {
|
||||||
input = input.multiplyiedBy(new BigNumber("10"));
|
input = input.multipliedBy(new BigNumber("10"));
|
||||||
} else if (units === "Nanoseconds (ns)") {
|
} else if (units === "Nanoseconds (ns)") {
|
||||||
input = input.dividedBy(new BigNumber("100"));
|
input = input.dividedBy(new BigNumber("100"));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class URLEncode extends Operation {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
encodeAllChars (str) {
|
encodeAllChars (str) {
|
||||||
// TODO Do this programatically
|
// TODO Do this programmatically
|
||||||
return encodeURIComponent(str)
|
return encodeURIComponent(str)
|
||||||
.replace(/!/g, "%21")
|
.replace(/!/g, "%21")
|
||||||
.replace(/#/g, "%23")
|
.replace(/#/g, "%23")
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class VigenèreDecode extends Operation {
|
|||||||
keyIndex = alphabet.indexOf(chr);
|
keyIndex = alphabet.indexOf(chr);
|
||||||
msgIndex = alphabet.indexOf(input[i]);
|
msgIndex = alphabet.indexOf(input[i]);
|
||||||
// Subtract indexes from each other, add 26 just in case the value is negative,
|
// 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];
|
output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
|
||||||
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
||||||
chr = key[(i - fail) % key.length].toLowerCase();
|
chr = key[(i - fail) % key.length].toLowerCase();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Whirlpool extends Operation {
|
|||||||
|
|
||||||
this.name = "Whirlpool";
|
this.name = "Whirlpool";
|
||||||
this.module = "Crypto";
|
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.infoURL = "https://wikipedia.org/wiki/Whirlpool_(cryptography)";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import NodeDish from "./NodeDish.mjs";
|
|||||||
import NodeRecipe from "./NodeRecipe.mjs";
|
import NodeRecipe from "./NodeRecipe.mjs";
|
||||||
import OperationConfig from "../core/config/OperationConfig.json";
|
import OperationConfig from "../core/config/OperationConfig.json";
|
||||||
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
|
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.
|
* Explain that the given operation is not included in the Node.js version.
|
||||||
* @param {String} name - name of operation
|
* @param {String} name - name of operation
|
||||||
*/
|
*/
|
||||||
export function _explainExludedFunction(name) {
|
export function _explainExcludedFunction(name) {
|
||||||
/**
|
/**
|
||||||
* Throw new error type with useful message.
|
* Throw new error type with useful message.
|
||||||
*/
|
*/
|
||||||
const func = () => {
|
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.
|
// Add opName prop so NodeRecipe can handle it, just like wrap does.
|
||||||
func.opName = name;
|
func.opName = name;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function sanitise(str) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sonething like this => somethingLikeThis
|
* something like this => somethingLikeThis
|
||||||
* ABC a sentence => ABCASentence
|
* ABC a sentence => ABCASentence
|
||||||
*/
|
*/
|
||||||
export function sentenceToCamelCase(str) {
|
export function sentenceToCamelCase(str) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Operations to exlude from the Node API
|
* Operations to exclude from the Node API
|
||||||
*
|
*
|
||||||
* @author d98762656 [d98762625@gmail.com]
|
* @author d98762656 [d98762625@gmail.com]
|
||||||
* @copyright Crown Copyright 2018
|
* @copyright Crown Copyright 2018
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ let code = `/**
|
|||||||
|
|
||||||
|
|
||||||
import NodeDish from "./NodeDish.mjs";
|
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 File from "./File.mjs";
|
||||||
|
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index";
|
||||||
import {
|
import {
|
||||||
// import as core_ to avoid name clashes after wrap.
|
// import as core_ to avoid name clashes after wrap.
|
||||||
`;
|
`;
|
||||||
@@ -69,7 +70,7 @@ includedOperations.forEach((op) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
excludedOperations.forEach((op) => {
|
excludedOperations.forEach((op) => {
|
||||||
code += ` "${decapitalise(op)}": _explainExludedFunction("${op}"),\n`;
|
code += ` "${decapitalise(op)}": _explainExcludedFunction("${op}"),\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code += ` };
|
code += ` };
|
||||||
@@ -115,6 +116,9 @@ Object.keys(operations).forEach((op) => {
|
|||||||
code += " NodeDish as Dish,\n";
|
code += " NodeDish as Dish,\n";
|
||||||
code += " prebaked as bake,\n";
|
code += " prebaked as bake,\n";
|
||||||
code += " help,\n";
|
code += " help,\n";
|
||||||
|
code += " OperationError,\n";
|
||||||
|
code += " ExcludedOperationError,\n";
|
||||||
|
code += " DishError,\n";
|
||||||
code += "};\n";
|
code += "};\n";
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
@@ -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 |
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
/* Libraries */
|
/* Libraries */
|
||||||
import "highlight.js/styles/vs.css";
|
import "highlight.js/styles/vs.css";
|
||||||
import "../static/clippy_assets/clippy.css";
|
|
||||||
|
|
||||||
/* Frameworks */
|
/* Frameworks */
|
||||||
import "./vendors/bootstrap.scss";
|
import "./vendors/bootstrap.scss";
|
||||||
|
|||||||
@@ -82,14 +82,6 @@ a:focus {
|
|||||||
border-color: var(--btn-success-hover-border-colour);
|
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]) {
|
select.form-control:not([size]):not([multiple]), select.custom-file-control:not([size]):not([multiple]) {
|
||||||
height: unset !important;
|
height: unset !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ControlsWaiter {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise Bootstrap componenets
|
* Initialise Bootstrap components
|
||||||
*/
|
*/
|
||||||
initComponents() {
|
initComponents() {
|
||||||
$("body").bootstrapMaterialDesign();
|
$("body").bootstrapMaterialDesign();
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class OperationsWaiter {
|
|||||||
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
|
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
|
||||||
.popover({trigger: "manual"})
|
.popover({trigger: "manual"})
|
||||||
.on("mouseenter", function(e) {
|
.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;
|
const _this = this;
|
||||||
$(this).popover("show");
|
$(this).popover("show");
|
||||||
$(".popover").on("mouseleave", function () {
|
$(".popover").on("mouseleave", function () {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class OptionsWaiter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for options click events.
|
* Handler for options click events.
|
||||||
* Dispays the options pane.
|
* Displays the options pane.
|
||||||
*
|
*
|
||||||
* @param {event} e
|
* @param {event} e
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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} bakeId
|
||||||
* @param {number} inputNum
|
* @param {number} inputNum
|
||||||
|
|||||||
@@ -4,17 +4,13 @@
|
|||||||
* @license Apache-2.0
|
* @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.
|
* Waiter to handle seasonal events and easter eggs.
|
||||||
*/
|
*/
|
||||||
class SeasonalWaiter {
|
class SeasonalWaiter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SeasonalWaiter contructor.
|
* SeasonalWaiter constructor.
|
||||||
*
|
*
|
||||||
* @param {App} app - The main view object for CyberChef.
|
* @param {App} app - The main view object for CyberChef.
|
||||||
* @param {Manager} manager - The CyberChef event manager.
|
* @param {Manager} manager - The CyberChef event manager.
|
||||||
@@ -22,8 +18,6 @@ class SeasonalWaiter {
|
|||||||
constructor(app, manager) {
|
constructor(app, manager) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
|
|
||||||
this.clippyAgent = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -34,14 +28,6 @@ class SeasonalWaiter {
|
|||||||
// Konami code
|
// Konami code
|
||||||
this.kkeys = [];
|
this.kkeys = [];
|
||||||
window.addEventListener("keydown", this.konamiCodeListener.bind(this));
|
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)')&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')&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;
|
export default SeasonalWaiter;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class WindowWaiter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for window blur events.
|
* 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.
|
* focus is returned.
|
||||||
*/
|
*/
|
||||||
windowBlur() {
|
windowBlur() {
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ class WorkerWaiter {
|
|||||||
* @param {object} workerObj - Object containing the worker information
|
* @param {object} workerObj - Object containing the worker information
|
||||||
* @param {ChefWorker} workerObj.worker - The actual worker object
|
* @param {ChefWorker} workerObj.worker - The actual worker object
|
||||||
* @param {number} workerObj.inputNum - The inputNum of the input being baked by the worker
|
* @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) {
|
workerFinished(workerObj) {
|
||||||
const workerIdx = this.chefWorkers.indexOf(workerObj);
|
const workerIdx = this.chefWorkers.indexOf(workerObj);
|
||||||
|
|||||||
@@ -945,7 +945,7 @@ self.updateMaxTabs = function(maxTabs, activeTab) {
|
|||||||
* @param {boolean} searchData.showLoading - If true, include loading inputs in the results
|
* @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 {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.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
|
* @param {number} searchData.numResults - The maximum number of results to be returned
|
||||||
*/
|
*/
|
||||||
self.filterTabs = function(searchData) {
|
self.filterTabs = function(searchData) {
|
||||||
|
|||||||
@@ -104,8 +104,6 @@ class TestRegister {
|
|||||||
* Run all api related tests and wrap results in report format
|
* Run all api related tests and wrap results in report format
|
||||||
*/
|
*/
|
||||||
runApiTests() {
|
runApiTests() {
|
||||||
console.log("Running tests...");
|
|
||||||
|
|
||||||
return Promise.all(this.apiTests.map(async function(test, i) {
|
return Promise.all(this.apiTests.map(async function(test, i) {
|
||||||
const result = {
|
const result = {
|
||||||
test: test,
|
test: test,
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
/**
|
/**
|
||||||
* Print useful stack on error
|
* Print useful stack on error
|
||||||
*/
|
*/
|
||||||
const wrapRun = (run) => () => {
|
const wrapRun = (run) => async () => {
|
||||||
try {
|
try {
|
||||||
run();
|
await run();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.dir(e);
|
console.dir(e);
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -13,13 +13,16 @@
|
|||||||
import {
|
import {
|
||||||
setLongTestFailure,
|
setLongTestFailure,
|
||||||
logTestReport,
|
logTestReport,
|
||||||
} from "../lib/utils";
|
} from "../lib/utils.mjs";
|
||||||
|
|
||||||
import TestRegister from "../lib/TestRegister.mjs";
|
import TestRegister from "../lib/TestRegister.mjs";
|
||||||
import "./tests/nodeApi";
|
import "./tests/nodeApi.mjs";
|
||||||
import "./tests/operations";
|
import "./tests/operations.mjs";
|
||||||
import "./tests/File";
|
import "./tests/File.mjs";
|
||||||
import "./tests/NodeDish";
|
import "./tests/Dish.mjs";
|
||||||
|
import "./tests/NodeDish.mjs";
|
||||||
|
import "./tests/Utils.mjs";
|
||||||
|
import "./tests/Categories.mjs";
|
||||||
|
|
||||||
const testStatus = {
|
const testStatus = {
|
||||||
allTestsPassing: true,
|
allTestsPassing: true,
|
||||||
|
|||||||
19
tests/node/tests/Categories.mjs
Normal file
19
tests/node/tests/Categories.mjs
Normal 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 TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import Dish from "../../src/core/Dish.mjs";
|
import Dish from "../../../src/core/Dish.mjs";
|
||||||
import it from "../node/assertionHandler.mjs";
|
import it from "../../node/assertionHandler.mjs";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
|
||||||
TestRegister.addApiTests([
|
TestRegister.addApiTests([
|
||||||
23
tests/node/tests/Utils.mjs
Normal file
23
tests/node/tests/Utils.mjs
Normal 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("\\\\\\'"), "\\'");
|
||||||
|
}),
|
||||||
|
|
||||||
|
]);
|
||||||
@@ -130,11 +130,14 @@ Tiger-128`;
|
|||||||
it("atBash Cipher", () => {
|
it("atBash Cipher", () => {
|
||||||
const result = chef.atbashCipher("Happy as a Clam");
|
const result = chef.atbashCipher("Happy as a Clam");
|
||||||
assert.strictEqual(result.toString(), "Szkkb zh z Xozn");
|
assert.strictEqual(result.toString(), "Szkkb zh z Xozn");
|
||||||
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Bcrypt", async () => {
|
it("Bcrypt", async () => {
|
||||||
const result = await chef.bcrypt("Put a Sock In It");
|
const result = await chef.bcrypt("Put a Sock In It");
|
||||||
assert.strictEqual(result.toString(), "$2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6");
|
const strResult = result.toString();
|
||||||
|
assert.equal(strResult.length, 60);
|
||||||
|
assert.equal(strResult.slice(0, 7), "$2a$10$");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("bcryptCompare", async() => {
|
it("bcryptCompare", async() => {
|
||||||
@@ -397,7 +400,7 @@ color: white;
|
|||||||
},
|
},
|
||||||
iv: {
|
iv: {
|
||||||
string: "threetwo",
|
string: "threetwo",
|
||||||
option: "Hex",
|
option: "utf8",
|
||||||
},
|
},
|
||||||
mode: "ECB",
|
mode: "ECB",
|
||||||
});
|
});
|
||||||
@@ -412,7 +415,7 @@ color: white;
|
|||||||
},
|
},
|
||||||
iv: {
|
iv: {
|
||||||
string: "threetwo",
|
string: "threetwo",
|
||||||
option: "Hex",
|
option: "utf8",
|
||||||
},
|
},
|
||||||
mode: "ECB",
|
mode: "ECB",
|
||||||
});
|
});
|
||||||
@@ -583,47 +586,7 @@ Password: 034148`;
|
|||||||
const result = await chef.generatePGPKeyPair("Back To the Drawing Board", {
|
const result = await chef.generatePGPKeyPair("Back To the Drawing Board", {
|
||||||
keyType: "ECC-256",
|
keyType: "ECC-256",
|
||||||
});
|
});
|
||||||
const expected = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
assert.strictEqual(result.toString().length, 2005);
|
||||||
Version: Keybase OpenPGP v2.0.77
|
|
||||||
Comment: https://keybase.io/crypto
|
|
||||||
|
|
||||||
xYgEW3KciQEBAK96Lx9G0WZiw1yhC35IogdumoxEJXsLdAVIjmskXeAfABEBAAEA
|
|
||||||
AP4wK+OZu3AqojwtRoyIK1pHKU93OAuam1iaLCOGCwCckQCA5PjU0aLNZqy/eKyX
|
|
||||||
T3rpKQCAxDDT5hHGAUfFPUu73KWABwB/WKpeUp7KwurMSbYVhgr1TijszQDCVAQT
|
|
||||||
AQoAHgUCW3KciQIbLwMLCQcDFQoIAh4BAheAAxYCAQIZAQAKCRD0VeyUMgmpz3OE
|
|
||||||
AP9qsnhhoK85Tnu6VKwKm1iMiJAssDQnFztDaMmmVdrN/MeIBFtynIkBAQDDhjIw
|
|
||||||
fxOprqVMYLk6aC45JyPAA2POzu0Zb/rx0tKeBwARAQABAAD/XAr66oiP9ZORHiT0
|
|
||||||
XZH4m7vwZt7AHuq4pYtVlMQXk60AgPw2Mno/wStvE/SBa9R7AtsAgMZ2BkJjvNPZ
|
|
||||||
9YA6cl4lW0UAgI1+kJVLZ5VR9fPENfJR80EtncKDBBgBCgAPBQJbcpyJBQkPCZwA
|
|
||||||
AhsuAEgJEPRV7JQyCanPPSAEGQEKAAYFAltynIkACgkQrewgWMQZ/b2blwD/dbwh
|
|
||||||
/3F9xv+YGAwq8i1mzzswg4qBct6LoSIjGglULT9RIQD/cYd31YfKrEnbSBWD5PLi
|
|
||||||
zcSsxtBGKphwXiPAlQJ1Q5DHiARbcpyJAQEAs8V418lf1T74PpAwdBTiViEUX9jB
|
|
||||||
e+ZrAEVaq5nu1C8AEQEAAQAA/iPWhS23hnRTllealR4/H5OofZRwxvIQrxAJp6z1
|
|
||||||
ICRxAIDayRpCAbK5EC3DzRU2z4VpAIDSWYSs9inI1VTfamJPMWHXAIC3aaukzCP4
|
|
||||||
GEGeFobX/thnKhnCgwQYAQoADwUCW3KciQUJA8JnAAIbLgBICRD0VeyUMgmpzz0g
|
|
||||||
BBkBCgAGBQJbcpyJAAoJEB4jzL1hmQIXamUA/0c1M6BSqVtxNowPcOAXKYIxMca1
|
|
||||||
VFcRWolHnZqdZQ7k/J8A/3HvNLRS3p1HvjQEfXl/qKoRRn843Py09ptDHh+xpGKh
|
|
||||||
=d+Vp
|
|
||||||
-----END PGP PRIVATE KEY BLOCK-----
|
|
||||||
|
|
||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
Version: Keybase OpenPGP v2.0.77
|
|
||||||
Comment: https://keybase.io/crypto
|
|
||||||
|
|
||||||
xi0EW3KciQEBAK96Lx9G0WZiw1yhC35IogdumoxEJXsLdAVIjmskXeAfABEBAAHN
|
|
||||||
AMJUBBMBCgAeBQJbcpyJAhsvAwsJBwMVCggCHgECF4ADFgIBAhkBAAoJEPRV7JQy
|
|
||||||
CanPc4QA/2qyeGGgrzlOe7pUrAqbWIyIkCywNCcXO0NoyaZV2s38zi0EW3KciQEB
|
|
||||||
AMOGMjB/E6mupUxguTpoLjknI8ADY87O7Rlv+vHS0p4HABEBAAHCgwQYAQoADwUC
|
|
||||||
W3KciQUJDwmcAAIbLgBICRD0VeyUMgmpzz0gBBkBCgAGBQJbcpyJAAoJEK3sIFjE
|
|
||||||
Gf29m5cA/3W8If9xfcb/mBgMKvItZs87MIOKgXLei6EiIxoJVC0/USEA/3GHd9WH
|
|
||||||
yqxJ20gVg+Ty4s3ErMbQRiqYcF4jwJUCdUOQzi0EW3KciQEBALPFeNfJX9U++D6Q
|
|
||||||
MHQU4lYhFF/YwXvmawBFWquZ7tQvABEBAAHCgwQYAQoADwUCW3KciQUJA8JnAAIb
|
|
||||||
LgBICRD0VeyUMgmpzz0gBBkBCgAGBQJbcpyJAAoJEB4jzL1hmQIXamUA/0c1M6BS
|
|
||||||
qVtxNowPcOAXKYIxMca1VFcRWolHnZqdZQ7k/J8A/3HvNLRS3p1HvjQEfXl/qKoR
|
|
||||||
Rn843Py09ptDHh+xpGKh
|
|
||||||
=ySwG
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
||||||
assert.strictEqual(result.toString(), expected);
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Generate UUID", () => {
|
it("Generate UUID", () => {
|
||||||
@@ -737,43 +700,105 @@ CPU
|
|||||||
assert.strictEqual(result.toString(), expected);
|
assert.strictEqual(result.toString(), expected);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("PGP Encrypt", async () => {
|
it("PGP Encrypt and decrypt", async () => {
|
||||||
const pbkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
const pbkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
Version: GnuPG v1
|
Version: Keybase OpenPGP v2.1.3
|
||||||
|
|
||||||
mI0EVWOihAEEALzwFAVWTrD0KiWCH5tX6q6QsGjlRn4IP2uj/xWsJZDNbCKm+JAe
|
|
||||||
1RvIootpW1+PNNMJlIInwUgtCjtJ9gZbGBpXeqwdSn0oYuj9X86ekXOUnZsRoPCj
|
|
||||||
RwS8kpbrvRVfhWN8hYuXFcXK2J2Ld0ZpVyJzkncpFdpAgzTPMfrO1HS5ABEBAAG0
|
|
||||||
GmdwZyBuYW1lIChjb21tZW50KSA8ZW1AaWw+iLgEEwECACIFAlVjooQCGwMGCwkI
|
|
||||||
BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEBg8dTRwi4g5I40D/2+uUuQxa3uMrAeI
|
|
||||||
dXLaJWz3V0cl1rotfBP47apDUGbkm1HVgULJUo8Bo15Ii83ST8TUsyja3XcLutHb
|
|
||||||
IwYSWo41gEV48+NKoN6Oy3HwqBoHfH06bu0If75vdSjnZpB2dO/Ph7L9kz78gc4y
|
|
||||||
tZx4bE64MTlL2AYghZxyYpFyydjXuI0EVWOihAEEANE4UU+4iB2hMAXq93hiBzIh
|
|
||||||
AMtn/DlWbJkpdUgrjKOG6tILs28mrw9rI4PivmT7grkyNW8sa3ATsmWC1xChxGTN
|
|
||||||
T1guyh0Hhbc3Otfng2BFSWcBkPwUoNaOdrVFpP9J51IYrsQHsjbZlY45ghDBzM6t
|
|
||||||
sISfkmmFCsp0l7w/XAcvABEBAAGInwQYAQIACQUCVWOihAIbDAAKCRAYPHU0cIuI
|
|
||||||
OQ2BA/9KWqOhXZW75ac7CuJMfileZR7vRy9CkKyNG21cZtAlqftAX+m8FGdG0duU
|
|
||||||
jKHiPvjXhSfP3lmrQ7brja9LgSzkiBqQzvPW55G67nGQdUC+mqZNJNlRh+8atf9I
|
|
||||||
5nxg2i8zn6F5cLaNWz7cl27m1/mXKcH3gult1PLR4PiYLiC9aw==
|
|
||||||
=xw3e
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----`;
|
|
||||||
|
|
||||||
const result = await chef.PGPEncrypt("A Fool and His Money are Soon Parted", {
|
|
||||||
publicKeyOfRecipient: pbkey,
|
|
||||||
});
|
|
||||||
const expected = `-----BEGIN PGP MESSAGE-----
|
|
||||||
Version: Keybase OpenPGP v2.0.77
|
|
||||||
Comment: https://keybase.io/crypto
|
Comment: https://keybase.io/crypto
|
||||||
|
|
||||||
wYwDv1kIXPPNwmABA/4syW+oO+S/mfpjdp83/MZJiKh6XNQoPr/N5/1Is/QXYu9V
|
xo0EXZtlowEEAKUqTFownTmqgXWu2KDrtyNYtFck7a16WM5QD95bFoAFFdnlwZ45
|
||||||
/v8/b+eReOpUVC6cVrJ8U5cB19y1Az3NQWHXLEC0jND2wL3cUM4sv87hlvv2PLhc
|
6Vw8G8LCzHdyRXYp/JF1GknDrAd7nIRE+SuSz2yVK5nlOCfO1HFcg2Ov7e7/pBwd
|
||||||
okv8OHNCitRiweo7NZHVygHGdFvY082G47e1PkyPAuVynvzdD450ta/s/KOxZdJg
|
qawx9GUIsCKd/6NxwDuT4YqarLFsuwljRC/eQiibO+ejnhoiKcU69sTNABEBAAHN
|
||||||
ARbZIrC6WmjYNLwhbpRYawKD+3N4I5qliRpU2POKRi9UROAW9dth6egy60TTCvyO
|
AMK0BBMBCgAeBQJdm2WjAhsvAwsJBwMVCggCHgECF4ADFgIBAhkBAAoJEGS79V2S
|
||||||
jmPGsv1elXxVzqs58UZLD2c3vBhGkU2BV6kRKh+lj/EcVrzsFhGCz/7DKxPoDHLS
|
7D0owtMD/RT+o4BQJ8NSQBDgkYf42uOOu1Ud6GuN89nX6n20yAZbmqQ8CHnHY+Qc
|
||||||
=IBYt
|
l6ft4HnbIaNrI3arp/C2C+cwFypmt1BKyFEJUXO7ft3i/IxnjpCorDyAMCDckDvq
|
||||||
-----END PGP MESSAGE-----
|
uma1LWtUHLb5s/ZuGMSHnhuji74IRWuIofNPdf7bCZW1GMbW9jNUzo0EXZtlowEE
|
||||||
`;
|
AL38zaNkPmUVQaowP696fayBo18Nxs0yOzC4+0TYv1B/k5aUb0Air2h+o/Xw4E42
|
||||||
assert.strictEqual(result.toString(), expected);
|
Jh9gVdPSvhOAEqdV0UDe71wxa4cfAVMDY9v8ta81MWunChj3ISUk1oIQylTJNsY/
|
||||||
|
b4KWOrLaOtBD9dyFGCzss5vLVdqdMjVIW2Cz0hb6IYG7ABEBAAHCwIMEGAEKAA8F
|
||||||
|
Al2bZaMFCQ8JnAACGy4AqAkQZLv1XZLsPSidIAQZAQoABgUCXZtlowAKCRA16MU2
|
||||||
|
u2hFTX+JBACZ27xk0Afny2jjSoRzqLMrhzE7DBGcg2QqecMdNre12hVompAWcS4l
|
||||||
|
NFmPShKRi6UT8Zb38nD43vwfqwZImn60dOPqqAep3YF/Axm1u5HJb0aMEsb8O9jV
|
||||||
|
sVmNJv9jVTzPdlTGFQjuaeJfk5lwxB+5/O9NcgDhPgRAk9xb4FrT+xzmA/4tD11C
|
||||||
|
AdcITUkTZT4ZOo2418DGeaiaEqWcIkZeQG4Vh5TMj4QtZDwsYQhXPl5Zj1zKIN/1
|
||||||
|
gRrKC+ztaQoDG8pJXTTtc9inRU++dhMqnRGrPcz0VfVXFaiH7PUCy+4WpP6r5Bs5
|
||||||
|
YQ9ESHo+FsmIvDzU3e/PD0SfXfO4vqBrFYN8986NBF2bZaMBBADJafe0w9diaCNx
|
||||||
|
3A7e8MqjbNrhrLkD2cPxXspCATX3SuI19d2+hMiHZfKTyadBTIa+ICxvqoxwxyZD
|
||||||
|
raHSY3CWVZd1V4KB5mqf+3Zj5riLeGU0dtXwi/5c0bdUhBUgHiAMhi75p05jYih5
|
||||||
|
KsNxPcK9hEwPu7B+QeHURMiIgojTGQARAQABwsCDBBgBCgAPBQJdm2WjBQkDwmcA
|
||||||
|
AhsuAKgJEGS79V2S7D0onSAEGQEKAAYFAl2bZaMACgkQzdkMJSM5Bqg2rwP/Ue28
|
||||||
|
m3Fdfgh5JxouZ3Dm2KUDhZL95B+vdMk72acdoU7SRjlyDT8cApRqYx+MIXb8WrPN
|
||||||
|
1xCZnOM4zXeWIM0CAPQ1e/sCrK58L+P+eVngNmrW9epKtZ4L6hx+dqqja9vPZGQK
|
||||||
|
CsFAhA6A1gWB++OLk9Y6H23tWIdKEXMeAX7492zDYgP+OSPS79EWAqXL8SvmDrbl
|
||||||
|
WI5eiM6X5hAMrOjQqzXhatD7eP41N/FC3SfhyhX7hFbagO7MJG2AS5bmSvcuCdcN
|
||||||
|
wDwXd94B+7bfYgJIRKbr272yDwkyzGn+zmxzvMUt6ak5PNzfmadvhMZvIfDftswp
|
||||||
|
GYpXIUU0GObOgP2tpCGTErs=
|
||||||
|
=m++F
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
||||||
|
const privateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: Keybase OpenPGP v2.1.3
|
||||||
|
Comment: https://keybase.io/crypto
|
||||||
|
|
||||||
|
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
|
||||||
|
pCGTErs=
|
||||||
|
=Ya+/
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||||
|
|
||||||
|
const message = "A Fool and His Money are Soon Parted";
|
||||||
|
|
||||||
|
const encrypted = await chef.PGPEncrypt(message, {
|
||||||
|
publicKeyOfRecipient: pbkey,
|
||||||
|
});
|
||||||
|
const result = await chef.PGPDecrypt(encrypted, {
|
||||||
|
privateKeyOfRecipient: privateKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(result.toString(), message);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Raw deflate", () => {
|
it("Raw deflate", () => {
|
||||||
@@ -860,17 +885,17 @@ smothering ampersand abreast
|
|||||||
it("toBase64: editableOption", () => {
|
it("toBase64: editableOption", () => {
|
||||||
const result = toBase64("some input", {
|
const result = toBase64("some input", {
|
||||||
alphabet: {
|
alphabet: {
|
||||||
value: "0-9A-W"
|
value: "0-9A-W+/a-zXYZ="
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.toString(), "SPI1R1T0");
|
assert.strictEqual(result.toString(), "StXkPI1gRe1sT0==");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("toBase64: editableOptions key is value", () => {
|
it("toBase64: editableOptions key is value", () => {
|
||||||
const result = toBase64("some input", {
|
const result = toBase64("some input", {
|
||||||
alphabet: "0-9A-W",
|
alphabet: "0-9A-W+/a-zXYZ=",
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.toString(), "SPI1R1T0");
|
assert.strictEqual(result.toString(), "StXkPI1gRe1sT0==");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("toBase64: editableOptions default", () => {
|
it("toBase64: editableOptions default", () => {
|
||||||
@@ -918,10 +943,10 @@ smothering ampersand abreast
|
|||||||
chef.tripleDESDecrypt(
|
chef.tripleDESDecrypt(
|
||||||
chef.tripleDESEncrypt("Destroy Money", {
|
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"},
|
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"},
|
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(),
|
}).toString(),
|
||||||
"Destroy Money");
|
"Destroy Money");
|
||||||
}),
|
}),
|
||||||
@@ -1003,7 +1028,7 @@ ExifImageHeight: 57`);
|
|||||||
const zipped = chef.zip("some file content", {
|
const zipped = chef.zip("some file content", {
|
||||||
filename: "sample.zip",
|
filename: "sample.zip",
|
||||||
comment: "added",
|
comment: "added",
|
||||||
operaringSystem: "Unix",
|
operatingSystem: "Unix",
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.strictEqual(zipped.type, 7);
|
assert.strictEqual(zipped.type, 7);
|
||||||
|
|||||||
@@ -95,9 +95,6 @@ import "./tests/ParseUDP.mjs";
|
|||||||
// Cannot test operations that use the File type yet
|
// Cannot test operations that use the File type yet
|
||||||
// import "./tests/SplitColourChannels.mjs";
|
// import "./tests/SplitColourChannels.mjs";
|
||||||
|
|
||||||
// import "./tests/nodeApi/nodeApi.mjs";
|
|
||||||
// import "./tests/nodeApi/ops.mjs";
|
|
||||||
|
|
||||||
const testStatus = {
|
const testStatus = {
|
||||||
allTestsPassing: true,
|
allTestsPassing: true,
|
||||||
counts: {
|
counts: {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ TestRegister.addTests([
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Generate Base64 Windows Powershell",
|
name: "Generate Base64 Windows PowerShell",
|
||||||
input: "ZABpAHIAIAAiAGMAOgBcAHAAcgBvAGcAcgBhAG0AIABmAGkAbABlAHMAIgAgAA==",
|
input: "ZABpAHIAIAAiAGMAOgBcAHAAcgBvAGcAcgBhAG0AIABmAGkAbABlAHMAIgAgAA==",
|
||||||
expectedOutput: "dir \"c:\\program files\" ",
|
expectedOutput: "dir \"c:\\program files\" ",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
|
|||||||
Reference in New Issue
Block a user