Initial commit

This commit is contained in:
n1474335 2016-11-28 10:42:58 +00:00
commit b1d73a725d
238 changed files with 105357 additions and 0 deletions

52
src/js/operations/Base.js Executable file
View file

@ -0,0 +1,52 @@
/**
* Numerical base operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Base = {
/**
* @constant
* @default
*/
DEFAULT_RADIX: 36,
/**
* To Base operation.
*
* @param {number} input
* @param {Object[]} args
* @returns {string}
*/
run_to: function(input, args) {
if (!input) {
throw ("Error: Input must be a number");
}
var radix = args[0] || Base.DEFAULT_RADIX;
if (radix < 2 || radix > 36) {
throw "Error: Radix argument must be between 2 and 36";
}
return input.toString(radix);
},
/**
* From Base operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
run_from: function(input, args) {
var radix = args[0] || Base.DEFAULT_RADIX;
if (radix < 2 || radix > 36) {
throw "Error: Radix argument must be between 2 and 36";
}
return parseInt(input.replace(/\s/g, ""), radix);
},
};

341
src/js/operations/Base64.js Executable file
View file

@ -0,0 +1,341 @@
/**
* Base64 operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Base64 = {
/**
* @constant
* @default
*/
ALPHABET: "A-Za-z0-9+/=",
/**
* @constant
* @default
*/
ALPHABET_OPTIONS: [
{name: "Standard: A-Za-z0-9+/=", value: "A-Za-z0-9+/="},
{name: "URL safe: A-Za-z0-9-_", value: "A-Za-z0-9-_"},
{name: "Filename safe: A-Za-z0-9+-=", value: "A-Za-z0-9+\\-="},
{name: "itoa64: ./0-9A-Za-z=", value: "./0-9A-Za-z="},
{name: "XML: A-Za-z0-9_.", value: "A-Za-z0-9_."},
{name: "y64: A-Za-z0-9._-", value: "A-Za-z0-9._-"},
{name: "z64: 0-9a-zA-Z+/=", value: "0-9a-zA-Z+/="},
{name: "Radix-64: 0-9A-Za-z+/=", value: "0-9A-Za-z+/="},
{name: "Uuencoding: [space]-_", value: " -_"},
{name: "Xxencoding: +-0-9A-Za-z", value: "+\\-0-9A-Za-z"},
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},
{name: "ROT13: N-ZA-Mn-za-m0-9+/=", value: "N-ZA-Mn-za-m0-9+/="},
],
/**
* To Base64 operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET;
return Utils.to_base64(input, alphabet);
},
/**
* @constant
* @default
*/
REMOVE_NON_ALPH_CHARS: true,
/**
* From Base64 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET,
remove_non_alph_chars = args[1];
return Utils.from_base64(input, alphabet, "byte_array", remove_non_alph_chars);
},
/**
* @constant
* @default
*/
BASE32_ALPHABET: "A-Z2-7=",
/**
* To Base32 operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to_32: function(input, args) {
if (!input) return "";
var alphabet = args[0] ?
Utils.expand_alph_range(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
output = "",
chr1, chr2, chr3, chr4, chr5,
enc1, enc2, enc3, enc4, enc5, enc6, enc7, enc8,
i = 0;
while (i < input.length) {
chr1 = input[i++];
chr2 = input[i++];
chr3 = input[i++];
chr4 = input[i++];
chr5 = input[i++];
enc1 = chr1 >> 3;
enc2 = ((chr1 & 7) << 2) | (chr2 >> 6);
enc3 = (chr2 >> 1) & 31;
enc4 = ((chr2 & 1) << 4) | (chr3 >> 4);
enc5 = ((chr3 & 15) << 1) | (chr4 >> 7);
enc6 = (chr4 >> 2) & 63;
enc7 = ((chr4 & 3) << 3) | (chr5 >> 5);
enc8 = chr5 & 31;
if (isNaN(chr2)) {
enc3 = enc4 = enc5 = enc6 = enc7 = enc8 = 32;
} else if (isNaN(chr3)) {
enc5 = enc6 = enc7 = enc8 = 32;
} else if (isNaN(chr4)) {
enc6 = enc7 = enc8 = 32;
} else if (isNaN(chr5)) {
enc8 = 32;
}
output += alphabet.charAt(enc1) + alphabet.charAt(enc2) + alphabet.charAt(enc3) +
alphabet.charAt(enc4) + alphabet.charAt(enc5) + alphabet.charAt(enc6) +
alphabet.charAt(enc7) + alphabet.charAt(enc8);
}
return output;
},
/**
* From Base32 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_32: function(input, args) {
if (!input) return [];
var alphabet = args[0] ?
Utils.expand_alph_range(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
remove_non_alph_chars = args[0];
var output = [],
chr1, chr2, chr3, chr4, chr5,
enc1, enc2, enc3, enc4, enc5, enc6, enc7, enc8,
i = 0;
if (remove_non_alph_chars) {
var re = new RegExp("[^" + alphabet.replace(/[\]\\\-^]/g, "\\$&") + "]", "g");
input = input.replace(re, "");
}
while (i < input.length) {
enc1 = alphabet.indexOf(input.charAt(i++));
enc2 = alphabet.indexOf(input.charAt(i++) || "=");
enc3 = alphabet.indexOf(input.charAt(i++) || "=");
enc4 = alphabet.indexOf(input.charAt(i++) || "=");
enc5 = alphabet.indexOf(input.charAt(i++) || "=");
enc6 = alphabet.indexOf(input.charAt(i++) || "=");
enc7 = alphabet.indexOf(input.charAt(i++) || "=");
enc8 = alphabet.indexOf(input.charAt(i++) || "=");
chr1 = (enc1 << 3) | (enc2 >> 2);
chr2 = ((enc2 & 3) << 6) | (enc3 << 1) | (enc4 >> 4);
chr3 = ((enc4 & 15) << 4) | (enc5 >> 1);
chr4 = ((enc5 & 1) << 7) | (enc6 << 2) | (enc7 >> 3);
chr5 = ((enc7 & 7) << 5) | enc8;
output.push(chr1);
if (enc2 & 3 !== 0 || enc3 !== 32) output.push(chr2);
if (enc4 & 15 !== 0 || enc5 !== 32) output.push(chr3);
if (enc5 & 1 !== 0 || enc6 !== 32) output.push(chr4);
if (enc7 & 7 !== 0 || enc8 !== 32) output.push(chr5);
}
return output;
},
/**
* @constant
* @default
*/
SHOW_IN_BINARY: false,
/**
* @constant
* @default
*/
OFFSETS_SHOW_VARIABLE: true,
/**
* Show Base64 offsets operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {html}
*/
run_offsets: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET,
show_variable = args[1],
offset0 = Utils.to_base64(input, alphabet),
offset1 = Utils.to_base64([0].concat(input), alphabet),
offset2 = Utils.to_base64([0, 0].concat(input), alphabet),
len0 = offset0.indexOf("="),
len1 = offset1.indexOf("="),
len2 = offset2.indexOf("="),
script = "<script type='application/javascript'>$('[data-toggle=\"tooltip\"]').tooltip()</script>",
static_section = "",
padding = "";
if (input.length < 1) {
return "Please enter a string.";
}
// Highlight offset 0
if (len0 % 4 == 2) {
static_section = offset0.slice(0, -3);
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64(static_section, alphabet).slice(0, -2) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>";
} else if (len0 % 4 == 3) {
static_section = offset0.slice(0, -2);
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64(static_section, alphabet).slice(0, -1) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>";
} else {
static_section = offset0;
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64(static_section, alphabet) + "'>" +
static_section + "</span>";
}
if (!show_variable) {
offset0 = static_section;
}
// Highlight offset 1
padding = "<span class='hlred'>" + offset1.substr(0, 1) + "</span>" +
"<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>";
offset1 = offset1.substr(2);
if (len1 % 4 == 2) {
static_section = offset1.slice(0, -3);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AA" + static_section, alphabet).slice(1, -2) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>";
} else if (len1 % 4 == 3) {
static_section = offset1.slice(0, -2);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AA" + static_section, alphabet).slice(1, -1) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>";
} else {
static_section = offset1;
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AA" + static_section, alphabet).slice(1) + "'>" +
static_section + "</span>";
}
if (!show_variable) {
offset1 = static_section;
}
// Highlight offset 2
padding = "<span class='hlred'>" + offset2.substr(0, 2) + "</span>" +
"<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>";
offset2 = offset2.substr(3);
if (len2 % 4 == 2) {
static_section = offset2.slice(0, -3);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AAA" + static_section, alphabet).slice(2, -2) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>";
} else if (len2 % 4 == 3) {
static_section = offset2.slice(0, -2);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AAA" + static_section, alphabet).slice(2, -2) + "'>" +
static_section + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>";
} else {
static_section = offset2;
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.from_base64("AAA" + static_section, alphabet).slice(2) + "'>" +
static_section + "</span>";
}
if (!show_variable) {
offset2 = static_section;
}
return (show_variable ? "Characters highlighted in <span class='hlgreen'>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." +
"\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" +
"\nOffset 0: " + offset0 +
"\nOffset 1: " + offset1 +
"\nOffset 2: " + offset2 +
script :
offset0 + "\n" + offset1 + "\n" + offset2);
},
/**
* Highlight to Base64
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_to: function(pos, args) {
pos[0].start = Math.floor(pos[0].start / 3 * 4);
pos[0].end = Math.ceil(pos[0].end / 3 * 4);
return pos;
},
/**
* Highlight from Base64
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_from: function(pos, args) {
pos[0].start = Math.ceil(pos[0].start / 4 * 3);
pos[0].end = Math.floor(pos[0].end / 4 * 3);
return pos;
},
};

299
src/js/operations/BitwiseOp.js Executable file
View file

@ -0,0 +1,299 @@
/* globals CryptoJS */
/**
* Bitwise operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var BitwiseOp = {
/**
* Runs bitwise operations across the input data.
*
* @private
* @param {byte_array} input
* @param {byte_array} key
* @param {function} func - The bitwise calculation to carry out
* @param {boolean} null_preserving
* @param {boolean} differential
* @returns {byte_array}
*/
_bit_op: function (input, key, func, null_preserving, differential) {
if (!key || !key.length) key = [0];
var result = [],
x = null,
k = null,
o = null;
for (var i = 0; i < input.length; i++) {
k = key[i % key.length];
o = input[i];
x = null_preserving && (o === 0 || o == k) ? o : func(o, k);
result.push(x);
if (differential && !(null_preserving && (o === 0 || o == k))) {
key[i % key.length] = x;
}
}
return result;
},
/**
* @constant
* @default
*/
XOR_PRESERVE_NULLS: false,
/**
* @constant
* @default
*/
XOR_DIFFERENTIAL: false,
/**
* @constant
* @default
*/
KEY_FORMAT: ["Hex", "Base64", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
/**
* XOR operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_xor: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
null_preserving = args[1],
differential = args[2];
key = Utils.word_array_to_byte_array(key);
return BitwiseOp._bit_op(input, key, BitwiseOp._xor, null_preserving, differential);
},
/**
* @constant
* @default
*/
XOR_BRUTE_KEY_LENGTH: ["1", "2"],
/**
* @constant
* @default
*/
XOR_BRUTE_SAMPLE_LENGTH: 100,
/**
* @constant
* @default
*/
XOR_BRUTE_SAMPLE_OFFSET: 0,
/**
* @constant
* @default
*/
XOR_BRUTE_PRINT_KEY: true,
/**
* @constant
* @default
*/
XOR_BRUTE_OUTPUT_HEX: false,
/**
* XOR Brute Force operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_xor_brute: function (input, args) {
var key_length = parseInt(args[0], 10),
sample_length = args[1],
sample_offset = args[2],
null_preserving = args[3],
differential = args[4],
crib = args[5],
print_key = args[6],
output_hex = args[7],
regex;
var output = "",
result,
result_utf8;
input = input.slice(sample_offset, sample_offset + sample_length);
if (crib !== "") {
regex = new RegExp(crib, "im");
}
for (var key = 1, l = Math.pow(256, key_length); key < l; key++) {
result = BitwiseOp._bit_op(input, Utils.hex_to_byte_array(key.toString(16)), BitwiseOp._xor, null_preserving, differential);
result_utf8 = Utils.byte_array_to_utf8(result);
if (crib !== "" && result_utf8.search(regex) === -1) continue;
if (print_key) output += "Key = " + Utils.hex(key, (2*key_length)) + ": ";
if (output_hex)
output += Utils.byte_array_to_hex(result) + "\n";
else
output += Utils.printable(result_utf8, false) + "\n";
if (print_key) output += "\n";
}
return output;
},
/**
* NOT operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_not: function (input, args) {
return BitwiseOp._bit_op(input, null, BitwiseOp._not);
},
/**
* AND operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_and: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.word_array_to_byte_array(key);
return BitwiseOp._bit_op(input, key, BitwiseOp._and);
},
/**
* OR operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_or: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.word_array_to_byte_array(key);
return BitwiseOp._bit_op(input, key, BitwiseOp._or);
},
/**
* ADD operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_add: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.word_array_to_byte_array(key);
return BitwiseOp._bit_op(input, key, BitwiseOp._add);
},
/**
* SUB operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_sub: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.word_array_to_byte_array(key);
return BitwiseOp._bit_op(input, key, BitwiseOp._sub);
},
/**
* XOR bitwise calculation.
*
* @private
* @param {number} operand
* @param {number} key
* @returns {number}
*/
_xor: function (operand, key) {
return operand ^ key;
},
/**
* NOT bitwise calculation.
*
* @private
* @param {number} operand
* @returns {number}
*/
_not: function (operand, _) {
return ~operand & 0xff;
},
/**
* AND bitwise calculation.
*
* @private
* @param {number} operand
* @param {number} key
* @returns {number}
*/
_and: function (operand, key) {
return operand & key;
},
/**
* OR bitwise calculation.
*
* @private
* @param {number} operand
* @param {number} key
* @returns {number}
*/
_or: function (operand, key) {
return operand | key;
},
/**
* ADD bitwise calculation.
*
* @private
* @param {number} operand
* @param {number} key
* @returns {number}
*/
_add: function (operand, key) {
return (operand + key) % 256;
},
/**
* SUB bitwise calculation.
*
* @private
* @param {number} operand
* @param {number} key
* @returns {number}
*/
_sub: function (operand, key) {
var result = operand - key;
return (result < 0) ? 256 + result : result;
},
};

394
src/js/operations/ByteRepr.js Executable file
View file

@ -0,0 +1,394 @@
/* globals app */
/**
* Byte representation operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var ByteRepr = {
/**
* @constant
* @default
*/
DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"],
/**
* @constant
* @default
*/
HEX_DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"],
/**
* @constant
* @default
*/
BIN_DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"],
/**
* To Hex operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to_hex: function(input, args) {
var delim = Utils.char_rep[args[0] || "Space"];
return Utils.to_hex(input, delim, 2);
},
/**
* From Hex operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_hex: function(input, args) {
var delim = args[0] || "Space";
return Utils.from_hex(input, delim, 2);
},
/**
* @constant
* @default
*/
CHARCODE_BASE: 16,
/**
* To Charcode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_to_charcode: function(input, args) {
var delim = Utils.char_rep[args[0] || "Space"],
base = args[1],
output = "",
padding = 2,
ordinal;
if (base < 2 || base > 36) {
throw "Error: Base argument must be between 2 and 36";
}
for (var i = 0; i < input.length; i++) {
ordinal = Utils.ord(input[i]);
if (base == 16) {
if (ordinal < 256) padding = 2;
else if (ordinal < 65536) padding = 4;
else if (ordinal < 16777216) padding = 6;
else if (ordinal < 4294967296) padding = 8;
else padding = 2;
if (padding > 2) app.options.attempt_highlight = false;
output += Utils.hex(ordinal, padding) + delim;
} else {
app.options.attempt_highlight = false;
output += ordinal.toString(base) + delim;
}
}
return output.slice(0, -delim.length);
},
/**
* From Charcode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_charcode: function(input, args) {
var delim = Utils.char_rep[args[0] || "Space"],
base = args[1],
bites = input.split(delim),
i = 0;
if (base < 2 || base > 36) {
throw "Error: Base argument must be between 2 and 36";
}
if (base != 16) {
app.options.attempt_highlight = false;
}
// Split into groups of 2 if the whole string is concatenated and
// too long to be a single character
if (bites.length == 1 && input.length > 17) {
bites = [];
for (i = 0; i < input.length; i += 2) {
bites.push(input.slice(i, i+2));
}
}
var latin1 = "";
for (i = 0; i < bites.length; i++) {
latin1 += Utils.chr(parseInt(bites[i], base));
}
return Utils.str_to_byte_array(latin1);
},
/**
* Highlight to hex
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_to: function(pos, args) {
var delim = Utils.char_rep[args[0] || "Space"],
len = delim == "\r\n" ? 1 : delim.length;
pos[0].start = pos[0].start * (2 + len);
pos[0].end = pos[0].end * (2 + len) - len;
// 0x and \x are added to the beginning if they are selected, so increment the positions accordingly
if (delim == "0x" || delim == "\\x") {
pos[0].start += 2;
pos[0].end += 2;
}
return pos;
},
/**
* Highlight to hex
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_from: function(pos, args) {
var delim = Utils.char_rep[args[0] || "Space"],
len = delim == "\r\n" ? 1 : delim.length,
width = len + 2;
// 0x and \x are added to the beginning if they are selected, so increment the positions accordingly
if (delim == "0x" || delim == "\\x") {
if (pos[0].start > 1) pos[0].start -= 2;
else pos[0].start = 0;
if (pos[0].end > 1) pos[0].end -= 2;
else pos[0].end = 0;
}
pos[0].start = pos[0].start === 0 ? 0 : Math.round(pos[0].start / width);
pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / width);
return pos;
},
/**
* To Decimal operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to_decimal: function(input, args) {
var delim = Utils.char_rep[args[0]];
return input.join(delim);
},
/**
* From Decimal operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_decimal: function(input, args) {
var delim = Utils.char_rep[args[0]];
var byte_str = input.split(delim), output = [];
if (byte_str[byte_str.length-1] === "")
byte_str = byte_str.slice(0, byte_str.length-1);
for (var i = 0; i < byte_str.length; i++) {
output[i] = parseInt(byte_str[i]);
}
return output;
},
/**
* To Binary operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to_binary: function(input, args) {
var delim = Utils.char_rep[args[0] || "Space"],
output = "",
padding = 8;
for (var i = 0; i < input.length; i++) {
output += Utils.pad(input[i].toString(2), padding) + delim;
}
if (delim.length) {
return output.slice(0, -delim.length);
} else {
return output;
}
},
/**
* From Binary operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_binary: function(input, args) {
if (args[0] != "None") {
var delim_regex = Utils.regex_rep[args[0] || "Space"];
input = input.replace(delim_regex, '');
}
var output = [];
var byte_len = 8;
for (var i = 0; i < input.length; i += byte_len) {
output.push(parseInt(input.substr(i, byte_len), 2));
}
return output;
},
/**
* Highlight to binary
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_to_binary: function(pos, args) {
var delim = Utils.char_rep[args[0] || "Space"];
pos[0].start = pos[0].start * (8 + delim.length);
pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
return pos;
},
/**
* Highlight from binary
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_from_binary: function(pos, args) {
var delim = Utils.char_rep[args[0] || "Space"];
pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
return pos;
},
/**
* @constant
* @default
*/
HEX_CONTENT_CONVERT_WHICH: ["Only special chars", "Only special chars including spaces", "All chars"],
/**
* @constant
* @default
*/
HEX_CONTENT_SPACES_BETWEEN_BYTES: false,
/**
* To Hex Content operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to_hex_content: function(input, args) {
var convert = args[0];
var spaces = args[1];
if (convert == "All chars") {
var result = "|" + Utils.to_hex(input) + "|";
if (!spaces) result = result.replace(/ /g, "");
return result;
}
var output = "",
in_hex = false,
convert_spaces = convert == "Only special chars including spaces",
b;
for (var i = 0; i < input.length; i++) {
b = input[i];
if ((b == 32 && convert_spaces) || (b < 48 && b != 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
if (!in_hex) {
output += "|";
in_hex = true;
} else if (spaces) output += " ";
output += Utils.to_hex([b]);
} else {
if (in_hex) {
output += "|";
in_hex = false;
}
output += Utils.chr(input[i]);
}
}
if (in_hex) output += "|";
return output;
},
/**
* From Hex Content operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from_hex_content: function(input, args) {
var regex = /\|([a-f\d ]{2,})\|/gi;
var output = [], m, i = 0;
while (!!(m = regex.exec(input))) {
// Add up to match
for (; i < m.index;)
output.push(Utils.ord(input[i++]));
// Add match
var bytes = Utils.from_hex(m[1]);
if (bytes) {
for (var a = 0; a < bytes.length;)
output.push(bytes[a++]);
} else {
// Not valid hex, print as normal
for (; i < regex.lastIndex;)
output.push(Utils.ord(input[i++]));
}
i = regex.lastIndex;
}
// Add all after final match
for (; i < input.length;)
output.push(Utils.ord(input[i++]));
return output;
},
};

46
src/js/operations/CharEnc.js Executable file
View file

@ -0,0 +1,46 @@
/* globals CryptoJS */
/**
* Character encoding operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var CharEnc = {
/**
* @constant
* @default
*/
IO_FORMAT: ["UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1", "Windows-1251", "Hex", "Base64"],
/**
* Text encoding operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run: function(input, args) {
var input_format = args[0],
output_format = args[1];
if (input_format == "Windows-1251") {
input = Utils.win1251_to_unicode(input);
input = CryptoJS.enc.Utf8.parse(input);
} else {
input = Utils.format[input_format].parse(input);
}
if (output_format == "Windows-1251") {
input = CryptoJS.enc.Utf8.stringify(input);
return Utils.unicode_to_win1251(input);
} else {
return Utils.format[output_format].stringify(input);
}
},
};

130
src/js/operations/Checksum.js Executable file
View file

@ -0,0 +1,130 @@
/**
* Checksum operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Checksum = {
/**
* Fletcher-16 Checksum operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_fletcher16: function(input, args) {
var a = 0,
b = 0;
for (var i = 0; i < input.length; i++) {
a = (a + input[i]) % 0xff;
b = (b + a) % 0xff;
}
return Utils.hex(((b << 8) | a) >>> 0, 4);
},
/**
* Adler-32 Checksum operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_adler32: function(input, args) {
var MOD_ADLER = 65521,
a = 1,
b = 0;
for (var i = 0; i < input.length; i++) {
a += input[i];
b += a;
}
a %= MOD_ADLER;
b %= MOD_ADLER;
return Utils.hex(((b << 16) | a) >>> 0, 8);
},
/**
* CRC-32 Checksum operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_crc32: function(input, args) {
var crc_table = window.crc_table || (window.crc_table = Checksum._gen_crc_table()),
crc = 0 ^ (-1);
for (var i = 0; i < input.length; i++) {
crc = (crc >>> 8) ^ crc_table[(crc ^ input[i]) & 0xff];
}
return Utils.hex((crc ^ (-1)) >>> 0);
},
/**
* TCP/IP Checksum operation.
*
* @author GCHQ Contributor [1]
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*
* @example
* // returns '3f2c'
* Checksum.run_tcp_ip([0x45,0x00,0x00,0x87,0xa3,0x1b,0x40,0x00,0x40,0x06,
* 0x00,0x00,0xac,0x11,0x00,0x04,0xac,0x11,0x00,0x03])
*
* // returns 'a249'
* Checksum.run_tcp_ip([0x45,0x00,0x01,0x11,0x3f,0x74,0x40,0x00,0x40,0x06,
* 0x00,0x00,0xac,0x11,0x00,0x03,0xac,0x11,0x00,0x04])
*/
run_tcp_ip: function(input, args) {
var csum = 0;
for (var i = 0; i < input.length; i++) {
if(i % 2 === 0) {
csum += (input[i] << 8);
} else {
csum += input[i];
}
}
csum = (csum >> 16) + (csum & 0xffff);
return Utils.hex(0xffff - csum);
},
/**
* Generates a CRC table for use with CRC checksums.
*
* @private
* @returns {array}
*/
_gen_crc_table: function() {
var c,
crc_table = [];
for (var n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crc_table[n] = c;
}
return crc_table;
},
};

429
src/js/operations/Cipher.js Executable file
View file

@ -0,0 +1,429 @@
/* globals CryptoJS, blowfish */
/**
* Cipher operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Cipher = {
/**
* @constant
* @default
*/
IO_FORMAT1: ["Hex", "Base64", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
/**
* @constant
* @default
*/
IO_FORMAT2: ["UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1", "Hex", "Base64"],
/**
* @constant
* @default
*/
IO_FORMAT3: ["Hex", "Base64", "UTF16", "UTF16LE", "UTF16BE", "Latin1"],
/**
* @constant
* @default
*/
IO_FORMAT4: ["Latin1", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Hex", "Base64"],
/**
* @constant
* @default
*/
MODES: ["CBC", "CFB", "CTR", "OFB", "ECB"],
/**
* @constant
* @default
*/
PADDING: ["Pkcs7", "Iso97971", "AnsiX923", "Iso10126", "ZeroPadding", "NoPadding"],
/**
* @constant
* @default
*/
RESULT_TYPE: ["Show all", "Ciphertext", "Key", "IV", "Salt"],
/**
* Runs encryption operations using the CryptoJS framework.
*
* @private
* @param {function} algo - The CryptoJS algorithm to use
* @param {byte_array} input
* @param {function} args
* @returns {string}
*/
_enc: function (algo, input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]],
result_option = args[5].toLowerCase(),
output_format = args[6];
if (iv.sigBytes === 0) {
// Use passphrase rather than key. Need to convert it to a string.
key = key.toString(CryptoJS.enc.Latin1);
}
var encrypted = algo.encrypt(input, key, {
salt: salt.sigBytes > 0 ? salt : false,
iv: iv.sigBytes > 0 ? iv : null,
mode: mode,
padding: padding
});
var result = "";
if (result_option == "show all") {
result += "Key: " + encrypted.key.toString(Utils.format[output_format]);
result += "\nIV: " + encrypted.iv.toString(Utils.format[output_format]);
if (encrypted.salt) result += "\nSalt: " + encrypted.salt.toString(Utils.format[output_format]);
result += "\n\nCiphertext: " + encrypted.ciphertext.toString(Utils.format[output_format]);
} else {
result = encrypted[result_option].toString(Utils.format[output_format]);
}
return result;
},
/**
* Runs decryption operations using the CryptoJS framework.
*
* @private
* @param {function} algo - The CryptoJS algorithm to use
* @param {byte_array} input
* @param {function} args
* @returns {string}
*/
_dec: function (algo, input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
padding = CryptoJS.pad[args[4]],
input_format = args[5],
output_format = args[6];
// The ZeroPadding option causes a crash when the input length is 0
if (!input.length) {
return "No input";
}
var ciphertext = Utils.format[input_format].parse(input);
if (iv.sigBytes === 0) {
// Use passphrase rather than key. Need to convert it to a string.
key = key.toString(CryptoJS.enc.Latin1);
}
var decrypted = algo.decrypt({
ciphertext: ciphertext,
salt: salt.sigBytes > 0 ? salt : false
}, key, {
iv: iv.sigBytes > 0 ? iv : null,
mode: mode,
padding: padding
});
var result;
try {
result = decrypted.toString(Utils.format[output_format]);
} catch (err) {
result = "Decrypt error: " + err.message;
}
return result;
},
/**
* AES Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_aes_enc: function (input, args) {
return Cipher._enc(CryptoJS.AES, input, args);
},
/**
* AES Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_aes_dec: function (input, args) {
return Cipher._dec(CryptoJS.AES, input, args);
},
/**
* DES Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_des_enc: function (input, args) {
return Cipher._enc(CryptoJS.DES, input, args);
},
/**
* DES Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_des_dec: function (input, args) {
return Cipher._dec(CryptoJS.DES, input, args);
},
/**
* Triple DES Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_triple_des_enc: function (input, args) {
return Cipher._enc(CryptoJS.TripleDES, input, args);
},
/**
* Triple DES Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_triple_des_dec: function (input, args) {
return Cipher._dec(CryptoJS.TripleDES, input, args);
},
/**
* Rabbit Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_rabbit_enc: function (input, args) {
return Cipher._enc(CryptoJS.Rabbit, input, args);
},
/**
* Rabbit Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_rabbit_dec: function (input, args) {
return Cipher._dec(CryptoJS.Rabbit, input, args);
},
/**
* @constant
* @default
*/
BLOWFISH_MODES: ["ECB", "CBC", "PCBC", "CFB", "OFB", "CTR"],
/**
* @constant
* @default
*/
BLOWFISH_OUTPUT_TYPES: ["Base64", "Hex", "String", "Raw"],
/**
* Blowfish Encrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_blowfish_enc: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
mode = args[1],
output_format = args[2];
if (key.length === 0) return "Enter a key";
var enc_hex = blowfish.encrypt(input, key, {
outputType: 1,
cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
}),
enc = CryptoJS.enc.Hex.parse(enc_hex);
return enc.toString(Utils.format[output_format]);
},
/**
* Blowfish Decrypt operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_blowfish_dec: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
mode = args[1],
input_format = args[2];
if (key.length === 0) return "Enter a key";
input = Utils.format[input_format].parse(input);
return blowfish.decrypt(input.toString(CryptoJS.enc.Base64), key, {
outputType: 0, // This actually means inputType. The library is weird.
cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
});
},
/**
* @constant
* @default
*/
KDF_KEY_SIZE: 256,
/**
* @constant
* @default
*/
KDF_ITERATIONS: 1,
/**
* Derive PBKDF2 key operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_pbkdf2: function (input, args) {
var key_size = args[0] / 32,
iterations = args[1],
salt = CryptoJS.enc.Hex.parse(args[2] || ""),
input_format = args[3],
output_format = args[4],
passphrase = Utils.format[input_format].parse(input),
key = CryptoJS.PBKDF2(passphrase, salt, { keySize: key_size, iterations: iterations });
return key.toString(Utils.format[output_format]);
},
/**
* Derive EVP key operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_evpkdf: function (input, args) {
var key_size = args[0] / 32,
iterations = args[1],
salt = CryptoJS.enc.Hex.parse(args[2] || ""),
input_format = args[3],
output_format = args[4],
passphrase = Utils.format[input_format].parse(input),
key = CryptoJS.EvpKDF(passphrase, salt, { keySize: key_size, iterations: iterations });
return key.toString(Utils.format[output_format]);
},
/**
* RC4 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_rc4: function (input, args) {
var message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
encrypted = CryptoJS.RC4.encrypt(message, passphrase);
return encrypted.ciphertext.toString(Utils.format[args[2]]);
},
/**
* @constant
* @default
*/
RC4DROP_BYTES: 768,
/**
* RC4 Drop operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_rc4drop: function (input, args) {
var message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
drop = args[3],
encrypted = CryptoJS.RC4Drop.encrypt(message, passphrase, { drop: drop });
return encrypted.ciphertext.toString(Utils.format[args[2]]);
},
};
/**
* Overwriting the CryptoJS OpenSSL key derivation function so that it is possible to not pass a
* salt in.
* @param {string} password - The password to derive from.
* @param {number} keySize - The size in words of the key to generate.
* @param {number} ivSize - The size in words of the IV to generate.
* @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be
* generated randomly. If set to false, no salt will be added.
*
* @returns {CipherParams} A cipher params object with the key, IV, and salt.
*
* @static
*
* @example
* // Randomly generates a salt
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
* // Uses the salt 'saltsalt'
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
* // Does not use a salt
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, false);
*/
CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
// Generate random salt if no salt specified and not set to false
// This line changed from `if (!salt) {` to the following
if (salt === undefined || salt === null) {
salt = CryptoJS.lib.WordArray.random(64/8);
}
// Derive key and IV
var key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
// Separate key and IV
var iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
key.sigBytes = keySize * 4;
// Return params
return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt });
};

305
src/js/operations/Code.js Executable file
View file

@ -0,0 +1,305 @@
/* globals prettyPrintOne, vkbeautify */
/**
* Code operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Code = {
/**
* @constant
* @default
*/
LANGUAGES: ["default-code", "default-markup", "bash", "bsh", "c", "cc", "coffee", "cpp", "cs", "csh", "cv", "cxx", "cyc", "htm", "html", "in.tag", "java", "javascript", "js", "json", "m", "mxml", "perl", "pl", "pm", "py", "python", "rb", "rc", "rs", "ruby", "rust", "sh", "uq.val", "xhtml", "xml", "xsl"],
/**
* @constant
* @default
*/
LINE_NUMS: false,
/**
* Syntax highlighter operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_syntax_highlight: function(input, args) {
var language = args[0],
line_nums = args[1];
return "<code class='prettyprint'>" + prettyPrintOne(Utils.escape_html(input), language, line_nums) + "</code>";
},
/**
* @constant
* @default
*/
BEAUTIFY_INDENT: "\\t",
/**
* XML Beautify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_xml_beautify: function(input, args) {
var indent_str = args[0];
return vkbeautify.xml(input, indent_str);
},
/**
* JSON Beautify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_json_beautify: function(input, args) {
var indent_str = args[0];
return vkbeautify.json(input, indent_str);
},
/**
* CSS Beautify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_css_beautify: function(input, args) {
var indent_str = args[0];
return vkbeautify.css(input, indent_str);
},
/**
* SQL Beautify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sql_beautify: function(input, args) {
var indent_str = args[0];
return vkbeautify.sql(input, indent_str);
},
/**
* @constant
* @default
*/
PRESERVE_COMMENTS: false,
/**
* XML Minify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_xml_minify: function(input, args) {
var preserve_comments = args[0];
return vkbeautify.xmlmin(input, preserve_comments);
},
/**
* JSON Minify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_json_minify: function(input, args) {
return vkbeautify.jsonmin(input);
},
/**
* CSS Minify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_css_minify: function(input, args) {
var preserve_comments = args[0];
return vkbeautify.cssmin(input, preserve_comments);
},
/**
* SQL Minify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sql_minify: function(input, args) {
return vkbeautify.sqlmin(input);
},
/**
* Generic Code Beautify operation.
*
* Yeeeaaah...
*
* I'm not proud of this code, but seriously, try writing a generic lexer and parser that
* correctly generates an AST for multiple different languages. I have tried, and I can tell
* you it's pretty much impossible.
*
* This basically works. That'll have to be good enough. It's not meant to produce working code,
* just slightly more readable code.
*
* Things that don't work:
* - For loop formatting
* - Do-While loop formatting
* - Switch/Case indentation
* - Bit shift operators
*
* @author n1474335 [n1474335@gmail.com]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_generic_beautify: function(input, args) {
var code = input,
t = 0,
preserved_tokens = [],
m;
// Remove strings
var sstrings = /'([^'\\]|\\.)*'/g;
while (!!(m = sstrings.exec(code))) {
code = preserve_token(code, m, t++);
sstrings.lastIndex = m.index;
}
var dstrings = /"([^"\\]|\\.)*"/g;
while (!!(m = dstrings.exec(code))) {
code = preserve_token(code, m, t++);
dstrings.lastIndex = m.index;
}
// Remove comments
var scomments = /\/\/[^\n\r]*/g;
while (!!(m = scomments.exec(code))) {
code = preserve_token(code, m, t++);
scomments.lastIndex = m.index;
}
var mcomments = /\/\*[\s\S]*?\*\//gm;
while (!!(m = mcomments.exec(code))) {
code = preserve_token(code, m, t++);
mcomments.lastIndex = m.index;
}
var hcomments = /(^|\n)#[^\n\r#]+/g;
while (!!(m = hcomments.exec(code))) {
code = preserve_token(code, m, t++);
hcomments.lastIndex = m.index;
}
// Remove regexes
var regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
while (!!(m = regexes.exec(code))) {
code = preserve_token(code, m, t++);
regexes.lastIndex = m.index;
}
// Create newlines after ;
code = code.replace(/;/g, ";\n");
// Create newlines after { and around }
code = code.replace(/{/g, "{\n");
code = code.replace(/}/g, "\n}\n");
// Remove carriage returns
code = code.replace(/\r/g, "");
// Remove all indentation
code = code.replace(/^\s+/g, "");
code = code.replace(/\n\s+/g, "\n");
// Remove trailing spaces
code = code.replace(/\s*$/g, "");
// Remove newlines before {
code = code.replace(/\n{/g, "{");
// Indent
var i = 0,
level = 0;
while (i < code.length) {
switch(code[i]) {
case "{":
level++;
break;
case "\n":
if (i+1 >= code.length) break;
if (code[i+1] == "}") level--;
var indent = (level >= 0) ? Array(level*4+1).join(" ") : "";
code = code.substring(0, i+1) + indent + code.substring(i+1);
if (level > 0) i += level*4;
break;
}
i++;
}
// Add strategic spaces
code = code.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ");
code = code.replace(/\s*<([=]?)\s*/g, " <$1 ");
code = code.replace(/\s*>([=]?)\s*/g, " >$1 ");
code = code.replace(/([^+])\+([^+=])/g, "$1 + $2");
code = code.replace(/([^-])-([^-=])/g, "$1 - $2");
code = code.replace(/([^*])\*([^*=])/g, "$1 * $2");
code = code.replace(/([^/])\/([^/=])/g, "$1 / $2");
code = code.replace(/\s*,\s*/g, ", ");
code = code.replace(/\s*{/g, " {");
code = code.replace(/}\n/g, "}\n\n");
// Just... don't look at this
code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3");
code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3");
code = code.replace(/else\s*\n([^{])/gim, "else\n $1");
code = code.replace(/else\s+([^{])/gim, "else $1");
// Remove strategic spaces
code = code.replace(/\s+;/g, ";");
code = code.replace(/\{\s+\}/g, "{}");
code = code.replace(/\[\s+\]/g, "[]");
code = code.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
// Replace preserved tokens
var ptokens = /###preserved_token(\d+)###/g;
while (!!(m = ptokens.exec(code))) {
var ti = parseInt(m[1]);
code = code.substring(0, m.index) + preserved_tokens[ti] + code.substring(m.index + m[0].length);
ptokens.lastIndex = m.index;
}
return code;
function preserve_token(str, match, t) {
preserved_tokens[t] = match[0];
return str.substring(0, match.index) +
"###preserved_token" + t + "###" +
str.substring(match.index + match[0].length);
}
},
};

349
src/js/operations/Compress.js Executable file
View file

@ -0,0 +1,349 @@
/* globals Zlib, bzip2 */
/**
* Compression operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Compress = {
/**
* @constant
* @default
*/
COMPRESSION_TYPE: ["Dynamic Huffman Coding", "Fixed Huffman Coding", "None (Store)"],
/**
* @constant
* @default
*/
INFLATE_BUFFER_TYPE: ["Adaptive", "Block"],
/**
* @constant
* @default
*/
COMPRESSION_METHOD: ["Deflate", "None (Store)"],
/**
* @constant
* @default
*/
OS: ["MSDOS", "Unix", "Macintosh"],
/**
* @constant
* @default
*/
RAW_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.RawDeflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.RawDeflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.RawDeflate.CompressionType.NONE,
},
/**
* Raw Deflate operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_raw_deflate: function(input, args) {
var deflate = new Zlib.RawDeflate(input, {
compressionType: Compress.RAW_COMPRESSION_TYPE_LOOKUP[args[0]]
});
return Array.prototype.slice.call(deflate.compress());
},
/**
* @constant
* @default
*/
INFLATE_INDEX: 0,
/**
* @constant
* @default
*/
INFLATE_BUFFER_SIZE: 0,
/**
* @constant
* @default
*/
INFLATE_RESIZE: false,
/**
* @constant
* @default
*/
INFLATE_VERIFY: false,
/**
* @constant
* @default
*/
RAW_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE,
"Block" : Zlib.RawInflate.BufferType.BLOCK,
},
/**
* Raw Inflate operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_raw_inflate: function(input, args) {
// Deal with character encoding issues
input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
var inflate = new Zlib.RawInflate(input, {
index: args[0],
bufferSize: args[1],
bufferType: Compress.RAW_BUFFER_TYPE_LOOKUP[args[2]],
resize: args[3],
verify: args[4]
}),
result = Array.prototype.slice.call(inflate.decompress());
// Raw Inflate somethimes messes up and returns nonsense like this:
// ]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]....]...
// e.g. Input data of [8b, 1d, dc, 44]
// Look for the first two square brackets:
if (result.length > 158 && result[0] == 93 && result[5] == 93) {
// If the first two square brackets are there, check that the others
// are also there. If they are, throw an error. If not, continue.
var valid = false;
for (var i = 0; i < 155; i += 5) {
if (result[i] != 93) {
valid = true;
}
}
if (!valid) {
throw "Error: Unable to inflate data";
}
}
// Trust me, this is the easiest way...
return result;
},
/**
* @constant
* @default
*/
ZLIB_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.Deflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.Deflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.Deflate.CompressionType.NONE,
},
/**
* Zlib Deflate operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_zlib_deflate: function(input, args) {
var deflate = new Zlib.Deflate(input, {
compressionType: Compress.ZLIB_COMPRESSION_TYPE_LOOKUP[args[0]]
});
return Array.prototype.slice.call(deflate.compress());
},
/**
* @constant
* @default
*/
ZLIB_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.Inflate.BufferType.ADAPTIVE,
"Block" : Zlib.Inflate.BufferType.BLOCK,
},
/**
* Zlib Inflate operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_zlib_inflate: function(input, args) {
// Deal with character encoding issues
input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
var inflate = new Zlib.Inflate(input, {
index: args[0],
bufferSize: args[1],
bufferType: Compress.ZLIB_BUFFER_TYPE_LOOKUP[args[2]],
resize: args[3],
verify: args[4]
});
return Array.prototype.slice.call(inflate.decompress());
},
/**
* @constant
* @default
*/
GZIP_CHECKSUM: false,
/**
* Gzip operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_gzip: function(input, args) {
var filename = args[1],
comment = args[2],
options = {
deflateOptions: {
compressionType: Compress.ZLIB_COMPRESSION_TYPE_LOOKUP[args[0]]
},
flags: {
fhcrc: args[3]
}
};
if (filename.length) {
options.flags.fname = true;
options.filename = filename;
}
if (comment.length) {
options.flags.fcommenct = true;
options.comment = comment;
}
var gzip = new Zlib.Gzip(input, options);
return Array.prototype.slice.call(gzip.compress());
},
/**
* Gunzip operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_gunzip: function(input, args) {
// Deal with character encoding issues
input = Utils.str_to_byte_array(Utils.byte_array_to_utf8(input));
var gunzip = new Zlib.Gunzip(input);
return Array.prototype.slice.call(gunzip.decompress());
},
/**
* @constant
* @default
*/
PKZIP_FILENAME: "file.txt",
/**
* @constant
* @default
*/
ZIP_COMPRESSION_METHOD_LOOKUP: {
"Deflate" : Zlib.Zip.CompressionMethod.DEFLATE,
"None (Store)" : Zlib.Zip.CompressionMethod.STORE
},
/**
* @constant
* @default
*/
ZIP_OS_LOOKUP: {
"MSDOS" : Zlib.Zip.OperatingSystem.MSDOS,
"Unix" : Zlib.Zip.OperatingSystem.UNIX,
"Macintosh" : Zlib.Zip.OperatingSystem.MACINTOSH
},
/**
* Zip operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_pkzip: function(input, args) {
var password = Utils.str_to_byte_array(args[2]),
options = {
filename: Utils.str_to_byte_array(args[0]),
comment: Utils.str_to_byte_array(args[1]),
compressionMethod: Compress.ZIP_COMPRESSION_METHOD_LOOKUP[args[3]],
os: Compress.ZIP_OS_LOOKUP[args[4]],
deflateOption: {
compressionType: Compress.ZLIB_COMPRESSION_TYPE_LOOKUP[args[5]]
},
},
zip = new Zlib.Zip();
if (password.length)
zip.setPassword(password);
zip.addFile(input, options);
return Array.prototype.slice.call(zip.compress());
},
/**
* @constant
* @default
*/
PKUNZIP_VERIFY: false,
/**
* Unzip operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_pkunzip: function(input, args) {
var options = {
password: Utils.str_to_byte_array(args[0]),
verify: args[1]
},
file = "",
unzip = new Zlib.Unzip(input, options),
filenames = unzip.getFilenames(),
output = "<div style='padding: 5px;'>" + filenames.length + " file(s) found</div>\n";
output += "<div class='panel-group' id='zip-accordion' role='tablist' aria-multiselectable='true'>";
window.uzip = unzip;
for (var i = 0; i < filenames.length; i++) {
file = Utils.byte_array_to_utf8(unzip.decompress(filenames[i]));
output += "<div class='panel panel-default'>" +
"<div class='panel-heading' role='tab' id='heading" + i + "'>" +
"<h4 class='panel-title'>" +
"<a class='collapsed' role='button' data-toggle='collapse' data-parent='#zip-accordion' href='#collapse" + i +
"' aria-expanded='true' aria-controls='collapse" + i + "'>" +
filenames[i] + "<span class='pull-right'>" + file.length.toLocaleString() + " bytes</span></a></h4></div>" +
"<div id='collapse" + i + "' class='panel-collapse collapse' role='tabpanel' aria-labelledby='heading" + i + "'>" +
"<div class='panel-body'>" +
Utils.escape_html(file) + "</div></div></div>";
}
return output + "</div>";
},
/**
* Bzip2 Decompress operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_bzip2_decompress: function(input, args) {
var compressed = new Uint8Array(input),
bzip2_reader,
plain = "";
bzip2_reader = bzip2.array(compressed);
plain = bzip2.simple(bzip2_reader);
return plain;
},
};

412
src/js/operations/Convert.js Executable file
View file

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

454
src/js/operations/DateTime.js Executable file
View file

@ -0,0 +1,454 @@
/* globals moment */
/**
* Date and time operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var DateTime = {
/**
* @constant
* @default
*/
UNITS: ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"],
/**
* From UNIX Timestamp operation.
*
* @param {number} input
* @param {Object[]} args
* @returns {string}
*/
run_from_unix_timestamp: function(input, args) {
var units = args[0],
d;
input = parseFloat(input);
if (units == "Seconds (s)") {
d = moment.unix(input);
return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss") + " UTC";
} else if (units == "Milliseconds (ms)") {
d = moment(input);
return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC";
} else if (units == "Microseconds (μs)") {
d = moment(input / 1000);
return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC";
} else if (units == "Nanoseconds (ns)") {
d = moment(input / 1000000);
return d.tz("UTC").format("ddd D MMMM YYYY HH:mm:ss.SSS") + " UTC";
} else {
throw "Unrecognised unit";
}
},
/**
* To UNIX Timestamp operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
run_to_unix_timestamp: function(input, args) {
var units = args[0],
d = moment(input);
if (units == "Seconds (s)") {
return d.unix();
} else if (units == "Milliseconds (ms)") {
return d.valueOf();
} else if (units == "Microseconds (μs)") {
return d.valueOf() * 1000;
} else if (units == "Nanoseconds (ns)") {
return d.valueOf() * 1000000;
} else {
throw "Unrecognised unit";
}
},
/**
* @constant
* @default
*/
DATETIME_FORMATS: [
{
name: "Standard date and time",
value: "DD/MM/YYYY HH:mm:ss"
},
{
name: "American-style date and time",
value: "MM/DD/YYYY HH:mm:ss"
},
{
name: "International date and time",
value: "YYYY-MM-DD HH:mm:ss"
},
{
name: "Verbose date and time",
value: "dddd Do MMMM YYYY HH:mm:ss Z z"
},
{
name: "UNIX timestamp (seconds)",
value: "X"
},
{
name: "UNIX timestamp offset (milliseconds)",
value: "x"
},
{
name: "Automatic",
value: ""
},
],
/**
* @constant
* @default
*/
INPUT_FORMAT_STRING: "DD/MM/YYYY HH:mm:ss",
/**
* @constant
* @default
*/
OUTPUT_FORMAT_STRING: "dddd Do MMMM YYYY HH:mm:ss Z z",
/**
* @constant
* @default
*/
TIMEZONES: ["UTC"].concat(moment.tz.names()),
/**
* Translate DateTime Format operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_translate_format: function(input, args) {
var input_format = args[1],
input_timezone = args[2],
output_format = args[3],
output_timezone = args[4],
date;
try {
date = moment.tz(input, input_format, input_timezone);
if (!date || date.format() == "Invalid date") throw Error;
} catch(err) {
return "Invalid format.\n\n" + DateTime.FORMAT_EXAMPLES;
}
return date.tz(output_timezone).format(output_format);
},
/**
* Parse DateTime operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_parse: function(input, args) {
var input_format = args[1],
input_timezone = args[2],
date,
output = "";
try {
date = moment.tz(input, input_format, input_timezone);
if (!date || date.format() == "Invalid date") throw Error;
} catch(err) {
return "Invalid format.\n\n" + DateTime.FORMAT_EXAMPLES;
}
output += "Date: " + date.format("dddd Do MMMM YYYY") +
"\nTime: " + date.format("HH:mm:ss") +
"\nPeriod: " + date.format("A") +
"\nTimezone: " + date.format("z") +
"\nUTC offset: " + date.format("ZZ") +
"\n\nDaylight Saving Time: " + date.isDST() +
"\nLeap year: " + date.isLeapYear() +
"\nDays in this month: " + date.daysInMonth() +
"\n\nDay of year: " + date.dayOfYear() +
"\nWeek number: " + date.weekYear() +
"\nQuarter: " + date.quarter();
return output;
},
/**
* @constant
*/
FORMAT_EXAMPLES: "Format string tokens:\n\n\
<table class='table table-striped table-hover table-condensed table-bordered' style='font-family: sans-serif'>\
<thead>\
<tr>\
<th>Category</th>\
<th>Token</th>\
<th>Output</th>\
</tr>\
</thead>\
<tbody>\
<tr>\
<td><b>Month</b></td>\
<td>M</td>\
<td>1 2 ... 11 12</td>\
</tr>\
<tr>\
<td></td>\
<td>Mo</td>\
<td>1st 2nd ... 11th 12th</td>\
</tr>\
<tr>\
<td></td>\
<td>MM</td>\
<td>01 02 ... 11 12</td>\
</tr>\
<tr>\
<td></td>\
<td>MMM</td>\
<td>Jan Feb ... Nov Dec</td>\
</tr>\
<tr>\
<td></td>\
<td>MMMM</td>\
<td>January February ... November December</td>\
</tr>\
<tr>\
<td><b>Quarter</b></td>\
<td>Q</td>\
<td>1 2 3 4</td>\
</tr>\
<tr>\
<td><b>Day of Month</b></td>\
<td>D</td>\
<td>1 2 ... 30 31</td>\
</tr>\
<tr>\
<td></td>\
<td>Do</td>\
<td>1st 2nd ... 30th 31st</td>\
</tr>\
<tr>\
<td></td>\
<td>DD</td>\
<td>01 02 ... 30 31</td>\
</tr>\
<tr>\
<td><b>Day of Year</b></td>\
<td>DDD</td>\
<td>1 2 ... 364 365</td>\
</tr>\
<tr>\
<td></td>\
<td>DDDo</td>\
<td>1st 2nd ... 364th 365th</td>\
</tr>\
<tr>\
<td></td>\
<td>DDDD</td>\
<td>001 002 ... 364 365</td>\
</tr>\
<tr>\
<td><b>Day of Week</b></td>\
<td>d</td>\
<td>0 1 ... 5 6</td>\
</tr>\
<tr>\
<td></td>\
<td>do</td>\
<td>0th 1st ... 5th 6th</td>\
</tr>\
<tr>\
<td></td>\
<td>dd</td>\
<td>Su Mo ... Fr Sa</td>\
</tr>\
<tr>\
<td></td>\
<td>ddd</td>\
<td>Sun Mon ... Fri Sat</td>\
</tr>\
<tr>\
<td></td>\
<td>dddd</td>\
<td>Sunday Monday ... Friday Saturday</td>\
</tr>\
<tr>\
<td><b>Day of Week (Locale)</b></td>\
<td>e</td>\
<td>0 1 ... 5 6</td>\
</tr>\
<tr>\
<td><b>Day of Week (ISO)</b></td>\
<td>E</td>\
<td>1 2 ... 6 7</td>\
</tr>\
<tr>\
<td><b>Week of Year</b></td>\
<td>w</td>\
<td>1 2 ... 52 53</td>\
</tr>\
<tr>\
<td></td>\
<td>wo</td>\
<td>1st 2nd ... 52nd 53rd</td>\
</tr>\
<tr>\
<td></td>\
<td>ww</td>\
<td>01 02 ... 52 53</td>\
</tr>\
<tr>\
<td><b>Week of Year (ISO)</b></td>\
<td>W</td>\
<td>1 2 ... 52 53</td>\
</tr>\
<tr>\
<td></td>\
<td>Wo</td>\
<td>1st 2nd ... 52nd 53rd</td>\
</tr>\
<tr>\
<td></td>\
<td>WW</td>\
<td>01 02 ... 52 53</td>\
</tr>\
<tr>\
<td><b>Year</b></td>\
<td>YY</td>\
<td>70 71 ... 29 30</td>\
</tr>\
<tr>\
<td></td>\
<td>YYYY</td>\
<td>1970 1971 ... 2029 2030</td>\
</tr>\
<tr>\
<td><b>Week Year</b></td>\
<td>gg</td>\
<td>70 71 ... 29 30</td>\
</tr>\
<tr>\
<td></td>\
<td>gggg</td>\
<td>1970 1971 ... 2029 2030</td>\
</tr>\
<tr>\
<td><b>Week Year (ISO)</b></td>\
<td>GG</td>\
<td>70 71 ... 29 30</td>\
</tr>\
<tr>\
<td></td>\
<td>GGGG</td>\
<td>1970 1971 ... 2029 2030</td>\
</tr>\
<tr>\
<td><b>AM/PM</b></td>\
<td>A</td>\
<td>AM PM</td>\
</tr>\
<tr>\
<td></td>\
<td>a</td>\
<td>am pm</td>\
</tr>\
<tr>\
<td><b>Hour</b></td>\
<td>H</td>\
<td>0 1 ... 22 23</td>\
</tr>\
<tr>\
<td></td>\
<td>HH</td>\
<td>00 01 ... 22 23</td>\
</tr>\
<tr>\
<td></td>\
<td>h</td>\
<td>1 2 ... 11 12</td>\
</tr>\
<tr>\
<td></td>\
<td>hh</td>\
<td>01 02 ... 11 12</td>\
</tr>\
<tr>\
<td><b>Minute</b></td>\
<td>m</td>\
<td>0 1 ... 58 59</td>\
</tr>\
<tr>\
<td></td>\
<td>mm</td>\
<td>00 01 ... 58 59</td>\
</tr>\
<tr>\
<td><b>Second</b></td>\
<td>s</td>\
<td>0 1 ... 58 59</td>\
</tr>\
<tr>\
<td></td>\
<td>ss</td>\
<td>00 01 ... 58 59</td>\
</tr>\
<tr>\
<td><b>Fractional Second</b></td>\
<td>S</td>\
<td>0 1 ... 8 9</td>\
</tr>\
<tr>\
<td></td>\
<td>SS</td>\
<td>00 01 ... 98 99</td>\
</tr>\
<tr>\
<td></td>\
<td>SSS</td>\
<td>000 001 ... 998 999</td>\
</tr>\
<tr>\
<td></td>\
<td>SSSS ... SSSSSSSSS</td>\
<td>000[0..] 001[0..] ... 998[0..] 999[0..]</td>\
</tr>\
<tr>\
<td><b>Timezone</b></td>\
<td>z or zz</td>\
<td>EST CST ... MST PST</td>\
</tr>\
<tr>\
<td></td>\
<td>Z</td>\
<td>-07:00 -06:00 ... +06:00 +07:00</td>\
</tr>\
<tr>\
<td></td>\
<td>ZZ</td>\
<td>-0700 -0600 ... +0600 +0700</td>\
</tr>\
<tr>\
<td><b>Unix Timestamp</b></td>\
<td>X</td>\
<td>1360013296</td>\
</tr>\
<tr>\
<td><b>Unix Millisecond Timestamp</b></td>\
<td>x</td>\
<td>1360013296123</td>\
</tr>\
</tbody>\
</table>",
};

94
src/js/operations/Endian.js Executable file
View file

@ -0,0 +1,94 @@
/**
* Endian operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Endian = {
/**
* @constant
* @default
*/
DATA_FORMAT: ["Hex", "Raw"],
/**
* @constant
* @default
*/
WORD_LENGTH: 4,
/**
* @constant
* @default
*/
PAD_INCOMPLETE_WORDS: true,
/**
* Swap endianness operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_swap_endianness: function(input, args) {
var data_format = args[0],
word_length = args[1],
pad_incomplete_words = args[2],
data = [],
result = [],
words = [],
i = 0,
j = 0;
if (word_length <= 0) {
return "Word length must be greater than 0";
}
// Convert input to raw data based on specified data format
switch (data_format) {
case "Hex":
data = Utils.from_hex(input);
break;
case "Raw":
data = Utils.str_to_byte_array(input);
break;
default:
data = input;
}
// Split up into words
for (i = 0; i < data.length; i += word_length) {
var word = data.slice(i, i + word_length);
// Pad word if too short
if (pad_incomplete_words && word.length < word_length){
for (j = word.length; j < word_length; j++) {
word.push(0);
}
}
words.push(word);
}
// Swap endianness and flatten
for (i = 0; i < words.length; i++) {
j = words[i].length;
while (j--) {
result.push(words[i][j]);
}
}
// Convert data back to specified data format
switch (data_format) {
case "Hex":
return Utils.to_hex(result);
case "Raw":
return Utils.byte_array_to_utf8(result);
default:
return result;
}
},
};

166
src/js/operations/Entropy.js Executable file
View file

@ -0,0 +1,166 @@
/**
* Entropy operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Entropy = {
/**
* @constant
* @default
*/
CHUNK_SIZE: 1000,
/**
* Entropy operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {html}
*/
run_entropy: function(input, args) {
var chunk_size = args[0],
output = "",
entropy = Entropy._calc_entropy(input);
output += "Shannon entropy: " + entropy + "\n" +
"<br><canvas id='chart-area'></canvas><br>\n" +
"- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.\n" +
"- Standard English text usually falls somewhere between 3.5 and 5.\n" +
"- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.\n\n" +
"The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.\n\n" +
"<br><script>\
var canvas = document.getElementById('chart-area'),\
parent_rect = canvas.parentNode.getBoundingClientRect(),\
entropy = " + entropy + ",\
height = parent_rect.height * 0.25;\
\
canvas.width = parent_rect.width * 0.95;\
canvas.height = height > 150 ? 150 : height;\
\
CanvasComponents.draw_scale_bar(canvas, entropy, 8, [\
{\
label: 'English text',\
min: 3.5,\
max: 5\
},{\
label: 'Encrypted/compressed',\
min: 7.5,\
max: 8\
}\
]);\
</script>";
var chunk_entropy = 0;
if (chunk_size !== 0) {
for (var i = 0; i < input.length; i += chunk_size) {
chunk_entropy = Entropy._calc_entropy(input.slice(i, i+chunk_size));
output += "Bytes " + i + " to " + (i+chunk_size) + ": " + chunk_entropy + "\n";
}
} else {
output += "Chunk size cannot be 0.";
}
return output;
},
/**
* @constant
* @default
*/
FREQ_ZEROS: false,
/**
* Frequency distribution operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {html}
*/
run_freq_distrib: function (input, args) {
if (!input.length) return "No data";
var distrib = new Array(256),
percentages = new Array(256),
len = input.length,
show_zeroes = args[0];
// Initialise distrib to 0
for (var i = 0; i < 256; i++) {
distrib[i] = 0;
}
// Count bytes
for (i = 0; i < len; i++) {
distrib[input[i]]++;
}
// Calculate percentages
var repr = 0;
for (i = 0; i < 256; i++) {
if (distrib[i] > 0) repr++;
percentages[i] = distrib[i] / len * 100;
}
// Print
var output = "<canvas id='chart-area'></canvas><br>" +
"Total data length: " + len +
"\nNumber of bytes represented: " + repr +
"\nNumber of bytes not represented: " + (256-repr) +
"\n\nByte Percentage\n" +
"<script>\
var canvas = document.getElementById('chart-area'),\
parent_rect = canvas.parentNode.getBoundingClientRect(),\
scores = " + JSON.stringify(percentages) + ";\
\
canvas.width = parent_rect.width * 0.95;\
canvas.height = parent_rect.height * 0.9;\
\
CanvasComponents.draw_bar_chart(canvas, scores, 'Byte', 'Frequency %', 16, 6);\
</script>";
for (i = 0; i < 256; i++) {
if (distrib[i] || show_zeroes) {
output += " " + Utils.hex(i, 2) + " (" +
Utils.pad_right(percentages[i].toFixed(2).replace(".00", "") + "%)", 8) +
Array(Math.ceil(percentages[i])+1).join("|") + "\n";
}
}
return output;
},
/**
* Calculates the Shannon entropy for a given chunk of data.
*
* @private
* @param {byte_array} data
* @returns {number}
*/
_calc_entropy: function(data) {
var prob = [],
uniques = data.unique(),
str = Utils.byte_array_to_chars(data);
for (var i = 0; i < uniques.length; i++) {
prob.push(str.count(Utils.chr(uniques[i])) / data.length);
}
var entropy = 0,
p;
for (i = 0; i < prob.length; i++) {
p = prob[i];
entropy += p * Math.log(p) / Math.log(2);
}
return -entropy;
},
};

297
src/js/operations/Extract.js Executable file
View file

@ -0,0 +1,297 @@
/**
* Identifier extraction operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Extract = {
/**
* Runs search operations across the input data using refular expressions.
*
* @private
* @param {string} input
* @param {RegExp} search_regex
* @param {RegExp} remove_regex - A regular expression defining results to remove from the
* final list
* @param {boolean} include_total - Whether or not to include the total number of results
* @returns {string}
*/
_search: function(input, search_regex, remove_regex, include_total) {
var output = "",
total = 0,
match;
while (!!(match = search_regex.exec(input))) {
if (remove_regex && remove_regex.test(match[0]))
continue;
total++;
output += match[0] + "\n";
}
if (include_total)
output = "Total found: " + total + "\n\n" + output;
return output;
},
/**
* @constant
* @default
*/
MIN_STRING_LEN: 3,
/**
* @constant
* @default
*/
DISPLAY_TOTAL: false,
/**
* Strings operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_strings: function(input, args) {
var min_len = args[0] || Extract.MIN_STRING_LEN,
display_total = args[1],
strings = "[A-Z\\d/\\-:.,_$%'\"()<>= !\\[\\]{}@]",
regex = new RegExp(strings + "{" + min_len + ",}", "ig");
return Extract._search(input, regex, null, display_total);
},
/**
* @constant
* @default
*/
INCLUDE_IPV4: true,
/**
* @constant
* @default
*/
INCLUDE_IPV6: false,
/**
* @constant
* @default
*/
REMOVE_LOCAL: false,
/**
* Extract IP addresses operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_ip: function(input, args) {
var include_ipv4 = args[0],
include_ipv6 = args[1],
remove_local = args[2],
display_total = args[3],
ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})",
ips = "";
if (include_ipv4 && include_ipv6) {
ips = ipv4 + "|" + ipv6;
} else if (include_ipv4) {
ips = ipv4;
} else if (include_ipv6) {
ips = ipv6;
}
if (ips) {
var regex = new RegExp(ips, "ig");
if (remove_local) {
var ten = "10\\..+",
oneninetwo = "192\\.168\\..+",
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
onetwoseven = "127\\..+",
remove_regex = new RegExp("^(?:" + ten + "|" + oneninetwo +
"|" + oneseventwo + "|" + onetwoseven + ")");
return Extract._search(input, regex, remove_regex, display_total);
} else {
return Extract._search(input, regex, null, display_total);
}
} else {
return "";
}
},
/**
* Extract email addresses operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_email: function(input, args) {
var display_total = args[0],
regex = /\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}/ig;
return Extract._search(input, regex, null, display_total);
},
/**
* Extract MAC addresses operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_mac: function(input, args) {
var display_total = args[0],
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
return Extract._search(input, regex, null, display_total);
},
/**
* Extract URLs operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_urls: function(input, args) {
var display_total = args[0],
protocol = "[A-Z]+://",
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
port = ":\\d+",
path = "/[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]*";
path += "(?:[.!,?]+[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]+)*";
var regex = new RegExp(protocol + hostname + "(?:" + port +
")?(?:" + path + ")?", "ig");
return Extract._search(input, regex, null, display_total);
},
/**
* Extract domains operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_domains: function(input, args) {
var display_total = args[0],
protocol = "https?://",
hostname = "[-\\w\\.]+",
tld = "\\.(?:com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+",
regex = new RegExp("(?:" + protocol + ")?" + hostname + tld, "ig");
return Extract._search(input, regex, null, display_total);
},
/**
* @constant
* @default
*/
INCLUDE_WIN_PATH: true,
/**
* @constant
* @default
*/
INCLUDE_UNIX_PATH: true,
/**
* Extract file paths operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_file_paths: function(input, args) {
var include_win_path = args[0],
include_unix_path = args[1],
display_total = args[2],
win_drive = "[A-Z]:\\\\",
win_name = "[A-Z\\d][A-Z\\d\\- '_\\(\\)]{0,61}",
win_ext = "[A-Z\\d]{1,6}",
win_path = win_drive + "(?:" + win_name + "\\\\?)*" + win_name +
"(?:\\." + win_ext + ")?",
unix_path = "(?:/[A-Z\\d.][A-Z\\d\\-.]{0,61})+",
file_paths = "";
if (include_win_path && include_unix_path) {
file_paths = win_path + "|" + unix_path;
} else if (include_win_path) {
file_paths = win_path;
} else if (include_unix_path) {
file_paths = unix_path;
}
if (file_paths) {
var regex = new RegExp(file_paths, "ig");
return Extract._search(input, regex, null, display_total);
} else {
return "";
}
},
/**
* Extract dates operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_dates: function(input, args) {
var display_total = args[0],
date1 = "(?:19|20)\\d\\d[- /.](?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])", // yyyy-mm-dd
date2 = "(?:0[1-9]|[12][0-9]|3[01])[- /.](?:0[1-9]|1[012])[- /.](?:19|20)\\d\\d", // dd/mm/yyyy
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
return Extract._search(input, regex, null, display_total);
},
/**
* Extract all identifiers operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_all_idents: function(input, args) {
var output = "";
output += "IP addresses\n";
output += Extract.run_ip(input, [true, true, false]);
output += "\nEmail addresses\n";
output += Extract.run_email(input, []);
output += "\nMAC addresses\n";
output += Extract.run_mac(input, []);
output += "\nURLs\n";
output += Extract.run_urls(input, []);
output += "\nDomain names\n";
output += Extract.run_domains(input, []);
output += "\nFile paths\n";
output += Extract.run_file_paths(input, [true, true]);
output += "\nDates\n";
output += Extract.run_dates(input, []);
return output;
},
};

526
src/js/operations/FileType.js Executable file
View file

@ -0,0 +1,526 @@
/**
* File type operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var FileType = {
/**
* Detect File Type operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_detect: function(input, args) {
var type = FileType._magic_type(input);
if (!type) {
return "Unknown file type. Have you tried checking the entropy of this data to determine whether it might be encrypted or compressed?";
} else {
var output = "File extension: " + type.ext + "\n" +
"MIME type: " + type.mime;
if (type.desc && type.desc.length) {
output += "\nDescription: " + type.desc;
}
return output;
}
},
/**
* @constant
* @default
*/
IGNORE_COMMON_BYTE_SEQUENCES: true,
/**
* Scan for Embedded Files operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_scan_for_embedded_files: function(input, args) {
var output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any suffiently long file is likely to contain these magic bytes coincidentally.\n",
type,
ignore_common = args[0],
common_exts = ["ico", "ttf", ""],
num_found = 0,
num_common_found = 0;
for (var i = 0; i < input.length; i++) {
type = FileType._magic_type(input.slice(i));
if (type) {
if (ignore_common && common_exts.indexOf(type.ext) > -1) {
num_common_found++;
continue;
}
num_found++;
output += "\nOffset " + i + " (0x" + Utils.hex(i) + "):\n" +
" File extension: " + type.ext + "\n" +
" MIME type: " + type.mime + "\n";
if (type.desc && type.desc.length) {
output += " Description: " + type.desc + "\n";
}
}
}
if (num_found === 0) {
output += "\nNo embedded files were found.";
}
if (num_common_found > 0) {
output += "\n\n" + num_common_found;
output += num_common_found == 1 ?
" file type was detected that has a common byte sequence. This is likely to be a false positive." :
" file types were detected that have common byte sequences. These are likely to be false positives.";
output += " Run this operation with the 'Ignore common byte sequences' option unchecked to see details.";
}
return output;
},
/**
* Given a buffer, detects magic byte sequences at specific positions and returns the
* extension and mime type.
*
* @private
* @param {byte_array} buf
* @returns {Object} type
* @returns {string} type.ext - File extension
* @returns {string} type.mime - Mime type
* @returns {string} [type.desc] - Description
*/
_magic_type: function (buf) {
if (!(buf && buf.length > 1)) {
return null;
}
if (buf[0] === 0xFF && buf[1] === 0xD8 && buf[2] === 0xFF) {
return {
ext: 'jpg',
mime: 'image/jpeg'
};
}
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47) {
return {
ext: 'png',
mime: 'image/png'
};
}
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) {
return {
ext: 'gif',
mime: 'image/gif'
};
}
if (buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
return {
ext: 'webp',
mime: 'image/webp'
};
}
// needs to be before `tif` check
if (((buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) || (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)) && buf[8] === 0x43 && buf[9] === 0x52) {
return {
ext: 'cr2',
mime: 'image/x-canon-cr2'
};
}
if ((buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) || (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)) {
return {
ext: 'tif',
mime: 'image/tiff'
};
}
if (buf[0] === 0x42 && buf[1] === 0x4D) {
return {
ext: 'bmp',
mime: 'image/bmp'
};
}
if (buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0xBC) {
return {
ext: 'jxr',
mime: 'image/vnd.ms-photo'
};
}
if (buf[0] === 0x38 && buf[1] === 0x42 && buf[2] === 0x50 && buf[3] === 0x53) {
return {
ext: 'psd',
mime: 'image/vnd.adobe.photoshop'
};
}
// needs to be before `zip` check
if (buf[0] === 0x50 && buf[1] === 0x4B && buf[2] === 0x3 && buf[3] === 0x4 && buf[30] === 0x6D && buf[31] === 0x69 && buf[32] === 0x6D && buf[33] === 0x65 && buf[34] === 0x74 && buf[35] === 0x79 && buf[36] === 0x70 && buf[37] === 0x65 && buf[38] === 0x61 && buf[39] === 0x70 && buf[40] === 0x70 && buf[41] === 0x6C && buf[42] === 0x69 && buf[43] === 0x63 && buf[44] === 0x61 && buf[45] === 0x74 && buf[46] === 0x69 && buf[47] === 0x6F && buf[48] === 0x6E && buf[49] === 0x2F && buf[50] === 0x65 && buf[51] === 0x70 && buf[52] === 0x75 && buf[53] === 0x62 && buf[54] === 0x2B && buf[55] === 0x7A && buf[56] === 0x69 && buf[57] === 0x70) {
return {
ext: 'epub',
mime: 'application/epub+zip'
};
}
if (buf[0] === 0x50 && buf[1] === 0x4B && (buf[2] === 0x3 || buf[2] === 0x5 || buf[2] === 0x7) && (buf[3] === 0x4 || buf[3] === 0x6 || buf[3] === 0x8)) {
return {
ext: 'zip',
mime: 'application/zip'
};
}
if (buf[257] === 0x75 && buf[258] === 0x73 && buf[259] === 0x74 && buf[260] === 0x61 && buf[261] === 0x72) {
return {
ext: 'tar',
mime: 'application/x-tar'
};
}
if (buf[0] === 0x52 && buf[1] === 0x61 && buf[2] === 0x72 && buf[3] === 0x21 && buf[4] === 0x1A && buf[5] === 0x7 && (buf[6] === 0x0 || buf[6] === 0x1)) {
return {
ext: 'rar',
mime: 'application/x-rar-compressed'
};
}
if (buf[0] === 0x1F && buf[1] === 0x8B && buf[2] === 0x8) {
return {
ext: 'gz',
mime: 'application/gzip'
};
}
if (buf[0] === 0x42 && buf[1] === 0x5A && buf[2] === 0x68) {
return {
ext: 'bz2',
mime: 'application/x-bzip2'
};
}
if (buf[0] === 0x37 && buf[1] === 0x7A && buf[2] === 0xBC && buf[3] === 0xAF && buf[4] === 0x27 && buf[5] === 0x1C) {
return {
ext: '7z',
mime: 'application/x-7z-compressed'
};
}
if (buf[0] === 0x78 && buf[1] === 0x01) {
return {
ext: 'dmg',
mime: 'application/x-apple-diskimage'
};
}
if ((buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && (buf[3] === 0x18 || buf[3] === 0x20) && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) || (buf[0] === 0x33 && buf[1] === 0x67 && buf[2] === 0x70 && buf[3] === 0x35) || (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x6D && buf[9] === 0x70 && buf[10] === 0x34 && buf[11] === 0x32 && buf[16] === 0x6D && buf[17] === 0x70 && buf[18] === 0x34 && buf[19] === 0x31 && buf[20] === 0x6D && buf[21] === 0x70 && buf[22] === 0x34 && buf[23] === 0x32 && buf[24] === 0x69 && buf[25] === 0x73 && buf[26] === 0x6F && buf[27] === 0x6D)) {
return {
ext: 'mp4',
mime: 'video/mp4'
};
}
if ((buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D && buf[9] === 0x34 && buf[10] === 0x56)) {
return {
ext: 'm4v',
mime: 'video/x-m4v'
};
}
if (buf[0] === 0x4D && buf[1] === 0x54 && buf[2] === 0x68 && buf[3] === 0x64) {
return {
ext: 'mid',
mime: 'audio/midi'
};
}
// needs to be before the `webm` check
if (buf[31] === 0x6D && buf[32] === 0x61 && buf[33] === 0x74 && buf[34] === 0x72 && buf[35] === 0x6f && buf[36] === 0x73 && buf[37] === 0x6B && buf[38] === 0x61) {
return {
ext: 'mkv',
mime: 'video/x-matroska'
};
}
if (buf[0] === 0x1A && buf[1] === 0x45 && buf[2] === 0xDF && buf[3] === 0xA3) {
return {
ext: 'webm',
mime: 'video/webm'
};
}
if (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x14 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) {
return {
ext: 'mov',
mime: 'video/quicktime'
};
}
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x41 && buf[9] === 0x56 && buf[10] === 0x49) {
return {
ext: 'avi',
mime: 'video/x-msvideo'
};
}
if (buf[0] === 0x30 && buf[1] === 0x26 && buf[2] === 0xB2 && buf[3] === 0x75 && buf[4] === 0x8E && buf[5] === 0x66 && buf[6] === 0xCF && buf[7] === 0x11 && buf[8] === 0xA6 && buf[9] === 0xD9) {
return {
ext: 'wmv',
mime: 'video/x-ms-wmv'
};
}
if (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x1 && buf[3].toString(16)[0] === 'b') {
return {
ext: 'mpg',
mime: 'video/mpeg'
};
}
if ((buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) || (buf[0] === 0xFF && buf[1] === 0xfb)) {
return {
ext: 'mp3',
mime: 'audio/mpeg'
};
}
if ((buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D && buf[9] === 0x34 && buf[10] === 0x41) || (buf[0] === 0x4D && buf[1] === 0x34 && buf[2] === 0x41 && buf[3] === 0x20)) {
return {
ext: 'm4a',
mime: 'audio/m4a'
};
}
if (buf[0] === 0x4F && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53) {
return {
ext: 'ogg',
mime: 'audio/ogg'
};
}
if (buf[0] === 0x66 && buf[1] === 0x4C && buf[2] === 0x61 && buf[3] === 0x43) {
return {
ext: 'flac',
mime: 'audio/x-flac'
};
}
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45) {
return {
ext: 'wav',
mime: 'audio/x-wav'
};
}
if (buf[0] === 0x23 && buf[1] === 0x21 && buf[2] === 0x41 && buf[3] === 0x4D && buf[4] === 0x52 && buf[5] === 0x0A) {
return {
ext: 'amr',
mime: 'audio/amr'
};
}
if (buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46) {
return {
ext: 'pdf',
mime: 'application/pdf'
};
}
if (buf[0] === 0x4D && buf[1] === 0x5A) {
return {
ext: 'exe',
mime: 'application/x-msdownload'
};
}
if ((buf[0] === 0x43 || buf[0] === 0x46) && buf[1] === 0x57 && buf[2] === 0x53) {
return {
ext: 'swf',
mime: 'application/x-shockwave-flash'
};
}
if (buf[0] === 0x7B && buf[1] === 0x5C && buf[2] === 0x72 && buf[3] === 0x74 && buf[4] === 0x66) {
return {
ext: 'rtf',
mime: 'application/rtf'
};
}
if (buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x46 && buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) {
return {
ext: 'woff',
mime: 'application/font-woff'
};
}
if (buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x32 && buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) {
return {
ext: 'woff2',
mime: 'application/font-woff'
};
}
if (buf[34] === 0x4C && buf[35] === 0x50 && ((buf[8] === 0x02 && buf[9] === 0x00 && buf[10] === 0x01) || (buf[8] === 0x01 && buf[9] === 0x00 && buf[10] === 0x00) || (buf[8] === 0x02 && buf[9] === 0x00 && buf[10] === 0x02))) {
return {
ext: 'eot',
mime: 'application/octet-stream'
};
}
if (buf[0] === 0x00 && buf[1] === 0x01 && buf[2] === 0x00 && buf[3] === 0x00 && buf[4] === 0x00) {
return {
ext: 'ttf',
mime: 'application/font-sfnt'
};
}
if (buf[0] === 0x4F && buf[1] === 0x54 && buf[2] === 0x54 && buf[3] === 0x4F && buf[4] === 0x00) {
return {
ext: 'otf',
mime: 'application/font-sfnt'
};
}
if (buf[0] === 0x00 && buf[1] === 0x00 && buf[2] === 0x01 && buf[3] === 0x00) {
return {
ext: 'ico',
mime: 'image/x-icon'
};
}
if (buf[0] === 0x46 && buf[1] === 0x4C && buf[2] === 0x56 && buf[3] === 0x01) {
return {
ext: 'flv',
mime: 'video/x-flv'
};
}
if (buf[0] === 0x25 && buf[1] === 0x21) {
return {
ext: 'ps',
mime: 'application/postscript'
};
}
if (buf[0] === 0xFD && buf[1] === 0x37 && buf[2] === 0x7A && buf[3] === 0x58 && buf[4] === 0x5A && buf[5] === 0x00) {
return {
ext: 'xz',
mime: 'application/x-xz'
};
}
if (buf[0] === 0x53 && buf[1] === 0x51 && buf[2] === 0x4C && buf[3] === 0x69) {
return {
ext: 'sqlite',
mime: 'application/x-sqlite3'
};
}
// Added by n1474335 [n1474335@gmail.com] from here on
// ################################################################## //
if ((buf[0] === 0x1F && buf[1] === 0x9D) || (buf[0] === 0x1F && buf[1] === 0xA0)) {
return {
ext: 'z, tar.z',
mime: 'application/x-gtar'
};
}
if (buf[0] === 0x7F && buf[1] === 0x45 && buf[2] === 0x4C && buf[3] === 0x46) {
return {
ext: 'none, axf, bin, elf, o, prx, puff, so',
mime: 'application/x-executable',
desc: 'Executable and Linkable Format file. No standard file extension.'
};
}
if (buf[0] === 0xCA && buf[1] === 0xFE && buf[2] === 0xBA && buf[3] === 0xBE) {
return {
ext: 'class',
mime: 'application/java-vm'
};
}
if (buf[0] === 0xEF && buf[1] === 0xBB && buf[2] === 0xBF) {
return {
ext: 'txt',
mime: 'text/plain',
desc: 'UTF-8 encoded Unicode byte order mark detected, commonly but not exclusively seen in text files.'
};
}
// Must be before Little-endian UTF-16 BOM
if (buf[0] === 0xFF && buf[1] === 0xFE && buf[2] === 0x00 && buf[3] === 0x00) {
return {
ext: '',
mime: '',
desc: 'Little-endian UTF-32 encoded Unicode byte order mark detected.'
};
}
if (buf[0] === 0xFF && buf[1] === 0xFE) {
return {
ext: '',
mime: '',
desc: 'Little-endian UTF-16 encoded Unicode byte order mark detected.'
};
}
if ((buf[0x8001] === 0x43 && buf[0x8002] === 0x44 && buf[0x8003] === 0x30 && buf[0x8004] === 0x30 && buf[0x8005] === 0x31) ||
(buf[0x8801] === 0x43 && buf[0x8802] === 0x44 && buf[0x8803] === 0x30 && buf[0x8804] === 0x30 && buf[0x8805] === 0x31) ||
(buf[0x9001] === 0x43 && buf[0x9002] === 0x44 && buf[0x9003] === 0x30 && buf[0x9004] === 0x30 && buf[0x9005] === 0x31)) {
return {
ext: 'iso',
mime: 'application/octet-stream',
desc: 'ISO 9660 CD/DVD image file'
};
}
if (buf[0] === 0xD0 && buf[1] === 0xCF && buf[2] === 0x11 && buf[3] === 0xE0 && buf[4] === 0xA1 && buf[5] === 0xB1 && buf[6] === 0x1A && buf[7] === 0xE1) {
return {
ext: 'doc, xls, ppt',
mime: 'application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint',
desc: 'Microsoft Office documents'
};
}
if (buf[0] === 0x64 && buf[1] === 0x65 && buf[2] === 0x78 && buf[3] === 0x0A && buf[4] === 0x30 && buf[5] === 0x33 && buf[6] === 0x35 && buf[7] === 0x00) {
return {
ext: 'dex',
mime: 'application/octet-stream',
desc: 'Dalvik Executable (Android)'
};
}
if (buf[0] === 0x4B && buf[1] === 0x44 && buf[2] === 0x4D) {
return {
ext: 'vmdk',
mime: 'application/vmdk, application/x-virtualbox-vmdk'
};
}
if (buf[0] === 0x43 && buf[1] === 0x72 && buf[2] === 0x32 && buf[3] == 0x34) {
return {
ext: 'crx',
mime: 'application/crx',
desc: 'Google Chrome extension or packaged app'
};
}
return null;
},
};

851
src/js/operations/HTML.js Executable file
View file

@ -0,0 +1,851 @@
/**
* HTML operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var HTML = {
/**
* @constant
* @default
*/
CONVERT_ALL: false,
/**
* @constant
* @default
*/
CONVERT_OPTIONS: ["Named entities where possible", "Numeric entities", "Hex entities"],
/**
* To HTML Entity operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_to_entity: function(input, args) {
var convert_all = args[0],
numeric = args[1] == "Numeric entities",
hexa = args[1] == "Hex entities";
var charcodes = Utils.str_to_charcode(input);
var output = "";
for (var i = 0; i < charcodes.length; i++) {
if (convert_all && numeric) {
output += "&#" + charcodes[i] + ";";
} else if (convert_all && hexa) {
output += "&#x" + Utils.hex(charcodes[i]) + ";";
} else if (convert_all) {
output += HTML._byte_to_entity[charcodes[i]] || "&#" + charcodes[i] + ";";
} else if (numeric) {
if (charcodes[i] > 255 || HTML._byte_to_entity.hasOwnProperty(charcodes[i])) {
output += "&#" + charcodes[i] + ";";
} else {
output += Utils.chr(charcodes[i]);
}
} else if (hexa) {
if (charcodes[i] > 255 || HTML._byte_to_entity.hasOwnProperty(charcodes[i])) {
output += "&#x" + Utils.hex(charcodes[i]) + ";";
} else {
output += Utils.chr(charcodes[i]);
}
} else {
output += HTML._byte_to_entity[charcodes[i]] || (
charcodes[i] > 255 ?
"&#" + charcodes[i] + ";" :
Utils.chr(charcodes[i])
);
}
}
return output;
},
/**
* From HTML Entity operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_from_entity: function(input, args) {
var regex = /&(#?x?[a-zA-Z0-9]{1,8});/g,
output = "",
m,
i = 0;
while (!!(m = regex.exec(input))) {
// Add up to match
for (; i < m.index;)
output += input[i++];
// Add match
var bite = HTML._entity_to_byte[m[1]];
if (bite) {
output += Utils.chr(bite);
} else if (!bite && m[1][0] == "#" && m[1].length > 1 && /^#\d{1,5}$/.test(m[1])) {
// Numeric entity (e.g. &#10;)
var num = m[1].slice(1,m[1].length);
output += Utils.chr(parseInt(num, 10));
} else if (!bite && m[1][0] == "#" && m[1].length > 3 && /^#x[\dA-F]{2,8}$/i.test(m[1])) {
// Hex entity (e.g. &#x3A;)
var hex = m[1].slice(2,m[1].length);
output += Utils.chr(parseInt(hex, 16));
} else {
// Not a valid entity, print as normal
for (; i < regex.lastIndex;)
output += input[i++];
}
i = regex.lastIndex;
}
// Add all after final match
for (; i < input.length;)
output += input[i++];
return output;
},
/**
* @constant
* @default
*/
REMOVE_INDENTATION: true,
/**
* @constant
* @default
*/
REMOVE_LINE_BREAKS: true,
/**
* Strip HTML tags operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_strip_tags: function(input, args) {
var remove_indentation = args[0],
remove_line_breaks = args[1];
input = Utils.strip_html_tags(input);
if (remove_indentation) {
input = input.replace(/\n[ \f\t]+/g, "\n");
}
if (remove_line_breaks) {
input = input.replace(/^\s*\n/, "") // first line
.replace(/(\n\s*){2,}/g, "\n"); // all others
}
return input;
},
/**
* Parse colour code operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_parse_colour_code: function(input, args) {
var m = null,
r = 0, g = 0, b = 0, a = 1;
// Read in the input
if (!!(m = input.match(/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/i))) {
// Hex - #d9edf7
r = parseInt(m[1], 16);
g = parseInt(m[2], 16);
b = parseInt(m[3], 16);
} else if (!!(m = input.match(/rgba?\((\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?)(?:,\s?(\d(?:\.\d+)?))?\)/i))) {
// RGB or RGBA - rgb(217,237,247) or rgba(217,237,247,1)
r = parseFloat(m[1]);
g = parseFloat(m[2]);
b = parseFloat(m[3]);
a = m[4] ? parseFloat(m[4]) : 1;
} else if (!!(m = input.match(/hsla?\((\d{1,3}(?:\.\d+)?),\s?(\d{1,3}(?:\.\d+)?)%,\s?(\d{1,3}(?:\.\d+)?)%(?:,\s?(\d(?:\.\d+)?))?\)/i))) {
// HSL or HSLA - hsl(200, 65%, 91%) or hsla(200, 65%, 91%, 1)
var h_ = parseFloat(m[1]) / 360,
s_ = parseFloat(m[2]) / 100,
l_ = parseFloat(m[3]) / 100,
rgb_ = HTML._hsl_to_rgb(h_, s_, l_);
r = rgb_[0];
g = rgb_[1];
b = rgb_[2];
a = m[4] ? parseFloat(m[4]) : 1;
} else if (!!(m = input.match(/cmyk\((\d(?:\.\d+)?),\s?(\d(?:\.\d+)?),\s?(\d(?:\.\d+)?),\s?(\d(?:\.\d+)?)\)/i))) {
// CMYK - cmyk(0.12, 0.04, 0.00, 0.03)
var c_ = parseFloat(m[1]),
m_ = parseFloat(m[2]),
y_ = parseFloat(m[3]),
k_ = parseFloat(m[4]);
r = Math.round(255 * (1 - c_) * (1 - k_));
g = Math.round(255 * (1 - m_) * (1 - k_));
b = Math.round(255 * (1 - y_) * (1 - k_));
}
var hsl_ = HTML._rgb_to_hsl(r, g, b),
h = Math.round(hsl_[0] * 360),
s = Math.round(hsl_[1] * 100),
l = Math.round(hsl_[2] * 100),
k = 1 - Math.max(r/255, g/255, b/255),
c = (1 - r/255 - k) / (1 - k),
m = (1 - g/255 - k) / (1 - k), // jshint ignore:line
y = (1 - b/255 - k) / (1 - k);
c = isNaN(c) ? "0" : c.toFixed(2);
m = isNaN(m) ? "0" : m.toFixed(2);
y = isNaN(y) ? "0" : y.toFixed(2);
k = k.toFixed(2);
var hex = "#" +
Utils.pad_left(Math.round(r).toString(16), 2) +
Utils.pad_left(Math.round(g).toString(16), 2) +
Utils.pad_left(Math.round(b).toString(16), 2),
rgb = "rgb(" + r + ", " + g + ", " + b + ")",
rgba = "rgba(" + r + ", " + g + ", " + b + ", " + a + ")",
hsl = "hsl(" + h + ", " + s + "%, " + l + "%)",
hsla = "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")",
cmyk = "cmyk(" + c + ", " + m + ", " + y + ", " + k + ")";
// Generate output
return "<div id='colorpicker' style='display: inline-block'></div>" +
"Hex: " + hex + "\n" +
"RGB: " + rgb + "\n" +
"RGBA: " + rgba + "\n" +
"HSL: " + hsl + "\n" +
"HSLA: " + hsla + "\n" +
"CMYK: " + cmyk +
"<script>\
$('#colorpicker').colorpicker({\
format: 'rgba',\
color: '" + rgba + "',\
container: true,\
inline: true,\
}).on('changeColor', function(e) {\
var color = e.color.toRGB();\
document.getElementById('input-text').value = 'rgba(' +\
color.r + ', ' + color.g + ', ' + color.b + ', ' + color.a + ')';\
window.app.auto_bake();\
});\
</script>";
},
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @private
* @author Mohsen (http://stackoverflow.com/a/9493060)
*
* @param {number} h - The hue
* @param {number} s - The saturation
* @param {number} l - The lightness
* @return {Array} The RGB representation
*/
_hsl_to_rgb: function(h, s, l){
var r, g, b;
if (s === 0){
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
},
/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* @private
* @author Mohsen (http://stackoverflow.com/a/9493060)
*
* @param {number} r - The red color value
* @param {number} g - The green color value
* @param {number} b - The blue color value
* @return {Array} The HSL representation
*/
_rgb_to_hsl: function(r, g, b) {
r /= 255; g /= 255; b /= 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b),
h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
},
/**
* Lookup table to translate byte values to their HTML entity codes.
*
* @private
* @constant
*/
_byte_to_entity: {
34 : "&quot;",
38 : "&amp;",
39 : "&apos;",
60 : "&lt;",
62 : "&gt;",
160 : "&nbsp;",
161 : "&iexcl;",
162 : "&cent;",
163 : "&pound;",
164 : "&curren;",
165 : "&yen;",
166 : "&brvbar;",
167 : "&sect;",
168 : "&uml;",
169 : "&copy;",
170 : "&ordf;",
171 : "&laquo;",
172 : "&not;",
173 : "&shy;",
174 : "&reg;",
175 : "&macr;",
176 : "&deg;",
177 : "&plusmn;",
178 : "&sup2;",
179 : "&sup3;",
180 : "&acute;",
181 : "&micro;",
182 : "&para;",
183 : "&middot;",
184 : "&cedil;",
185 : "&sup1;",
186 : "&ordm;",
187 : "&raquo;",
188 : "&frac14;",
189 : "&frac12;",
190 : "&frac34;",
191 : "&iquest;",
192 : "&Agrave;",
193 : "&Aacute;",
194 : "&Acirc;",
195 : "&Atilde;",
196 : "&Auml;",
197 : "&Aring;",
198 : "&AElig;",
199 : "&Ccedil;",
200 : "&Egrave;",
201 : "&Eacute;",
202 : "&Ecirc;",
203 : "&Euml;",
204 : "&Igrave;",
205 : "&Iacute;",
206 : "&Icirc;",
207 : "&Iuml;",
208 : "&ETH;",
209 : "&Ntilde;",
210 : "&Ograve;",
211 : "&Oacute;",
212 : "&Ocirc;",
213 : "&Otilde;",
214 : "&Ouml;",
215 : "&times;",
216 : "&Oslash;",
217 : "&Ugrave;",
218 : "&Uacute;",
219 : "&Ucirc;",
220 : "&Uuml;",
221 : "&Yacute;",
222 : "&THORN;",
223 : "&szlig;",
224 : "&agrave;",
225 : "&aacute;",
226 : "&acirc;",
227 : "&atilde;",
228 : "&auml;",
229 : "&aring;",
230 : "&aelig;",
231 : "&ccedil;",
232 : "&egrave;",
233 : "&eacute;",
234 : "&ecirc;",
235 : "&euml;",
236 : "&igrave;",
237 : "&iacute;",
238 : "&icirc;",
239 : "&iuml;",
240 : "&eth;",
241 : "&ntilde;",
242 : "&ograve;",
243 : "&oacute;",
244 : "&ocirc;",
245 : "&otilde;",
246 : "&ouml;",
247 : "&divide;",
248 : "&oslash;",
249 : "&ugrave;",
250 : "&uacute;",
251 : "&ucirc;",
252 : "&uuml;",
253 : "&yacute;",
254 : "&thorn;",
255 : "&yuml;",
338 : "&OElig;",
339 : "&oelig;",
352 : "&Scaron;",
353 : "&scaron;",
376 : "&Yuml;",
402 : "&fnof;",
710 : "&circ;",
732 : "&tilde;",
913 : "&Alpha;",
914 : "&Beta;",
915 : "&Gamma;",
916 : "&Delta;",
917 : "&Epsilon;",
918 : "&Zeta;",
919 : "&Eta;",
920 : "&Theta;",
921 : "&Iota;",
922 : "&Kappa;",
923 : "&Lambda;",
924 : "&Mu;",
925 : "&Nu;",
926 : "&Xi;",
927 : "&Omicron;",
928 : "&Pi;",
929 : "&Rho;",
931 : "&Sigma;",
932 : "&Tau;",
933 : "&Upsilon;",
934 : "&Phi;",
935 : "&Chi;",
936 : "&Psi;",
937 : "&Omega;",
945 : "&alpha;",
946 : "&beta;",
947 : "&gamma;",
948 : "&delta;",
949 : "&epsilon;",
950 : "&zeta;",
951 : "&eta;",
952 : "&theta;",
953 : "&iota;",
954 : "&kappa;",
955 : "&lambda;",
956 : "&mu;",
957 : "&nu;",
958 : "&xi;",
959 : "&omicron;",
960 : "&pi;",
961 : "&rho;",
962 : "&sigmaf;",
963 : "&sigma;",
964 : "&tau;",
965 : "&upsilon;",
966 : "&phi;",
967 : "&chi;",
968 : "&psi;",
969 : "&omega;",
977 : "&thetasym;",
978 : "&upsih;",
982 : "&piv;",
8194 : "&ensp;",
8195 : "&emsp;",
8201 : "&thinsp;",
8204 : "&zwnj;",
8205 : "&zwj;",
8206 : "&lrm;",
8207 : "&rlm;",
8211 : "&ndash;",
8212 : "&mdash;",
8216 : "&lsquo;",
8217 : "&rsquo;",
8218 : "&sbquo;",
8220 : "&ldquo;",
8221 : "&rdquo;",
8222 : "&bdquo;",
8224 : "&dagger;",
8225 : "&Dagger;",
8226 : "&bull;",
8230 : "&hellip;",
8240 : "&permil;",
8242 : "&prime;",
8243 : "&Prime;",
8249 : "&lsaquo;",
8250 : "&rsaquo;",
8254 : "&oline;",
8260 : "&frasl;",
8364 : "&euro;",
8465 : "&image;",
8472 : "&weierp;",
8476 : "&real;",
8482 : "&trade;",
8501 : "&alefsym;",
8592 : "&larr;",
8593 : "&uarr;",
8594 : "&rarr;",
8595 : "&darr;",
8596 : "&harr;",
8629 : "&crarr;",
8656 : "&lArr;",
8657 : "&uArr;",
8658 : "&rArr;",
8659 : "&dArr;",
8660 : "&hArr;",
8704 : "&forall;",
8706 : "&part;",
8707 : "&exist;",
8709 : "&empty;",
8711 : "&nabla;",
8712 : "&isin;",
8713 : "&notin;",
8715 : "&ni;",
8719 : "&prod;",
8721 : "&sum;",
8722 : "&minus;",
8727 : "&lowast;",
8730 : "&radic;",
8733 : "&prop;",
8734 : "&infin;",
8736 : "&ang;",
8743 : "&and;",
8744 : "&or;",
8745 : "&cap;",
8746 : "&cup;",
8747 : "&int;",
8756 : "&there4;",
8764 : "&sim;",
8773 : "&cong;",
8776 : "&asymp;",
8800 : "&ne;",
8801 : "&equiv;",
8804 : "&le;",
8805 : "&ge;",
8834 : "&sub;",
8835 : "&sup;",
8836 : "&nsub;",
8838 : "&sube;",
8839 : "&supe;",
8853 : "&oplus;",
8855 : "&otimes;",
8869 : "&perp;",
8901 : "&sdot;",
8942 : "&vellip;",
8968 : "&lceil;",
8969 : "&rceil;",
8970 : "&lfloor;",
8971 : "&rfloor;",
9001 : "&lang;",
9002 : "&rang;",
9674 : "&loz;",
9824 : "&spades;",
9827 : "&clubs;",
9829 : "&hearts;",
9830 : "&diams;",
},
/**
* Lookup table to translate HTML entity codes to their byte values.
*
* @private
* @constant
*/
_entity_to_byte : {
"quot" : 34,
"amp" : 38,
"apos" : 39,
"lt" : 60,
"gt" : 62,
"nbsp" : 160,
"iexcl" : 161,
"cent" : 162,
"pound" : 163,
"curren" : 164,
"yen" : 165,
"brvbar" : 166,
"sect" : 167,
"uml" : 168,
"copy" : 169,
"ordf" : 170,
"laquo" : 171,
"not" : 172,
"shy" : 173,
"reg" : 174,
"macr" : 175,
"deg" : 176,
"plusmn" : 177,
"sup2" : 178,
"sup3" : 179,
"acute" : 180,
"micro" : 181,
"para" : 182,
"middot" : 183,
"cedil" : 184,
"sup1" : 185,
"ordm" : 186,
"raquo" : 187,
"frac14" : 188,
"frac12" : 189,
"frac34" : 190,
"iquest" : 191,
"Agrave" : 192,
"Aacute" : 193,
"Acirc" : 194,
"Atilde" : 195,
"Auml" : 196,
"Aring" : 197,
"AElig" : 198,
"Ccedil" : 199,
"Egrave" : 200,
"Eacute" : 201,
"Ecirc" : 202,
"Euml" : 203,
"Igrave" : 204,
"Iacute" : 205,
"Icirc" : 206,
"Iuml" : 207,
"ETH" : 208,
"Ntilde" : 209,
"Ograve" : 210,
"Oacute" : 211,
"Ocirc" : 212,
"Otilde" : 213,
"Ouml" : 214,
"times" : 215,
"Oslash" : 216,
"Ugrave" : 217,
"Uacute" : 218,
"Ucirc" : 219,
"Uuml" : 220,
"Yacute" : 221,
"THORN" : 222,
"szlig" : 223,
"agrave" : 224,
"aacute" : 225,
"acirc" : 226,
"atilde" : 227,
"auml" : 228,
"aring" : 229,
"aelig" : 230,
"ccedil" : 231,
"egrave" : 232,
"eacute" : 233,
"ecirc" : 234,
"euml" : 235,
"igrave" : 236,
"iacute" : 237,
"icirc" : 238,
"iuml" : 239,
"eth" : 240,
"ntilde" : 241,
"ograve" : 242,
"oacute" : 243,
"ocirc" : 244,
"otilde" : 245,
"ouml" : 246,
"divide" : 247,
"oslash" : 248,
"ugrave" : 249,
"uacute" : 250,
"ucirc" : 251,
"uuml" : 252,
"yacute" : 253,
"thorn" : 254,
"yuml" : 255,
"OElig" : 338,
"oelig" : 339,
"Scaron" : 352,
"scaron" : 353,
"Yuml" : 376,
"fnof" : 402,
"circ" : 710,
"tilde" : 732,
"Alpha" : 913,
"Beta" : 914,
"Gamma" : 915,
"Delta" : 916,
"Epsilon" : 917,
"Zeta" : 918,
"Eta" : 919,
"Theta" : 920,
"Iota" : 921,
"Kappa" : 922,
"Lambda" : 923,
"Mu" : 924,
"Nu" : 925,
"Xi" : 926,
"Omicron" : 927,
"Pi" : 928,
"Rho" : 929,
"Sigma" : 931,
"Tau" : 932,
"Upsilon" : 933,
"Phi" : 934,
"Chi" : 935,
"Psi" : 936,
"Omega" : 937,
"alpha" : 945,
"beta" : 946,
"gamma" : 947,
"delta" : 948,
"epsilon" : 949,
"zeta" : 950,
"eta" : 951,
"theta" : 952,
"iota" : 953,
"kappa" : 954,
"lambda" : 955,
"mu" : 956,
"nu" : 957,
"xi" : 958,
"omicron" : 959,
"pi" : 960,
"rho" : 961,
"sigmaf" : 962,
"sigma" : 963,
"tau" : 964,
"upsilon" : 965,
"phi" : 966,
"chi" : 967,
"psi" : 968,
"omega" : 969,
"thetasym" : 977,
"upsih" : 978,
"piv" : 982,
"ensp" : 8194,
"emsp" : 8195,
"thinsp" : 8201,
"zwnj" : 8204,
"zwj" : 8205,
"lrm" : 8206,
"rlm" : 8207,
"ndash" : 8211,
"mdash" : 8212,
"lsquo" : 8216,
"rsquo" : 8217,
"sbquo" : 8218,
"ldquo" : 8220,
"rdquo" : 8221,
"bdquo" : 8222,
"dagger" : 8224,
"Dagger" : 8225,
"bull" : 8226,
"hellip" : 8230,
"permil" : 8240,
"prime" : 8242,
"Prime" : 8243,
"lsaquo" : 8249,
"rsaquo" : 8250,
"oline" : 8254,
"frasl" : 8260,
"euro" : 8364,
"image" : 8465,
"weierp" : 8472,
"real" : 8476,
"trade" : 8482,
"alefsym" : 8501,
"larr" : 8592,
"uarr" : 8593,
"rarr" : 8594,
"darr" : 8595,
"harr" : 8596,
"crarr" : 8629,
"lArr" : 8656,
"uArr" : 8657,
"rArr" : 8658,
"dArr" : 8659,
"hArr" : 8660,
"forall" : 8704,
"part" : 8706,
"exist" : 8707,
"empty" : 8709,
"nabla" : 8711,
"isin" : 8712,
"notin" : 8713,
"ni" : 8715,
"prod" : 8719,
"sum" : 8721,
"minus" : 8722,
"lowast" : 8727,
"radic" : 8730,
"prop" : 8733,
"infin" : 8734,
"ang" : 8736,
"and" : 8743,
"or" : 8744,
"cap" : 8745,
"cup" : 8746,
"int" : 8747,
"there4" : 8756,
"sim" : 8764,
"cong" : 8773,
"asymp" : 8776,
"ne" : 8800,
"equiv" : 8801,
"le" : 8804,
"ge" : 8805,
"sub" : 8834,
"sup" : 8835,
"nsub" : 8836,
"sube" : 8838,
"supe" : 8839,
"oplus" : 8853,
"otimes" : 8855,
"perp" : 8869,
"sdot" : 8901,
"vellip" : 8942,
"lceil" : 8968,
"rceil" : 8969,
"lfloor" : 8970,
"rfloor" : 8971,
"lang" : 9001,
"rang" : 9002,
"loz" : 9674,
"spades" : 9824,
"clubs" : 9827,
"hearts" : 9829,
"diams" : 9830,
},
};

53
src/js/operations/HTTP.js Executable file
View file

@ -0,0 +1,53 @@
/* globals UAS_parser */
/**
* HTTP operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var HTTP = {
/**
* Strip HTTP headers operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_strip_headers: function(input, args) {
var header_end = input.indexOf("\r\n\r\n") +
(header_end < 0) ? input.indexOf("\n\n") + 2 : header_end + 4;
return (header_end < 2) ? input : input.slice(header_end, input.length);
},
/**
* Parse User Agent operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse_user_agent: function(input, args) {
var ua = UAS_parser.parse(input);
return "Type: " + ua.type + "\n" +
"Family: " + ua.uaFamily + "\n" +
"Name: " + ua.uaName + "\n" +
"URL: " + ua.uaUrl + "\n" +
"Company: " + ua.uaCompany + "\n" +
"Company URL: " + ua.uaCompanyUrl + "\n\n" +
"OS Family: " + ua.osFamily + "\n" +
"OS Name: " + ua.osName + "\n" +
"OS URL: " + ua.osUrl + "\n" +
"OS Company: " + ua.osCompany + "\n" +
"OS Company URL: " + ua.osCompanyUrl + "\n" +
"Device Type: " + ua.deviceType + "\n";
},
};

341
src/js/operations/Hash.js Executable file
View file

@ -0,0 +1,341 @@
/* globals CryptoJS, Checksum */
/**
* Hashing operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Hash = {
/**
* MD5 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_md5: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input); // Cast to WordArray
return CryptoJS.MD5(input).toString(CryptoJS.enc.Hex);
},
/**
* SHA1 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha1: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.SHA1(input).toString(CryptoJS.enc.Hex);
},
/**
* SHA224 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha224: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.SHA224(input).toString(CryptoJS.enc.Hex);
},
/**
* SHA256 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha256: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.SHA256(input).toString(CryptoJS.enc.Hex);
},
/**
* SHA384 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha384: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.SHA384(input).toString(CryptoJS.enc.Hex);
},
/**
* SHA512 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha512: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.SHA512(input).toString(CryptoJS.enc.Hex);
},
/**
* @constant
* @default
*/
SHA3_LENGTH: ["512", "384", "256", "224"],
/**
* SHA3 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sha3: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
var sha3_length = args[0],
options = {
outputLength: parseInt(sha3_length, 10)
};
return CryptoJS.SHA3(input, options).toString(CryptoJS.enc.Hex);
},
/**
* RIPEMD-160 operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_ripemd160: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
return CryptoJS.RIPEMD160(input).toString(CryptoJS.enc.Hex);
},
/**
* @constant
* @default
*/
HMAC_FUNCTIONS: ["MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "RIPEMD-160"],
/**
* HMAC operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_hmac: function (input, args) {
var hash_func = args[1];
input = CryptoJS.enc.Latin1.parse(input);
var execute = {
"MD5": CryptoJS.HmacMD5(input, args[0]),
"SHA1": CryptoJS.HmacSHA1(input, args[0]),
"SHA224": CryptoJS.HmacSHA224(input, args[0]),
"SHA256": CryptoJS.HmacSHA256(input, args[0]),
"SHA384": CryptoJS.HmacSHA384(input, args[0]),
"SHA512": CryptoJS.HmacSHA512(input, args[0]),
"SHA3": CryptoJS.HmacSHA3(input, args[0]),
"RIPEMD-160": CryptoJS.HmacRIPEMD160(input, args[0]),
};
return execute[hash_func].toString(CryptoJS.enc.Hex);
},
/**
* Generate all hashes operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_all: function (input, args) {
var byte_array = Utils.str_to_byte_array(input),
output = "MD5: " + Hash.run_md5(input, []) +
"\nSHA1: " + Hash.run_sha1(input, []) +
"\nSHA2 224: " + Hash.run_sha224(input, []) +
"\nSHA2 256: " + Hash.run_sha256(input, []) +
"\nSHA2 384: " + Hash.run_sha384(input, []) +
"\nSHA2 512: " + Hash.run_sha512(input, []) +
"\nSHA3 224: " + Hash.run_sha3(input, ["224"]) +
"\nSHA3 256: " + Hash.run_sha3(input, ["256"]) +
"\nSHA3 384: " + Hash.run_sha3(input, ["384"]) +
"\nSHA3 512: " + Hash.run_sha3(input, ["512"]) +
"\nRIPEMD-160: " + Hash.run_ripemd160(input, []) +
"\n\nChecksums:" +
"\nFletcher-16: " + Checksum.run_fletcher16(byte_array, []) +
"\nAdler-32: " + Checksum.run_adler32(byte_array, []) +
"\nCRC-32: " + Checksum.run_crc32(byte_array, []);
return output;
},
/**
* Analyse hash operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_analyse: function(input, args) {
input = input.replace(/\s/g, "");
var output = "",
byte_length = input.length / 2,
bit_length = byte_length * 8,
possible_hash_functions = [];
if (!/^[a-f0-9]+$/i.test(input)) {
return "Invalid hash";
}
output += "Hash length: " + input.length + "\n" +
"Byte length: " + byte_length + "\n" +
"Bit length: " + bit_length + "\n\n" +
"Based on the length, this hash could have been generated by one of the following hashing functions:\n";
switch (bit_length) {
case 4:
possible_hash_functions = [
"Fletcher-4",
"Luhn algorithm",
"Verhoeff algorithm",
];
break;
case 8:
possible_hash_functions = [
"Fletcher-8",
];
break;
case 16:
possible_hash_functions = [
"BSD checksum",
"CRC-16",
"SYSV checksum",
"Fletcher-16"
];
break;
case 32:
possible_hash_functions = [
"CRC-32",
"Fletcher-32",
"Adler-32",
];
break;
case 64:
possible_hash_functions = [
"CRC-64",
"RIPEMD-64",
"SipHash",
];
break;
case 128:
possible_hash_functions = [
"MD5",
"MD4",
"MD2",
"HAVAL-128",
"RIPEMD-128",
"Snefru",
"Tiger-128",
];
break;
case 160:
possible_hash_functions = [
"SHA-1",
"SHA-0",
"FSB-160",
"HAS-160",
"HAVAL-160",
"RIPEMD-160",
"Tiger-160",
];
break;
case 192:
possible_hash_functions = [
"Tiger",
"HAVAL-192",
];
break;
case 224:
possible_hash_functions = [
"SHA-224",
"SHA3-224",
"ECOH-224",
"FSB-224",
"HAVAL-224",
];
break;
case 256:
possible_hash_functions = [
"SHA-256",
"SHA3-256",
"BLAKE-256",
"ECOH-256",
"FSB-256",
"GOST",
"Grøstl-256",
"HAVAL-256",
"PANAMA",
"RIPEMD-256",
"Snefru",
];
break;
case 320:
possible_hash_functions = [
"RIPEMD-320",
];
break;
case 384:
possible_hash_functions = [
"SHA-384",
"SHA3-384",
"ECOH-384",
"FSB-384",
];
break;
case 512:
possible_hash_functions = [
"SHA-512",
"SHA3-512",
"BLAKE-512",
"ECOH-512",
"FSB-512",
"Grøstl-512",
"JH",
"MD6",
"Spectral Hash",
"SWIFFT",
"Whirlpool",
];
break;
case 1024:
possible_hash_functions = [
"Fowler-Noll-Vo",
];
break;
default:
possible_hash_functions = [
"Unknown"
];
break;
}
return output + possible_hash_functions.join("\n");
},
};

195
src/js/operations/Hexdump.js Executable file
View file

@ -0,0 +1,195 @@
/* globals app */
/**
* Hexdump operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Hexdump = {
/**
* @constant
* @default
*/
WIDTH: 16,
/**
* @constant
* @default
*/
UPPER_CASE: false,
/**
* @constant
* @default
*/
INCLUDE_FINAL_LENGTH: false,
/**
* To Hexdump operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to: function(input, args) {
var length = args[0] || Hexdump.WIDTH;
var upper_case = args[1];
var include_final_length = args[2];
var output = "", padding = 2;
for (var i = 0; i < input.length; i += length) {
var buff = input.slice(i, i+length);
var hexa = "";
for (var j = 0; j < buff.length; j++) {
hexa += Utils.hex(buff[j], padding) + " ";
}
var line_no = Utils.hex(i, 8);
if (upper_case) {
hexa = hexa.toUpperCase();
line_no = line_no.toUpperCase();
}
output += line_no + " " +
Utils.pad_right(hexa, (length*(padding+1))) +
" |" + Utils.pad_right(Utils.printable(Utils.byte_array_to_chars(buff)), buff.length) + "|\n";
if (include_final_length && i+buff.length == input.length) {
output += Utils.hex(i+buff.length, 8) + "\n";
}
}
return output.slice(0, -1);
},
/**
* From Hexdump operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from: function(input, args) {
var output = [],
regex = /^\s*(?:[\dA-F]{4,16}:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
block, line;
while (!!(block = regex.exec(input))) {
line = Utils.from_hex(block[1].replace(/-/g, " "));
for (var i = 0; i < line.length; i++) {
output.push(line[i]);
}
}
// Is this a CyberChef hexdump or is it from a different tool?
var width = input.indexOf("\n");
var w = (width - 13) / 4;
// w should be the specified width of the hexdump and therefore a round number
if (Math.floor(w) != w || input.indexOf("\r") != -1 || output.indexOf(13) != -1) {
app.options.attempt_highlight = false;
}
return output;
},
/**
* Highlight to hexdump
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_to: function(pos, args) {
// Calculate overall selection
var w = args[0] || 16,
width = 14 + (w*4),
line = Math.floor(pos[0].start / w),
offset = pos[0].start % w,
start = 0,
end = 0;
pos[0].start = line*width + 10 + offset*3;
line = Math.floor(pos[0].end / w);
offset = pos[0].end % w;
if (offset === 0) { line--; offset = w; }
pos[0].end = line*width + 10 + offset*3 - 1;
// Set up multiple selections for bytes
var start_line_num = Math.floor(pos[0].start / width);
var end_line_num = Math.floor(pos[0].end / width);
if (start_line_num == end_line_num) {
pos.push(pos[0]);
} else {
start = pos[0].start;
end = (start_line_num+1) * width - w - 5;
pos.push({ start: start, end: end });
while (end < pos[0].end) {
start_line_num++;
start = start_line_num * width + 10;
end = (start_line_num+1) * width - w - 5;
if (end > pos[0].end) end = pos[0].end;
pos.push({ start: start, end: end });
}
}
// Set up multiple selections for ASCII
var len = pos.length, line_num = 0;
start = 0;
end = 0;
for (var i = 1; i < len; i++) {
line_num = Math.floor(pos[i].start / width);
start = (((pos[i].start - (line_num * width)) - 10) / 3) + (width - w -2) + (line_num * width);
end = (((pos[i].end + 1 - (line_num * width)) - 10) / 3) + (width - w -2) + (line_num * width);
pos.push({ start: start, end: end });
}
return pos;
},
/**
* Highlight from hexdump
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight_from: function(pos, args) {
var w = args[0] || 16;
var width = 14 + (w*4);
var line = Math.floor(pos[0].start / width);
var offset = pos[0].start % width;
if (offset < 10) { // In line number section
pos[0].start = line*w;
} else if (offset > 10+(w*3)) { // In ASCII section
pos[0].start = (line+1)*w;
} else { // In byte section
pos[0].start = line*w + Math.floor((offset-10)/3);
}
line = Math.floor(pos[0].end / width);
offset = pos[0].end % width;
if (offset < 10) { // In line number section
pos[0].end = line*w;
} else if (offset > 10+(w*3)) { // In ASCII section
pos[0].end = (line+1)*w;
} else { // In byte section
pos[0].end = line*w + Math.ceil((offset-10)/3);
}
return pos;
},
};

802
src/js/operations/IP.js Executable file
View file

@ -0,0 +1,802 @@
/* globals BigInteger */
/**
* Internet Protocol address operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var IP = {
/**
* @constant
* @default
*/
INCLUDE_NETWORK_INFO: true,
/**
* @constant
* @default
*/
ENUMERATE_ADDRESSES: true,
/**
* @constant
* @default
*/
ALLOW_LARGE_LIST: false,
/**
* Parse IP range operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse_ip_range: function (input, args) {
var include_network_info = args[0],
enumerate_addresses = args[1],
allow_large_list = args[2];
// Check what type of input we are looking at
var ipv4_cidr_regex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
ipv4_range_regex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*-\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
ipv6_cidr_regex = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\/(\d\d?\d?)\s*$/i,
ipv6_range_regex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
match;
if (!!(match = ipv4_cidr_regex.exec(input))) {
return IP._ipv4_cidr_range(match, include_network_info, enumerate_addresses, allow_large_list);
} else if (!!(match = ipv4_range_regex.exec(input))) {
return IP._ipv4_hyphenated_range(match, include_network_info, enumerate_addresses, allow_large_list);
} else if (!!(match = ipv6_cidr_regex.exec(input))) {
return IP._ipv6_cidr_range(match, include_network_info);
} else if (!!(match = ipv6_range_regex.exec(input))) {
return IP._ipv6_hyphenated_range(match, include_network_info);
} else {
return "Invalid input.\n\nEnter either a CIDR range (e.g. 10.0.0.0/24) or a hyphenated range (e.g. 10.0.0.0 - 10.0.1.0). IPv6 also supported.";
}
},
/**
* @constant
* @default
*/
IPv4_REGEX: /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
/**
* @constant
* @default
*/
IPv6_REGEX: /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
/**
* Parse IPv6 address operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse_ipv6: function (input, args) {
var match,
output = "";
if (!!(match = IP.IPv6_REGEX.exec(input))) {
var ipv6 = IP._str_to_ipv6(match[1]),
longhand = IP._ipv6_to_str(ipv6),
shorthand = IP._ipv6_to_str(ipv6, true);
output += "Longhand: " + longhand + "\nShorthand: " + shorthand + "\n";
// Detect reserved addresses
if (shorthand == "::") {
// Unspecified address
output += "\nUnspecified address corresponding to 0.0.0.0/32 in IPv4.";
output += "\nUnspecified address range: ::/128";
} else if (shorthand == "::1") {
// Loopback address
output += "\nLoopback address to the local host corresponding to 127.0.0.1/8 in IPv4.";
output += "\nLoopback addresses range: ::1/128";
} else if (ipv6[0] === 0 && ipv6[1] === 0 && ipv6[2] === 0 &&
ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0xffff) {
// IPv4-mapped IPv6 address
output += "\nIPv4-mapped IPv6 address detected. IPv6 clients will be handled natively by default, and IPv4 clients appear as IPv6 clients at their IPv4-mapped IPv6 address.";
output += "\nMapped IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
output += "\nIPv4-mapped IPv6 addresses range: ::ffff:0:0/96";
} else if (ipv6[0] === 0 && ipv6[1] === 0 && ipv6[2] === 0 &&
ipv6[3] === 0 && ipv6[4] === 0xffff && ipv6[5] === 0) {
// IPv4-translated address
output += "\nIPv4-translated address detected. Used by Stateless IP/ICMP Translation (SIIT). See RFCs 6145 and 6052 for more details.";
output += "\nTranslated IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
output += "\nIPv4-translated addresses range: ::ffff:0:0:0/96";
} else if (ipv6[0] === 0x100) {
// Discard prefix per RFC 6666
output += "\nDiscard prefix detected. This is used when forwarding traffic to a sinkhole router to mitigate the effects of a denial-of-service attack. See RFC 6666 for more details.";
output += "\nDiscard range: 100::/64";
} else if (ipv6[0] === 0x64 && ipv6[1] === 0xff9b && ipv6[2] === 0 &&
ipv6[3] === 0 && ipv6[4] === 0 && ipv6[5] === 0) {
// IPv4/IPv6 translation per RFC 6052
output += "\n'Well-Known' prefix for IPv4/IPv6 translation detected. See RFC 6052 for more details.";
output += "\nTranslated IPv4 address: " + IP._ipv4_to_str((ipv6[6] << 16) + ipv6[7]);
output += "\n'Well-Known prefix range: 64:ff9b::/96";
} else if (ipv6[0] === 0x2001 && ipv6[1] === 0) {
// Teredo tunneling
output += "\nTeredo tunneling IPv6 address detected\n";
var server_ipv4 = (ipv6[2] << 16) + ipv6[3],
udp_port = (~ipv6[5]) & 0xffff,
client_ipv4 = ~((ipv6[6] << 16) + ipv6[7]),
flag_cone = (ipv6[4] >>> 15) & 1,
flag_r = (ipv6[4] >>> 14) & 1,
flag_random1 = (ipv6[4] >>> 10) & 15,
flag_ug = (ipv6[4] >>> 8) & 3,
flag_random2 = ipv6[4] & 255;
output += "\nServer IPv4 address: " + IP._ipv4_to_str(server_ipv4) +
"\nClient IPv4 address: " + IP._ipv4_to_str(client_ipv4) +
"\nClient UDP port: " + udp_port +
"\nFlags:" +
"\n\tCone: " + flag_cone;
if (flag_cone) {
output += " (Client is behind a cone NAT)";
} else {
output += " (Client is not behind a cone NAT)";
}
output += "\n\tR: " + flag_r;
if (flag_r) {
output += " Error: This flag should be set to 0. See RFC 5991 and RFC 4380.";
}
output += "\n\tRandom1: " + Utils.bin(flag_random1, 4) +
"\n\tUG: " + Utils.bin(flag_ug, 2);
if (flag_ug) {
output += " Error: This flag should be set to 00. See RFC 4380.";
}
output += "\n\tRandom2: " + Utils.bin(flag_random2, 8);
if (!flag_r && !flag_ug && flag_random1 && flag_random2) {
output += "\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991.";
} else if (!flag_r && !flag_ug) {
output += "\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field.";
} else {
output += "\n\nThis is an invalid Teredo address.";
}
output += "\n\nTeredo prefix range: 2001::/32";
} else if (ipv6[0] === 0x2001 && ipv6[1] === 0x2 && ipv6[2] === 0) {
// Benchmarking
output += "\nAssigned to the Benchmarking Methodology Working Group (BMWG) for benchmarking IPv6. Corresponds to 198.18.0.0/15 for benchmarking IPv4. See RFC 5180 for more details.";
output += "\nBMWG range: 2001:2::/48";
} else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x10 && ipv6[1] <= 0x1f) {
// ORCHIDv1
output += "\nDeprecated, previously ORCHIDv1 (Overlay Routable Cryptographic Hash Identifiers).\nORCHIDv1 range: 2001:10::/28\nORCHIDv2 now uses 2001:20::/28.";
} else if (ipv6[0] == 0x2001 && ipv6[1] >= 0x20 && ipv6[1] <= 0x2f) {
// ORCHIDv2
output += "\nORCHIDv2 (Overlay Routable Cryptographic Hash Identifiers).\nThese are non-routed IPv6 addresses used for Cryptographic Hash Identifiers.";
output += "\nORCHIDv2 range: 2001:20::/28";
} else if (ipv6[0] == 0x2001 && ipv6[1] == 0xdb8) {
// Documentation
output += "\nThis is a documentation IPv6 address. This range should be used whenever an example IPv6 address is given or to model networking scenarios. Corresponds to 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in IPv4.";
output += "\nDocumentation range: 2001:db8::/32";
} else if (ipv6[0] == 0x2002) {
// 6to4
output += "\n6to4 transition IPv6 address detected. See RFC 3056 for more details." +
"\n6to4 prefix range: 2002::/16";
var v4_addr = IP._ipv4_to_str((ipv6[1] << 16) + ipv6[2]),
sla_id = ipv6[3],
interface_id_str = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
interface_id = new BigInteger(interface_id_str, 16);
output += "\n\nEncapsulated IPv4 address: " + v4_addr +
"\nSLA ID: " + sla_id +
"\nInterface ID (base 16): " + interface_id_str +
"\nInterface ID (base 10): " + interface_id.toString();
} else if (ipv6[0] >= 0xfc00 && ipv6[0] <= 0xfdff) {
// Unique local address
output += "\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details.";
output += "\nUnique local addresses range: fc00::/7";
} else if (ipv6[0] >= 0xfe80 && ipv6[0] <= 0xfebf) {
// Link-local address
output += "\nThis is a link-local address comparable to the auto-configuration addresses 169.254.0.0/16 in IPv4.";
output += "\nLink-local addresses range: fe80::/10";
} else if (ipv6[0] >= 0xff00) {
// Multicast
output += "\nThis is a reserved multicast address.";
output += "\nMulticast addresses range: ff00::/8";
}
} else {
return "Invalid IPv6 address";
}
return output;
},
/**
* @constant
* @default
*/
IP_FORMAT_LIST: ["Dotted Decimal", "Decimal", "Hex"],
/**
* Change IP format operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_change_ip_format: function(input, args) {
var in_format = args[0],
out_format = args[1],
lines = input.split("\n"),
output = "",
j = 0;
for (var i = 0; i < lines.length; i++) {
if (lines[i] === "") continue;
var ba_ip = [];
if (in_format == out_format) {
output += lines[i] + "\n";
continue;
}
// Convert to byte array IP from input format
switch (in_format) {
case "Dotted Decimal":
var octets = lines[i].split(".");
for (j = 0; j < octets.length; j++) {
ba_ip.push(parseInt(octets[j], 10));
}
break;
case "Decimal":
var decimal = lines[i].toString();
ba_ip.push(decimal >> 24 & 255);
ba_ip.push(decimal >> 16 & 255);
ba_ip.push(decimal >> 8 & 255);
ba_ip.push(decimal & 255);
break;
case "Hex":
ba_ip = Utils.hex_to_byte_array(lines[i]);
break;
default:
throw "Unsupported input IP format";
}
// Convert byte array IP to output format
switch (out_format) {
case "Dotted Decimal":
var dd_ip = "";
for (j = 0; j < ba_ip.length; j++) {
dd_ip += ba_ip[j] + ".";
}
output += dd_ip.slice(0, dd_ip.length-1) + "\n";
break;
case "Decimal":
var dec_ip = ((ba_ip[0] << 24) | (ba_ip[1] << 16) | (ba_ip[2] << 8) | ba_ip[3]) >>> 0;
output += dec_ip.toString() + "\n";
break;
case "Hex":
var hex_ip = "";
for (j = 0; j < ba_ip.length; j++) {
hex_ip += Utils.hex(ba_ip[j]);
}
output += hex_ip + "\n";
break;
default:
throw "Unsupported output IP format";
}
}
return output.slice(0, output.length-1);
},
/**
* @constant
* @default
*/
DELIM_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon"],
/**
* @constant
* @default
*/
GROUP_CIDR: 24,
/**
* @constant
* @default
*/
GROUP_ONLY_SUBNET: false,
/**
* Group IP addresses operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_group_ips: function(input, args) {
var delim = Utils.char_rep[args[0]],
cidr = args[1],
only_subnets = args[2],
ipv4_mask = cidr < 32 ? ~(0xFFFFFFFF >>> cidr) : 0xFFFFFFFF,
ipv6_mask = IP._gen_ipv6_mask(cidr),
ips = input.split(delim),
ipv4_networks = {},
ipv6_networks = {},
match = null,
output = "",
ip = null,
network = null,
network_str = "";
if (cidr < 0 || cidr > 127) {
return "CIDR must be less than 32 for IPv4 or 128 for IPv6";
}
// Parse all IPs and add to network dictionary
for (var i = 0; i < ips.length; i++) {
if (!!(match = IP.IPv4_REGEX.exec(ips[i]))) {
ip = IP._str_to_ipv4(match[1]) >>> 0;
network = ip & ipv4_mask;
if (ipv4_networks.hasOwnProperty(network)) {
ipv4_networks[network].push(ip);
} else {
ipv4_networks[network] = [ip];
}
} else if (!!(match = IP.IPv6_REGEX.exec(ips[i]))) {
ip = IP._str_to_ipv6(match[1]);
network = [];
network_str = "";
for (var j = 0; j < 8; j++) {
network.push(ip[j] & ipv6_mask[j]);
}
network_str = IP._ipv6_to_str(network, true);
if (ipv6_networks.hasOwnProperty(network_str)) {
ipv6_networks[network_str].push(ip);
} else {
ipv6_networks[network_str] = [ip];
}
}
}
// Sort IPv4 network dictionaries and print
for (network in ipv4_networks) {
ipv4_networks[network] = ipv4_networks[network].sort();
output += IP._ipv4_to_str(network) + "/" + cidr + "\n";
if (!only_subnets) {
for (i = 0; i < ipv4_networks[network].length; i++) {
output += " " + IP._ipv4_to_str(ipv4_networks[network][i]) + "\n";
}
output += "\n";
}
}
// Sort IPv6 network dictionaries and print
for (network_str in ipv6_networks) {
//ipv6_networks[network_str] = ipv6_networks[network_str].sort(); TODO
output += network_str + "/" + cidr + "\n";
if (!only_subnets) {
for (i = 0; i < ipv6_networks[network_str].length; i++) {
output += " " + IP._ipv6_to_str(ipv6_networks[network_str][i], true) + "\n";
}
output += "\n";
}
}
return output;
},
/**
* @constant
* @default
* @private
*/
_LARGE_RANGE_ERROR: "The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the \"Allow large queries\" option. You are advised to turn off \"Auto Bake\" whilst editing large ranges.",
/**
* Parses an IPv4 CIDR range (e.g. 192.168.0.0/24) and displays information about it.
*
* @private
* @param {RegExp} cidr
* @param {boolean} include_network_info
* @param {boolean} enumerate_addresses
* @param {boolean} allow_large_list
* @returns {string}
*/
_ipv4_cidr_range: function(cidr, include_network_info, enumerate_addresses, allow_large_list) {
var output = "",
network = IP._str_to_ipv4(cidr[1]),
cidr_range = parseInt(cidr[2], 10);
if (cidr_range < 0 || cidr_range > 31) {
return "IPv4 CIDR must be less than 32";
}
var mask = ~(0xFFFFFFFF >>> cidr_range),
ip1 = network & mask,
ip2 = ip1 | ~mask;
if (include_network_info) {
output += "Network: " + IP._ipv4_to_str(network) + "\n";
output += "CIDR: " + cidr_range + "\n";
output += "Mask: " + IP._ipv4_to_str(mask) + "\n";
output += "Range: " + IP._ipv4_to_str(ip1) + " - " + IP._ipv4_to_str(ip2) + "\n";
output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
}
if (enumerate_addresses) {
if (cidr_range >= 16 || allow_large_list) {
output += IP._generate_ipv4_range(ip1, ip2).join("\n");
} else {
output += IP._LARGE_RANGE_ERROR;
}
}
return output;
},
/**
* Parses an IPv6 CIDR range (e.g. ff00::/48) and displays information about it.
*
* @private
* @param {RegExp} cidr
* @param {boolean} include_network_info
* @returns {string}
*/
_ipv6_cidr_range: function(cidr, include_network_info) {
var output = "",
network = IP._str_to_ipv6(cidr[1]),
cidr_range = parseInt(cidr[cidr.length-1], 10);
if (cidr_range < 0 || cidr_range > 127) {
return "IPv6 CIDR must be less than 128";
}
var mask = IP._gen_ipv6_mask(cidr_range),
ip1 = new Array(8),
ip2 = new Array(8),
total_diff = "",
total = new Array(128);
for (var i = 0; i < 8; i++) {
ip1[i] = network[i] & mask[i];
ip2[i] = ip1[i] | (~mask[i] & 0x0000FFFF);
total_diff = (ip2[i] - ip1[i]).toString(2);
if (total_diff != "0") {
for (var n = 0; n < total_diff.length; n++) {
total[i*16 + 16-(total_diff.length-n)] = total_diff[n];
}
}
}
if (include_network_info) {
output += "Network: " + IP._ipv6_to_str(network) + "\n";
output += "Shorthand: " + IP._ipv6_to_str(network, true) + "\n";
output += "CIDR: " + cidr_range + "\n";
output += "Mask: " + IP._ipv6_to_str(mask) + "\n";
output += "Range: " + IP._ipv6_to_str(ip1) + " - " + IP._ipv6_to_str(ip2) + "\n";
output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
}
return output;
},
/**
* Generates an IPv6 subnet mask given a CIDR value.
*
* @private
* @param {number} cidr
* @returns {number[]}
*/
_gen_ipv6_mask: function(cidr) {
var mask = new Array(8),
shift;
for (var i = 0; i < 8; i++) {
if (cidr > ((i+1)*16)) {
mask[i] = 0x0000FFFF;
} else {
shift = cidr-(i*16);
if (shift < 0) shift = 0;
mask[i] = ~((0x0000FFFF >>> shift) | 0xFFFF0000);
}
}
return mask;
},
/**
* Parses an IPv4 hyphenated range (e.g. 192.168.0.0 - 192.168.0.255) and displays information
* about it.
*
* @private
* @param {RegExp} range
* @param {boolean} include_network_info
* @param {boolean} enumerate_addresses
* @param {boolean} allow_large_list
* @returns {string}
*/
_ipv4_hyphenated_range: function(range, include_network_info, enumerate_addresses, allow_large_list) {
var output = "",
ip1 = IP._str_to_ipv4(range[1]),
ip2 = IP._str_to_ipv4(range[2]);
// Calculate mask
var diff = ip1 ^ ip2,
cidr = 32,
mask = 0;
while (diff !== 0) {
diff >>= 1;
cidr--;
mask = (mask << 1) | 1;
}
mask = ~mask >>> 0;
var network = ip1 & mask,
sub_ip1 = network & mask,
sub_ip2 = sub_ip1 | ~mask;
if (include_network_info) {
output += "Minimum subnet required to hold this range:\n";
output += "\tNetwork: " + IP._ipv4_to_str(network) + "\n";
output += "\tCIDR: " + cidr + "\n";
output += "\tMask: " + IP._ipv4_to_str(mask) + "\n";
output += "\tSubnet range: " + IP._ipv4_to_str(sub_ip1) + " - " + IP._ipv4_to_str(sub_ip2) + "\n";
output += "\tTotal addresses in subnet: " + (((sub_ip2 - sub_ip1) >>> 0) + 1) + "\n\n";
output += "Range: " + IP._ipv4_to_str(ip1) + " - " + IP._ipv4_to_str(ip2) + "\n";
output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
}
if (enumerate_addresses) {
if (((ip2 - ip1) >>> 0) <= 65536 || allow_large_list) {
output += IP._generate_ipv4_range(ip1, ip2).join("\n");
} else {
output += IP._LARGE_RANGE_ERROR;
}
}
return output;
},
/**
* Parses an IPv6 hyphenated range (e.g. ff00:: - ffff::) and displays information about it.
*
* @private
* @param {RegExp} range
* @param {boolean} include_network_info
* @returns {string}
*/
_ipv6_hyphenated_range: function(range, include_network_info) {
var output = "",
ip1 = IP._str_to_ipv6(range[1]),
ip2 = IP._str_to_ipv6(range[14]);
var t = "",
total = new Array(128);
// Initialise total array to "0"
for (var i = 0; i < 128; i++)
total[i] = "0";
for (i = 0; i < 8; i++) {
t = (ip2[i] - ip1[i]).toString(2);
if (t != "0") {
for (var n = 0; n < t.length; n++) {
total[i*16 + 16-(t.length-n)] = t[n];
}
}
}
if (include_network_info) {
output += "Range: " + IP._ipv6_to_str(ip1) + " - " + IP._ipv6_to_str(ip2) + "\n";
output += "Shorthand range: " + IP._ipv6_to_str(ip1, true) + " - " + IP._ipv6_to_str(ip2, true) + "\n";
output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
}
return output;
},
/**
* Converts an IPv4 address from string format to numerical format.
*
* @private
* @param {string} ip_str
* @returns {number}
*
* @example
* // returns 168427520
* IP._str_to_ipv4("10.10.0.0");
*/
_str_to_ipv4: function (ip_str) {
var blocks = ip_str.split("."),
num_blocks = parse_blocks(blocks),
result = 0;
result += num_blocks[0] << 24;
result += num_blocks[1] << 16;
result += num_blocks[2] << 8;
result += num_blocks[3];
return result;
function parse_blocks(blocks) {
if (blocks.length != 4)
throw "More than 4 blocks.";
var num_blocks = [];
for (var i = 0; i < 4; i++) {
num_blocks[i] = parseInt(blocks[i], 10);
if (num_blocks[i] < 0 || num_blocks[i] > 255)
throw "Block out of range.";
}
return num_blocks;
}
},
/**
* Converts an IPv4 address from numerical format to string format.
*
* @private
* @param {number} ip_int
* @returns {string}
*
* @example
* // returns "10.10.0.0"
* IP._ipv4_to_str(168427520);
*/
_ipv4_to_str: function(ip_int) {
var blockA = (ip_int >> 24) & 255,
blockB = (ip_int >> 16) & 255,
blockC = (ip_int >> 8) & 255,
blockD = ip_int & 255;
return blockA + "." + blockB + "." + blockC + "." + blockD;
},
/**
* Converts an IPv6 address from string format to numerical array format.
*
* @private
* @param {string} ip_str
* @returns {number[]}
*
* @example
* // returns [65280, 0, 0, 0, 0, 0, 4369, 8738]
* IP._str_to_ipv6("ff00::1111:2222");
*/
_str_to_ipv6: function(ip_str) {
var blocks = ip_str.split(":"),
num_blocks = parse_blocks(blocks),
j = 0,
ipv6 = new Array(8);
for (var i = 0; i < 8; i++) {
if (isNaN(num_blocks[j])) {
ipv6[i] = 0;
if (i == (8-num_blocks.slice(j).length)) j++;
} else {
ipv6[i] = num_blocks[j];
j++;
}
}
return ipv6;
function parse_blocks(blocks) {
if (blocks.length < 3 || blocks.length > 8)
throw "Badly formatted IPv6 address.";
var num_blocks = [];
for (var i = 0; i < blocks.length; i++) {
num_blocks[i] = parseInt(blocks[i], 16);
if (num_blocks[i] < 0 || num_blocks[i] > 65535)
throw "Block out of range.";
}
return num_blocks;
}
},
/**
* Converts an IPv6 address from numerical array format to string format.
*
* @private
* @param {number[]} ipv6
* @param {boolean} compact - Whether or not to return the address in shorthand or not
* @returns {string}
*
* @example
* // returns "ff00::1111:2222"
* IP._ipv6_to_str([65280, 0, 0, 0, 0, 0, 4369, 8738], true);
*
* // returns "ff00:0000:0000:0000:0000:0000:1111:2222"
* IP._ipv6_to_str([65280, 0, 0, 0, 0, 0, 4369, 8738], false);
*/
_ipv6_to_str: function(ipv6, compact) {
var output = "",
skips = 0,
i = 0;
if (compact) {
var start = -1,
end = -1,
s = 0,
e = -1;
for (i = 0; i < 8; i++) {
if (ipv6[i] === 0 && e === (i-1)) {
e = i;
} else if (ipv6[i] === 0) {
s = i; e = i;
}
if (e >= 0 && (e-s) > (end - start)) {
start = s;
end = e;
}
}
for (i = 0; i < 8; i++) {
if (i != start) {
output += Utils.hex(ipv6[i],1) + ":";
} else {
output += ":";
i = end;
if (end === 7) output += ":";
}
}
if (output[0] === ":")
output = ":" + output;
} else {
for (i = 0; i < 8; i++) {
output += Utils.hex(ipv6[i],4) + ":";
}
}
return output.slice(0,output.length-1);
},
/**
* Generates a list of IPv4 addresses in string format between two given numerical values.
*
* @private
* @param {number} ip
* @param {number} end_ip
* @returns {string[]}
*
* @example
* // returns ["0.0.0.1", "0.0.0.2", "0.0.0.3"]
* IP._generate_ipv4_range(1, 3);
*/
_generate_ipv4_range: function(ip, end_ip) {
var range = [];
if (end_ip >= ip) {
for (; ip <= end_ip; ip++) {
range.push(IP._ipv4_to_str(ip));
}
} else {
range[0] = "Second IP address smaller than first.";
}
return range;
},
};

159
src/js/operations/JS.js Executable file
View file

@ -0,0 +1,159 @@
/* globals esprima, escodegen, esmangle */
/**
* JavaScript operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var JS = {
/**
* @constant
* @default
*/
PARSE_LOC: false,
/**
* @constant
* @default
*/
PARSE_RANGE: false,
/**
* @constant
* @default
*/
PARSE_TOKENS: false,
/**
* @constant
* @default
*/
PARSE_COMMENT: false,
/**
* @constant
* @default
*/
PARSE_TOLERANT: false,
/**
* JavaScript Parser operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse: function (input, args) {
var parse_loc = args[0],
parse_range = args[1],
parse_tokens = args[2],
parse_comment = args[3],
parse_tolerant = args[4],
result = {},
options = {
loc: parse_loc,
range: parse_range,
tokens: parse_tokens,
comment: parse_comment,
tolerant: parse_tolerant
};
result = esprima.parse(input, options);
return JSON.stringify(result, null, 2);
},
/**
* @constant
* @default
*/
BEAUTIFY_INDENT: "\\t",
/**
* @constant
* @default
*/
BEAUTIFY_QUOTES: ["Auto", "Single", "Double"],
/**
* @constant
* @default
*/
BEAUTIFY_SEMICOLONS: true,
/**
* @constant
* @default
*/
BEAUTIFY_COMMENT: true,
/**
* JavaScript Beautify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_beautify: function(input, args) {
var beautify_indent = args[0] || JS.BEAUTIFY_INDENT,
quotes = args[1].toLowerCase(),
beautify_semicolons = args[2],
beautify_comment = args[3],
result = "",
AST;
try {
AST = esprima.parse(input, {
range: true,
tokens: true,
comment: true
});
var options = {
format: {
indent: {
style: beautify_indent
},
quotes: quotes,
semicolons: beautify_semicolons,
},
comment: beautify_comment
};
if (options.comment)
AST = escodegen.attachComments(AST, AST.comments, AST.tokens);
result = escodegen.generate(AST, options);
} catch(e) {
// Leave original error so the user can see the detail
throw "Unable to parse JavaScript.<br>" + e.message;
}
return result;
},
/**
* JavaScript Minify operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_minify: function(input, args) {
var result = "",
AST = esprima.parse(input),
optimised_AST = esmangle.optimize(AST, null),
mangled_AST = esmangle.mangle(optimised_AST);
result = escodegen.generate(mangled_AST, {
format: {
renumber: true,
hexadecimal: true,
escapeless: true,
compact: true,
semicolons: false,
parentheses: false
}
});
return result;
},
};

88
src/js/operations/MAC.js Executable file
View file

@ -0,0 +1,88 @@
/**
* MAC address operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var MAC = {
/**
* @constant
* @default
*/
OUTPUT_CASE: ["Both", "Upper only", "Lower only"],
/**
* @constant
* @default
*/
NO_DELIM: true,
/**
* @constant
* @default
*/
DASH_DELIM: true,
/**
* @constant
* @default
*/
COLON_DELIM: true,
/**
* @constant
* @default
*/
CISCO_STYLE: false,
/**
* Format MAC addresses operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_format: function(input, args) {
if (!input) return "";
var output_case = args[0],
no_delim = args[1],
dash_delim = args[2],
colon_delim = args[3],
cisco_style = args[4],
output_list = [],
macs = input.toLowerCase().split(/[,\s\r\n]+/);
macs.forEach(function(mac) {
var cleanMac = mac.replace(/[:.-]+/g, ''),
macHyphen = cleanMac.replace(/(.{2}(?=.))/g, '$1-'),
macColon = cleanMac.replace(/(.{2}(?=.))/g, '$1:'),
macCisco = cleanMac.replace(/(.{4}(?=.))/g, '$1.');
if (output_case == "Lower only") {
if (no_delim) output_list.push(cleanMac);
if (dash_delim) output_list.push(macHyphen);
if (colon_delim) output_list.push(macColon);
if (cisco_style) output_list.push(macCisco);
} else if (output_case == "Upper only") {
if (no_delim) output_list.push(cleanMac.toUpperCase());
if (dash_delim) output_list.push(macHyphen.toUpperCase());
if (colon_delim) output_list.push(macColon.toUpperCase());
if (cisco_style) output_list.push(macCisco.toUpperCase());
} else {
if (no_delim) output_list.push(cleanMac, cleanMac.toUpperCase());
if (dash_delim) output_list.push(macHyphen, macHyphen.toUpperCase());
if (colon_delim) output_list.push(macColon, macColon.toUpperCase());
if (cisco_style) output_list.push(macCisco, macCisco.toUpperCase());
}
output_list.push(
"" // Empty line to delimit groups
);
});
// Return the data as a string
return output_list.join('\n');
},
};

27
src/js/operations/Numberwang.js Executable file
View file

@ -0,0 +1,27 @@
/**
* Numberwang operations.
*
* @author Unknown Male 282
* @namespace
*/
var Numberwang = {
/**
* Numberwang operation. Remain indoors.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run: function(input, args) {
if (!input) return "Let's play Wangernumb!";
var match = input.match(/\d+/);
if (match) {
return match[0] + "! That's Numberwang!";
} else {
// That's a bad miss!
return "Sorry, that's not Numberwang. Let's rotate the board!";
}
},
};

309
src/js/operations/OS.js Executable file
View file

@ -0,0 +1,309 @@
/**
* Operating system operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var OS = {
/**
* Parse UNIX file permissions operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse_unix_perms: function(input, args) {
var perms = {
d : false, // directory
sl : false, // symbolic link
np : false, // named pipe
s : false, // socket
cd : false, // character device
bd : false, // block device
dr : false, // door
sb : false, // sticky bit
su : false, // setuid
sg : false, // setgid
ru : false, // read user
wu : false, // write user
eu : false, // execute user
rg : false, // read group
wg : false, // write group
eg : false, // execute group
ro : false, // read other
wo : false, // write other
eo : false // execute other
},
d = 0,
u = 0,
g = 0,
o = 0,
output = "",
octal = null,
textual = null;
if (input.search(/\s*[0-7]{1,4}\s*/i) === 0) {
// Input is octal
octal = input.match(/\s*([0-7]{1,4})\s*/i)[1];
if (octal.length == 4) {
d = parseInt(octal[0], 8);
u = parseInt(octal[1], 8);
g = parseInt(octal[2], 8);
o = parseInt(octal[3], 8);
} else {
if (octal.length > 0) u = parseInt(octal[0], 8);
if (octal.length > 1) g = parseInt(octal[1], 8);
if (octal.length > 2) o = parseInt(octal[2], 8);
}
perms.su = d >> 2 & 0x1;
perms.sg = d >> 1 & 0x1;
perms.sb = d & 0x1;
perms.ru = u >> 2 & 0x1;
perms.wu = u >> 1 & 0x1;
perms.eu = u & 0x1;
perms.rg = g >> 2 & 0x1;
perms.wg = g >> 1 & 0x1;
perms.eg = g & 0x1;
perms.ro = o >> 2 & 0x1;
perms.wo = o >> 1 & 0x1;
perms.eo = o & 0x1;
} else if (input.search(/\s*[dlpcbDrwxsStT-]{1,10}\s*/) === 0) {
// Input is textual
textual = input.match(/\s*([dlpcbDrwxsStT-]{1,10})\s*/)[1];
switch (textual[0]) {
case "d":
perms.d = true;
break;
case "l":
perms.sl = true;
break;
case "p":
perms.np = true;
break;
case "s":
perms.s = true;
break;
case "c":
perms.cd = true;
break;
case "b":
perms.bd = true;
break;
case "D":
perms.dr = true;
break;
}
if (textual.length > 1) perms.ru = textual[1] == "r";
if (textual.length > 2) perms.wu = textual[2] == "w";
if (textual.length > 3) {
switch (textual[3]) {
case "x":
perms.eu = true;
break;
case "s":
perms.eu = true;
perms.su = true;
break;
case "S":
perms.su = true;
break;
}
}
if (textual.length > 4) perms.rg = textual[4] == "r";
if (textual.length > 5) perms.wg = textual[5] == "w";
if (textual.length > 6) {
switch (textual[6]) {
case "x":
perms.eg = true;
break;
case "s":
perms.eg = true;
perms.sg = true;
break;
case "S":
perms.sg = true;
break;
}
}
if (textual.length > 7) perms.ro = textual[7] == "r";
if (textual.length > 8) perms.wo = textual[8] == "w";
if (textual.length > 9) {
switch (textual[9]) {
case "x":
perms.eo = true;
break;
case "t":
perms.eo = true;
perms.sb = true;
break;
case "T":
perms.sb = true;
break;
}
}
} else {
return "Invalid input format.\nPlease enter the permissions in either octal (e.g. 755) or textual (e.g. drwxr-xr-x) format.";
}
output += "Textual representation: " + OS._perms_to_str(perms);
output += "\nOctal representation: " + OS._perms_to_octal(perms);
// File type
if (textual) {
output += "\nFile type: " + OS._ft_from_perms(perms);
}
// setuid, setgid
if (perms.su) {
output += "\nThe setuid flag is set";
}
if (perms.sg) {
output += "\nThe setgid flag is set";
}
// sticky bit
if (perms.sb) {
output += "\nThe sticky bit is set";
}
// Permission matrix
output += "\n\n +---------+-------+-------+-------+\n" +
" | | User | Group | Other |\n" +
" +---------+-------+-------+-------+\n" +
" | Read | " + (perms.ru ? "X" : " ") + " | " + (perms.rg ? "X" : " ") + " | " + (perms.ro ? "X" : " ") + " |\n" +
" +---------+-------+-------+-------+\n" +
" | Write | " + (perms.wu ? "X" : " ") + " | " + (perms.wg ? "X" : " ") + " | " + (perms.wo ? "X" : " ") + " |\n" +
" +---------+-------+-------+-------+\n" +
" | Execute | " + (perms.eu ? "X" : " ") + " | " + (perms.eg ? "X" : " ") + " | " + (perms.eo ? "X" : " ") + " |\n" +
" +---------+-------+-------+-------+\n";
return output;
},
/**
* Given a permissions object dictionary, generates a textual permissions string.
*
* @private
* @param {Object} perms
* @returns {string}
*/
_perms_to_str: function(perms) {
var str = "",
type = "-";
if (perms.d) type = "d";
if (perms.sl) type = "l";
if (perms.np) type = "p";
if (perms.s) type = "s";
if (perms.cd) type = "c";
if (perms.bd) type = "b";
if (perms.dr) type = "D";
str = type;
str += perms.ru ? "r" : "-";
str += perms.wu ? "w" : "-";
if (perms.eu && perms.su) {
str += "s";
} else if (perms.su) {
str += "S";
} else if (perms.eu) {
str += "x";
} else {
str += "-";
}
str += perms.rg ? "r" : "-";
str += perms.wg ? "w" : "-";
if (perms.eg && perms.sg) {
str += "s";
} else if (perms.sg) {
str += "S";
} else if (perms.eg) {
str += "x";
} else {
str += "-";
}
str += perms.ro ? "r" : "-";
str += perms.wo ? "w" : "-";
if (perms.eo && perms.sb) {
str += "t";
} else if (perms.sb) {
str += "T";
} else if (perms.eo) {
str += "x";
} else {
str += "-";
}
return str;
},
/**
* Given a permissions object dictionary, generates an octal permissions string.
*
* @private
* @param {Object} perms
* @returns {string}
*/
_perms_to_octal: function(perms) {
var d = 0,
u = 0,
g = 0,
o = 0;
if (perms.su) d += 4;
if (perms.sg) d += 2;
if (perms.sb) d += 1;
if (perms.ru) u += 4;
if (perms.wu) u += 2;
if (perms.eu) u += 1;
if (perms.rg) g += 4;
if (perms.wg) g += 2;
if (perms.eg) g += 1;
if (perms.ro) o += 4;
if (perms.wo) o += 2;
if (perms.eo) o += 1;
return d.toString() + u.toString() + g.toString() + o.toString();
},
/**
* Given a permissions object dictionary, returns the file type.
*
* @private
* @param {Object} perms
* @returns {string}
*/
_ft_from_perms: function(perms) {
if (perms.d) return "Directory";
if (perms.sl) return "Symbolic link";
if (perms.np) return "Named pipe";
if (perms.s) return "Socket";
if (perms.cd) return "Character device";
if (perms.bd) return "Block device";
if (perms.dr) return "Door";
return "Regular file";
},
};

1053
src/js/operations/PublicKey.js Executable file

File diff suppressed because it is too large Load diff

55
src/js/operations/Punycode.js Executable file
View file

@ -0,0 +1,55 @@
/* globals punycode */
/**
* Punycode operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Punycode = {
/**
* @constant
* @default
*/
IDN: false,
/**
* To Punycode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_to_ascii: function(input, args) {
var idn = args[0];
if (idn) {
return punycode.ToASCII(input);
} else {
return punycode.encode(input);
}
},
/**
* From Punycode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_to_unicode: function(input, args) {
var idn = args[0];
if (idn) {
return punycode.ToUnicode(input);
} else {
return punycode.decode(input);
}
},
};

View file

@ -0,0 +1,270 @@
/** @license
========================================================================
mimelib: http://github.com/andris9/mimelib
Copyright (c) 2011-2012 Andris Reinman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* Quoted Printable operations.
* Some parts taken from mimelib (http://github.com/andris9/mimelib)
*
* @author Andris Reinman
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var QuotedPrintable = {
/**
* To Quoted Printable operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {string}
*/
run_to: function (input, args) {
var mimeEncodedStr = QuotedPrintable.mimeEncode(input);
// fix line breaks
mimeEncodedStr = mimeEncodedStr.replace(/\r?\n|\r/g, function() {
return "\r\n";
}).replace(/[\t ]+$/gm, function(spaces) {
return spaces.replace(/ /g, "=20").replace(/\t/g, "=09");
});
return QuotedPrintable._addSoftLinebreaks(mimeEncodedStr, "qp");
},
/**
* From Quoted Printable operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_from: function (input, args) {
var str = input.replace(/\=(?:\r?\n|$)/g, "");
return QuotedPrintable.mimeDecode(str);
},
/**
* Decodes mime-encoded data.
*
* @param {string} str
* @returns {byte_array}
*/
mimeDecode: function(str) {
var encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
bufferLength = str.length - encodedBytesCount * 2,
chr, hex,
buffer = new Array(bufferLength),
bufferPos = 0;
for (var i = 0, len = str.length; i < len; i++) {
chr = str.charAt(i);
if (chr == "=" && (hex = str.substr(i + 1, 2)) && /[\da-fA-F]{2}/.test(hex)) {
buffer[bufferPos++] = parseInt(hex, 16);
i += 2;
continue;
}
buffer[bufferPos++] = chr.charCodeAt(0);
}
return buffer;
},
/**
* Encodes mime data.
*
* @param {byte_array} buffer
* @returns {string}
*/
mimeEncode: function(buffer) {
var ranges = [
[0x09],
[0x0A],
[0x0D],
[0x20],
[0x21],
[0x23, 0x3C],
[0x3E],
[0x40, 0x5E],
[0x60, 0x7E]
],
result = "";
for (var i = 0, len = buffer.length; i < len; i++) {
if (this._checkRanges(buffer[i], ranges)) {
result += String.fromCharCode(buffer[i]);
continue;
}
result += "=" + (buffer[i] < 0x10 ? "0" : "") + buffer[i].toString(16).toUpperCase();
}
return result;
},
/**
* Checks if a given number falls within a given set of ranges.
*
* @private
* @param {number} nr
* @param {byte_array[]} ranges
* @returns {bolean}
*/
_checkRanges: function(nr, ranges) {
for (var i = ranges.length - 1; i >= 0; i--) {
if (!ranges[i].length)
continue;
if (ranges[i].length == 1 && nr == ranges[i][0])
return true;
if (ranges[i].length == 2 && nr >= ranges[i][0] && nr <= ranges[i][1])
return true;
}
return false;
},
/**
* Adds soft line breaks to a string.
* Lines can't be longer that 76 + <CR><LF> = 78 bytes
* http://tools.ietf.org/html/rfc2045#section-6.7
*
* @private
* @param {string} str
* @param {string} encoding
* @returns {string}
*/
_addSoftLinebreaks: function(str, encoding) {
var lineLengthMax = 76;
encoding = (encoding || "base64").toString().toLowerCase().trim();
if (encoding == "qp") {
return this._addQPSoftLinebreaks(str, lineLengthMax);
} else {
return this._addBase64SoftLinebreaks(str, lineLengthMax);
}
},
/**
* Adds soft line breaks to a base64 string.
*
* @private
* @param {string} base64EncodedStr
* @param {number} lineLengthMax
* @returns {string}
*/
_addBase64SoftLinebreaks: function(base64EncodedStr, lineLengthMax) {
base64EncodedStr = (base64EncodedStr || "").toString().trim();
return base64EncodedStr.replace(new RegExp(".{" + lineLengthMax + "}", "g"), "$&\r\n").trim();
},
/**
* Adds soft line breaks to a quoted printable string.
*
* @private
* @param {string} mimeEncodedStr
* @param {number} lineLengthMax
* @returns {string}
*/
_addQPSoftLinebreaks: function(mimeEncodedStr, lineLengthMax) {
var pos = 0,
len = mimeEncodedStr.length,
match, code, line,
lineMargin = Math.floor(lineLengthMax / 3),
result = "";
// insert soft linebreaks where needed
while (pos < len) {
line = mimeEncodedStr.substr(pos, lineLengthMax);
if ((match = line.match(/\r\n/))) {
line = line.substr(0, match.index + match[0].length);
result += line;
pos += line.length;
continue;
}
if (line.substr(-1) == "\n") {
// nothing to change here
result += line;
pos += line.length;
continue;
} else if ((match = line.substr(-lineMargin).match(/\n.*?$/))) {
// truncate to nearest line break
line = line.substr(0, line.length - (match[0].length - 1));
result += line;
pos += line.length;
continue;
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) {
// truncate to nearest space
line = line.substr(0, line.length - (match[0].length - 1));
} else if (line.substr(-1) == "\r") {
line = line.substr(0, line.length - 1);
} else {
if (line.match(/\=[\da-f]{0,2}$/i)) {
// push incomplete encoding sequences to the next line
if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
line = line.substr(0, line.length - match[0].length);
}
// 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))) {
code = parseInt(match[0].substr(1, 2), 16);
if (code < 128) {
break;
}
line = line.substr(0, line.length - 3);
if (code >= 0xC0) {
break;
}
}
}
}
if (pos + line.length < len && line.substr(-1) != "\n") {
if (line.length == 76 && line.match(/\=[\da-f]{2}$/i)) {
line = line.substr(0, line.length - 3);
} else if (line.length == 76) {
line = line.substr(0, line.length - 1);
}
pos += line.length;
line += "=\r\n";
} else {
pos += line.length;
}
result += line;
}
return result;
},
};

206
src/js/operations/Rotate.js Executable file
View file

@ -0,0 +1,206 @@
/**
* Bit rotation operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*
* @todo Support for UTF16
*/
var Rotate = {
/**
* @constant
* @default
*/
ROTATE_AMOUNT: 1,
/**
* @constant
* @default
*/
ROTATE_WHOLE: false,
/**
* Runs rotation operations across the input data.
*
* @private
* @param {byte_array} data
* @param {number} amount
* @param {function} algo - The rotation operation to carry out
* @returns {byte_array}
*/
_rot: function(data, amount, algo) {
var result = [];
for (var i = 0; i < data.length; i++) {
var b = data[i];
for (var j = 0; j < amount; j++) {
b = algo(b);
}
result.push(b);
}
return result;
},
/**
* Rotate right operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_rotr: function(input, args) {
if (args[1]) {
return Rotate._rotr_whole(input, args[0]);
} else {
return Rotate._rot(input, args[0], Rotate._rotr);
}
},
/**
* Rotate left operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_rotl: function(input, args) {
if (args[1]) {
return Rotate._rotl_whole(input, args[0]);
} else {
return Rotate._rot(input, args[0], Rotate._rotl);
}
},
/**
* @constant
* @default
*/
ROT13_AMOUNT: 13,
/**
* @constant
* @default
*/
ROT13_LOWERCASE: true,
/**
* @constant
* @default
*/
ROT13_UPPERCASE: true,
/**
* ROT13 operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_rot13: function(input, args) {
var amount = args[2],
output = input,
chr,
rot13_lowercase = args[0],
rot13_upperacse = args[1];
if (amount) {
if (amount < 0) {
amount = 26 - (Math.abs(amount) % 26);
}
for (var i = 0; i < input.length; i++) {
chr = input[i];
if (rot13_upperacse && chr >= 65 && chr <= 90) { // Upper case
chr = (chr - 65 + amount) % 26;
output[i] = chr + 65;
} else if (rot13_lowercase && chr >= 97 && chr <= 122) { // Lower case
chr = (chr - 97 + amount) % 26;
output[i] = chr + 97;
}
}
}
return output;
},
/**
* Rotate right bitwise op.
*
* @private
* @param {byte} b
* @returns {byte}
*/
_rotr: function(b) {
var bit = (b & 1) << 7;
return (b >> 1) | bit;
},
/**
* Rotate left bitwise op.
*
* @private
* @param {byte} b
* @returns {byte}
*/
_rotl: function(b) {
var bit = (b >> 7) & 1;
return ((b << 1) | bit) & 0xFF;
},
/**
* Rotates a byte array to the right by a specific amount as a whole, so that bits are wrapped
* from the end of the array to the beginning.
*
* @private
* @param {byte_array} data
* @param {number} amount
* @returns {byte_array}
*/
_rotr_whole: function(data, amount) {
var carry_bits = 0,
new_byte,
result = [];
amount = amount % 8;
for (var i = 0; i < data.length; i++) {
var old_byte = data[i] >>> 0;
new_byte = (old_byte >> amount) | carry_bits;
carry_bits = (old_byte & (Math.pow(2, amount)-1)) << (8-amount);
result.push(new_byte);
}
result[0] |= carry_bits;
return result;
},
/**
* Rotates a byte array to the left by a specific amount as a whole, so that bits are wrapped
* from the beginning of the array to the end.
*
* @private
* @param {byte_array} data
* @param {number} amount
* @returns {byte_array}
*/
_rotl_whole: function(data, amount) {
var carry_bits = 0,
new_byte,
result = [];
amount = amount % 8;
for (var i = data.length-1; i >= 0; i--) {
var old_byte = data[i];
new_byte = ((old_byte << amount) | carry_bits) & 0xFF;
carry_bits = (old_byte >> (8-amount)) & (Math.pow(2, amount)-1);
result[i] = (new_byte);
}
result[data.length-1] = result[data.length-1] | carry_bits;
return result;
},
};

220
src/js/operations/SeqUtils.js Executable file
View file

@ -0,0 +1,220 @@
/**
* Sequence utility operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var SeqUtils = {
/**
* @constant
* @default
*/
DELIMITER_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"],
/**
* @constant
* @default
*/
SORT_REVERSE: false,
/**
* @constant
* @default
*/
SORT_ORDER: ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address"],
/**
* Sort operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_sort: function (input, args) {
var delim = Utils.char_rep[args[0]],
sort_reverse = args[1],
order = args[2],
sorted = input.split(delim);
if (order == "Alphabetical (case sensitive)") {
sorted = sorted.sort();
} else if (order == "Alphabetical (case insensitive)") {
sorted = sorted.sort(SeqUtils._case_insensitive_sort);
} else if (order == "IP address") {
sorted = sorted.sort(SeqUtils._ip_sort);
}
if (sort_reverse) sorted.reverse();
return sorted.join(delim);
},
/**
* Unique operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_unique: function (input, args) {
var delim = Utils.char_rep[args[0]];
return input.split(delim).unique().join(delim);
},
/**
* @constant
* @default
*/
SEARCH_TYPE: ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"],
/**
* Count occurrences operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
run_count: function(input, args) {
var search = args[0].string,
type = args[0].option;
if (type == "Regex" && search) {
try {
var regex = new RegExp(search, "gi"),
matches = input.match(regex);
return matches.length;
} catch(err) {
return 0;
}
} else if (search) {
if (type.indexOf("Extended") === 0) {
search = Utils.parse_escaped_chars(search);
}
return input.count(search);
} else {
return 0;
}
},
/**
* @constant
* @default
*/
REVERSE_BY: ["Character", "Line"],
/**
* Reverse operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_reverse: function (input, args) {
if (args[0] == "Line") {
var lines = [],
line = [],
result = [];
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x0a) {
lines.push(line);
line = [];
} else {
line.push(input[i]);
}
}
lines.push(line);
lines.reverse();
for (i = 0; i < lines.length; i++) {
result = result.concat(lines[i]);
result.push(0x0a);
}
return result.slice(0, input.length);
} else {
return input.reverse();
}
},
/**
* Add line numbers operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_add_line_numbers: function(input, args) {
var lines = input.split("\n"),
output = "",
width = lines.length.toString().length;
for (var n = 0; n < lines.length; n++) {
output += Utils.pad((n+1).toString(), width, " ") + " " + lines[n] + "\n";
}
return output.slice(0, output.length-1);
},
/**
* Remove line numbers operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_remove_line_numbers: function(input, args) {
return input.replace(/^[ \t]{0,5}\d+[\s:|\-,.)\]]/gm, "");
},
/**
* Expand alphabet range operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_expand_alph_range: function(input, args) {
return Utils.expand_alph_range(input).join(args[0]);
},
/**
* Comparison operation for sorting of strings ignoring case.
*
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
_case_insensitive_sort: function(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
},
/**
* Comparison operation for sorting of IPv4 addresses.
*
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
_ip_sort: function(a, b) {
var a_ = a.split("."),
b_ = b.split(".");
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
if (isNaN(a_) && !isNaN(b_)) return 1;
if (!isNaN(a_) && isNaN(b_)) return -1;
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
return a_ - b_;
},
};

512
src/js/operations/StrUtils.js Executable file
View file

@ -0,0 +1,512 @@
/* globals JsDiff */
/**
* String utility operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var StrUtils = {
/**
* @constant
* @default
*/
REGEX_PRE_POPULATE: [
{
name: "User defined",
value: ""
},
{
name: "IPv4 address",
value: "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?"
},
{
name: "IPv6 address",
value: "((?=.*::)(?!.*::.+::)(::)?([\\dA-Fa-f]{1,4}:(:|\\b)|){5}|([\\dA-Fa-f]{1,4}:){6})((([\\dA-Fa-f]{1,4}((?!\\3)::|:\\b|(?![\\dA-Fa-f])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})"
},
{
name: "Email address",
value: "(\\w[-.\\w]*)@([-\\w]+(?:\\.[-\\w]+)*)\\.([A-Za-z]{2,4})"
},
{
name: "URL",
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
},
{
name: "Domain",
value: "(?:(https?):\\/\\/)?([-\\w.]+)\\.(com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+"
},
{
name: "Windows file path",
value: "([A-Za-z]):\\\\((?:[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)]{0,61}\\\\?)*[A-Za-z\\d][A-Za-z\\d\\- \\x27_\\(\\)]{0,61})(\\.[A-Za-z\\d]{1,6})?"
},
{
name: "UNIX file path",
value: "(?:/[A-Za-z\\d.][A-Za-z\\d\\-.]{0,61})+"
},
{
name: "MAC address",
value: "[A-Fa-f\\d]{2}(?:[:-][A-Fa-f\\d]{2}){5}"
},
{
name: "Date (yyyy-mm-dd)",
value: "((?:19|20)\\d\\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])"
},
{
name: "Date (dd/mm/yyyy)",
value: "(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Date (mm/dd/yyyy)",
value: "(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.]((?:19|20)\\d\\d)"
},
{
name: "Strings",
value: "[A-Za-z\\d/\\-:.,_$%\\x27\"()<>= !\\[\\]{}@]{4,}"
},
],
/**
* @constant
* @default
*/
REGEX_CASE_INSENSITIVE: true,
/**
* @constant
* @default
*/
REGEX_MULTILINE_MATCHING: true,
/**
* @constant
* @default
*/
OUTPUT_FORMAT: ["Highlight matches", "List matches", "List capture groups", "List matches with capture groups"],
/**
* @constant
* @default
*/
DISPLAY_TOTAL: false,
/**
* Regular expression operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_regex: function(input, args) {
var user_regex = args[1],
i = args[2],
m = args[3],
display_total = args[4],
output_format = args[5],
modifiers = "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (user_regex && user_regex != "^" && user_regex != "$") {
try {
var regex = new RegExp(user_regex, modifiers);
switch (output_format) {
case "Highlight matches":
return StrUtils._regex_highlight(input, regex, display_total);
case "List matches":
return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, true, false));
case "List capture groups":
return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, false, true));
case "List matches with capture groups":
return Utils.escape_html(StrUtils._regex_list(input, regex, display_total, true, true));
default:
return "Error: Invalid output format";
}
} catch (err) {
return "Invalid regex. Details: " + err.message;
}
} else {
return Utils.escape_html(input);
}
},
/**
* @constant
* @default
*/
CASE_SCOPE: ["All", "Word", "Sentence", "Paragraph"],
/**
* To Upper case operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_upper: function (input, args) {
var scope = args[0];
switch (scope) {
case "Word":
return input.replace(/(\b\w)/gi, function(m) {
return m.toUpperCase();
});
case "Sentence":
return input.replace(/(?:\.|^)\s*(\b\w)/gi, function(m) {
return m.toUpperCase();
});
case "Paragraph":
return input.replace(/(?:\n|^)\s*(\b\w)/gi, function(m) {
return m.toUpperCase();
});
case "All":
/* falls through */
default:
return input.toUpperCase();
}
},
/**
* To Upper case operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_lower: function (input, args) {
return input.toLowerCase();
},
/**
* @constant
* @default
*/
SEARCH_TYPE: ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"],
/**
* @constant
* @default
*/
FIND_REPLACE_GLOBAL : true,
/**
* @constant
* @default
*/
FIND_REPLACE_CASE : false,
/**
* @constant
* @default
*/
FIND_REPLACE_MULTILINE : true,
/**
* Find / Replace operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_find_replace: function(input, args) {
var find = args[0].string,
type = args[0].option,
replace = args[1],
g = args[2],
i = args[3],
m = args[4],
modifiers = "";
if (g) modifiers += "g";
if (i) modifiers += "i";
if (m) modifiers += "m";
if (type == "Regex") {
find = new RegExp(find, modifiers);
} else if (type.indexOf("Extended") === 0) {
find = Utils.parse_escaped_chars(find);
}
return input.replace(find, replace, modifiers);
// Non-standard addition of flags in the third argument. This will work in Firefox but
// probably nowhere else. The purpose is to allow global matching when the `find` parameter
// is just a string.
},
/**
* @constant
* @default
*/
SPLIT_DELIM: ",",
/**
* @constant
* @default
*/
DELIMITER_OPTIONS: ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"],
/**
* Split operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_split: function(input, args) {
var split_delim = args[0] || StrUtils.SPLIT_DELIM,
join_delim = Utils.char_rep[args[1]],
sections = input.split(split_delim);
return sections.join(join_delim);
},
/**
* @constant
* @default
*/
DIFF_SAMPLE_DELIMITER: "\\n\\n",
/**
* @constant
* @default
*/
DIFF_BY: ["Character", "Word", "Line", "Sentence", "CSS", "JSON"],
/**
* Diff operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_diff: function(input, args) {
var sample_delim = args[0],
diff_by = args[1],
show_added = args[2],
show_removed = args[3],
ignore_whitespace = args[4],
samples = input.split(sample_delim),
output = "",
diff;
if (!samples || samples.length != 2) {
return "Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?";
}
switch (diff_by) {
case "Character":
diff = JsDiff.diffChars(samples[0], samples[1]);
break;
case "Word":
if (ignore_whitespace) {
diff = JsDiff.diffWords(samples[0], samples[1]);
} else {
diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
}
break;
case "Line":
if (ignore_whitespace) {
diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
} else {
diff = JsDiff.diffLines(samples[0], samples[1]);
}
break;
case "Sentence":
diff = JsDiff.diffSentences(samples[0], samples[1]);
break;
case "CSS":
diff = JsDiff.diffCss(samples[0], samples[1]);
break;
case "JSON":
diff = JsDiff.diffJson(samples[0], samples[1]);
break;
default:
return "Invalid 'Diff by' option.";
}
for (var i = 0; i < diff.length; i++) {
if (diff[i].added) {
if (show_added) output += "<span class='hlgreen'>" + Utils.escape_html(diff[i].value) + "</span>";
} else if (diff[i].removed) {
if (show_removed) output += "<span class='hlred'>" + Utils.escape_html(diff[i].value) + "</span>";
} else {
output += Utils.escape_html(diff[i].value);
}
}
return output;
},
/**
* @constant
* @default
*/
OFF_CHK_SAMPLE_DELIMITER: "\\n\\n",
/**
* Offset checker operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run_offset_checker: function(input, args) {
var sample_delim = args[0],
samples = input.split(sample_delim),
outputs = [],
i = 0,
s = 0,
match = false,
in_match = false,
chr;
if (!samples || samples.length < 2) {
return "Not enough samples, perhaps you need to modify the sample delimiter or add more data?";
}
// Initialise output strings
for (s = 0; s < samples.length; s++) {
outputs[s] = "";
}
// Loop through each character in the first sample
for (i = 0; i < samples[0].length; i++) {
chr = samples[0][i];
match = false;
// Loop through each sample to see if the chars are the same
for (s = 1; s < samples.length; s++) {
if (samples[s][i] != chr) {
match = false;
break;
}
match = true;
}
// Write output for each sample
for (s = 0; s < samples.length; s++) {
if (samples[s].length <= i) {
if (in_match) outputs[s] += "</span>";
if (s == samples.length - 1) in_match = false;
continue;
}
if (match && !in_match) {
outputs[s] += "<span class='hlgreen'>" + Utils.escape_html(samples[s][i]);
if (samples[s].length == i + 1) outputs[s] += "</span>";
if (s == samples.length - 1) in_match = true;
} else if (!match && in_match) {
outputs[s] += "</span>" + Utils.escape_html(samples[s][i]);
if (s == samples.length - 1) in_match = false;
} else {
outputs[s] += Utils.escape_html(samples[s][i]);
if (in_match && samples[s].length == i + 1) {
outputs[s] += "</span>";
if (samples[s].length - 1 != i) in_match = false;
}
}
if (samples[0].length - 1 == i) {
if (in_match) outputs[s] += "</span>";
outputs[s] += Utils.escape_html(samples[s].substring(i + 1));
}
}
}
return outputs.join(sample_delim);
},
/**
* Parse escaped string operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse_escaped_string: function(input, args) {
return Utils.parse_escaped_chars(input);
},
/**
* Adds HTML highlights to matches within a string.
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} display_total
* @returns {string}
*/
_regex_highlight: function(input, regex, display_total) {
var output = "",
m,
hl = 1,
i = 0,
total = 0;
while (!!(m = regex.exec(input))) {
// Add up to match
output += Utils.escape_html(input.slice(i, m.index));
// Add match with highlighting
output += "<span class='hl"+hl+"'>" + Utils.escape_html(m[0]) + "</span>";
// Switch highlight
hl = hl == 1 ? 2 : 1;
i = regex.lastIndex;
total++;
}
// Add all after final match
output += Utils.escape_html(input.slice(i, input.length));
if (display_total)
output = "Total found: " + total + "\n\n" + output;
return output;
},
/**
* Creates a string listing the matches within a string.
*
* @private
* @param {string} input
* @param {RegExp} regex
* @param {boolean} display_total
* @param {boolean} matches - Display full match
* @param {boolean} capture_groups - Display each of the capture groups separately
* @returns {string}
*/
_regex_list: function(input, regex, display_total, matches, capture_groups) {
var output = "",
total = 0,
match;
while (!!(match = regex.exec(input))) {
total++;
if (matches) {
output += match[0] + "\n";
}
if (capture_groups) {
for (var i = 1; i < match.length; i++) {
if (matches) {
output += " Group " + i + ": ";
}
output += match[i] + "\n";
}
}
}
if (display_total)
output = "Total found: " + total + "\n\n" + output;
return output;
},
};

238
src/js/operations/Tidy.js Executable file
View file

@ -0,0 +1,238 @@
/**
* Tidy operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Tidy = {
/**
* @constant
* @default
*/
REMOVE_SPACES : true,
/**
* @constant
* @default
*/
REMOVE_CARIAGE_RETURNS : true,
/**
* @constant
* @default
*/
REMOVE_LINE_FEEDS : true,
/**
* @constant
* @default
*/
REMOVE_TABS : true,
/**
* @constant
* @default
*/
REMOVE_FORM_FEEDS : true,
/**
* @constant
* @default
*/
REMOVE_FULL_STOPS : false,
/**
* Remove whitespace operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_remove_whitespace: function (input, args) {
var remove_spaces = args[0],
remove_cariage_returns = args[1],
remove_line_feeds = args[2],
remove_tabs = args[3],
remove_form_feeds = args[4],
remove_full_stops = args[5],
data = input;
if (remove_spaces) data = data.replace(/ /g, "");
if (remove_cariage_returns) data = data.replace(/\r/g, "");
if (remove_line_feeds) data = data.replace(/\n/g, "");
if (remove_tabs) data = data.replace(/\t/g, "");
if (remove_form_feeds) data = data.replace(/\f/g, "");
if (remove_full_stops) data = data.replace(/\./g, "");
return data;
},
/**
* Remove null bytes operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_remove_nulls: function (input, args) {
var output = [];
for (var i = 0; i < input.length; i++) {
if (input[i] !== 0) output.push(input[i]);
}
return output;
},
/**
* @constant
* @default
*/
APPLY_TO_EACH_LINE : false,
/**
* @constant
* @default
*/
DROP_START : 0,
/**
* @constant
* @default
*/
DROP_LENGTH : 5,
/**
* Drop bytes operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_drop_bytes: function(input, args) {
var start = args[0],
length = args[1],
apply_to_each_line = args[2];
if (start < 0 || length < 0)
throw "Error: Invalid value";
if (!apply_to_each_line)
return input.slice(0, start).concat(input.slice(start+length, input.length));
// Split input into lines
var lines = [],
line = [];
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x0a) {
lines.push(line);
line = [];
} else {
line.push(input[i]);
}
}
lines.push(line);
var output = [];
for (i = 0; i < lines.length; i++) {
output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
output.push(0x0a);
}
return output.slice(0, output.length-1);
},
/**
* @constant
* @default
*/
TAKE_START: 0,
/**
* @constant
* @default
*/
TAKE_LENGTH: 5,
/**
* Take bytes operation.
*
* @param {byte_array} input
* @param {Object[]} args
* @returns {byte_array}
*/
run_take_bytes: function(input, args) {
var start = args[0],
length = args[1],
apply_to_each_line = args[2];
if (start < 0 || length < 0)
throw "Error: Invalid value";
if (!apply_to_each_line)
return input.slice(start, start+length);
// Split input into lines
var lines = [],
line = [];
for (var i = 0; i < input.length; i++) {
if (input[i] == 0x0a) {
lines.push(line);
line = [];
} else {
line.push(input[i]);
}
}
lines.push(line);
var output = [];
for (i = 0; i < lines.length; i++) {
output = output.concat(lines[i].slice(start, start+length));
output.push(0x0a);
}
return output.slice(0, output.length-1);
},
/**
* @constant
* @default
*/
PAD_POSITION : ["Start", "End"],
/**
* @constant
* @default
*/
PAD_LENGTH : 5,
/**
* @constant
* @default
*/
PAD_CHAR : " ",
/**
* Pad lines operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_pad: function(input, args) {
var position = args[0],
len = args[1],
chr = args[2],
lines = input.split("\n"),
output = "",
i = 0;
if (position == "Start") {
for (i = 0; i < lines.length; i++) {
output += Utils.pad_left(lines[i], lines[i].length+len, chr) + "\n";
}
} else if (position == "End") {
for (i = 0; i < lines.length; i++) {
output += Utils.pad_right(lines[i], lines[i].length+len, chr) + "\n";
}
}
return output.slice(0, output.length-1);
},
};

130
src/js/operations/URL.js Executable file
View file

@ -0,0 +1,130 @@
/* globals unescape */
/**
* URL operations.
* Namespace is appended with an underscore to prevent overwriting the global URL object.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var URL_ = {
/**
* @constant
* @default
*/
ENCODE_ALL: false,
/**
* URL Encode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_to: function(input, args) {
var encode_all = args[0];
return encode_all ? URL_._encode_all_chars(input) : encodeURI(input);
},
/**
* URL Decode operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_from: function(input, args) {
var data = input.replace(/\+/g, "%20");
try {
return decodeURIComponent(data);
} catch(err) {
return unescape(data);
}
},
/**
* Parse URI operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_parse: function(input, args) {
var a = document.createElement("a");
// Overwrite base href which will be the current CyberChef URL to reduce confusion.
a.href = "http://example.com/";
a.href = input;
if (a.protocol) {
var output = "";
if (a.hostname != window.location.hostname) {
output = "Protocol:\t" + a.protocol + "\n";
if (a.hostname) output += "Hostname:\t" + a.hostname + "\n";
if (a.port) output += "Port:\t\t" + a.port + "\n";
}
if (a.pathname) {
var pathname = a.pathname;
if (pathname.indexOf(window.location.pathname) === 0)
pathname = pathname.replace(window.location.pathname, "");
if (pathname)
output += "Path name:\t" + pathname + "\n";
}
if (a.hash) {
output += "Hash:\t\t" + a.hash + "\n";
}
if (a.search) {
output += "Arguments:\n";
var args_ = (a.search.slice(1, a.search.length)).split("&");
var split_args = [], padding = 0;
for (var i = 0; i < args_.length; i++) {
split_args.push(args_[i].split("="));
padding = (split_args[i][0].length > padding) ? split_args[i][0].length : padding;
}
for (i = 0; i < split_args.length; i++) {
output += "\t" + Utils.pad_right(split_args[i][0], padding);
if (split_args[i].length > 1 && split_args[i][1].length)
output += " = " + split_args[i][1] + "\n";
else output += "\n";
}
}
return output;
}
return "Invalid URI";
},
/**
* URL encodes additional special characters beyond the standard set.
*
* @private
* @param {string} str
* @returns {string}
*/
_encode_all_chars: function(str) {
//TODO Do this programatically
return encodeURIComponent(str)
.replace(/!/g, "%21")
.replace(/#/g, "%23")
.replace(/'/g, "%27")
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
.replace(/\*/g, "%2A")
.replace(/\-/g, "%2D")
.replace(/\./g, "%2E")
.replace(/_/g, "%5F")
.replace(/~/g, "%7E");
},
};

39
src/js/operations/UUID.js Executable file
View file

@ -0,0 +1,39 @@
/**
* UUID operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var UUID = {
/**
* Generate UUID operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_generate_v4: function(input, args) {
if (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') {
var buf = new Uint32Array(4),
i = 0;
window.crypto.getRandomValues(buf);
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf,
v = c === "x" ? r : (r & 0x3 | 0x8);
i++;
return v.toString(16);
});
} else {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c === "x" ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
},
};

62
src/js/operations/Unicode.js Executable file
View file

@ -0,0 +1,62 @@
/**
* Unicode operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
var Unicode = {
/**
* @constant
* @default
*/
PREFIXES: ["\\u", "%u", "U+"],
/**
* Unescape Unicode Characters operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run_unescape: function(input, args) {
var prefix = Unicode._prefix_to_regex[args[0]],
regex = new RegExp(prefix+"([a-f\\d]{4,6})", "ig"),
output = "",
m,
i = 0;
while (!!(m = regex.exec(input))) {
// Add up to match
output += input.slice(i, m.index);
i = m.index;
// Add match
output += Utils.chr(parseInt(m[1], 16));
i = regex.lastIndex;
}
// Add all after final match
output += input.slice(i, input.length);
return output;
},
/**
* Lookup table to add prefixes to unicode delimiters so that they can be used in a regex.
*
* @private
* @constant
*/
_prefix_to_regex: {
"\\u": "\\\\u",
"%u": "%u",
"U+": "U\\+"
},
};