Merged master into esm branch
commit
a98d37e61c
|
@ -280,7 +280,7 @@ module.exports = function (grunt) {
|
||||||
chunks: false,
|
chunks: false,
|
||||||
modules: false,
|
modules: false,
|
||||||
entrypoints: false,
|
entrypoints: false,
|
||||||
warningsFilter: /source-map/,
|
warningsFilter: [/source-map/, /dependency is an expression/],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
start: {
|
start: {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "7.9.0",
|
"version": "7.11.1",
|
||||||
"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",
|
||||||
|
@ -30,14 +30,14 @@
|
||||||
"main": "build/node/CyberChef.js",
|
"main": "build/node/CyberChef.js",
|
||||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.3",
|
||||||
"babel-loader": "^7.1.3",
|
"babel-loader": "^7.1.4",
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"css-loader": "^0.28.10",
|
"css-loader": "^0.28.11",
|
||||||
"eslint": "^4.18.1",
|
"eslint": "^4.19.1",
|
||||||
"exports-loader": "^0.7.0",
|
"exports-loader": "^0.7.0",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
||||||
"file-loader": "^1.1.10",
|
"file-loader": "^1.1.11",
|
||||||
"grunt": ">=1.0.2",
|
"grunt": ">=1.0.2",
|
||||||
"grunt-accessibility": "~6.0.0",
|
"grunt-accessibility": "~6.0.0",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
|
@ -48,23 +48,23 @@
|
||||||
"grunt-eslint": "^20.1.0",
|
"grunt-eslint": "^20.1.0",
|
||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-jsdoc": "^2.2.1",
|
"grunt-jsdoc": "^2.2.1",
|
||||||
"grunt-webpack": "^3.0.2",
|
"grunt-webpack": "^3.1.1",
|
||||||
"html-webpack-plugin": "^3.0.4",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"imports-loader": "^0.8.0",
|
"imports-loader": "^0.8.0",
|
||||||
"ink-docstrap": "^1.3.2",
|
"ink-docstrap": "^1.3.2",
|
||||||
"jsdoc-babel": "^0.3.0",
|
"jsdoc-babel": "^0.4.0",
|
||||||
"less": "^3.0.1",
|
"less": "^3.0.2",
|
||||||
"less-loader": "^4.0.6",
|
"less-loader": "^4.1.0",
|
||||||
"postcss-css-variables": "^0.8.0",
|
"postcss-css-variables": "^0.8.1",
|
||||||
"postcss-import": "^11.1.0",
|
"postcss-import": "^11.1.0",
|
||||||
"postcss-loader": "^2.1.1",
|
"postcss-loader": "^2.1.4",
|
||||||
"sitemap": "^1.13.0",
|
"sitemap": "^1.13.0",
|
||||||
"style-loader": "^0.20.2",
|
"style-loader": "^0.21.0",
|
||||||
"url-loader": "^0.6.2",
|
"url-loader": "^1.0.1",
|
||||||
"web-resource-inliner": "^4.2.1",
|
"web-resource-inliner": "^4.2.1",
|
||||||
"webpack": "^4.0.1",
|
"webpack": "^4.6.0",
|
||||||
"webpack-dev-server": "^3.1.0",
|
"webpack-dev-server": "^3.1.3",
|
||||||
"webpack-node-externals": "^1.6.0",
|
"webpack-node-externals": "^1.7.2",
|
||||||
"webpack-synchronizable-shell-plugin": "0.0.7",
|
"webpack-synchronizable-shell-plugin": "0.0.7",
|
||||||
"worker-loader": "^1.1.1"
|
"worker-loader": "^1.1.1"
|
||||||
},
|
},
|
||||||
|
@ -72,20 +72,21 @@
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bignumber.js": "^6.0.0",
|
"bignumber.js": "^7.0.1",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^3.3.7",
|
||||||
"bootstrap-colorpicker": "^2.5.2",
|
"bootstrap-colorpicker": "^2.5.2",
|
||||||
"bootstrap-switch": "^3.3.4",
|
"bootstrap-switch": "^3.3.4",
|
||||||
"bson": "^2.0.4",
|
"bson": "^2.0.6",
|
||||||
"crypto-api": "^0.8.0",
|
"crypto-api": "^0.8.0",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"diff": "^3.4.0",
|
"diff": "^3.5.0",
|
||||||
"escodegen": "^1.9.1",
|
"escodegen": "^1.9.1",
|
||||||
|
"es6-promisify": "^6.0.0",
|
||||||
"esmangle": "^1.0.1",
|
"esmangle": "^1.0.1",
|
||||||
"esprima": "^4.0.0",
|
"esprima": "^4.0.0",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"file-saver": "^1.3.3",
|
"file-saver": "^1.3.8",
|
||||||
"highlight.js": "^9.12.0",
|
"highlight.js": "^9.12.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
"js-crc": "^0.2.0",
|
"js-crc": "^0.2.0",
|
||||||
|
@ -93,15 +94,16 @@
|
||||||
"jsbn": "^1.1.0",
|
"jsbn": "^1.1.0",
|
||||||
"jsesc": "^2.5.1",
|
"jsesc": "^2.5.1",
|
||||||
"jsonpath": "^1.0.0",
|
"jsonpath": "^1.0.0",
|
||||||
"jsrsasign": "8.0.6",
|
"jsrsasign": "8.0.12",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.10",
|
||||||
"loglevel": "^1.6.1",
|
"loglevel": "^1.6.1",
|
||||||
|
"kbpgp": "^2.0.77",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"moment": "^2.20.1",
|
"moment": "^2.22.1",
|
||||||
"moment-timezone": "^0.5.14",
|
"moment-timezone": "^0.5.16",
|
||||||
"node-forge": "^0.7.2",
|
"node-forge": "^0.7.5",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
"nwmatcher": "^1.4.3",
|
"nwmatcher": "^1.4.4",
|
||||||
"otp": "^0.1.3",
|
"otp": "^0.1.3",
|
||||||
"scryptsy": "^2.0.0",
|
"scryptsy": "^2.0.0",
|
||||||
"sladex-blowfish": "^0.8.1",
|
"sladex-blowfish": "^0.8.1",
|
||||||
|
|
|
@ -524,36 +524,43 @@ class Utils {
|
||||||
* Parses CSV data and returns it as a two dimensional array or strings.
|
* Parses CSV data and returns it as a two dimensional array or strings.
|
||||||
*
|
*
|
||||||
* @param {string} data
|
* @param {string} data
|
||||||
|
* @param {string[]} [cellDelims=[","]]
|
||||||
|
* @param {string[]} [lineDelims=["\n", "\r"]]
|
||||||
* @returns {string[][]}
|
* @returns {string[][]}
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // returns [["head1", "head2"], ["data1", "data2"]]
|
* // returns [["head1", "head2"], ["data1", "data2"]]
|
||||||
* Utils.parseCSV("head1,head2\ndata1,data2");
|
* Utils.parseCSV("head1,head2\ndata1,data2");
|
||||||
*/
|
*/
|
||||||
static parseCSV(data) {
|
static parseCSV(data, cellDelims=[","], lineDelims=["\n", "\r"]) {
|
||||||
let b,
|
let b,
|
||||||
ignoreNext = false,
|
next,
|
||||||
|
renderNext = false,
|
||||||
inString = false,
|
inString = false,
|
||||||
cell = "",
|
cell = "",
|
||||||
line = [];
|
line = [];
|
||||||
const lines = [];
|
const lines = [];
|
||||||
|
|
||||||
|
// Remove BOM, often present in Excel CSV files
|
||||||
|
if (data.length && data[0] === "\uFEFF") data = data.substr(1);
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
b = data[i];
|
b = data[i];
|
||||||
if (ignoreNext) {
|
next = data[i+1] || "";
|
||||||
|
if (renderNext) {
|
||||||
cell += b;
|
cell += b;
|
||||||
ignoreNext = false;
|
renderNext = false;
|
||||||
} else if (b === "\\") {
|
} else if (b === "\\") {
|
||||||
cell += b;
|
renderNext = true;
|
||||||
ignoreNext = true;
|
|
||||||
} else if (b === "\"" && !inString) {
|
} else if (b === "\"" && !inString) {
|
||||||
inString = true;
|
inString = true;
|
||||||
} else if (b === "\"" && inString) {
|
} else if (b === "\"" && inString) {
|
||||||
inString = false;
|
if (next === "\"") renderNext = true;
|
||||||
} else if (b === "," && !inString) {
|
else inString = false;
|
||||||
|
} else if (!inString && cellDelims.indexOf(b) >= 0) {
|
||||||
line.push(cell);
|
line.push(cell);
|
||||||
cell = "";
|
cell = "";
|
||||||
} else if ((b === "\n" || b === "\r") && !inString) {
|
} else if (!inString && lineDelims.indexOf(b) >= 0) {
|
||||||
line.push(cell);
|
line.push(cell);
|
||||||
cell = "";
|
cell = "";
|
||||||
lines.push(line);
|
lines.push(line);
|
||||||
|
|
|
@ -94,7 +94,12 @@
|
||||||
"PEM to Hex",
|
"PEM to Hex",
|
||||||
"Hex to PEM",
|
"Hex to PEM",
|
||||||
"Hex to Object Identifier",
|
"Hex to Object Identifier",
|
||||||
"Object Identifier to Hex"
|
"Object Identifier to Hex",
|
||||||
|
"Generate PGP Key Pair",
|
||||||
|
"PGP Encrypt",
|
||||||
|
"PGP Decrypt",
|
||||||
|
"PGP Encrypt and Sign",
|
||||||
|
"PGP Decrypt and Verify"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -164,6 +169,7 @@
|
||||||
"To Lower case",
|
"To Lower case",
|
||||||
"Add line numbers",
|
"Add line numbers",
|
||||||
"Remove line numbers",
|
"Remove line numbers",
|
||||||
|
"To Table",
|
||||||
"Reverse",
|
"Reverse",
|
||||||
"Sort",
|
"Sort",
|
||||||
"Unique",
|
"Unique",
|
||||||
|
|
|
@ -672,6 +672,34 @@ const OP_CONFIG = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"To Table": {
|
||||||
|
module: "Default",
|
||||||
|
description: "Data can be split on different characters and rendered as an HTML or ASCII table with an optional header row.<br><br>Supports the CSV (Comma Separated Values) file format by default. Change the cell delimiter argument to <code>\\t</code> to support TSV (Tab Separated Values) or <code>|</code> for PSV (Pipe Separated Values).<br><br>You can enter as many delimiters as you like. Each character will be treat as a separate possible delimiter.",
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "html",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Cell delimiters",
|
||||||
|
type: "binaryShortString",
|
||||||
|
value: ","
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Row delimiters",
|
||||||
|
type: "binaryShortString",
|
||||||
|
value: "\\n\\r"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Make first row header",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Format",
|
||||||
|
type: "option",
|
||||||
|
value: "ToTable.FORMATS"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"From Hex": {
|
"From Hex": {
|
||||||
module: "Default",
|
module: "Default",
|
||||||
description: "Converts a hexadecimal byte string back into its raw value.<br><br>e.g. <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code> becomes the UTF-8 encoded string <code>Γειά σου</code>",
|
description: "Converts a hexadecimal byte string back into its raw value.<br><br>e.g. <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code> becomes the UTF-8 encoded string <code>Γειά σου</code>",
|
||||||
|
@ -3363,14 +3391,14 @@ const OP_CONFIG = {
|
||||||
"CRC-32 Checksum": {
|
"CRC-32 Checksum": {
|
||||||
module: "Hashing",
|
module: "Hashing",
|
||||||
description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.",
|
description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.",
|
||||||
inputType: "string",
|
inputType: "ArrayBuffer",
|
||||||
outputType: "string",
|
outputType: "string",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
"CRC-16 Checksum": {
|
"CRC-16 Checksum": {
|
||||||
module: "Hashing",
|
module: "Hashing",
|
||||||
description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.",
|
description: "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.",
|
||||||
inputType: "string",
|
inputType: "ArrayBuffer",
|
||||||
outputType: "string",
|
outputType: "string",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
|
@ -3423,7 +3451,7 @@ const OP_CONFIG = {
|
||||||
},
|
},
|
||||||
"Parse X.509 certificate": {
|
"Parse X.509 certificate": {
|
||||||
module: "PublicKey",
|
module: "PublicKey",
|
||||||
description: "X.509 is an ITU-T standard for a public key infrastructure (PKI) and Privilege Management Infrastructure (PMI). It is commonly involved with SSL/TLS security.<br><br>This operation displays the contents of a certificate in a human readable format, similar to the openssl command line tool.",
|
description: "X.509 is an ITU-T standard for a public key infrastructure (PKI) and Privilege Management Infrastructure (PMI). It is commonly involved with SSL/TLS security.<br><br>This operation displays the contents of a certificate in a human readable format, similar to the openssl command line tool.<br><br>Tags: X509, server hello, handshake",
|
||||||
inputType: "string",
|
inputType: "string",
|
||||||
outputType: "string",
|
outputType: "string",
|
||||||
args: [
|
args: [
|
||||||
|
@ -4219,6 +4247,150 @@ const OP_CONFIG = {
|
||||||
outputType: "string",
|
outputType: "string",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
|
"Generate PGP Key Pair": {
|
||||||
|
module: "PGP",
|
||||||
|
description: "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.",
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "string",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Key type",
|
||||||
|
type: "option",
|
||||||
|
value: "PGP.KEY_TYPES"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Password (optional)",
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Name (optional)",
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Email (optional)",
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PGP Encrypt": {
|
||||||
|
module: "PGP",
|
||||||
|
description: [
|
||||||
|
"Input: the message you want to encrypt.",
|
||||||
|
"<br><br>",
|
||||||
|
"Arguments: the ASCII-armoured PGP public key of the recipient.",
|
||||||
|
"<br><br>",
|
||||||
|
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
|
||||||
|
"<br><br>",
|
||||||
|
"This function uses the Keybase implementation of PGP.",
|
||||||
|
].join("\n"),
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "string",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Public key of recipient",
|
||||||
|
type: "text",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PGP Decrypt": {
|
||||||
|
module: "PGP",
|
||||||
|
description: [
|
||||||
|
"Input: the ASCII-armoured PGP message you want to decrypt.",
|
||||||
|
"<br><br>",
|
||||||
|
"Arguments: the ASCII-armoured PGP private key of the recipient, ",
|
||||||
|
"(and the private key password if necessary).",
|
||||||
|
"<br><br>",
|
||||||
|
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
|
||||||
|
"<br><br>",
|
||||||
|
"This function uses the Keybase implementation of PGP.",
|
||||||
|
].join("\n"),
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "string",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Private key of recipient",
|
||||||
|
type: "text",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private key passphrase",
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PGP Encrypt and Sign": {
|
||||||
|
module: "PGP",
|
||||||
|
description: [
|
||||||
|
"Input: the cleartext you want to sign.",
|
||||||
|
"<br><br>",
|
||||||
|
"Arguments: the ASCII-armoured private key of the signer (plus the private key password if necessary)",
|
||||||
|
"and the ASCII-armoured PGP public key of the recipient.",
|
||||||
|
"<br><br>",
|
||||||
|
"This operation uses PGP to produce an encrypted digital signature.",
|
||||||
|
"<br><br>",
|
||||||
|
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
|
||||||
|
"<br><br>",
|
||||||
|
"This function uses the Keybase implementation of PGP.",
|
||||||
|
].join("\n"),
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "string",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Private key of signer",
|
||||||
|
type: "text",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private key passphrase",
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public key of recipient",
|
||||||
|
type: "text",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PGP Decrypt and Verify": {
|
||||||
|
module: "PGP",
|
||||||
|
description: [
|
||||||
|
"Input: the ASCII-armoured encrypted PGP message you want to verify.",
|
||||||
|
"<br><br>",
|
||||||
|
"Arguments: the ASCII-armoured PGP public key of the signer, ",
|
||||||
|
"the ASCII-armoured private key of the recipient (and the private key password if necessary).",
|
||||||
|
"<br><br>",
|
||||||
|
"This operation uses PGP to decrypt and verify an encrypted digital signature.",
|
||||||
|
"<br><br>",
|
||||||
|
"Pretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.",
|
||||||
|
"<br><br>",
|
||||||
|
"This function uses the Keybase implementation of PGP.",
|
||||||
|
].join("\n"),
|
||||||
|
inputType: "string",
|
||||||
|
outputType: "string",
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "Public key of signer",
|
||||||
|
type: "text",
|
||||||
|
value: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private key of recipient",
|
||||||
|
type: "text",
|
||||||
|
value: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private key password",
|
||||||
|
type: "string",
|
||||||
|
value: "",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
|
@ -84,9 +84,9 @@ export function toHexFast(data) {
|
||||||
* fromHex("0a:14:1e", "Colon");
|
* fromHex("0a:14:1e", "Colon");
|
||||||
*/
|
*/
|
||||||
export function fromHex(data, delim, byteLen=2) {
|
export function fromHex(data, delim, byteLen=2) {
|
||||||
delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
|
delim = delim || "Auto";
|
||||||
if (delim !== "None") {
|
if (delim !== "None") {
|
||||||
const delimRegex = Utils.regexRep(delim);
|
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep(delim);
|
||||||
data = data.replace(delimRegex, "");
|
data = data.replace(delimRegex, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,12 @@ export function fromHex(data, delim, byteLen=2) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hexadecimal delimiters.
|
* To Hexadecimal delimiters.
|
||||||
*/
|
*/
|
||||||
export const HEX_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
export const TO_HEX_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Hexadecimal delimiters.
|
||||||
|
*/
|
||||||
|
export const FROM_HEX_DELIM_OPTIONS = ["Auto"].concat(TO_HEX_DELIM_OPTIONS);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import {fromHex, HEX_DELIM_OPTIONS} from "../lib/Hex";
|
import {fromHex, FROM_HEX_DELIM_OPTIONS} from "../lib/Hex";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +28,7 @@ class FromHex extends Operation {
|
||||||
{
|
{
|
||||||
name: "Delimiter",
|
name: "Delimiter",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: HEX_DELIM_OPTIONS
|
value: FROM_HEX_DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import {toHex, HEX_DELIM_OPTIONS} from "../lib/Hex";
|
import {toHex, TO_HEX_DELIM_OPTIONS} from "../lib/Hex";
|
||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +28,7 @@ class ToHex extends Operation {
|
||||||
{
|
{
|
||||||
name: "Delimiter",
|
name: "Delimiter",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: HEX_DELIM_OPTIONS
|
value: TO_HEX_DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ const BSON = {
|
||||||
const data = JSON.parse(input);
|
const data = JSON.parse(input);
|
||||||
return bson.serialize(data).buffer;
|
return bson.serialize(data).buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return err.toString();
|
throw err.toString();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,16 @@ const ByteRepr = {
|
||||||
* @default
|
* @default
|
||||||
*/
|
*/
|
||||||
DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"],
|
DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"],
|
||||||
|
/**
|
||||||
|
* @constant
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
TO_HEX_DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
|
||||||
|
/**
|
||||||
|
* @constant
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
FROM_HEX_DELIM_OPTIONS: ["Auto", "Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
|
||||||
/**
|
/**
|
||||||
* @constant
|
* @constant
|
||||||
* @default
|
* @default
|
||||||
|
|
|
@ -120,7 +120,7 @@ const Checksum = {
|
||||||
/**
|
/**
|
||||||
* CRC-32 Checksum operation.
|
* CRC-32 Checksum operation.
|
||||||
*
|
*
|
||||||
* @param {string} input
|
* @param {ArrayBuffer} input
|
||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +132,7 @@ const Checksum = {
|
||||||
/**
|
/**
|
||||||
* CRC-16 Checksum operation.
|
* CRC-16 Checksum operation.
|
||||||
*
|
*
|
||||||
* @param {string} input
|
* @param {ArrayBuffer} input
|
||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,364 @@
|
||||||
|
import * as kbpgp from "kbpgp";
|
||||||
|
import {promisify} from "es6-promisify";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP operations.
|
||||||
|
*
|
||||||
|
* @author tlwr [toby@toby.codes]
|
||||||
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
* @namespace
|
||||||
|
*/
|
||||||
|
const PGP = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constant
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
KEY_TYPES: ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get size of subkey
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {number} keySize
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
_getSubkeySize(keySize) {
|
||||||
|
return {
|
||||||
|
1024: 1024,
|
||||||
|
2048: 1024,
|
||||||
|
4096: 2048,
|
||||||
|
256: 256,
|
||||||
|
384: 256,
|
||||||
|
}[keySize];
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Progress callback
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_ASP: new kbpgp.ASP({
|
||||||
|
"progress_hook": info => {
|
||||||
|
let msg = "";
|
||||||
|
|
||||||
|
switch (info.what) {
|
||||||
|
case "guess":
|
||||||
|
msg = "Guessing a prime";
|
||||||
|
break;
|
||||||
|
case "fermat":
|
||||||
|
msg = "Factoring prime using Fermat's factorization method";
|
||||||
|
break;
|
||||||
|
case "mr":
|
||||||
|
msg = "Performing Miller-Rabin primality test";
|
||||||
|
break;
|
||||||
|
case "passed_mr":
|
||||||
|
msg = "Passed Miller-Rabin primality test";
|
||||||
|
break;
|
||||||
|
case "failed_mr":
|
||||||
|
msg = "Failed Miller-Rabin primality test";
|
||||||
|
break;
|
||||||
|
case "found":
|
||||||
|
msg = "Prime found";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg = `Stage: ${info.what}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ENVIRONMENT_IS_WORKER())
|
||||||
|
self.sendStatusMessage(msg);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import private key and unlock if necessary
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} privateKey
|
||||||
|
* @param {string} [passphrase]
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
async _importPrivateKey(privateKey, passphrase) {
|
||||||
|
try {
|
||||||
|
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
|
||||||
|
armored: privateKey,
|
||||||
|
opts: {
|
||||||
|
"no_check_keys": true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (key.is_pgp_locked()) {
|
||||||
|
if (passphrase) {
|
||||||
|
await promisify(key.unlock_pgp.bind(key))({
|
||||||
|
passphrase
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw "Did not provide passphrase with locked private key.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
} catch (err) {
|
||||||
|
throw `Could not import private key: ${err}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import public key
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} publicKey
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
async _importPublicKey (publicKey) {
|
||||||
|
try {
|
||||||
|
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
|
||||||
|
armored: publicKey,
|
||||||
|
opts: {
|
||||||
|
"no_check_keys": true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return key;
|
||||||
|
} catch (err) {
|
||||||
|
throw `Could not import public key: ${err}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate PGP Key Pair operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
runGenerateKeyPair(input, args) {
|
||||||
|
let [keyType, keySize] = args[0].split("-"),
|
||||||
|
password = args[1],
|
||||||
|
name = args[2],
|
||||||
|
email = args[3],
|
||||||
|
userIdentifier = "";
|
||||||
|
|
||||||
|
if (name) userIdentifier += name;
|
||||||
|
if (email) userIdentifier += ` <${email}>`;
|
||||||
|
|
||||||
|
let flags = kbpgp.const.openpgp.certify_keys;
|
||||||
|
flags |= kbpgp.const.openpgp.sign_data;
|
||||||
|
flags |= kbpgp.const.openpgp.auth;
|
||||||
|
flags |= kbpgp.const.openpgp.encrypt_comm;
|
||||||
|
flags |= kbpgp.const.openpgp.encrypt_storage;
|
||||||
|
|
||||||
|
let keyGenerationOptions = {
|
||||||
|
userid: userIdentifier,
|
||||||
|
ecc: keyType === "ecc",
|
||||||
|
primary: {
|
||||||
|
"nbits": keySize,
|
||||||
|
"flags": flags,
|
||||||
|
"expire_in": 0
|
||||||
|
},
|
||||||
|
subkeys: [{
|
||||||
|
"nbits": PGP._getSubkeySize(keySize),
|
||||||
|
"flags": kbpgp.const.openpgp.sign_data,
|
||||||
|
"expire_in": 86400 * 365 * 8
|
||||||
|
}, {
|
||||||
|
"nbits": PGP._getSubkeySize(keySize),
|
||||||
|
"flags": kbpgp.const.openpgp.encrypt_comm | kbpgp.const.openpgp.encrypt_storage,
|
||||||
|
"expire_in": 86400 * 365 * 2
|
||||||
|
}],
|
||||||
|
asp: PGP._ASP
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const unsignedKey = await promisify(kbpgp.KeyManager.generate)(keyGenerationOptions);
|
||||||
|
await promisify(unsignedKey.sign.bind(unsignedKey))({});
|
||||||
|
let signedKey = unsignedKey;
|
||||||
|
let privateKeyExportOptions = {};
|
||||||
|
if (password) privateKeyExportOptions.passphrase = password;
|
||||||
|
const privateKey = await promisify(signedKey.export_pgp_private.bind(signedKey))(privateKeyExportOptions);
|
||||||
|
const publicKey = await promisify(signedKey.export_pgp_public.bind(signedKey))({});
|
||||||
|
resolve(privateKey + "\n" + publicKey.trim());
|
||||||
|
} catch (err) {
|
||||||
|
reject(`Error whilst generating key pair: ${err}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP Encrypt operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async runEncrypt(input, args) {
|
||||||
|
let plaintextMessage = input,
|
||||||
|
plainPubKey = args[0],
|
||||||
|
key,
|
||||||
|
encryptedMessage;
|
||||||
|
|
||||||
|
if (!plainPubKey) return "Enter the public key of the recipient.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
|
||||||
|
armored: plainPubKey,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw `Could not import public key: ${err}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
encryptedMessage = await promisify(kbpgp.box)({
|
||||||
|
"msg": plaintextMessage,
|
||||||
|
"encrypt_for": key,
|
||||||
|
"asp": PGP._ASP
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw `Couldn't encrypt message with provided public key: ${err}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return encryptedMessage.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP Decrypt operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async runDecrypt(input, args) {
|
||||||
|
let encryptedMessage = input,
|
||||||
|
privateKey = args[0],
|
||||||
|
passphrase = args[1],
|
||||||
|
keyring = new kbpgp.keyring.KeyRing(),
|
||||||
|
plaintextMessage;
|
||||||
|
|
||||||
|
if (!privateKey) return "Enter the private key of the recipient.";
|
||||||
|
|
||||||
|
const key = await PGP._importPrivateKey(privateKey, passphrase);
|
||||||
|
keyring.add_key_manager(key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
plaintextMessage = await promisify(kbpgp.unbox)({
|
||||||
|
armored: encryptedMessage,
|
||||||
|
keyfetch: keyring,
|
||||||
|
asp: PGP._ASP
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw `Couldn't decrypt message with provided private key: ${err}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintextMessage.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP Sign Message operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async runSign(input, args) {
|
||||||
|
let message = input,
|
||||||
|
privateKey = args[0],
|
||||||
|
passphrase = args[1],
|
||||||
|
publicKey = args[2],
|
||||||
|
signedMessage;
|
||||||
|
|
||||||
|
if (!privateKey) return "Enter the private key of the signer.";
|
||||||
|
if (!publicKey) return "Enter the public key of the recipient.";
|
||||||
|
const privKey = await PGP._importPrivateKey(privateKey, passphrase);
|
||||||
|
const pubKey = await PGP._importPublicKey(publicKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
signedMessage = await promisify(kbpgp.box)({
|
||||||
|
"msg": message,
|
||||||
|
"encrypt_for": pubKey,
|
||||||
|
"sign_with": privKey,
|
||||||
|
"asp": PGP._ASP
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw `Couldn't sign message: ${err}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return signedMessage;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PGP Verify Message operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async runVerify(input, args) {
|
||||||
|
let signedMessage = input,
|
||||||
|
publicKey = args[0],
|
||||||
|
privateKey = args[1],
|
||||||
|
passphrase = args[2],
|
||||||
|
keyring = new kbpgp.keyring.KeyRing(),
|
||||||
|
unboxedLiterals;
|
||||||
|
|
||||||
|
if (!publicKey) return "Enter the public key of the signer.";
|
||||||
|
if (!privateKey) return "Enter the private key of the recipient.";
|
||||||
|
const privKey = await PGP._importPrivateKey(privateKey, passphrase);
|
||||||
|
const pubKey = await PGP._importPublicKey(publicKey);
|
||||||
|
keyring.add_key_manager(privKey);
|
||||||
|
keyring.add_key_manager(pubKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
unboxedLiterals = await promisify(kbpgp.unbox)({
|
||||||
|
armored: signedMessage,
|
||||||
|
keyfetch: keyring,
|
||||||
|
asp: PGP._ASP
|
||||||
|
});
|
||||||
|
const ds = unboxedLiterals[0].get_data_signer();
|
||||||
|
if (ds) {
|
||||||
|
const km = ds.get_key_manager();
|
||||||
|
if (km) {
|
||||||
|
const signer = km.get_userids_mark_primary()[0].components;
|
||||||
|
let text = "Signed by ";
|
||||||
|
if (signer.email || signer.username || signer.comment) {
|
||||||
|
if (signer.username) {
|
||||||
|
text += `${signer.username} `;
|
||||||
|
}
|
||||||
|
if (signer.comment) {
|
||||||
|
text += `${signer.comment} `;
|
||||||
|
}
|
||||||
|
if (signer.email) {
|
||||||
|
text += `<${signer.email}>`;
|
||||||
|
}
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
text += [
|
||||||
|
`PGP fingerprint: ${km.get_pgp_fingerprint().toString("hex")}`,
|
||||||
|
`Signed on ${new Date(ds.sig.hashed_subpackets[0].time * 1000).toUTCString()}`,
|
||||||
|
"----------------------------------\n"
|
||||||
|
].join("\n");
|
||||||
|
text += unboxedLiterals.toString();
|
||||||
|
return text.trim();
|
||||||
|
} else {
|
||||||
|
return "Could not identify a key manager.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "The data does not appear to be signed.";
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return `Couldn't verify message: ${err}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PGP;
|
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* ToTable operations.
|
||||||
|
*
|
||||||
|
* @author Mark Jones [github.com/justanothermark]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
* @namespace
|
||||||
|
*/
|
||||||
|
import Utils from "../Utils.js";
|
||||||
|
|
||||||
|
const ToTable = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constant
|
||||||
|
* @default
|
||||||
|
*/
|
||||||
|
FORMATS: [
|
||||||
|
"ASCII",
|
||||||
|
"HTML"
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Table operation.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
runToTable: function (input, args) {
|
||||||
|
const [cellDelims, rowDelims, firstRowHeader, format] = args;
|
||||||
|
|
||||||
|
// Process the input into a nested array of elements.
|
||||||
|
const tableData = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
|
||||||
|
|
||||||
|
if (!tableData.length) return "";
|
||||||
|
|
||||||
|
// Render the data in the requested format.
|
||||||
|
switch (format) {
|
||||||
|
case "ASCII":
|
||||||
|
return asciiOutput(tableData);
|
||||||
|
case "HTML":
|
||||||
|
default:
|
||||||
|
return htmlOutput(tableData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs an array of data as an ASCII table.
|
||||||
|
*
|
||||||
|
* @param {string[][]} tableData
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function asciiOutput(tableData) {
|
||||||
|
const horizontalBorder = "-";
|
||||||
|
const verticalBorder = "|";
|
||||||
|
const crossBorder = "+";
|
||||||
|
|
||||||
|
let output = "";
|
||||||
|
let longestCells = [];
|
||||||
|
|
||||||
|
// Find longestCells value per column to pad cells equally.
|
||||||
|
tableData.forEach(function(row, index) {
|
||||||
|
row.forEach(function(cell, cellIndex) {
|
||||||
|
if (longestCells[cellIndex] === undefined || cell.length > longestCells[cellIndex]) {
|
||||||
|
longestCells[cellIndex] = cell.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the top border of the table to the output.
|
||||||
|
output += outputHorizontalBorder(longestCells);
|
||||||
|
|
||||||
|
// If the first row is a header, remove the row from the data and
|
||||||
|
// add it to the output with another horizontal border.
|
||||||
|
if (firstRowHeader) {
|
||||||
|
let row = tableData.shift();
|
||||||
|
output += outputRow(row, longestCells);
|
||||||
|
output += outputHorizontalBorder(longestCells);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest of the table rows.
|
||||||
|
tableData.forEach(function(row, index) {
|
||||||
|
output += outputRow(row, longestCells);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close the table with a final horizontal border.
|
||||||
|
output += outputHorizontalBorder(longestCells);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a row of correctly padded cells.
|
||||||
|
*/
|
||||||
|
function outputRow(row, longestCells) {
|
||||||
|
let rowOutput = verticalBorder;
|
||||||
|
row.forEach(function(cell, index) {
|
||||||
|
rowOutput += " " + cell + " ".repeat(longestCells[index] - cell.length) + " " + verticalBorder;
|
||||||
|
});
|
||||||
|
rowOutput += "\n";
|
||||||
|
return rowOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a horizontal border with a different character where
|
||||||
|
* the horizontal border meets a vertical border.
|
||||||
|
*/
|
||||||
|
function outputHorizontalBorder(longestCells) {
|
||||||
|
let rowOutput = crossBorder;
|
||||||
|
longestCells.forEach(function(cellLength) {
|
||||||
|
rowOutput += horizontalBorder.repeat(cellLength + 2) + crossBorder;
|
||||||
|
});
|
||||||
|
rowOutput += "\n";
|
||||||
|
return rowOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a table of data as a HTML table.
|
||||||
|
*
|
||||||
|
* @param {string[][]} tableData
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function htmlOutput(tableData) {
|
||||||
|
// Start the HTML output with suitable classes for styling.
|
||||||
|
let output = "<table class='table table-hover table-condensed table-bordered table-nonfluid'>";
|
||||||
|
|
||||||
|
// If the first row is a header then put it in <thead> with <th> cells.
|
||||||
|
if (firstRowHeader) {
|
||||||
|
let row = tableData.shift();
|
||||||
|
output += "<thead>";
|
||||||
|
output += outputRow(row, "th");
|
||||||
|
output += "</thead>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the rest of the rows in the <tbody>.
|
||||||
|
output += "<tbody>";
|
||||||
|
tableData.forEach(function(row, index) {
|
||||||
|
output += outputRow(row, "td");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close the body and table elements.
|
||||||
|
output += "</tbody></table>";
|
||||||
|
return output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a table row.
|
||||||
|
*
|
||||||
|
* @param {string[]} row
|
||||||
|
* @param {string} cellType
|
||||||
|
*/
|
||||||
|
function outputRow(row, cellType) {
|
||||||
|
let output = "<tr>";
|
||||||
|
row.forEach(function(cell) {
|
||||||
|
output += "<" + cellType + ">" + cell + "</" + cellType + ">";
|
||||||
|
});
|
||||||
|
output += "</tr>";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToTable;
|
|
@ -83,6 +83,9 @@ App.prototype.loaded = function() {
|
||||||
// Clear the loading message interval
|
// Clear the loading message interval
|
||||||
clearInterval(window.loadingMsgsInt);
|
clearInterval(window.loadingMsgsInt);
|
||||||
|
|
||||||
|
// Remove the loading error handler
|
||||||
|
window.removeEventListener("error", window.loadingErrorHandler);
|
||||||
|
|
||||||
document.dispatchEvent(this.manager.apploaded);
|
document.dispatchEvent(this.manager.apploaded);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define loading messages
|
// Define loading messages
|
||||||
const loadingMsgs = [
|
var loadingMsgs = [
|
||||||
"Proving P = NP...",
|
"Proving P = NP...",
|
||||||
"Computing 6 x 9...",
|
"Computing 6 x 9...",
|
||||||
"Mining bitcoin...",
|
"Mining bitcoin...",
|
||||||
|
@ -66,18 +66,18 @@
|
||||||
|
|
||||||
// Shuffle array using Durstenfeld algorithm
|
// Shuffle array using Durstenfeld algorithm
|
||||||
for (let i = loadingMsgs.length - 1; i > 0; --i) {
|
for (let i = loadingMsgs.length - 1; i > 0; --i) {
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
var j = Math.floor(Math.random() * (i + 1));
|
||||||
const temp = loadingMsgs[i];
|
var temp = loadingMsgs[i];
|
||||||
loadingMsgs[i] = loadingMsgs[j];
|
loadingMsgs[i] = loadingMsgs[j];
|
||||||
loadingMsgs[j] = temp;
|
loadingMsgs[j] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show next loading message and move it to the end of the array
|
// Show next loading message and move it to the end of the array
|
||||||
function changeLoadingMsg() {
|
function changeLoadingMsg() {
|
||||||
const msg = loadingMsgs.shift();
|
var msg = loadingMsgs.shift();
|
||||||
loadingMsgs.push(msg);
|
loadingMsgs.push(msg);
|
||||||
try {
|
try {
|
||||||
const el = document.getElementById("preloader-msg");
|
var el = document.getElementById("preloader-msg");
|
||||||
if (!el.classList.contains("loading"))
|
if (!el.classList.contains("loading"))
|
||||||
el.classList.add("loading"); // Causes CSS transition on first message
|
el.classList.add("loading"); // Causes CSS transition on first message
|
||||||
el.innerHTML = msg;
|
el.innerHTML = msg;
|
||||||
|
@ -86,6 +86,46 @@
|
||||||
|
|
||||||
changeLoadingMsg();
|
changeLoadingMsg();
|
||||||
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 2000) + 1500);
|
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 2000) + 1500);
|
||||||
|
|
||||||
|
// If any errors are thrown during loading, handle them here
|
||||||
|
function loadingErrorHandler(e) {
|
||||||
|
function escapeHtml(str) {
|
||||||
|
var HTML_CHARS = {
|
||||||
|
"&": "&",
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
'"': """,
|
||||||
|
"'": "'", // ' not recommended because it's not in the HTML spec
|
||||||
|
"/": "/", // forward slash is included as it helps end an HTML entity
|
||||||
|
"`": "`"
|
||||||
|
};
|
||||||
|
|
||||||
|
return str.replace(/[&<>"'/`]/g, function (match) {
|
||||||
|
return HTML_CHARS[match];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = e.message +
|
||||||
|
(e.filename ? "\nFilename: " + e.filename : "") +
|
||||||
|
(e.lineno ? "\nLine: " + e.lineno : "") +
|
||||||
|
(e.colno ? "\nColumn: " + e.colno : "") +
|
||||||
|
(e.error ? "\nError: " + e.error : "") +
|
||||||
|
"\nUser-Agent: " + navigator.userAgent +
|
||||||
|
"\nCyberChef version: <%= htmlWebpackPlugin.options.version %>";
|
||||||
|
|
||||||
|
clearInterval(window.loadingMsgsInt);
|
||||||
|
document.getElementById("preloader").remove();
|
||||||
|
document.getElementById("preloader-msg").remove();
|
||||||
|
document.getElementById("preloader-error").innerHTML =
|
||||||
|
"CyberChef encountered an error while loading.<br><br>" +
|
||||||
|
"The following browser versions are supported:" +
|
||||||
|
"<ul><li>Google Chrome 40+</li><li>Mozilla Firefox 35+</li><li>Microsoft Edge 14+</li></ul>" +
|
||||||
|
"Your user agent is:<br>" + escapeHtml(navigator.userAgent) + "<br><br>" +
|
||||||
|
"If your browser is supported, please <a href='https://github.com/gchq/CyberChef/issues/new'>" +
|
||||||
|
"raise an issue</a> including the following details:<br><br>" +
|
||||||
|
"<pre>" + escapeHtml(msg) + "</pre>";
|
||||||
|
};
|
||||||
|
window.addEventListener("error", loadingErrorHandler);
|
||||||
</script>
|
</script>
|
||||||
<% if (htmlWebpackPlugin.options.inline) { %>
|
<% if (htmlWebpackPlugin.options.inline) { %>
|
||||||
<meta name="robots" content="noindex" />
|
<meta name="robots" content="noindex" />
|
||||||
|
@ -100,6 +140,7 @@
|
||||||
<div id="loader-wrapper">
|
<div id="loader-wrapper">
|
||||||
<div id="preloader" class="loader"></div>
|
<div id="preloader" class="loader"></div>
|
||||||
<div id="preloader-msg" class="loading-msg"></div>
|
<div id="preloader-msg" class="loading-msg"></div>
|
||||||
|
<div id="preloader-error" class="loading-error"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End preloader overlay -->
|
<!-- End preloader overlay -->
|
||||||
<span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
|
<span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
|
||||||
|
|
|
@ -64,3 +64,4 @@ window.compileMessage = COMPILE_MSG;
|
||||||
window.CanvasComponents = CanvasComponents;
|
window.CanvasComponents = CanvasComponents;
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", main, false);
|
document.addEventListener("DOMContentLoaded", main, false);
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,14 @@
|
||||||
transition: all 0.1s ease-in;
|
transition: all 0.1s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-error {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 600px;
|
||||||
|
left: calc(50% - 300px);
|
||||||
|
top: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Loaded */
|
/* Loaded */
|
||||||
.loaded .loading-msg {
|
.loaded .loading-msg {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import "./tests/operations/Base64";
|
||||||
// import "./tests/operations/BSON.js";
|
// import "./tests/operations/BSON.js";
|
||||||
// import "./tests/operations/ByteRepr.js";
|
// import "./tests/operations/ByteRepr.js";
|
||||||
// import "./tests/operations/CharEnc.js";
|
// import "./tests/operations/CharEnc.js";
|
||||||
|
//import "./tests/operations/Checksum.js";
|
||||||
// import "./tests/operations/Cipher.js";
|
// import "./tests/operations/Cipher.js";
|
||||||
// import "./tests/operations/Code.js";
|
// import "./tests/operations/Code.js";
|
||||||
// import "./tests/operations/Compress.js";
|
// import "./tests/operations/Compress.js";
|
||||||
|
@ -45,7 +46,7 @@ import "./tests/operations/Base64";
|
||||||
// import "./tests/operations/NetBIOS.js";
|
// import "./tests/operations/NetBIOS.js";
|
||||||
// import "./tests/operations/OTP.js";
|
// import "./tests/operations/OTP.js";
|
||||||
// import "./tests/operations/Regex.js";
|
// import "./tests/operations/Regex.js";
|
||||||
import "./tests/operations/Rotate.mjs";
|
import "./tests/operations/Rotate";
|
||||||
// import "./tests/operations/StrUtils.js";
|
// import "./tests/operations/StrUtils.js";
|
||||||
// import "./tests/operations/SeqUtils.js";
|
// import "./tests/operations/SeqUtils.js";
|
||||||
import "./tests/operations/SetUnion";
|
import "./tests/operations/SetUnion";
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
/**
|
||||||
|
* Checksum tests.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../TestRegister.js";
|
||||||
|
|
||||||
|
const BASIC_STRING = "The ships hung in the sky in much the same way that bricks don't.";
|
||||||
|
const UTF8_STR = "ნუ პანიკას";
|
||||||
|
const ALL_BYTES = [
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||||
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||||
|
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
|
||||||
|
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
|
||||||
|
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
|
||||||
|
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
|
||||||
|
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
|
||||||
|
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
|
||||||
|
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
|
||||||
|
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
|
||||||
|
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
|
||||||
|
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
|
||||||
|
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
|
||||||
|
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
|
||||||
|
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
|
||||||
|
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
|
||||||
|
].join("");
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "CRC-16: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "0000",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-16 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-16: basic string",
|
||||||
|
input: BASIC_STRING,
|
||||||
|
expectedOutput: "0c70",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-16 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-16: UTF-8",
|
||||||
|
input: UTF8_STR,
|
||||||
|
expectedOutput: "dcf6",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-16 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-16: all bytes",
|
||||||
|
input: ALL_BYTES,
|
||||||
|
expectedOutput: "bad3",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-16 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-32: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "00000000",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-32 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-32: basic string",
|
||||||
|
input: BASIC_STRING,
|
||||||
|
expectedOutput: "bf4b739c",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-32 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-32: UTF-8",
|
||||||
|
input: UTF8_STR,
|
||||||
|
expectedOutput: "87553290",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-32 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CRC-32: all bytes",
|
||||||
|
input: ALL_BYTES,
|
||||||
|
expectedOutput: "29058c73",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "CRC-32 Checksum",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]);
|
|
@ -66,7 +66,7 @@ module.exports = {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.m?js$/,
|
test: /\.m?js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules\/(?!jsesc)/,
|
||||||
loader: "babel-loader?compact=false"
|
loader: "babel-loader?compact=false"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -118,7 +118,7 @@ module.exports = {
|
||||||
chunks: false,
|
chunks: false,
|
||||||
modules: false,
|
modules: false,
|
||||||
entrypoints: false,
|
entrypoints: false,
|
||||||
warningsFilter: /source-map/,
|
warningsFilter: [/source-map/, /dependency is an expression/],
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
fs: "empty"
|
fs: "empty"
|
||||||
|
|
Loading…
Reference in New Issue