Merge branch 'master' into feature-threading

This commit is contained in:
n1474335 2017-07-28 16:55:07 +01:00
commit e977a1006c
45 changed files with 3426 additions and 2588 deletions

View file

@ -52,6 +52,9 @@
"no-trailing-spaces": "warn", "no-trailing-spaces": "warn",
"eol-last": "error", "eol-last": "error",
"func-call-spacing": "error", "func-call-spacing": "error",
"key-spacing": ["warn", {
"mode": "minimum"
}],
"indent": ["error", 4, { "indent": ["error", 4, {
"ArrayExpression": "first", "ArrayExpression": "first",
"SwitchCase": 1 "SwitchCase": 1

1882
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{ {
"name": "cyberchef", "name": "cyberchef",
"version": "5.11.0", "version": "5.12.2",
"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",
@ -31,39 +31,39 @@
"bugs": "https://github.com/gchq/CyberChef/issues", "bugs": "https://github.com/gchq/CyberChef/issues",
"devDependencies": { "devDependencies": {
"babel-core": "^6.24.0", "babel-core": "^6.24.0",
"babel-loader": "^6.4.0", "babel-loader": "^7.1.1",
"babel-polyfill": "^6.23.0", "babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.6.0", "babel-preset-env": "^1.6.0",
"babel-regenerator-runtime": "^6.5.0", "babel-regenerator-runtime": "^6.5.0",
"css-loader": "^0.27.3", "css-loader": "^0.28.4",
"exports-loader": "^0.6.4", "exports-loader": "^0.6.4",
"extract-text-webpack-plugin": "^2.1.0", "extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.10.1", "file-loader": "^0.11.2",
"grunt": ">=0.4.5", "grunt": ">=0.4.5",
"grunt-accessibility": "~5.0.0", "grunt-accessibility": "~5.0.0",
"grunt-chmod": "~1.1.1", "grunt-chmod": "~1.1.1",
"grunt-contrib-clean": "~1.0.0", "grunt-contrib-clean": "~1.1.0",
"grunt-contrib-copy": "~1.0.0", "grunt-contrib-copy": "~1.0.0",
"grunt-eslint": "^19.0.0", "grunt-eslint": "^20.0.0",
"grunt-exec": "~1.0.1", "grunt-exec": "~2.0.0",
"grunt-execute": "^0.2.2", "grunt-execute": "^0.2.2",
"grunt-jsdoc": "^2.1.0", "grunt-jsdoc": "^2.1.0",
"grunt-webpack": "^2.0.1", "grunt-webpack": "^3.0.2",
"html-webpack-plugin": "^2.29.0", "html-webpack-plugin": "^2.29.0",
"imports-loader": "^0.7.1", "imports-loader": "^0.7.1",
"ink-docstrap": "^1.1.4", "ink-docstrap": "^1.1.4",
"jsdoc-babel": "^0.3.0", "jsdoc-babel": "^0.3.0",
"less": "^2.7.2", "less": "^2.7.2",
"less-loader": "^4.0.3", "less-loader": "^4.0.5",
"postcss-css-variables": "^0.7.0", "postcss-css-variables": "^0.7.0",
"postcss-import": "^10.0.0", "postcss-import": "^10.0.0",
"postcss-loader": "^2.0.5", "postcss-loader": "^2.0.5",
"style-loader": "^0.15.0", "style-loader": "^0.18.2",
"url-loader": "^0.5.8", "url-loader": "^0.5.8",
"value-loader": "^0.1.3", "value-loader": "^0.1.3",
"web-resource-inliner": "^4.1.0", "web-resource-inliner": "^4.1.0",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.5.0", "webpack-dev-server": "^2.5.0",
"webpack": "^3.3.0",
"worker-loader": "^0.8.0" "worker-loader": "^0.8.0"
}, },
"dependencies": { "dependencies": {
@ -72,15 +72,15 @@
"bootstrap-switch": "^3.3.4", "bootstrap-switch": "^3.3.4",
"crypto-api": "^0.6.2", "crypto-api": "^0.6.2",
"crypto-js": "^3.1.9-1", "crypto-js": "^3.1.9-1",
"diff": "^3.2.0", "diff": "^3.3.0",
"escodegen": "^1.8.1", "escodegen": "^1.8.1",
"esmangle": "^1.0.1", "esmangle": "^1.0.1",
"esprima": "^3.1.3", "esprima": "^4.0.0",
"exif-parser": "^0.1.9", "exif-parser": "^0.1.12",
"google-code-prettify": "^1.0.5", "google-code-prettify": "^1.0.5",
"jquery": "^3.1.1", "jquery": "^3.1.1",
"jsbn": "^1.1.0", "jsbn": "^1.1.0",
"jsrsasign": "7.1.3", "jsrsasign": "8.0.3",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"moment": "^2.17.1", "moment": "^2.17.1",
"moment-timezone": "^0.5.11", "moment-timezone": "^0.5.11",
@ -90,7 +90,7 @@
"vkbeautify": "^0.99.1", "vkbeautify": "^0.99.1",
"xmldom": "^0.1.27", "xmldom": "^0.1.27",
"xpath": "0.0.24", "xpath": "0.0.24",
"zlibjs": "^0.2.0" "zlibjs": "^0.3.1"
}, },
"scripts": { "scripts": {
"start": "grunt dev", "start": "grunt dev",

View file

@ -73,7 +73,7 @@ Ingredient.prepare = function(data, type) {
case "byteArray": case "byteArray":
if (typeof data == "string") { if (typeof data == "string") {
data = data.replace(/\s+/g, ""); data = data.replace(/\s+/g, "");
return Utils.hexToByteArray(data); return Utils.fromHex(data);
} else { } else {
return data; return data;
} }

View file

@ -164,10 +164,10 @@ Recipe.prototype.execute = async function(dish, startFrom) {
if (op.isFlowControl()) { if (op.isFlowControl()) {
// Package up the current state // Package up the current state
let state = { let state = {
"progress" : i, "progress": i,
"dish" : dish, "dish": dish,
"opList" : this.opList, "opList": this.opList,
"numJumps" : numJumps "numJumps": numJumps
}; };
state = await op.run(state); state = await op.run(state);

View file

@ -293,7 +293,7 @@ const Utils = {
* Utils.escapeRegex("[example]"); * Utils.escapeRegex("[example]");
*/ */
escapeRegex: function(str) { escapeRegex: function(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
}, },
@ -340,50 +340,6 @@ const Utils = {
}, },
/**
* Translates a hex string into an array of bytes.
*
* @param {string} hexStr
* @returns {byteArray}
*
* @example
* // returns [0xfe, 0x09, 0xa7]
* Utils.hexToByteArray("fe09a7");
*/
hexToByteArray: function(hexStr) {
// TODO: Handle errors i.e. input string is not hex
if (!hexStr) return [];
hexStr = hexStr.replace(/\s+/g, "");
const byteArray = [];
for (let i = 0; i < hexStr.length; i += 2) {
byteArray.push(parseInt(hexStr.substr(i, 2), 16));
}
return byteArray;
},
/**
* Translates an array of bytes to a hex string.
*
* @param {byteArray} byteArray
* @param {string} [delim=" "]
* @returns {string}
*
* @example
* // returns "fe09a7"
* Utils.byteArrayToHex([0xfe, 0x09, 0xa7], "");
*/
byteArrayToHex: function(byteArray, delim) {
if (!byteArray) return "";
delim = typeof delim === "undefined" ? " " : delim;
let hexStr = "";
for (let i = 0; i < byteArray.length; i++) {
hexStr += Utils.hex(byteArray[i]) + delim;
}
return hexStr.slice(0, hexStr.length - delim.length);
},
/** /**
* Converts a string to a byte array. * Converts a string to a byte array.
* Treats the string as UTF-8 if any values are over 255. * Treats the string as UTF-8 if any values are over 255.
@ -636,7 +592,7 @@ const Utils = {
i = 0; i = 0;
if (removeNonAlphChars) { if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[\[\]\\\-^$]/g, "\\$&") + "]", "g"); const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
data = data.replace(re, ""); data = data.replace(re, "");
} }
@ -828,7 +784,7 @@ const Utils = {
if (removeScriptAndStyle) { if (removeScriptAndStyle) {
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, ""); htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
} }
return htmlStr.replace(/<[^>\n]+>/g, ""); return htmlStr.replace(/<[^>]+>/g, "");
}, },
@ -854,7 +810,7 @@ const Utils = {
"`": "&#x60;" "`": "&#x60;"
}; };
return str.replace(/[&<>"'\/`]/g, function (match) { return str.replace(/[&<>"'/`]/g, function (match) {
return HTML_CHARS[match]; return HTML_CHARS[match];
}); });
}, },
@ -946,16 +902,19 @@ const Utils = {
* @returns {html} * @returns {html}
*/ */
displayFilesAsHTML: function(files) { displayFilesAsHTML: function(files) {
/* <NL> and <SP> used to denote newlines and spaces in HTML markup.
* If a non-html operation is used, all markup will be removed but these
* whitespace chars will remain for formatting purposes.
*/
const formatDirectory = function(file) { const formatDirectory = function(file) {
const html = "<div class='panel panel-default'>" + const html = `<div class='panel panel-default' style='white-space: normal;'>
"<div class='panel-heading' role='tab'>" + <div class='panel-heading' role='tab'>
"<h4 class='panel-title'>" + <h4 class='panel-title'>
Utils.escapeHtml(file.fileName) + <NL>${Utils.escapeHtml(file.fileName)}
// The following line is for formatting when HTML is stripped </h4>
"<span style='display: none'>\n0 bytes\n</span>" + </div>
"</h4>" + </div>`;
"</div>" +
"</div>";
return html; return html;
}; };
@ -966,45 +925,52 @@ const Utils = {
); );
const blobUrl = URL.createObjectURL(blob); const blobUrl = URL.createObjectURL(blob);
const downloadAnchorElem = "<a href='" + blobUrl + "' " + const viewFileElem = `<a href='#collapse${i}'
"title='Download " + Utils.escapeHtml(file.fileName) + "' " + class='collapsed'
"download='" + Utils.escapeHtml(file.fileName) + "'>\u21B4</a>"; data-toggle='collapse'
aria-expanded='true'
aria-controls='collapse${i}'
title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">&#x1f441;&#xfe0f;</a>`;
const expandFileContentsElem = "<a href='#collapse" + i + "' " + const downloadFileElem = `<a href='${blobUrl}'
"class='collapsed' " + title='Download ${Utils.escapeHtml(file.fileName)}'
"data-toggle='collapse' " + download='${Utils.escapeHtml(file.fileName)}'>&#x1f4be;</a>`;
"aria-expanded='true' " +
"aria-controls='collapse" + i + "' " +
"title=\"Show/hide contents of '" + Utils.escapeHtml(file.fileName) + "'\">&#x1F50D</a>";
const html = "<div class='panel panel-default'>" + const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
"<div class='panel-heading' role='tab' id='heading" + i + "'>" +
"<h4 class='panel-title'>" + const switchToInputElem = `<a href='#switchFileToInput${i}'
"<div>" + class='file-switch'
Utils.escapeHtml(file.fileName) + title='Move file to input as hex'
" " + expandFileContentsElem + fileValue='${hexFileData}'>&#x21e7;</a>`;
" " + downloadAnchorElem +
"<span class='pull-right'>" + const html = `<div class='panel panel-default' style='white-space: normal;'>
// These are for formatting when stripping HTML <div class='panel-heading' role='tab' id='heading${i}'>
"<span style='display: none'>\n</span>" + <h4 class='panel-title'>
file.size.toLocaleString() + " bytes" + <div>
"<span style='display: none'>\n</span>" + ${Utils.escapeHtml(file.fileName)}<NL>
"</span>" + ${viewFileElem}<SP>
"</div>" + ${downloadFileElem}<SP>
"</h4>" + ${switchToInputElem}<SP>
"</div>" + <span class='pull-right'>
"<div id='collapse" + i + "' class='panel-collapse collapse' " + <NL>${file.size.toLocaleString()} bytes
"role='tabpanel' aria-labelledby='heading" + i + "'>" + </span>
"<div class='panel-body'>" + </div>
"<pre><code>" + Utils.escapeHtml(file.contents) + "</pre></code></div>" + </h4>
"</div>" + </div>
"</div>"; <div id='collapse${i}' class='panel-collapse collapse'
role='tabpanel' aria-labelledby='heading${i}'>
<div class='panel-body'>
<NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
</div>
</div>
</div>`;
return html; return html;
}; };
let html = "<div style='padding: 5px;'>" + let html = `<div style='padding: 5px; white-space: normal;'>
files.length + ${files.length} file(s) found<NL>
" file(s) found</div>\n"; </div>`;
files.forEach(function(file, i) { files.forEach(function(file, i) {
if (typeof file.contents !== "undefined") { if (typeof file.contents !== "undefined") {
html += formatFile(file, i); html += formatFile(file, i);
@ -1012,7 +978,10 @@ const Utils = {
html += formatDirectory(file); html += formatDirectory(file);
} }
}); });
return html;
return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
.replace(/<NL>/g, "\n") // Replace <NP> with newlines
.replace(/<SP>/g, " "); // Replace <SP> with spaces
}, },
@ -1031,9 +1000,14 @@ const Utils = {
if (paramStr === "") return {}; if (paramStr === "") return {};
// Cut off ? or # and split on & // Cut off ? or # and split on &
const params = paramStr.substr(1).split("&"); if (paramStr[0] === "?" ||
paramStr[0] === "#") {
paramStr = paramStr.substr(1);
}
const params = paramStr.split("&");
const result = {}; const result = {};
for (let i = 0; i < params.length; i++) { for (let i = 0; i < params.length; i++) {
const param = params[i].split("="); const param = params[i].split("=");
if (param.length !== 2) { if (param.length !== 2) {

View file

@ -46,6 +46,8 @@ const Categories = [
"From Base58", "From Base58",
"To Base", "To Base",
"From Base", "From Base",
"To BCD",
"From BCD",
"To HTML Entity", "To HTML Entity",
"From HTML Entity", "From HTML Entity",
"URL Encode", "URL Encode",

View file

@ -2,6 +2,7 @@ import FlowControl from "../FlowControl.js";
import Base from "../operations/Base.js"; import Base from "../operations/Base.js";
import Base58 from "../operations/Base58.js"; import Base58 from "../operations/Base58.js";
import Base64 from "../operations/Base64.js"; import Base64 from "../operations/Base64.js";
import BCD from "../operations/BCD.js";
import BitwiseOp from "../operations/BitwiseOp.js"; import BitwiseOp from "../operations/BitwiseOp.js";
import ByteRepr from "../operations/ByteRepr.js"; import ByteRepr from "../operations/ByteRepr.js";
import CharEnc from "../operations/CharEnc.js"; import CharEnc from "../operations/CharEnc.js";
@ -330,30 +331,25 @@ const OperationConfig = {
value: BitwiseOp.XOR_BRUTE_KEY_LENGTH value: BitwiseOp.XOR_BRUTE_KEY_LENGTH
}, },
{ {
name: "Length of sample", name: "Sample length",
type: "number", type: "number",
value: BitwiseOp.XOR_BRUTE_SAMPLE_LENGTH value: BitwiseOp.XOR_BRUTE_SAMPLE_LENGTH
}, },
{ {
name: "Offset of sample", name: "Sample offset",
type: "number", type: "number",
value: BitwiseOp.XOR_BRUTE_SAMPLE_OFFSET value: BitwiseOp.XOR_BRUTE_SAMPLE_OFFSET
}, },
{
name: "Scheme",
type: "option",
value: BitwiseOp.XOR_SCHEME
},
{ {
name: "Null preserving", name: "Null preserving",
type: "boolean", type: "boolean",
value: BitwiseOp.XOR_PRESERVE_NULLS value: BitwiseOp.XOR_PRESERVE_NULLS
}, },
{
name: "Differential",
type: "boolean",
value: BitwiseOp.XOR_DIFFERENTIAL
},
{
name: "Crib (known plaintext string)",
type: "binaryString",
value: ""
},
{ {
name: "Print key", name: "Print key",
type: "boolean", type: "boolean",
@ -363,6 +359,11 @@ const OperationConfig = {
name: "Output as hex", name: "Output as hex",
type: "boolean", type: "boolean",
value: BitwiseOp.XOR_BRUTE_OUTPUT_HEX value: BitwiseOp.XOR_BRUTE_OUTPUT_HEX
},
{
name: "Crib (known plaintext string)",
type: "binaryString",
value: ""
} }
] ]
}, },
@ -2301,6 +2302,11 @@ const OperationConfig = {
name: "Output units", name: "Output units",
type: "option", type: "option",
value: DateTime.UNITS value: DateTime.UNITS
},
{
name: "Input format",
type: "option",
value: DateTime.FILETIME_FORMATS
} }
] ]
}, },
@ -2314,6 +2320,11 @@ const OperationConfig = {
name: "Input units", name: "Input units",
type: "option", type: "option",
value: DateTime.UNITS value: DateTime.UNITS
},
{
name: "Output format",
type: "option",
value: DateTime.FILETIME_FORMATS
} }
] ]
}, },
@ -3497,6 +3508,64 @@ const OperationConfig = {
} }
] ]
}, },
"From BCD": {
description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign.",
run: BCD.runFromBCD,
inputType: "string",
outputType: "number",
args: [
{
name: "Scheme",
type: "option",
value: BCD.ENCODING_SCHEME
},
{
name: "Packed",
type: "boolean",
value: true
},
{
name: "Signed",
type: "boolean",
value: false
},
{
name: "Input format",
type: "option",
value: BCD.FORMAT
}
]
},
"To BCD": {
description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign",
run: BCD.runToBCD,
inputType: "number",
outputType: "string",
args: [
{
name: "Scheme",
type: "option",
value: BCD.ENCODING_SCHEME
},
{
name: "Packed",
type: "boolean",
value: true
},
{
name: "Signed",
type: "boolean",
value: false
},
{
name: "Output format",
type: "option",
value: BCD.FORMAT
}
]
},
}; };
export default OperationConfig; export default OperationConfig;

214
src/core/operations/BCD.js Executable file
View file

@ -0,0 +1,214 @@
import Utils from "../Utils.js";
/**
* Binary-Coded Decimal operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
* @namespace
*/
const BCD = {
/**
* @constant
* @default
*/
ENCODING_SCHEME: [
"8 4 2 1",
"7 4 2 1",
"4 2 2 1",
"2 4 2 1",
"8 4 -2 -1",
"Excess-3",
"IBM 8 4 2 1",
],
/**
* Lookup table for the binary value of each digit representation.
*
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
* but unfortunately it's much easier (if less elegant) to use lookup tables
* when supporting multiple encoding schemes.
*
* "Practicality beats purity" - PEP 20
*
* In some schemes it is possible to represent the same value in multiple ways.
* For instance, in 4 2 2 1 encoding, 0100 and 0010 both represent 2. Support
* has not yet been added for this.
*
* @constant
*/
ENCODING_LOOKUP: {
"8 4 2 1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"7 4 2 1": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10],
"4 2 2 1": [0, 1, 4, 5, 8, 9, 12, 13, 14, 15],
"2 4 2 1": [0, 1, 2, 3, 4, 11, 12, 13, 14, 15],
"8 4 -2 -1": [0, 7, 6, 5, 4, 11, 10, 9, 8, 15],
"Excess-3": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"IBM 8 4 2 1": [10, 1, 2, 3, 4, 5, 6, 7, 8, 9],
},
/**
* @default
* @constant
*/
FORMAT: ["Nibbles", "Bytes", "Raw"],
/**
* To BCD operation.
*
* @param {number} input
* @param {Object[]} args
* @returns {string}
*/
runToBCD: function(input, args) {
if (isNaN(input))
return "Invalid input";
if (Math.floor(input) !== input)
return "Fractional values are not supported by BCD";
const encoding = BCD.ENCODING_LOOKUP[args[0]],
packed = args[1],
signed = args[2],
outputFormat = args[3];
// Split input number up into separate digits
const digits = input.toString().split("");
if (digits[0] === "-" || digits[0] === "+") {
digits.shift();
}
let nibbles = [];
digits.forEach(d => {
const n = parseInt(d, 10);
nibbles.push(encoding[n]);
});
if (signed) {
if (packed && digits.length % 2 === 0) {
// If there are an even number of digits, we add a leading 0 so
// that the sign nibble doesn't sit in its own byte, leading to
// ambiguity around whether the number ends with a 0 or not.
nibbles.unshift(encoding[0]);
}
nibbles.push(input > 0 ? 12 : 13);
// 12 ("C") for + (credit)
// 13 ("D") for - (debit)
}
let bytes = [];
if (packed) {
let encoded = 0,
little = false;
nibbles.forEach(n => {
encoded ^= little ? n : (n << 4);
if (little) {
bytes.push(encoded);
encoded = 0;
}
little = !little;
});
if (little) bytes.push(encoded);
} else {
bytes = nibbles;
// Add null high nibbles
nibbles = nibbles.map(n => {
return [0, n];
}).reduce((a, b) => {
return a.concat(b);
});
}
// Output
switch (outputFormat) {
case "Nibbles":
return nibbles.map(n => {
return Utils.padLeft(n.toString(2), 4);
}).join(" ");
case "Bytes":
return bytes.map(b => {
return Utils.padLeft(b.toString(2), 8);
}).join(" ");
case "Raw":
default:
return Utils.byteArrayToChars(bytes);
}
},
/**
* From BCD operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
runFromBCD: function(input, args) {
const encoding = BCD.ENCODING_LOOKUP[args[0]],
packed = args[1],
signed = args[2],
inputFormat = args[3];
let nibbles = [],
output = "",
byteArray;
// Normalise the input
switch (inputFormat) {
case "Nibbles":
case "Bytes":
input = input.replace(/\s/g, "");
for (let i = 0; i < input.length; i += 4) {
nibbles.push(parseInt(input.substr(i, 4), 2));
}
break;
case "Raw":
default:
byteArray = Utils.strToByteArray(input);
byteArray.forEach(b => {
nibbles.push(b >>> 4);
nibbles.push(b & 15);
});
break;
}
if (!packed) {
// Discard each high nibble
for (let i = 0; i < nibbles.length; i++) {
nibbles.splice(i, 1);
}
}
if (signed) {
const sign = nibbles.pop();
if (sign === 13 ||
sign === 11) {
// Negative
output += "-";
}
}
nibbles.forEach(n => {
if (isNaN(n)) throw "Invalid input";
let val = encoding.indexOf(n);
if (val < 0) throw `Value ${Utils.bin(n, 4)} not in encoding scheme`;
output += val.toString();
});
return parseInt(output, 10);
},
};
export default BCD;

View file

@ -221,15 +221,15 @@ const Base64 = {
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" + offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" + Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" + "<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>"; "<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
} else if (len0 % 4 === 3) { } else if (len0 % 4 === 3) {
staticSection = offset0.slice(0, -2); staticSection = offset0.slice(0, -2);
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" + offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" + Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" + "<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>"; "<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
} else { } else {
staticSection = offset0; staticSection = offset0;
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" + offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
@ -243,23 +243,23 @@ const Base64 = {
// Highlight offset 1 // Highlight offset 1
padding = "<span class='hlred'>" + offset1.substr(0, 1) + "</span>" + padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
"<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>"; "<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
offset1 = offset1.substr(2); offset1 = offset1.substr(2);
if (len1 % 4 === 2) { if (len1 % 4 === 2) {
staticSection = offset1.slice(0, -3); staticSection = offset1.slice(0, -3);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" + Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" + "<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>"; "<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
} else if (len1 % 4 === 3) { } else if (len1 % 4 === 3) {
staticSection = offset1.slice(0, -2); staticSection = offset1.slice(0, -2);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" + Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" + "<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>"; "<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
} else { } else {
staticSection = offset1; staticSection = offset1;
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
@ -272,23 +272,23 @@ const Base64 = {
} }
// Highlight offset 2 // Highlight offset 2
padding = "<span class='hlred'>" + offset2.substr(0, 2) + "</span>" + padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
"<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>"; "<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
offset2 = offset2.substr(3); offset2 = offset2.substr(3);
if (len2 % 4 === 2) { if (len2 % 4 === 2) {
staticSection = offset2.slice(0, -3); staticSection = offset2.slice(0, -3);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" + Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" + "<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>"; "<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
} else if (len2 % 4 === 3) { } else if (len2 % 4 === 3) {
staticSection = offset2.slice(0, -2); staticSection = offset2.slice(0, -2);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" + Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
staticSection + "</span>" + staticSection + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" + "<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>"; "<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
} else { } else {
staticSection = offset2; staticSection = offset2;
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" + offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
@ -300,8 +300,8 @@ const Base64 = {
offset2 = staticSection; offset2 = staticSection;
} }
return (showVariable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." + return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
"\nCharacters highlighted in <span class='hlred'>red</span> are for padding purposes only." + "\nCharacters highlighted in <span class='hl3'>red</span> are for padding purposes only." +
"\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." + "\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
"\nHover over the static sections to see what they decode to on their own.\n" + "\nHover over the static sections to see what they decode to on their own.\n" +
"\nOffset 0: " + offset0 + "\nOffset 0: " + offset0 +

View file

@ -36,7 +36,9 @@ const BitwiseOp = {
o = input[i]; o = input[i];
x = nullPreserving && (o === 0 || o === k) ? o : func(o, k); x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
result.push(x); result.push(x);
if (scheme !== "Standard" && !(nullPreserving && (o === 0 || o === k))) { if (scheme &&
scheme !== "Standard" &&
!(nullPreserving && (o === 0 || o === k))) {
switch (scheme) { switch (scheme) {
case "Input differential": case "Input differential":
key[i % key.length] = x; key[i % key.length] = x;
@ -120,19 +122,19 @@ const BitwiseOp = {
* @returns {string} * @returns {string}
*/ */
runXorBrute: function (input, args) { runXorBrute: function (input, args) {
let keyLength = parseInt(args[0], 10), const keyLength = parseInt(args[0], 10),
sampleLength = args[1], sampleLength = args[1],
sampleOffset = args[2], sampleOffset = args[2],
nullPreserving = args[3], scheme = args[3],
differential = args[4], nullPreserving = args[4],
crib = args[5], printKey = args[5],
printKey = args[6], outputHex = args[6],
outputHex = args[7], crib = args[7];
regex;
let output = "", let output = "",
result, result,
resultUtf8; resultUtf8,
regex;
input = input.slice(sampleOffset, sampleOffset + sampleLength); input = input.slice(sampleOffset, sampleOffset + sampleLength);
@ -142,14 +144,12 @@ const BitwiseOp = {
for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) { for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
result = BitwiseOp._bitOp(input, Utils.hexToByteArray(key.toString(16)), BitwiseOp._xor, nullPreserving, differential); result = BitwiseOp._bitOp(input, Utils.fromHex(key.toString(16)), BitwiseOp._xor, nullPreserving, scheme);
resultUtf8 = Utils.byteArrayToUtf8(result); resultUtf8 = Utils.byteArrayToUtf8(result);
if (crib !== "" && resultUtf8.search(regex) === -1) continue; if (crib !== "" && resultUtf8.search(regex) === -1) continue;
if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": "; if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
if (outputHex) if (outputHex) output += Utils.toHex(result) + "\n";
output += Utils.byteArrayToHex(result) + "\n"; else output += Utils.printable(resultUtf8, false) + "\n";
else
output += Utils.printable(resultUtf8, false) + "\n";
if (printKey) output += "\n"; if (printKey) output += "\n";
} }
return output; return output;

View file

@ -329,7 +329,7 @@ const Code = {
* @param {Object[]} args * @param {Object[]} args
* @returns {string} * @returns {string}
*/ */
runXpath:function(input, args) { runXpath: function(input, args) {
let query = args[0], let query = args[0],
delimiter = args[1]; delimiter = args[1];

View file

@ -54,9 +54,9 @@ const Compress = {
* @default * @default
*/ */
RAW_COMPRESSION_TYPE_LOOKUP: { RAW_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.RawDeflate.CompressionType.FIXED, "Fixed Huffman Coding": Zlib.RawDeflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.RawDeflate.CompressionType.DYNAMIC, "Dynamic Huffman Coding": Zlib.RawDeflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.RawDeflate.CompressionType.NONE, "None (Store)": Zlib.RawDeflate.CompressionType.NONE,
}, },
/** /**
@ -99,8 +99,8 @@ const Compress = {
* @default * @default
*/ */
RAW_BUFFER_TYPE_LOOKUP: { RAW_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE, "Adaptive": Zlib.RawInflate.BufferType.ADAPTIVE,
"Block" : Zlib.RawInflate.BufferType.BLOCK, "Block": Zlib.RawInflate.BufferType.BLOCK,
}, },
/** /**
@ -150,9 +150,9 @@ const Compress = {
* @default * @default
*/ */
ZLIB_COMPRESSION_TYPE_LOOKUP: { ZLIB_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.Deflate.CompressionType.FIXED, "Fixed Huffman Coding": Zlib.Deflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.Deflate.CompressionType.DYNAMIC, "Dynamic Huffman Coding": Zlib.Deflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.Deflate.CompressionType.NONE, "None (Store)": Zlib.Deflate.CompressionType.NONE,
}, },
/** /**
@ -175,8 +175,8 @@ const Compress = {
* @default * @default
*/ */
ZLIB_BUFFER_TYPE_LOOKUP: { ZLIB_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.Inflate.BufferType.ADAPTIVE, "Adaptive": Zlib.Inflate.BufferType.ADAPTIVE,
"Block" : Zlib.Inflate.BufferType.BLOCK, "Block": Zlib.Inflate.BufferType.BLOCK,
}, },
/** /**
@ -264,17 +264,17 @@ const Compress = {
* @default * @default
*/ */
ZIP_COMPRESSION_METHOD_LOOKUP: { ZIP_COMPRESSION_METHOD_LOOKUP: {
"Deflate" : Zlib.Zip.CompressionMethod.DEFLATE, "Deflate": Zlib.Zip.CompressionMethod.DEFLATE,
"None (Store)" : Zlib.Zip.CompressionMethod.STORE "None (Store)": Zlib.Zip.CompressionMethod.STORE
}, },
/** /**
* @constant * @constant
* @default * @default
*/ */
ZIP_OS_LOOKUP: { ZIP_OS_LOOKUP: {
"MSDOS" : Zlib.Zip.OperatingSystem.MSDOS, "MSDOS": Zlib.Zip.OperatingSystem.MSDOS,
"Unix" : Zlib.Zip.OperatingSystem.UNIX, "Unix": Zlib.Zip.OperatingSystem.UNIX,
"Macintosh" : Zlib.Zip.OperatingSystem.MACINTOSH "Macintosh": Zlib.Zip.OperatingSystem.MACINTOSH
}, },
/** /**

View file

@ -25,36 +25,36 @@ const Convert = {
* @default * @default
*/ */
DISTANCE_FACTOR: { // Multiples of a metre DISTANCE_FACTOR: { // Multiples of a metre
"Nanometres (nm)" : 1e-9, "Nanometres (nm)": 1e-9,
"Micrometres (µm)" : 1e-6, "Micrometres (µm)": 1e-6,
"Millimetres (mm)" : 1e-3, "Millimetres (mm)": 1e-3,
"Centimetres (cm)" : 1e-2, "Centimetres (cm)": 1e-2,
"Metres (m)" : 1, "Metres (m)": 1,
"Kilometers (km)" : 1e3, "Kilometers (km)": 1e3,
"Thou (th)" : 0.0000254, "Thou (th)": 0.0000254,
"Inches (in)" : 0.0254, "Inches (in)": 0.0254,
"Feet (ft)" : 0.3048, "Feet (ft)": 0.3048,
"Yards (yd)" : 0.9144, "Yards (yd)": 0.9144,
"Chains (ch)" : 20.1168, "Chains (ch)": 20.1168,
"Furlongs (fur)" : 201.168, "Furlongs (fur)": 201.168,
"Miles (mi)" : 1609.344, "Miles (mi)": 1609.344,
"Leagues (lea)" : 4828.032, "Leagues (lea)": 4828.032,
"Fathoms (ftm)" : 1.853184, "Fathoms (ftm)": 1.853184,
"Cables" : 185.3184, "Cables": 185.3184,
"Nautical miles" : 1853.184, "Nautical miles": 1853.184,
"Cars (4m)" : 4, "Cars (4m)": 4,
"Buses (8.4m)" : 8.4, "Buses (8.4m)": 8.4,
"American football fields (91m)": 91, "American football fields (91m)": 91,
"Football pitches (105m)": 105, "Football pitches (105m)": 105,
"Earth-to-Moons" : 380000000, "Earth-to-Moons": 380000000,
"Earth's equators" : 40075016.686, "Earth's equators": 40075016.686,
"Astronomical units (au)": 149597870700, "Astronomical units (au)": 149597870700,
"Light-years (ly)" : 9460730472580800, "Light-years (ly)": 9460730472580800,
"Parsecs (pc)" : 3.0856776e16 "Parsecs (pc)": 3.0856776e16
}, },
/** /**
@ -90,52 +90,52 @@ const Convert = {
* @default * @default
*/ */
DATA_FACTOR: { // Multiples of a bit DATA_FACTOR: { // Multiples of a bit
"Bits (b)" : 1, "Bits (b)": 1,
"Nibbles" : 4, "Nibbles": 4,
"Octets" : 8, "Octets": 8,
"Bytes (B)" : 8, "Bytes (B)": 8,
// Binary bits (2^n) // Binary bits (2^n)
"Kibibits (Kib)" : 1024, "Kibibits (Kib)": 1024,
"Mebibits (Mib)" : 1048576, "Mebibits (Mib)": 1048576,
"Gibibits (Gib)" : 1073741824, "Gibibits (Gib)": 1073741824,
"Tebibits (Tib)" : 1099511627776, "Tebibits (Tib)": 1099511627776,
"Pebibits (Pib)" : 1125899906842624, "Pebibits (Pib)": 1125899906842624,
"Exbibits (Eib)" : 1152921504606846976, "Exbibits (Eib)": 1152921504606846976,
"Zebibits (Zib)" : 1180591620717411303424, "Zebibits (Zib)": 1180591620717411303424,
"Yobibits (Yib)" : 1208925819614629174706176, "Yobibits (Yib)": 1208925819614629174706176,
// Decimal bits (10^n) // Decimal bits (10^n)
"Decabits" : 10, "Decabits": 10,
"Hectobits" : 100, "Hectobits": 100,
"Kilobits (Kb)" : 1e3, "Kilobits (Kb)": 1e3,
"Megabits (Mb)" : 1e6, "Megabits (Mb)": 1e6,
"Gigabits (Gb)" : 1e9, "Gigabits (Gb)": 1e9,
"Terabits (Tb)" : 1e12, "Terabits (Tb)": 1e12,
"Petabits (Pb)" : 1e15, "Petabits (Pb)": 1e15,
"Exabits (Eb)" : 1e18, "Exabits (Eb)": 1e18,
"Zettabits (Zb)" : 1e21, "Zettabits (Zb)": 1e21,
"Yottabits (Yb)" : 1e24, "Yottabits (Yb)": 1e24,
// Binary bytes (8 x 2^n) // Binary bytes (8 x 2^n)
"Kibibytes (KiB)" : 8192, "Kibibytes (KiB)": 8192,
"Mebibytes (MiB)" : 8388608, "Mebibytes (MiB)": 8388608,
"Gibibytes (GiB)" : 8589934592, "Gibibytes (GiB)": 8589934592,
"Tebibytes (TiB)" : 8796093022208, "Tebibytes (TiB)": 8796093022208,
"Pebibytes (PiB)" : 9007199254740992, "Pebibytes (PiB)": 9007199254740992,
"Exbibytes (EiB)" : 9223372036854775808, "Exbibytes (EiB)": 9223372036854775808,
"Zebibytes (ZiB)" : 9444732965739290427392, "Zebibytes (ZiB)": 9444732965739290427392,
"Yobibytes (YiB)" : 9671406556917033397649408, "Yobibytes (YiB)": 9671406556917033397649408,
// Decimal bytes (8 x 10^n) // Decimal bytes (8 x 10^n)
"Kilobytes (KB)" : 8e3, "Kilobytes (KB)": 8e3,
"Megabytes (MB)" : 8e6, "Megabytes (MB)": 8e6,
"Gigabytes (GB)" : 8e9, "Gigabytes (GB)": 8e9,
"Terabytes (TB)" : 8e12, "Terabytes (TB)": 8e12,
"Petabytes (PB)" : 8e15, "Petabytes (PB)": 8e15,
"Exabytes (EB)" : 8e18, "Exabytes (EB)": 8e18,
"Zettabytes (ZB)" : 8e21, "Zettabytes (ZB)": 8e21,
"Yottabytes (YB)" : 8e24, "Yottabytes (YB)": 8e24,
}, },
/** /**
@ -171,51 +171,51 @@ const Convert = {
*/ */
AREA_FACTOR: { // Multiples of a square metre AREA_FACTOR: { // Multiples of a square metre
// Metric // Metric
"Square metre (sq m)" : 1, "Square metre (sq m)": 1,
"Square kilometre (sq km)" : 1e6, "Square kilometre (sq km)": 1e6,
"Centiare (ca)" : 1, "Centiare (ca)": 1,
"Deciare (da)" : 10, "Deciare (da)": 10,
"Are (a)" : 100, "Are (a)": 100,
"Decare (daa)" : 1e3, "Decare (daa)": 1e3,
"Hectare (ha)" : 1e4, "Hectare (ha)": 1e4,
// Imperial // Imperial
"Square inch (sq in)" : 0.00064516, "Square inch (sq in)": 0.00064516,
"Square foot (sq ft)" : 0.09290304, "Square foot (sq ft)": 0.09290304,
"Square yard (sq yd)" : 0.83612736, "Square yard (sq yd)": 0.83612736,
"Square mile (sq mi)" : 2589988.110336, "Square mile (sq mi)": 2589988.110336,
"Perch (sq per)" : 42.21, "Perch (sq per)": 42.21,
"Rood (ro)" : 1011, "Rood (ro)": 1011,
"International acre (ac)" : 4046.8564224, "International acre (ac)": 4046.8564224,
// US customary units // US customary units
"US survey acre (ac)" : 4046.87261, "US survey acre (ac)": 4046.87261,
"US survey square mile (sq mi)" : 2589998.470305239, "US survey square mile (sq mi)": 2589998.470305239,
"US survey township" : 93239944.9309886, "US survey township": 93239944.9309886,
// Nuclear physics // Nuclear physics
"Yoctobarn (yb)" : 1e-52, "Yoctobarn (yb)": 1e-52,
"Zeptobarn (zb)" : 1e-49, "Zeptobarn (zb)": 1e-49,
"Attobarn (ab)" : 1e-46, "Attobarn (ab)": 1e-46,
"Femtobarn (fb)" : 1e-43, "Femtobarn (fb)": 1e-43,
"Picobarn (pb)" : 1e-40, "Picobarn (pb)": 1e-40,
"Nanobarn (nb)" : 1e-37, "Nanobarn (nb)": 1e-37,
"Microbarn (μb)" : 1e-34, "Microbarn (μb)": 1e-34,
"Millibarn (mb)" : 1e-31, "Millibarn (mb)": 1e-31,
"Barn (b)" : 1e-28, "Barn (b)": 1e-28,
"Kilobarn (kb)" : 1e-25, "Kilobarn (kb)": 1e-25,
"Megabarn (Mb)" : 1e-22, "Megabarn (Mb)": 1e-22,
"Planck area" : 2.6e-70, "Planck area": 2.6e-70,
"Shed" : 1e-52, "Shed": 1e-52,
"Outhouse" : 1e-34, "Outhouse": 1e-34,
// Comparisons // Comparisons
"Washington D.C." : 176119191.502848, "Washington D.C.": 176119191.502848,
"Isle of Wight" : 380000000, "Isle of Wight": 380000000,
"Wales" : 20779000000, "Wales": 20779000000,
"Texas" : 696241000000, "Texas": 696241000000,
}, },
/** /**
@ -252,81 +252,81 @@ const Convert = {
*/ */
MASS_FACTOR: { // Multiples of a gram MASS_FACTOR: { // Multiples of a gram
// Metric // Metric
"Yoctogram (yg)" : 1e-24, "Yoctogram (yg)": 1e-24,
"Zeptogram (zg)" : 1e-21, "Zeptogram (zg)": 1e-21,
"Attogram (ag)" : 1e-18, "Attogram (ag)": 1e-18,
"Femtogram (fg)" : 1e-15, "Femtogram (fg)": 1e-15,
"Picogram (pg)" : 1e-12, "Picogram (pg)": 1e-12,
"Nanogram (ng)" : 1e-9, "Nanogram (ng)": 1e-9,
"Microgram (μg)" : 1e-6, "Microgram (μg)": 1e-6,
"Milligram (mg)" : 1e-3, "Milligram (mg)": 1e-3,
"Centigram (cg)" : 1e-2, "Centigram (cg)": 1e-2,
"Decigram (dg)" : 1e-1, "Decigram (dg)": 1e-1,
"Gram (g)" : 1, "Gram (g)": 1,
"Decagram (dag)" : 10, "Decagram (dag)": 10,
"Hectogram (hg)" : 100, "Hectogram (hg)": 100,
"Kilogram (kg)" : 1000, "Kilogram (kg)": 1000,
"Megagram (Mg)" : 1e6, "Megagram (Mg)": 1e6,
"Tonne (t)" : 1e6, "Tonne (t)": 1e6,
"Gigagram (Gg)" : 1e9, "Gigagram (Gg)": 1e9,
"Teragram (Tg)" : 1e12, "Teragram (Tg)": 1e12,
"Petagram (Pg)" : 1e15, "Petagram (Pg)": 1e15,
"Exagram (Eg)" : 1e18, "Exagram (Eg)": 1e18,
"Zettagram (Zg)" : 1e21, "Zettagram (Zg)": 1e21,
"Yottagram (Yg)" : 1e24, "Yottagram (Yg)": 1e24,
// Imperial Avoirdupois // Imperial Avoirdupois
"Grain (gr)" : 64.79891e-3, "Grain (gr)": 64.79891e-3,
"Dram (dr)" : 1.7718451953125, "Dram (dr)": 1.7718451953125,
"Ounce (oz)" : 28.349523125, "Ounce (oz)": 28.349523125,
"Pound (lb)" : 453.59237, "Pound (lb)": 453.59237,
"Nail" : 3175.14659, "Nail": 3175.14659,
"Stone (st)" : 6.35029318e3, "Stone (st)": 6.35029318e3,
"Quarter (gr)" : 12700.58636, "Quarter (gr)": 12700.58636,
"Tod" : 12700.58636, "Tod": 12700.58636,
"US hundredweight (cwt)" : 45.359237e3, "US hundredweight (cwt)": 45.359237e3,
"Imperial hundredweight (cwt)" : 50.80234544e3, "Imperial hundredweight (cwt)": 50.80234544e3,
"US ton (t)" : 907.18474e3, "US ton (t)": 907.18474e3,
"Imperial ton (t)" : 1016.0469088e3, "Imperial ton (t)": 1016.0469088e3,
// Imperial Troy // Imperial Troy
"Pennyweight (dwt)" : 1.55517384, "Pennyweight (dwt)": 1.55517384,
"Troy dram (dr t)" : 3.8879346, "Troy dram (dr t)": 3.8879346,
"Troy ounce (oz t)" : 31.1034768, "Troy ounce (oz t)": 31.1034768,
"Troy pound (lb t)" : 373.2417216, "Troy pound (lb t)": 373.2417216,
"Mark" : 248.8278144, "Mark": 248.8278144,
// Archaic // Archaic
"Wey" : 76.5e3, "Wey": 76.5e3,
"Wool wey" : 101.7e3, "Wool wey": 101.7e3,
"Suffolk wey" : 161.5e3, "Suffolk wey": 161.5e3,
"Wool sack" : 153000, "Wool sack": 153000,
"Coal sack" : 50.80234544e3, "Coal sack": 50.80234544e3,
"Load" : 918000, "Load": 918000,
"Last" : 1836000, "Last": 1836000,
"Flax or feather last" : 770e3, "Flax or feather last": 770e3,
"Gunpowder last" : 1090e3, "Gunpowder last": 1090e3,
"Picul" : 60.478982e3, "Picul": 60.478982e3,
"Rice last" : 1200e3, "Rice last": 1200e3,
// Comparisons // Comparisons
"Big Ben (14 tonnes)" : 14e6, "Big Ben (14 tonnes)": 14e6,
"Blue whale (180 tonnes)" : 180e6, "Blue whale (180 tonnes)": 180e6,
"International Space Station (417 tonnes)" : 417e6, "International Space Station (417 tonnes)": 417e6,
"Space Shuttle (2,041 tonnes)" : 2041e6, "Space Shuttle (2,041 tonnes)": 2041e6,
"RMS Titanic (52,000 tonnes)" : 52000e6, "RMS Titanic (52,000 tonnes)": 52000e6,
"Great Pyramid of Giza (6,000,000 tonnes)" : 6e12, "Great Pyramid of Giza (6,000,000 tonnes)": 6e12,
"Earth's oceans (1.4 yottagrams)" : 1.4e24, "Earth's oceans (1.4 yottagrams)": 1.4e24,
// Astronomical // Astronomical
"A teaspoon of neutron star (5,500 million tonnes)" : 5.5e15, "A teaspoon of neutron star (5,500 million tonnes)": 5.5e15,
"Lunar mass (ML)" : 7.342e25, "Lunar mass (ML)": 7.342e25,
"Earth mass (M⊕)" : 5.97219e27, "Earth mass (M⊕)": 5.97219e27,
"Jupiter mass (MJ)" : 1.8981411476999997e30, "Jupiter mass (MJ)": 1.8981411476999997e30,
"Solar mass (M☉)" : 1.98855e33, "Solar mass (M☉)": 1.98855e33,
"Sagittarius A* (7.5 x 10^36 kgs-ish)" : 7.5e39, "Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39,
"Milky Way galaxy (1.2 x 10^42 kgs)" : 1.2e45, "Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45,
"The observable universe (1.45 x 10^53 kgs)" : 1.45e56, "The observable universe (1.45 x 10^53 kgs)": 1.45e56,
}, },
/** /**
@ -361,37 +361,37 @@ const Convert = {
*/ */
SPEED_FACTOR: { // Multiples of m/s SPEED_FACTOR: { // Multiples of m/s
// Metric // Metric
"Metres per second (m/s)" : 1, "Metres per second (m/s)": 1,
"Kilometres per hour (km/h)" : 0.2778, "Kilometres per hour (km/h)": 0.2778,
// Imperial // Imperial
"Miles per hour (mph)" : 0.44704, "Miles per hour (mph)": 0.44704,
"Knots (kn)" : 0.5144, "Knots (kn)": 0.5144,
// Comparisons // Comparisons
"Human hair growth rate" : 4.8e-9, "Human hair growth rate": 4.8e-9,
"Bamboo growth rate" : 1.4e-5, "Bamboo growth rate": 1.4e-5,
"World's fastest snail" : 0.00275, "World's fastest snail": 0.00275,
"Usain Bolt's top speed" : 12.42, "Usain Bolt's top speed": 12.42,
"Jet airliner cruising speed" : 250, "Jet airliner cruising speed": 250,
"Concorde" : 603, "Concorde": 603,
"SR-71 Blackbird" : 981, "SR-71 Blackbird": 981,
"Space Shuttle" : 1400, "Space Shuttle": 1400,
"International Space Station" : 7700, "International Space Station": 7700,
// Scientific // Scientific
"Sound in standard atmosphere" : 340.3, "Sound in standard atmosphere": 340.3,
"Sound in water" : 1500, "Sound in water": 1500,
"Lunar escape velocity" : 2375, "Lunar escape velocity": 2375,
"Earth escape velocity" : 11200, "Earth escape velocity": 11200,
"Earth's solar orbit" : 29800, "Earth's solar orbit": 29800,
"Solar system's Milky Way orbit" : 200000, "Solar system's Milky Way orbit": 200000,
"Milky Way relative to the cosmic microwave background" : 552000, "Milky Way relative to the cosmic microwave background": 552000,
"Solar escape velocity" : 617700, "Solar escape velocity": 617700,
"Neutron star escape velocity (0.3c)" : 100000000, "Neutron star escape velocity (0.3c)": 100000000,
"Light in a diamond (0.4136c)" : 124000000, "Light in a diamond (0.4136c)": 124000000,
"Signal in an optical fibre (0.667c)" : 200000000, "Signal in an optical fibre (0.667c)": 200000000,
"Light (c)" : 299792458, "Light (c)": 299792458,
}, },
/** /**

View file

@ -89,8 +89,17 @@ const DateTime = {
* @returns {string} * @returns {string}
*/ */
runFromFiletimeToUnix: function(input, args) { runFromFiletimeToUnix: function(input, args) {
let units = args[0]; let units = args[0],
input = new BigInteger(input).subtract(new BigInteger("116444736000000000")); format = args[1];
if (format === "Hex") {
input = new BigInteger(input, 16);
} else {
input = new BigInteger(input);
}
input = input.subtract(new BigInteger("116444736000000000"));
if (units === "Seconds (s)"){ if (units === "Seconds (s)"){
input = input.divide(new BigInteger("10000000")); input = input.divide(new BigInteger("10000000"));
} else if (units === "Milliseconds (ms)") { } else if (units === "Milliseconds (ms)") {
@ -102,6 +111,7 @@ const DateTime = {
} else { } else {
throw "Unrecognised unit"; throw "Unrecognised unit";
} }
return input.toString(); return input.toString();
}, },
@ -115,8 +125,11 @@ const DateTime = {
* @returns {string} * @returns {string}
*/ */
runToFiletimeFromUnix: function(input, args) { runToFiletimeFromUnix: function(input, args) {
let units = args[0]; let units = args[0],
format = args[1];
input = new BigInteger(input); input = new BigInteger(input);
if (units === "Seconds (s)"){ if (units === "Seconds (s)"){
input = input.multiply(new BigInteger("10000000")); input = input.multiply(new BigInteger("10000000"));
} else if (units === "Milliseconds (ms)") { } else if (units === "Milliseconds (ms)") {
@ -128,10 +141,24 @@ const DateTime = {
} else { } else {
throw "Unrecognised unit"; throw "Unrecognised unit";
} }
return input.add(new BigInteger("116444736000000000")).toString();
input = input.add(new BigInteger("116444736000000000"));
if (format === "Hex"){
return input.toString(16);
} else {
return input.toString();
}
}, },
/**
* @constant
* @default
*/
FILETIME_FORMATS: ["Decimal", "Hex"],
/** /**
* @constant * @constant
* @default * @default

File diff suppressed because it is too large Load diff

View file

@ -283,7 +283,7 @@ const IP = {
baIp.push(decimal & 255); baIp.push(decimal & 255);
break; break;
case "Hex": case "Hex":
baIp = Utils.hexToByteArray(lines[i]); baIp = Utils.fromHex(lines[i]);
break; break;
default: default:
throw "Unsupported input IP format"; throw "Unsupported input IP format";
@ -516,7 +516,7 @@ const IP = {
"<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>"; "<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>";
if (ihl > 5) { if (ihl > 5) {
output += "<tr><td>Options</td><td>" + Utils.byteArrayToHex(options) + "</td></tr>"; output += "<tr><td>Options</td><td>" + Utils.toHex(options) + "</td></tr>";
} }
return output + "</table>"; return output + "</table>";

View file

@ -1,4 +1,4 @@
import esprima from "esprima"; import * as esprima from "esprima";
import escodegen from "escodegen"; import escodegen from "escodegen";
import esmangle from "esmangle"; import esmangle from "esmangle";
@ -62,7 +62,7 @@ const JS = {
tolerant: parseTolerant tolerant: parseTolerant
}; };
result = esprima.parse(input, options); result = esprima.parseScript(input, options);
return JSON.stringify(result, null, 2); return JSON.stringify(result, null, 2);
}, },
@ -104,7 +104,7 @@ const JS = {
AST; AST;
try { try {
AST = esprima.parse(input, { AST = esprima.parseScript(input, {
range: true, range: true,
tokens: true, tokens: true,
comment: true comment: true
@ -142,7 +142,7 @@ const JS = {
*/ */
runMinify: function(input, args) { runMinify: function(input, args) {
let result = "", let result = "",
AST = esprima.parse(input), AST = esprima.parseScript(input),
optimisedAST = esmangle.optimize(AST, null), optimisedAST = esmangle.optimize(AST, null),
mangledAST = esmangle.mangle(optimisedAST); mangledAST = esmangle.mangle(optimisedAST);

View file

@ -18,25 +18,25 @@ const OS = {
*/ */
runParseUnixPerms: function(input, args) { runParseUnixPerms: function(input, args) {
let perms = { let perms = {
d : false, // directory d: false, // directory
sl : false, // symbolic link sl: false, // symbolic link
np : false, // named pipe np: false, // named pipe
s : false, // socket s: false, // socket
cd : false, // character device cd: false, // character device
bd : false, // block device bd: false, // block device
dr : false, // door dr: false, // door
sb : false, // sticky bit sb: false, // sticky bit
su : false, // setuid su: false, // setuid
sg : false, // setgid sg: false, // setgid
ru : false, // read user ru: false, // read user
wu : false, // write user wu: false, // write user
eu : false, // execute user eu: false, // execute user
rg : false, // read group rg: false, // read group
wg : false, // write group wg: false, // write group
eg : false, // execute group eg: false, // execute group
ro : false, // read other ro: false, // read other
wo : false, // write other wo: false, // write other
eo : false // execute other eo: false // execute other
}, },
d = 0, d = 0,
u = 0, u = 0,

File diff suppressed because it is too large Load diff

View file

@ -61,7 +61,7 @@ const QuotedPrintable = {
* @returns {byteArray} * @returns {byteArray}
*/ */
runFrom: function (input, args) { runFrom: function (input, args) {
const str = input.replace(/\=(?:\r?\n|$)/g, ""); const str = input.replace(/=(?:\r?\n|$)/g, "");
return QuotedPrintable.mimeDecode(str); return QuotedPrintable.mimeDecode(str);
}, },
@ -73,7 +73,7 @@ const QuotedPrintable = {
* @returns {byteArray} * @returns {byteArray}
*/ */
mimeDecode: function(str) { mimeDecode: function(str) {
let encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length, let encodedBytesCount = (str.match(/=[\da-fA-F]{2}/g) || []).length,
bufferLength = str.length - encodedBytesCount * 2, bufferLength = str.length - encodedBytesCount * 2,
chr, hex, chr, hex,
buffer = new Array(bufferLength), buffer = new Array(bufferLength),
@ -219,21 +219,21 @@ const QuotedPrintable = {
result += line; result += line;
pos += line.length; pos += line.length;
continue; continue;
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) { } else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t.,!?][^ \t.,!?]*$/))) {
// truncate to nearest space // truncate to nearest space
line = line.substr(0, line.length - (match[0].length - 1)); line = line.substr(0, line.length - (match[0].length - 1));
} else if (line.substr(-1) === "\r") { } else if (line.substr(-1) === "\r") {
line = line.substr(0, line.length - 1); line = line.substr(0, line.length - 1);
} else { } else {
if (line.match(/\=[\da-f]{0,2}$/i)) { if (line.match(/=[\da-f]{0,2}$/i)) {
// push incomplete encoding sequences to the next line // push incomplete encoding sequences to the next line
if ((match = line.match(/\=[\da-f]{0,1}$/i))) { if ((match = line.match(/=[\da-f]{0,1}$/i))) {
line = line.substr(0, line.length - match[0].length); line = line.substr(0, line.length - match[0].length);
} }
// ensure that utf-8 sequences are not split // ensure that utf-8 sequences are not split
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/\=[\da-f]{2}$/ig))) { while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/=[\da-f]{2}$/ig))) {
code = parseInt(match[0].substr(1, 2), 16); code = parseInt(match[0].substr(1, 2), 16);
if (code < 128) { if (code < 128) {
break; break;
@ -250,7 +250,7 @@ const QuotedPrintable = {
} }
if (pos + line.length < len && line.substr(-1) !== "\n") { if (pos + line.length < len && line.substr(-1) !== "\n") {
if (line.length === 76 && line.match(/\=[\da-f]{2}$/i)) { if (line.length === 76 && line.match(/=[\da-f]{2}$/i)) {
line = line.substr(0, line.length - 3); line = line.substr(0, line.length - 3);
} else if (line.length === 76) { } else if (line.length === 76) {
line = line.substr(0, line.length - 1); line = line.substr(0, line.length - 1);

View file

@ -193,17 +193,17 @@ const StrUtils = {
* @constant * @constant
* @default * @default
*/ */
FIND_REPLACE_GLOBAL : true, FIND_REPLACE_GLOBAL: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
FIND_REPLACE_CASE : false, FIND_REPLACE_CASE: false,
/** /**
* @constant * @constant
* @default * @default
*/ */
FIND_REPLACE_MULTILINE : true, FIND_REPLACE_MULTILINE: true,
/** /**
* Find / Replace operation. * Find / Replace operation.
@ -359,9 +359,9 @@ const StrUtils = {
for (let i = 0; i < diff.length; i++) { for (let i = 0; i < diff.length; i++) {
if (diff[i].added) { if (diff[i].added) {
if (showAdded) output += "<span class='hlgreen'>" + Utils.escapeHtml(diff[i].value) + "</span>"; if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else if (diff[i].removed) { } else if (diff[i].removed) {
if (showRemoved) output += "<span class='hlred'>" + Utils.escapeHtml(diff[i].value) + "</span>"; if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else { } else {
output += Utils.escapeHtml(diff[i].value); output += Utils.escapeHtml(diff[i].value);
} }
@ -424,7 +424,7 @@ const StrUtils = {
} }
if (match && !inMatch) { if (match && !inMatch) {
outputs[s] += "<span class='hlgreen'>" + Utils.escapeHtml(samples[s][i]); outputs[s] += "<span class='hl5'>" + Utils.escapeHtml(samples[s][i]);
if (samples[s].length === i + 1) outputs[s] += "</span>"; if (samples[s].length === i + 1) outputs[s] += "</span>";
if (s === samples.length - 1) inMatch = true; if (s === samples.length - 1) inMatch = true;
} else if (!match && inMatch) { } else if (!match && inMatch) {

View file

@ -16,32 +16,32 @@ const Tidy = {
* @constant * @constant
* @default * @default
*/ */
REMOVE_SPACES : true, REMOVE_SPACES: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
REMOVE_CARIAGE_RETURNS : true, REMOVE_CARIAGE_RETURNS: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
REMOVE_LINE_FEEDS : true, REMOVE_LINE_FEEDS: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
REMOVE_TABS : true, REMOVE_TABS: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
REMOVE_FORM_FEEDS : true, REMOVE_FORM_FEEDS: true,
/** /**
* @constant * @constant
* @default * @default
*/ */
REMOVE_FULL_STOPS : false, REMOVE_FULL_STOPS: false,
/** /**
* Remove whitespace operation. * Remove whitespace operation.
@ -89,17 +89,17 @@ const Tidy = {
* @constant * @constant
* @default * @default
*/ */
APPLY_TO_EACH_LINE : false, APPLY_TO_EACH_LINE: false,
/** /**
* @constant * @constant
* @default * @default
*/ */
DROP_START : 0, DROP_START: 0,
/** /**
* @constant * @constant
* @default * @default
*/ */
DROP_LENGTH : 5, DROP_LENGTH: 5,
/** /**
* Drop bytes operation. * Drop bytes operation.
@ -200,17 +200,17 @@ const Tidy = {
* @constant * @constant
* @default * @default
*/ */
PAD_POSITION : ["Start", "End"], PAD_POSITION: ["Start", "End"],
/** /**
* @constant * @constant
* @default * @default
*/ */
PAD_LENGTH : 5, PAD_LENGTH: 5,
/** /**
* @constant * @constant
* @default * @default
*/ */
PAD_CHAR : " ", PAD_CHAR: " ",
/** /**
* Pad lines operation. * Pad lines operation.

View file

@ -127,7 +127,7 @@ const URL_ = {
.replace(/\(/g, "%28") .replace(/\(/g, "%28")
.replace(/\)/g, "%29") .replace(/\)/g, "%29")
.replace(/\*/g, "%2A") .replace(/\*/g, "%2A")
.replace(/\-/g, "%2D") .replace(/-/g, "%2D")
.replace(/\./g, "%2E") .replace(/\./g, "%2E")
.replace(/_/g, "%5F") .replace(/_/g, "%5F")
.replace(/~/g, "%7E"); .replace(/~/g, "%7E");

View file

@ -266,13 +266,7 @@ App.prototype.silentBake = function() {
* @returns {string} * @returns {string}
*/ */
App.prototype.getInput = function() { App.prototype.getInput = function() {
const input = this.manager.input.get(); return this.manager.input.get();
// Save to session storage in case we need to restore it later
sessionStorage.setItem("inputLength", input.length);
sessionStorage.setItem("input", input);
return input;
}; };
@ -282,8 +276,6 @@ App.prototype.getInput = function() {
* @param {string} input - The string to set the input to * @param {string} input - The string to set the input to
*/ */
App.prototype.setInput = function(input) { App.prototype.setInput = function(input) {
sessionStorage.setItem("inputLength", input.length);
sessionStorage.setItem("input", input);
this.manager.input.set(input); this.manager.input.set(input);
}; };
@ -466,7 +458,12 @@ App.prototype.addFavourite = function(name) {
*/ */
App.prototype.loadURIParams = function() { App.prototype.loadURIParams = function() {
// Load query string or hash from URI (depending on which is populated) // Load query string or hash from URI (depending on which is populated)
const params = window.location.search || window.location.hash; // We prefer getting the hash by splitting the href rather than referencing
// location.hash as some browsers (Firefox) automatically URL decode it,
// which cause issues.
const params = window.location.search ||
window.location.href.split("#")[1] ||
window.location.hash;
this.uriParams = Utils.parseURIParams(params); this.uriParams = Utils.parseURIParams(params);
// Pause auto-bake while loading but don't modify `this.autoBake_` // Pause auto-bake while loading but don't modify `this.autoBake_`
@ -529,9 +526,7 @@ App.prototype.nextIngId = function() {
* @returns {Object[]} * @returns {Object[]}
*/ */
App.prototype.getRecipeConfig = function() { App.prototype.getRecipeConfig = function() {
const recipeConfig = this.manager.recipe.getConfig(); return this.manager.recipe.getConfig();
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
return recipeConfig;
}; };
@ -541,7 +536,6 @@ App.prototype.getRecipeConfig = function() {
* @param {Object[]} recipeConfig - The recipe configuration * @param {Object[]} recipeConfig - The recipe configuration
*/ */
App.prototype.setRecipeConfig = function(recipeConfig) { App.prototype.setRecipeConfig = function(recipeConfig) {
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
document.getElementById("rec-list").innerHTML = null; document.getElementById("rec-list").innerHTML = null;
for (let i = 0; i < recipeConfig.length; i++) { for (let i = 0; i < recipeConfig.length; i++) {
@ -596,15 +590,24 @@ App.prototype.resetLayout = function() {
App.prototype.setCompileMessage = function() { App.prototype.setCompileMessage = function() {
// Display time since last build and compile message // Display time since last build and compile message
let now = new Date(), let now = new Date(),
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime), timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime);
compileInfo = "<span style=\"font-weight: normal\">Last build: " +
timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1) + " ago"; // Calculate previous version to compare to
let prev = PKG_VERSION.split(".").map(n => {
return parseInt(n, 10);
});
if (prev[2] > 0) prev[2]--;
else if (prev[1] > 0) prev[1]--;
else prev[0]--;
const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
let compileInfo = `<a href='${compareURL}'>Last build: ${timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1)} ago</a>`;
if (window.compileMessage !== "") { if (window.compileMessage !== "") {
compileInfo += " - " + window.compileMessage; compileInfo += " - " + window.compileMessage;
} }
compileInfo += "</span>";
document.getElementById("notice").innerHTML = compileInfo; document.getElementById("notice").innerHTML = compileInfo;
}; };
@ -729,10 +732,20 @@ App.prototype.alertCloseClick = function() {
App.prototype.stateChange = function(e) { App.prototype.stateChange = function(e) {
this.autoBake(); this.autoBake();
// Set title
const recipeConfig = this.getRecipeConfig();
let title = "CyberChef";
if (recipeConfig.length === 1) {
title = `${recipeConfig[0].op} - ${title}`;
} else if (recipeConfig.length > 1) {
title = `${recipeConfig.length} operations - ${title}`;
}
document.title = title;
// Update the current history state (not creating a new one) // Update the current history state (not creating a new one)
if (this.options.updateUrl) { if (this.options.updateUrl) {
this.lastStateUrl = this.manager.controls.generateStateUrl(true, true); this.lastStateUrl = this.manager.controls.generateStateUrl(true, true, recipeConfig);
window.history.replaceState({}, "CyberChef", this.lastStateUrl); window.history.replaceState({}, title, this.lastStateUrl);
} }
}; };

View file

@ -493,7 +493,8 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
//if (colour) cssClass += "-"+colour; //if (colour) cssClass += "-"+colour;
// Remove HTML tags // Remove HTML tags
text = text.replace(/&/g, "&amp;") text = text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;") .replace(/</g, "&lt;")
.replace(/>/g, "&gt;") .replace(/>/g, "&gt;")
.replace(/\n/g, "&#10;") .replace(/\n/g, "&#10;")

View file

@ -166,7 +166,7 @@ InputWaiter.prototype.inputDrop = function(e) {
this.set(inputCharcode); this.set(inputCharcode);
const recipeConfig = this.app.getRecipeConfig(); const recipeConfig = this.app.getRecipeConfig();
if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") { if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
recipeConfig.unshift({op:"From Hex", args:["Space"]}); recipeConfig.unshift({op: "From Hex", args: ["Space"]});
this.app.setRecipeConfig(recipeConfig); this.app.setRecipeConfig(recipeConfig);
} }

View file

@ -145,6 +145,7 @@ Manager.prototype.initialiseEventListeners = function() {
document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter)); document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
this.addMultiEventListener("#output-text", "mousedown dblclick select", this.highlighter.outputMousedown, this.highlighter); this.addMultiEventListener("#output-text", "mousedown dblclick select", this.highlighter.outputMousedown, this.highlighter);
this.addMultiEventListener("#output-html", "mousedown dblclick select", this.highlighter.outputHtmlMousedown, this.highlighter); this.addMultiEventListener("#output-html", "mousedown dblclick select", this.highlighter.outputHtmlMousedown, this.highlighter);
this.addDynamicListener(".file-switch", "click", this.output.fileSwitch, this.output);
// Options // Options
document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options)); document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));

View file

@ -167,6 +167,17 @@ OutputWaiter.prototype.undoSwitchClick = function() {
document.getElementById("undo-switch").disabled = true; document.getElementById("undo-switch").disabled = true;
}; };
/**
* Handler for file switch click events.
* Moves a files data for items created via Utils.displayFilesAsHTML to the input.
*/
OutputWaiter.prototype.fileSwitch = function(e) {
e.preventDefault();
this.switchOrigData = this.manager.input.get();
this.app.setInput(e.target.getAttribute("fileValue"));
document.getElementById("undo-switch").disabled = false;
};
/** /**
* Handler for maximise output click events. * Handler for maximise output click events.

View file

@ -26,12 +26,14 @@
<title>CyberChef</title> <title>CyberChef</title>
<meta name="copyright" content="Crown Copyright 2016" /> <meta name="copyright" content="Crown Copyright 2016" />
<meta name="description" content="The Cyber Swiss Army Knife" /> <meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" /> <meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" /> <link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
<script type="application/javascript"> <script type="application/javascript">
"use strict";
// Load theme before the preloader is shown // Load theme before the preloader is shown
document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme; document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme;
@ -72,6 +74,11 @@
changeLoadingMsg(); changeLoadingMsg();
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000); window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000);
</script> </script>
<% if (!htmlWebpackPlugin.options.inline) { %>
<script type="application/ld+json">
<% print(JSON.stringify(require("../static/structuredData.json"))); %>
</script>
<% } %>
</head> </head>
<body> <body>
<!-- Preloader overlay --> <!-- Preloader overlay -->
@ -87,11 +94,14 @@
</div> </div>
<div id="content-wrapper"> <div id="content-wrapper">
<div id="banner"> <div id="banner">
<div class="col-md-4" style="text-align: left; padding-left: 10px;">
<% if (htmlWebpackPlugin.options.inline) { %> <% if (htmlWebpackPlugin.options.inline) { %>
<span style="float: left; margin-left: 10px;">Compile time: <%= htmlWebpackPlugin.options.compileTime %></span> <span>Version <%= htmlWebpackPlugin.options.version %></span>
<% } else { %> <% } else { %>
<a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a> <a href="cyberchef.htm" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
<% } %> <% } %>
</div>
<div class="col-md-4" style="text-align: center;">
<span id="notice"> <span id="notice">
<script type="text/javascript"> <script type="text/javascript">
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it... // Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
@ -102,8 +112,11 @@
</script> </script>
<noscript>JavaScript is not enabled. Good luck.</noscript> <noscript>JavaScript is not enabled. Good luck.</noscript>
</span> </span>
<a href="#" id="support" class="banner-right" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a> </div>
<a href="#" id="options" class="banner-right">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a> <div class="col-md-4" style="text-align: right; padding-right: 0;">
<a href="#" id="options">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
<a href="#" id="support" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
</div>
</div> </div>
<div id="workspace-wrapper"> <div id="workspace-wrapper">
<div id="operations" class="split split-horizontal no-select"> <div id="operations" class="split split-horizontal no-select">
@ -266,32 +279,32 @@
<label for="theme"> Theme (only supported in modern browsers)</label> <label for="theme"> Theme (only supported in modern browsers)</label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="checkbox" option="update_url" id="update_url" checked /> <input type="checkbox" option="updateUrl" id="updateUrl" checked />
<label for="update_url"> Update the URL when the input or recipe changes </label> <label for="updateUrl"> Update the URL when the input or recipe changes </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="checkbox" option="show_highlighter" id="show_highlighter" checked /> <input type="checkbox" option="showHighlighter" id="showHighlighter" checked />
<label for="show_highlighter"> Highlight selected bytes in output and input (when possible) </label> <label for="showHighlighter"> Highlight selected bytes in output and input (when possible) </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="checkbox" option="treat_as_utf8" id="treat_as_utf8" checked /> <input type="checkbox" option="treatAsUtf8" id="treatAsUtf8" checked />
<label for="treat_as_utf8"> Treat output as UTF-8 if possible </label> <label for="treatAsUtf8"> Treat output as UTF-8 if possible </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="checkbox" option="word_wrap" id="word_wrap" checked /> <input type="checkbox" option="wordWrap" id="wordWrap" checked />
<label for="word_wrap"> Word wrap the input and output </label> <label for="wordWrap"> Word wrap the input and output </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="checkbox" option="show_errors" id="show_errors" checked /> <input type="checkbox" option="showErrors" id="showErrors" checked />
<label for="show_errors"> Operation error reporting (recommended) </label> <label for="showErrors"> Operation error reporting (recommended) </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="number" option="error_timeout" id="error_timeout" /> <input type="number" option="errorTimeout" id="errorTimeout" />
<label for="error_timeout"> Operation error timeout in ms (0 for never) </label> <label for="errorTimeout"> Operation error timeout in ms (0 for never) </label>
</div> </div>
<div class="option-item"> <div class="option-item">
<input type="number" option="auto_bake_threshold" id="auto_bake_threshold"/> <input type="number" option="autoBakeThreshold" id="autoBakeThreshold"/>
<label for="auto_bake_threshold"> Auto Bake threshold in ms </label> <label for="autoBakeThreshold"> Auto Bake threshold in ms </label>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View file

@ -38,15 +38,15 @@ function main() {
]; ];
const defaultOptions = { const defaultOptions = {
updateUrl : true, updateUrl: true,
showHighlighter : true, showHighlighter: true,
treatAsUtf8 : true, treatAsUtf8: true,
wordWrap : true, wordWrap: true,
showErrors : true, showErrors: true,
errorTimeout : 4000, errorTimeout: 4000,
autoBakeThreshold : 200, autoBakeThreshold: 200,
attemptHighlight : true, attemptHighlight: true,
theme : "classic", theme: "classic",
}; };
document.removeEventListener("DOMContentLoaded", main, false); document.removeEventListener("DOMContentLoaded", main, false);

View file

@ -0,0 +1,23 @@
[
{
"@context": "http://schema.org",
"@type": "Organization",
"url": "https://gchq.github.io/CyberChef/",
"logo": "https://gchq.github.io/CyberChef/images/cyberchef-128x128.png",
"sameAs": [
"https://github.com/gchq/CyberChef",
"https://www.npmjs.com/package/cyberchef"
]
},
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": "https://gchq.github.io/CyberChef/",
"name": "CyberChef",
"potentialAction": {
"@type": "SearchAction",
"target": "https://gchq.github.io/CyberChef/?op={operation_search_term}",
"query-input": "required name=operation_search_term"
}
}
]

View file

@ -59,6 +59,7 @@
background-color: var(--arg-background); background-color: var(--arg-background);
border: 1px solid var(--arg-border-colour); border: 1px solid var(--arg-border-colour);
font-family: var(--fixed-width-font-family); font-family: var(--fixed-width-font-family);
text-overflow: ellipsis;
} }
.short-string { .short-string {

View file

@ -10,19 +10,15 @@
position: absolute; position: absolute;
height: 30px; height: 30px;
width: 100%; width: 100%;
text-align: center;
line-height: 30px; line-height: 30px;
border-bottom: 1px solid var(--primary-border-colour); border-bottom: 1px solid var(--primary-border-colour);
color: var(--banner-font-colour); color: var(--banner-font-colour);
background-color: var(--banner-bg-colour); background-color: var(--banner-bg-colour);
} }
.banner-right {
float: right;
margin-right: 10px;
}
#banner img { #banner img {
margin-bottom: 2px; margin-bottom: 2px;
margin-left: 8px; margin-left: 8px;
padding-right: 10px;
} }

View file

@ -46,8 +46,7 @@ import Chef from "../src/core/Chef.js";
{}, {},
0, 0,
false false
) ).then(function(result) {
.then(function(result) {
const ret = { const ret = {
test: test, test: test,
status: null, status: null,

View file

@ -12,6 +12,7 @@ import "babel-polyfill";
import TestRegister from "./TestRegister.js"; import TestRegister from "./TestRegister.js";
import "./tests/operations/Base58.js"; import "./tests/operations/Base58.js";
import "./tests/operations/BCD.js";
import "./tests/operations/ByteRepr.js"; import "./tests/operations/ByteRepr.js";
import "./tests/operations/CharEnc.js"; import "./tests/operations/CharEnc.js";
import "./tests/operations/Cipher.js"; import "./tests/operations/Cipher.js";

View file

@ -0,0 +1,103 @@
/**
* BCD tests
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
import TestRegister from "../../TestRegister.js";
TestRegister.addTests([
{
name: "To BCD: default 0",
input: "0",
expectedOutput: "0000",
recipeConfig: [
{
"op": "To BCD",
"args": ["8 4 2 1", true, false, "Nibbles"]
}
]
},
{
name: "To BCD: unpacked nibbles",
input: "1234567890",
expectedOutput: "0000 0001 0000 0010 0000 0011 0000 0100 0000 0101 0000 0110 0000 0111 0000 1000 0000 1001 0000 0000",
recipeConfig: [
{
"op": "To BCD",
"args": ["8 4 2 1", false, false, "Nibbles"]
}
]
},
{
name: "To BCD: packed, signed bytes",
input: "1234567890",
expectedOutput: "00000001 00100011 01000101 01100111 10001001 00001100",
recipeConfig: [
{
"op": "To BCD",
"args": ["8 4 2 1", true, true, "Bytes"]
}
]
},
{
name: "To BCD: packed, signed nibbles, 8 4 -2 -1",
input: "-1234567890",
expectedOutput: "0000 0111 0110 0101 0100 1011 1010 1001 1000 1111 0000 1101",
recipeConfig: [
{
"op": "To BCD",
"args": ["8 4 -2 -1", true, true, "Nibbles"]
}
]
},
{
name: "From BCD: default 0",
input: "0000",
expectedOutput: "0",
recipeConfig: [
{
"op": "From BCD",
"args": ["8 4 2 1", true, false, "Nibbles"]
}
]
},
{
name: "From BCD: packed, signed bytes",
input: "00000001 00100011 01000101 01100111 10001001 00001101",
expectedOutput: "-1234567890",
recipeConfig: [
{
"op": "From BCD",
"args": ["8 4 2 1", true, true, "Bytes"]
}
]
},
{
name: "From BCD: Excess-3, unpacked, unsigned",
input: "00000100 00000101 00000110 00000111 00001000 00001001 00001010 00001011 00001100 00000011",
expectedOutput: "1234567890",
recipeConfig: [
{
"op": "From BCD",
"args": ["Excess-3", false, false, "Nibbles"]
}
]
},
{
name: "BCD: raw 4 2 2 1, packed, signed",
input: "1234567890",
expectedOutput: "1234567890",
recipeConfig: [
{
"op": "To BCD",
"args": ["4 2 2 1", true, true, "Raw"]
},
{
"op": "From BCD",
"args": ["4 2 2 1", true, true, "Raw"]
}
]
},
]);

View file

@ -14,12 +14,12 @@ TestRegister.addTests([
expectedOutput: "The cat sat on the mat.", expectedOutput: "The cat sat on the mat.",
recipeConfig: [ recipeConfig: [
{ {
"op" : "From Hex", "op": "From Hex",
"args" : ["Space"] "args": ["Space"]
}, },
{ {
"op" : "Bzip2 Decompress", "op": "Bzip2 Decompress",
"args" : [] "args": []
} }
], ],
}, },

View file

@ -16,7 +16,7 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
op: "Windows Filetime to UNIX Timestamp", op: "Windows Filetime to UNIX Timestamp",
args: ["Nanoseconds (ns)"], args: ["Nanoseconds (ns)", "Decimal"],
}, },
], ],
}, },
@ -27,7 +27,7 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
op: "UNIX Timestamp to Windows Filetime", op: "UNIX Timestamp to Windows Filetime",
args: ["Nanoseconds (ns)"], args: ["Nanoseconds (ns)", "Decimal"],
}, },
], ],
}, },

View file

@ -59,11 +59,11 @@ TestRegister.addTests([
input: "Some data with a 1 in it\nSome data with a 2 in it", input: "Some data with a 1 in it\nSome data with a 2 in it",
expectedOutput: "U29tZSBkYXRhIHdpdGggYSAxIGluIGl0\n53 6f 6d 65 20 64 61 74 61 20 77 69 74 68 20 61 20 32 20 69 6e 20 69 74\n", expectedOutput: "U29tZSBkYXRhIHdpdGggYSAxIGluIGl0\n53 6f 6d 65 20 64 61 74 61 20 77 69 74 68 20 61 20 32 20 69 6e 20 69 74\n",
recipeConfig: [ recipeConfig: [
{"op":"Fork", "args":["\\n", "\\n", false]}, {"op": "Fork", "args": ["\\n", "\\n", false]},
{"op":"Conditional Jump", "args":["1", "2", "10"]}, {"op": "Conditional Jump", "args": ["1", "2", "10"]},
{"op":"To Hex", "args":["Space"]}, {"op": "To Hex", "args": ["Space"]},
{"op":"Return", "args":[]}, {"op": "Return", "args": []},
{"op":"To Base64", "args":["A-Za-z0-9+/="]} {"op": "To Base64", "args": ["A-Za-z0-9+/="]}
] ]
}, },
{ {

View file

@ -73,11 +73,11 @@ TestRegister.addTests([
"", "",
"Make: SONY", "Make: SONY",
"Model: DSC-H5", "Model: DSC-H5",
"XResolution: 72", "XResolution: 70",
"YResolution: 72", "YResolution: 70",
"ResolutionUnit: 2", "ResolutionUnit: 2",
"Software: Pictomio 1.2.31.0", "Software: Pictomio 1.2.31.0",
"ModifyDate: 2010:07:04 23:31:13", "ModifyDate: 1278286273",
"ExposureTime: 0.008", "ExposureTime: 0.008",
"FNumber: 3.7", "FNumber: 3.7",
"ExposureProgram: 3", "ExposureProgram: 3",

View file

@ -26,7 +26,7 @@ TestRegister.addTests([
{ {
name: "Diff, basic usage", name: "Diff, basic usage",
input: "testing23\n\ntesting123", input: "testing23\n\ntesting123",
expectedOutput: "testing<span class='hlgreen'>1</span>23", expectedOutput: "testing<span class='hl5'>1</span>23",
recipeConfig: [ recipeConfig: [
{ {
"op": "Diff", "op": "Diff",