2
0
mirror of https://github.com/gchq/CyberChef synced 2025-12-28 06:03:34 +00:00

Compare commits

..

19 Commits

Author SHA1 Message Date
n1474335
b28a891a40 9.7.10 2019-10-15 16:26:01 +01:00
n1474335
834ff95702 Base64 operations now throw a meaningful error if the alphabet is the wrong length 2019-10-15 16:25:52 +01:00
n1474335
3472484601 Merge branch 'd98762625-fix-node-tests' 2019-10-09 16:19:39 +01:00
n1474335
826a8c8a74 Merge branch 'fix-node-tests' of https://github.com/d98762625/CyberChef into d98762625-fix-node-tests 2019-10-09 16:18:54 +01:00
n1474335
c66703f0ca 9.7.9 2019-10-09 16:14:47 +01:00
n1474335
874e7d8d54 Merge branch 'expose-operationerror' 2019-10-09 16:14:38 +01:00
n1474335
4e2b85b8c8 Merge branch 'master' into expose-operationerror 2019-10-09 16:14:03 +01:00
n1474335
5314a456cb 9.7.8 2019-10-09 16:12:46 +01:00
n1474335
ba2a5b195c Improved PE extractor to also carve the overlay if possible 2019-10-09 16:12:41 +01:00
d98762625
f8115671ee fix linting tests 2019-10-07 18:05:28 +01:00
d98762625
494279edd8 update gitignore 2019-10-07 18:01:35 +01:00
d98762625
bd6673afed Merge branch 'master' of github.com:gchq/CyberChef into expose-operationerror 2019-10-07 17:59:00 +01:00
d98762625
210daf7324 make async node tests actually fail when they fail. Update tests that were failing 2019-10-07 17:41:51 +01:00
n1474335
06708949a1 9.7.7 2019-10-04 17:52:15 +01:00
n1474335
da901e20d9 Added several more file signatures. The background magic button now highlights when a file type has been detected. 2019-10-04 17:52:09 +01:00
n1474335
6810f38808 9.7.6 2019-10-01 17:11:36 +01:00
n1474335
087cc6b8fd Fixed webm signature 2019-10-01 17:11:31 +01:00
d98762625
014e70a7b1 add node index to source 2019-09-20 18:44:13 +01:00
d98762625
5148b16246 Export cyberchef error types to be used in consuming applications 2019-09-20 18:40:21 +01:00
15 changed files with 585 additions and 161 deletions

1
.gitignore vendored
View File

@@ -4,7 +4,6 @@ travis.log
build
.vscode
.*.swp
.DS_Store
src/core/config/modules/*
src/core/config/OperationConfig.json
src/core/operations/index.mjs

43
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.7.5",
"version": "9.7.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -6026,8 +6026,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@@ -6048,14 +6047,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -6070,20 +6067,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6200,8 +6194,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@@ -6213,7 +6206,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6228,7 +6220,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -6236,14 +6227,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -6262,7 +6251,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6343,8 +6331,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -6356,7 +6343,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -6442,8 +6428,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6479,7 +6464,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6499,7 +6483,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6543,14 +6526,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.7.5",
"version": "9.7.10",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",

View File

@@ -0,0 +1,9 @@
import OperationError from "./OperationError.mjs";
import DishError from "./DishError.mjs";
import ExcludedOperationError from "./ExcludedOperationError";
export {
OperationError,
DishError,
ExcludedOperationError,
};

View File

@@ -7,7 +7,7 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* 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("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
}
let output = "",
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 = 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 = [];
let chr1, chr2, chr3,

View File

@@ -415,10 +415,62 @@ export const FILE_SIGNATURES = {
6: 0x30
},
extractor: null
}
},
{
name: "AutoCAD Drawing",
extension: "dwg,123d",
mime: "application/acad",
description: "",
signature: {
0: 0x41,
1: 0x43,
2: 0x31,
3: 0x30,
4: [0x30, 0x31],
5: [0x30, 0x31, 0x32, 0x33, 0x34, 0x35],
6: 0x00
},
extractor: null
},
{
name: "AutoCAD Drawing",
extension: "dwg,dwt",
mime: "application/acad",
description: "",
signature: [
{
0: 0x41,
1: 0x43,
2: 0x31,
3: 0x30,
4: 0x31,
5: 0x38,
6: 0x00
},
{
0: 0x41,
1: 0x43,
2: 0x31,
3: 0x30,
4: 0x32,
5: 0x34,
6: 0x00
},
{
0: 0x41,
1: 0x43,
2: 0x31,
3: 0x30,
4: 0x32,
5: 0x37,
6: 0x00
}
],
extractor: null
},
],
"Video": [
{
{ // Place before webm
name: "Matroska Multimedia Container",
extension: "mkv",
mime: "video/x-matroska",
@@ -444,11 +496,7 @@ export const FILE_SIGNATURES = {
0: 0x1a,
1: 0x45,
2: 0xdf,
3: 0xa3,
4: 0x01,
5: 0x00,
6: 0x00,
7: 0x00
3: 0xa3
},
extractor: null
},
@@ -618,6 +666,59 @@ export const FILE_SIGNATURES = {
},
extractor: extractFLV
},
{
name: "OGG Video",
extension: "ogv,ogm,opus,ogx",
mime: "video/ogg",
description: "",
signature: [
{
0: 0x4f, // OggS
1: 0x67,
2: 0x67,
3: 0x53,
4: 0x00,
5: 0x02,
28: 0x01,
29: 0x76, // video
30: 0x69,
31: 0x64,
32: 0x65,
33: 0x6f
},
{
0: 0x4f, // OggS
1: 0x67,
2: 0x67,
3: 0x53,
4: 0x00,
5: 0x02,
28: 0x80,
29: 0x74, // theora
30: 0x68,
31: 0x65,
32: 0x6f,
33: 0x72,
34: 0x61
},
{
0: 0x4f, // OggS
1: 0x67,
2: 0x67,
3: 0x53,
4: 0x00,
5: 0x02,
28: 0x66, // fishead
29: 0x69,
30: 0x73,
31: 0x68,
32: 0x65,
33: 0x61,
34: 0x64
}
],
extractor: null
},
],
"Audio": [
{
@@ -885,6 +986,19 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{
name: "Encapsulated PostScript",
extension: "eps,ai",
mime: "application/eps",
description: "",
signature: {
0: 0xc5,
1: 0xd0,
2: 0xd3,
3: 0xc6
},
extractor: null
},
{
name: "Rich Text Format",
extension: "rtf",
@@ -1078,6 +1192,22 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{
name: "WordPerfect document",
extension: "wpd,wp,wp5,wp6,wpp,bk!,wcm",
mime: "application/wordperfect",
description: "",
signature: {
0: 0xff,
1: 0x57,
2: 0x50,
3: 0x43,
7: [0x00, 0x01, 0x02],
8: 0x01,
9: 0x0a
},
extractor: null
},
{
name: "EPUB e-book",
extension: "epub",
@@ -1124,7 +1254,7 @@ export const FILE_SIGNATURES = {
{
name: "Windows Portable Executable",
extension: "exe,dll,drv,vxd,sys,ocx,vbx,com,fon,scr",
mime: "application/x-msdownload",
mime: "application/vnd.microsoft.portable-executable",
description: "",
signature: {
0: 0x4d,
@@ -1135,7 +1265,7 @@ export const FILE_SIGNATURES = {
extractor: extractMZPE
},
{
name: "Executable and Linkable Format file",
name: "Executable and Linkable Format",
extension: "elf,bin,axf,o,prx,so",
mime: "application/x-executable",
description: "Executable and Linkable Format file. No standard file extension.",
@@ -1148,7 +1278,7 @@ export const FILE_SIGNATURES = {
extractor: extractELF
},
{
name: "MacOS Mach-O object file",
name: "MacOS Mach-O object",
extension: "dylib",
mime: "application/octet-stream",
description: "",
@@ -1165,7 +1295,7 @@ export const FILE_SIGNATURES = {
extractor: null
},
{
name: "MacOS Mach-O 64-bit object file",
name: "MacOS Mach-O 64-bit object",
extension: "dylib",
mime: "application/octet-stream",
description: "",
@@ -1553,7 +1683,7 @@ export const FILE_SIGNATURES = {
extractor: null
},
{
name: "Microsoft Cabinet file",
name: "Microsoft Cabinet",
extension: "cab",
mime: "vnd.ms-cab-compressed",
description: "",
@@ -1582,10 +1712,27 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{
name: "lzop compressed",
extension: "lzop,lzo",
mime: "application/x-lzop",
description: "",
signature: {
0: 0x89,
1: 0x4c, // LZO
2: 0x5a,
3: 0x4f,
4: 0x00,
5: 0x0d,
6: 0x0a,
7: 0x1a
},
extractor: null
},
],
"Miscellaneous": [
{
name: "UTF-8 text file",
name: "UTF-8 text",
extension: "txt",
mime: "text/plain",
description: "UTF-8 encoded Unicode byte order mark, commonly but not exclusively seen in text files.",
@@ -1596,8 +1743,8 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{ // Place before UTF-16 LE file
name: "UTF-32 LE file",
{ // Place before UTF-16 LE text
name: "UTF-32 LE text",
extension: "utf32le",
mime: "charset/utf32le",
description: "Little-endian UTF-32 encoded Unicode byte order mark.",
@@ -1610,7 +1757,7 @@ export const FILE_SIGNATURES = {
extractor: null
},
{
name: "UTF-16 LE file",
name: "UTF-16 LE text",
extension: "utf16le",
mime: "charset/utf16le",
description: "Little-endian UTF-16 encoded Unicode byte order mark.",
@@ -1968,6 +2115,223 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{
name: "TCP Packet",
extension: "tcp",
mime: "application/tcp",
description: "",
signature: {
12: 0x08,
13: 0x00,
14: 0x45,
15: 0x00,
21: 0x00,
22: b => b >= 0x01 && b <= 0x80,
23: 0x06
},
extractor: null
},
{
name: "UDP Packet",
extension: "udp",
mime: "application/udp",
description: "",
signature: {
12: 0x08,
13: 0x00,
14: 0x45,
15: 0x00,
16: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05],
22: b => b >= 0x01 && b <= 0x80,
23: 0x11
},
extractor: null
},
{
name: "Compiled HTML",
extension: "chm,chw,chi",
mime: "application/vnd.ms-htmlhelp",
description: "",
signature: {
0: 0x49, // ITSF
1: 0x54,
2: 0x53,
3: 0x46,
4: 0x03,
5: 0x00,
6: 0x00,
7: 0x00
},
extractor: null
},
{
name: "Windows Password",
extension: "pwl",
mime: "application/octet-stream",
description: "",
signature: {
0: 0xe3,
1: 0x82,
2: 0x85,
3: 0x96
},
extractor: null
},
{
name: "Bitlocker recovery key",
extension: "bitlocker",
mime: "application/octet-stream",
description: "",
signature: {
0: 0xff,
1: 0xfe,
2: 0x42,
3: 0x00,
4: 0x69,
5: 0x00,
6: 0x74,
7: 0x00,
8: 0x4c,
9: 0x00,
10: 0x6f,
11: 0x00,
12: 0x63,
13: 0x00,
14: 0x6b,
15: 0x00,
16: 0x65,
17: 0x00,
18: 0x72,
19: 0x00,
20: 0x20,
21: 0x00
},
extractor: null
},
{
name: "Certificate",
extension: "cer,cat,p7b,p7c,p7m,p7s,swz,rsa,crl,crt,der",
mime: "application/pkix-cert",
description: "",
signature: {
0: 0x30,
1: 0x82,
4: [0x06, 0x0a, 0x30]
},
extractor: null
},
{
name: "Certificate",
extension: "cat,swz,p7m",
mime: "application/vnd.ms-pki.seccat",
description: "",
signature: {
0: 0x30,
1: 0x83,
2: b => b !== 0x00,
5: 0x06,
6: 0x09
},
extractor: null
},
{
name: "PGP pubring",
extension: "pkr,gpg",
mime: "application/pgp-keys",
description: "",
signature: {
0: 0x99,
1: 0x01,
2: [0x0d, 0xa2],
3: 0x04
},
extractor: null
},
{
name: "PGP secring",
extension: "skr",
mime: "application/pgp-keys",
description: "",
signature: [
{
0: 0x95,
1: 0x01,
2: 0xcf,
3: 0x04
},
{
0: 0x95,
1: 0x03,
2: 0xc6,
3: 0x04
}
],
extractor: null
},
{
name: "PGP Safe",
extension: "pgd",
mime: "application/pgp-keys",
description: "",
signature: {
0: 0x50, // PGPdMAIN
1: 0x47,
2: 0x50,
3: 0x64,
4: 0x4d,
5: 0x41,
6: 0x49,
7: 0x4e,
8: 0x60,
9: 0x01,
10: 0x00
},
extractor: null
},
{
name: "Task Scheduler",
extension: "job",
mime: "application/octet-stream",
description: "",
signature: {
0: [0x00, 0x01, 0x02, 0x03],
1: [0x05, 0x06],
2: 0x01,
3: 0x00,
20: 0x46,
21: 0x00
},
extractor: null
},
{
name: "Windows Shortcut",
extension: "lnk",
mime: "application/x-ms-shortcut",
description: "",
signature: {
0: 0x4c,
1: 0x00,
2: 0x00,
3: 0x00,
4: 0x01,
5: 0x14,
6: 0x02,
7: 0x00,
8: 0x00,
9: 0x00,
10: 0x00,
11: 0x00,
12: 0xc0,
13: 0x00,
14: 0x00,
15: 0x00,
16: 0x00,
17: 0x00,
18: 0x00,
19: 0x46
},
extractor: null
}
]
};
@@ -2087,7 +2451,7 @@ export function extractJPEG(bytes, offset) {
export function extractMZPE(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to PE header pointer
// Read pointer to PE header
stream.moveTo(0x3c);
const peAddress = stream.readInt(4, "le");
@@ -2098,12 +2462,36 @@ export function extractMZPE(bytes, offset) {
stream.moveForwardsBy(6);
const numSections = stream.readInt(2, "le");
// Get optional header size
stream.moveForwardsBy(12);
const optionalHeaderSize = 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
stream.moveForwardsBy(16);
const optionalMagic = stream.readInt(2, "le");
const pe32Plus = optionalMagic === 0x20b;
// Move past optional header to section header
stream.moveForwardsBy(2 + optionalHeaderSize);
// Move to Data Directory
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
stream.moveForwardsBy((numSections - 1) * 0x28);
@@ -2311,9 +2699,10 @@ export function extractRTF(bytes, offset) {
export function extractPListXML(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Find closing tag (</plist>\n)
stream.continueUntil([0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a]);
stream.moveForwardsBy(9);
// Find closing tag (</plist>)
stream.continueUntil([0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e]);
stream.moveForwardsBy(8);
stream.consumeIf(0x0a);
return stream.carve();
}

View File

@@ -97,6 +97,7 @@ class Magic {
if (!fileType.length) return null;
return {
name: fileType[0].name,
ext: fileType[0].extension,
mime: fileType[0].mime,
desc: fileType[0].description

View File

@@ -47,7 +47,7 @@ class Bzip2Decompress extends Operation {
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
async run(input, args) {
const [small] = args;
if (input.byteLength <= 0) {
throw new OperationError("Please provide an input.");

View File

@@ -8,6 +8,13 @@ import Operation from "../Operation.mjs";
import {detectFileType} from "../lib/FileType.mjs";
import {FILE_SIGNATURES} from "../lib/FileSignatures.mjs";
// Concat all supported extensions into a single flat list
const exts = [].concat.apply([], Object.keys(FILE_SIGNATURES).map(cat =>
[].concat.apply([], FILE_SIGNATURES[cat].map(sig =>
sig.extension.split(",")
))
)).unique().sort().join(", ");
/**
* Detect File Type operation
*/
@@ -22,11 +29,7 @@ class DetectFileType extends Operation {
this.name = "Detect File Type";
this.module = "Default";
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: " +
Object.keys(FILE_SIGNATURES).map(cat =>
[].concat.apply([], FILE_SIGNATURES[cat].map(sig =>
sig.extension.split(",")
)).unique().join(", ")
).unique().join(", ") + ".";
exts + ".";
this.infoURL = "https://wikipedia.org/wiki/List_of_file_signatures";
this.inputType = "ArrayBuffer";
this.outputType = "string";

View File

@@ -58,7 +58,7 @@ class GeneratePGPKeyPair extends Operation {
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
async run(input, args) {
const [keyType, keySize] = args[0].split("-"),
password = args[1],
name = args[2],

View File

@@ -41,6 +41,7 @@ let code = `/**
import NodeDish from "./NodeDish.mjs";
import { _wrap, help, bake, _explainExludedFunction } from "./api.mjs";
import File from "./File.mjs";
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index";
import {
// import as core_ to avoid name clashes after wrap.
`;
@@ -115,6 +116,9 @@ Object.keys(operations).forEach((op) => {
code += " NodeDish as Dish,\n";
code += " prebaked as bake,\n";
code += " help,\n";
code += " OperationError,\n";
code += " ExcludedOperationError,\n";
code += " DishError,\n";
code += "};\n";

View File

@@ -1046,15 +1046,25 @@ class OutputWaiter {
* @param {Object[]} options
*/
backgroundMagicResult(options) {
if (!options.length ||
!options[0].recipe.length)
return;
if (!options.length) return;
const currentRecipeConfig = this.app.getRecipeConfig();
const newRecipeConfig = currentRecipeConfig.concat(options[0].recipe);
const opSequence = options[0].recipe.map(o => o.op).join(", ");
let msg = "",
newRecipeConfig;
this.showMagicButton(opSequence, options[0].data, newRecipeConfig);
if (options[0].recipe.length) {
const opSequence = options[0].recipe.map(o => o.op).join(", ");
newRecipeConfig = currentRecipeConfig.concat(options[0].recipe);
msg = `<i>${opSequence}</i> will produce <span class="data-text">"${Utils.escapeHtml(Utils.truncate(options[0].data), 30)}"</span>`;
} else if (options[0].fileType && options[0].fileType.name) {
const ft = options[0].fileType;
newRecipeConfig = currentRecipeConfig.concat([{op: "Detect File Type", args: []}]);
msg = `<i>${ft.name}</i> file detected`;
} else {
return;
}
this.showMagicButton(msg, newRecipeConfig);
}
/**
@@ -1072,15 +1082,14 @@ class OutputWaiter {
}
/**
* Displays the Magic button with a title and adds a link to a complete recipe.
* Displays the Magic button with a title and adds a link to a recipe.
*
* @param {string} opSequence
* @param {string} result
* @param {string} msg
* @param {Object[]} recipeConfig
*/
showMagicButton(opSequence, result, recipeConfig) {
showMagicButton(msg, recipeConfig) {
const magicButton = document.getElementById("magic");
magicButton.setAttribute("data-original-title", `<i>${opSequence}</i> will produce <span class="data-text">"${Utils.escapeHtml(Utils.truncate(result), 30)}"</span>`);
magicButton.setAttribute("data-original-title", msg);
magicButton.setAttribute("data-recipe", JSON.stringify(recipeConfig), null, "");
magicButton.classList.remove("hidden");
magicButton.classList.add("pulse");

View File

@@ -104,8 +104,6 @@ class TestRegister {
* Run all api related tests and wrap results in report format
*/
runApiTests() {
console.log("Running tests...");
return Promise.all(this.apiTests.map(async function(test, i) {
const result = {
test: test,

View File

@@ -15,9 +15,9 @@
/**
* Print useful stack on error
*/
const wrapRun = (run) => () => {
const wrapRun = (run) => async () => {
try {
run();
await run();
} catch (e) {
console.dir(e);
throw e;

View File

@@ -130,11 +130,14 @@ Tiger-128`;
it("atBash Cipher", () => {
const result = chef.atbashCipher("Happy as a Clam");
assert.strictEqual(result.toString(), "Szkkb zh z Xozn");
}),
it("Bcrypt", async () => {
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() => {
@@ -583,47 +586,7 @@ Password: 034148`;
const result = await chef.generatePGPKeyPair("Back To the Drawing Board", {
keyType: "ECC-256",
});
const expected = `-----BEGIN PGP PRIVATE KEY BLOCK-----
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);
assert.strictEqual(result.toString().length, 2005);
}),
it("Generate UUID", () => {
@@ -737,43 +700,105 @@ CPU
assert.strictEqual(result.toString(), expected);
}),
it("PGP Encrypt", async () => {
it("PGP Encrypt and decrypt", async () => {
const pbkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
Version: Keybase OpenPGP v2.1.3
Comment: https://keybase.io/crypto
wYwDv1kIXPPNwmABA/4syW+oO+S/mfpjdp83/MZJiKh6XNQoPr/N5/1Is/QXYu9V
/v8/b+eReOpUVC6cVrJ8U5cB19y1Az3NQWHXLEC0jND2wL3cUM4sv87hlvv2PLhc
okv8OHNCitRiweo7NZHVygHGdFvY082G47e1PkyPAuVynvzdD450ta/s/KOxZdJg
ARbZIrC6WmjYNLwhbpRYawKD+3N4I5qliRpU2POKRi9UROAW9dth6egy60TTCvyO
jmPGsv1elXxVzqs58UZLD2c3vBhGkU2BV6kRKh+lj/EcVrzsFhGCz/7DKxPoDHLS
=IBYt
-----END PGP MESSAGE-----
`;
assert.strictEqual(result.toString(), expected);
xo0EXZtlowEEAKUqTFownTmqgXWu2KDrtyNYtFck7a16WM5QD95bFoAFFdnlwZ45
6Vw8G8LCzHdyRXYp/JF1GknDrAd7nIRE+SuSz2yVK5nlOCfO1HFcg2Ov7e7/pBwd
qawx9GUIsCKd/6NxwDuT4YqarLFsuwljRC/eQiibO+ejnhoiKcU69sTNABEBAAHN
AMK0BBMBCgAeBQJdm2WjAhsvAwsJBwMVCggCHgECF4ADFgIBAhkBAAoJEGS79V2S
7D0owtMD/RT+o4BQJ8NSQBDgkYf42uOOu1Ud6GuN89nX6n20yAZbmqQ8CHnHY+Qc
l6ft4HnbIaNrI3arp/C2C+cwFypmt1BKyFEJUXO7ft3i/IxnjpCorDyAMCDckDvq
uma1LWtUHLb5s/ZuGMSHnhuji74IRWuIofNPdf7bCZW1GMbW9jNUzo0EXZtlowEE
AL38zaNkPmUVQaowP696fayBo18Nxs0yOzC4+0TYv1B/k5aUb0Air2h+o/Xw4E42
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", () => {
@@ -860,17 +885,17 @@ smothering ampersand abreast
it("toBase64: editableOption", () => {
const result = toBase64("some input", {
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", () => {
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", () => {