Merge branch 'artemisbot-esmconversion' into esm
commit
40b29d770a
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
* Public key resources.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { toHex, fromHex } from "./Hex";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats Distinguished Name (DN) strings.
|
||||||
|
*
|
||||||
|
* @param {string} dnStr
|
||||||
|
* @param {number} indent
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function formatDnStr (dnStr, indent) {
|
||||||
|
const fields = dnStr.substr(1).replace(/([^\\])\//g, "$1$1/").split(/[^\\]\//);
|
||||||
|
let output = "",
|
||||||
|
maxKeyLen = 0,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
i,
|
||||||
|
str;
|
||||||
|
|
||||||
|
for (i = 0; i < fields.length; i++) {
|
||||||
|
if (!fields[i].length) continue;
|
||||||
|
|
||||||
|
key = fields[i].split("=")[0];
|
||||||
|
|
||||||
|
maxKeyLen = key.length > maxKeyLen ? key.length : maxKeyLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < fields.length; i++) {
|
||||||
|
if (!fields[i].length) continue;
|
||||||
|
|
||||||
|
key = fields[i].split("=")[0];
|
||||||
|
value = fields[i].split("=")[1];
|
||||||
|
str = key.padEnd(maxKeyLen, " ") + " = " + value + "\n";
|
||||||
|
|
||||||
|
output += str.padStart(indent + str.length, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats byte strings by adding line breaks and delimiters.
|
||||||
|
*
|
||||||
|
* @param {string} byteStr
|
||||||
|
* @param {number} length - Line width
|
||||||
|
* @param {number} indent
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function formatByteStr (byteStr, length, indent) {
|
||||||
|
byteStr = toHex(fromHex(byteStr), ":");
|
||||||
|
length = length * 3;
|
||||||
|
let output = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < byteStr.length; i += length) {
|
||||||
|
const str = byteStr.slice(i, i + length) + "\n";
|
||||||
|
if (i === 0) {
|
||||||
|
output += str;
|
||||||
|
} else {
|
||||||
|
output += str.padStart(indent + str.length, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.slice(0, output.length-1);
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS Beautify operation
|
||||||
|
*/
|
||||||
|
class CSSBeautify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSSBeautify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "CSS Beautify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Indents and prettifies Cascading Style Sheets (CSS) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Indent string",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\t"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const indentStr = args[0];
|
||||||
|
return vkbeautify.css(input, indentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSBeautify;
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS Minify operation
|
||||||
|
*/
|
||||||
|
class CSSMinify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSSMinify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "CSS Minify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Compresses Cascading Style Sheets (CSS) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Preserve comments",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const preserveComments = args[0];
|
||||||
|
return vkbeautify.cssmin(input, preserveComments);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSMinify;
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import xmldom from "xmldom";
|
||||||
|
import nwmatcher from "nwmatcher";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS selector operation
|
||||||
|
*/
|
||||||
|
class CSSSelector extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSSSelector constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "CSS selector";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Extract information from an HTML document with a CSS selector";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "CSS selector",
|
||||||
|
"type": "string",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Delimiter",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\n"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [query, delimiter] = args,
|
||||||
|
parser = new xmldom.DOMParser();
|
||||||
|
let dom,
|
||||||
|
result;
|
||||||
|
|
||||||
|
if (!query.length || !input.length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
dom = parser.parseFromString(input);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Invalid input HTML.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const matcher = nwmatcher({document: dom});
|
||||||
|
result = matcher.select(query, dom);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Invalid CSS Selector. Details:\n" + err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeToString = function(node) {
|
||||||
|
return node.toString();
|
||||||
|
/* xmldom does not return the outerHTML value.
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case node.ELEMENT_NODE: return node.outerHTML;
|
||||||
|
case node.ATTRIBUTE_NODE: return node.value;
|
||||||
|
case node.TEXT_NODE: return node.wholeText;
|
||||||
|
case node.COMMENT_NODE: return node.data;
|
||||||
|
case node.DOCUMENT_NODE: return node.outerHTML;
|
||||||
|
default: throw new Error("Unknown Node Type: " + node.nodeType);
|
||||||
|
}*/
|
||||||
|
};
|
||||||
|
|
||||||
|
return result
|
||||||
|
.map(nodeToString)
|
||||||
|
.join(delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSSelector;
|
|
@ -71,36 +71,39 @@ class Diff extends Operation {
|
||||||
let output = "",
|
let output = "",
|
||||||
diff;
|
diff;
|
||||||
|
|
||||||
|
// Node and Webpack load modules slightly differently
|
||||||
|
const jsdiff = JsDiff.default ? JsDiff.default : JsDiff;
|
||||||
|
|
||||||
if (!samples || samples.length !== 2) {
|
if (!samples || samples.length !== 2) {
|
||||||
throw new OperationError("Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?");
|
throw new OperationError("Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (diffBy) {
|
switch (diffBy) {
|
||||||
case "Character":
|
case "Character":
|
||||||
diff = JsDiff.diffChars(samples[0], samples[1]);
|
diff = jsdiff.diffChars(samples[0], samples[1]);
|
||||||
break;
|
break;
|
||||||
case "Word":
|
case "Word":
|
||||||
if (ignoreWhitespace) {
|
if (ignoreWhitespace) {
|
||||||
diff = JsDiff.diffWords(samples[0], samples[1]);
|
diff = jsdiff.diffWords(samples[0], samples[1]);
|
||||||
} else {
|
} else {
|
||||||
diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
|
diff = jsdiff.diffWordsWithSpace(samples[0], samples[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Line":
|
case "Line":
|
||||||
if (ignoreWhitespace) {
|
if (ignoreWhitespace) {
|
||||||
diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
|
diff = jsdiff.diffTrimmedLines(samples[0], samples[1]);
|
||||||
} else {
|
} else {
|
||||||
diff = JsDiff.diffLines(samples[0], samples[1]);
|
diff = jsdiff.diffLines(samples[0], samples[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Sentence":
|
case "Sentence":
|
||||||
diff = JsDiff.diffSentences(samples[0], samples[1]);
|
diff = jsdiff.diffSentences(samples[0], samples[1]);
|
||||||
break;
|
break;
|
||||||
case "CSS":
|
case "CSS":
|
||||||
diff = JsDiff.diffCss(samples[0], samples[1]);
|
diff = jsdiff.diffCss(samples[0], samples[1]);
|
||||||
break;
|
break;
|
||||||
case "JSON":
|
case "JSON":
|
||||||
diff = JsDiff.diffJson(samples[0], samples[1]);
|
diff = jsdiff.diffJson(samples[0], samples[1]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new OperationError("Invalid 'Diff by' option.");
|
throw new OperationError("Invalid 'Diff by' option.");
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* @author tlwr [toby@toby.codes]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ExifParser from "exif-parser";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract EXIF operation
|
||||||
|
*/
|
||||||
|
class ExtractEXIF extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExtractEXIF constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Extract EXIF";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = [
|
||||||
|
"Extracts EXIF data from an image.",
|
||||||
|
"<br><br>",
|
||||||
|
"EXIF data is metadata embedded in images (JPEG, JPG, TIFF) and audio files.",
|
||||||
|
"<br><br>",
|
||||||
|
"EXIF data from photos usually contains information about the image file itself as well as the device used to create it.",
|
||||||
|
].join("\n");
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
try {
|
||||||
|
const parser = ExifParser.create(input);
|
||||||
|
const result = parser.parse();
|
||||||
|
|
||||||
|
const lines = [];
|
||||||
|
for (const tagName in result.tags) {
|
||||||
|
const value = result.tags[tagName];
|
||||||
|
lines.push(`${tagName}: ${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const numTags = lines.length;
|
||||||
|
lines.unshift(`Found ${numTags} tags.\n`);
|
||||||
|
return lines.join("\n");
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Could not extract EXIF data from image: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExtractEXIF;
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find / Replace operation
|
||||||
|
*/
|
||||||
|
class FindReplace extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FindReplace constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Find / Replace";
|
||||||
|
this.module = "Regex";
|
||||||
|
this.description = "Replaces all occurrences of the first string with the second.<br><br>Includes support for regular expressions (regex), simple strings and extended strings (which support \\n, \\r, \\t, \\b, \\f and escaped hex bytes using \\x notation, e.g. \\x00 for a null byte).";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Find",
|
||||||
|
"type": "toggleString",
|
||||||
|
"value": "",
|
||||||
|
"toggleValues": ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Replace",
|
||||||
|
"type": "binaryString",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Global match",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Case insensitive",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Multiline matching",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [{option: type}, replace, g, i, m] = args;
|
||||||
|
let find = args[0].string,
|
||||||
|
modifiers = "";
|
||||||
|
|
||||||
|
if (g) modifiers += "g";
|
||||||
|
if (i) modifiers += "i";
|
||||||
|
if (m) modifiers += "m";
|
||||||
|
|
||||||
|
if (type === "Regex") {
|
||||||
|
find = new RegExp(find, modifiers);
|
||||||
|
return input.replace(find, replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.indexOf("Extended") === 0) {
|
||||||
|
find = Utils.parseEscapedChars(find);
|
||||||
|
}
|
||||||
|
|
||||||
|
find = new RegExp(Utils.escapeRegex(find), modifiers);
|
||||||
|
|
||||||
|
return input.replace(find, replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FindReplace;
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex to Object Identifier operation
|
||||||
|
*/
|
||||||
|
class HexToObjectIdentifier extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HexToObjectIdentifier constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Hex to Object Identifier";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts a hexadecimal string into an object identifier (OID).";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return r.KJUR.asn1.ASN1Util.oidHexToInt(input.replace(/\s/g, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HexToObjectIdentifier;
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex to PEM operation
|
||||||
|
*/
|
||||||
|
class HexToPEM extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HexToPEM constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Hex to PEM";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts a hexadecimal DER (Distinguished Encoding Rules) string into PEM (Privacy Enhanced Mail) format.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Header string",
|
||||||
|
"type": "string",
|
||||||
|
"value": "CERTIFICATE"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return r.KJUR.asn1.ASN1Util.getPEMStringFromHex(input.replace(/\s/g, ""), args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HexToPEM;
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* @author Matt C (matt@artemisbot.uk)
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jpath from "jsonpath";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JPath expression operation
|
||||||
|
*/
|
||||||
|
class JPathExpression extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JPathExpression constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "JPath expression";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Extract information from a JSON object with a JPath query.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Query",
|
||||||
|
"type": "string",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Result delimiter",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\n"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [query, delimiter] = args;
|
||||||
|
let results,
|
||||||
|
obj;
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj = JSON.parse(input);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Invalid input JSON: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
results = jpath.query(obj, query);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Invalid JPath expression: ${err.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.map(result => JSON.stringify(result)).join(delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JPathExpression;
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Beautify operation
|
||||||
|
*/
|
||||||
|
class JSONBeautify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONBeautify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "JSON Beautify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Indents and prettifies JavaScript Object Notation (JSON) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Indent string",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\t"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const indentStr = args[0];
|
||||||
|
if (!input) return "";
|
||||||
|
return vkbeautify.json(input, indentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JSONBeautify;
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Minify operation
|
||||||
|
*/
|
||||||
|
class JSONMinify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSONMinify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "JSON Minify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Compresses JavaScript Object Notation (JSON) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (!input) return "";
|
||||||
|
return vkbeautify.jsonmin(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JSONMinify;
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object Identifier to Hex operation
|
||||||
|
*/
|
||||||
|
class ObjectIdentifierToHex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObjectIdentifierToHex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Object Identifier to Hex";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts an object identifier (OID) into a hexadecimal string.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return r.KJUR.asn1.ASN1Util.oidIntToHex(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ObjectIdentifierToHex;
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM to Hex operation
|
||||||
|
*/
|
||||||
|
class PEMToHex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEMToHex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "PEM to Hex";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts PEM (Privacy Enhanced Mail) format to a hexadecimal DER (Distinguished Encoding Rules) string.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (input.indexOf("-----BEGIN") < 0) {
|
||||||
|
// Add header so that the KEYUTIL function works
|
||||||
|
input = "-----BEGIN CERTIFICATE-----" + input;
|
||||||
|
}
|
||||||
|
if (input.indexOf("-----END") < 0) {
|
||||||
|
// Add footer so that the KEYUTIL function works
|
||||||
|
input = input + "-----END CERTIFICATE-----";
|
||||||
|
}
|
||||||
|
const cert = new r.X509();
|
||||||
|
cert.readCertPEM(input);
|
||||||
|
return cert.hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PEMToHex;
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse ASN.1 hex string operation
|
||||||
|
*/
|
||||||
|
class ParseASN1HexString extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParseASN1HexString constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Parse ASN.1 hex string";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.<br><br>This operation parses arbitrary ASN.1 data and presents the resulting tree.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Starting index",
|
||||||
|
"type": "number",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Truncate octet strings longer than",
|
||||||
|
"type": "number",
|
||||||
|
"value": 32
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [index, truncateLen] = args;
|
||||||
|
return r.ASN1HEX.dump(input.replace(/\s/g, ""), {
|
||||||
|
"ommitLongOctet": truncateLen
|
||||||
|
}, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParseASN1HexString;
|
|
@ -0,0 +1,216 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import { fromBase64 } from "../lib/Base64";
|
||||||
|
import { toHex } from "../lib/Hex";
|
||||||
|
import { formatByteStr, formatDnStr } from "../lib/PublicKey";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse X.509 certificate operation
|
||||||
|
*/
|
||||||
|
class ParseX509Certificate extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParseX509Certificate constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Parse X.509 certificate";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "X.509 is an ITU-T standard for a public key infrastructure (PKI) and Privilege Management Infrastructure (PMI). It is commonly involved with SSL/TLS security.<br><br>This operation displays the contents of a certificate in a human readable format, similar to the openssl command line tool.<br><br>Tags: X509, server hello, handshake";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Input format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["PEM", "DER Hex", "Base64", "Raw"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.patterns = [
|
||||||
|
{
|
||||||
|
"match": "^-+BEGIN CERTIFICATE-+\\r?\\n[\\da-z+/\\n\\r]+-+END CERTIFICATE-+\\r?\\n?$",
|
||||||
|
"flags": "i",
|
||||||
|
"args": [
|
||||||
|
"PEM"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (!input.length) {
|
||||||
|
return "No input";
|
||||||
|
}
|
||||||
|
|
||||||
|
const cert = new r.X509(),
|
||||||
|
inputFormat = args[0];
|
||||||
|
|
||||||
|
switch (inputFormat) {
|
||||||
|
case "DER Hex":
|
||||||
|
input = input.replace(/\s/g, "");
|
||||||
|
cert.readCertHex(input);
|
||||||
|
break;
|
||||||
|
case "PEM":
|
||||||
|
cert.readCertPEM(input);
|
||||||
|
break;
|
||||||
|
case "Base64":
|
||||||
|
cert.readCertHex(toHex(fromBase64(input, null, "byteArray"), ""));
|
||||||
|
break;
|
||||||
|
case "Raw":
|
||||||
|
cert.readCertHex(toHex(Utils.strToByteArray(input), ""));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Undefined input format";
|
||||||
|
}
|
||||||
|
|
||||||
|
const sn = cert.getSerialNumberHex(),
|
||||||
|
issuer = cert.getIssuerString(),
|
||||||
|
subject = cert.getSubjectString(),
|
||||||
|
pk = cert.getPublicKey(),
|
||||||
|
pkFields = [],
|
||||||
|
sig = cert.getSignatureValueHex();
|
||||||
|
|
||||||
|
let pkStr = "",
|
||||||
|
sigStr = "",
|
||||||
|
extensions = "";
|
||||||
|
|
||||||
|
// Public Key fields
|
||||||
|
pkFields.push({
|
||||||
|
key: "Algorithm",
|
||||||
|
value: pk.type
|
||||||
|
});
|
||||||
|
|
||||||
|
if (pk.type === "EC") { // ECDSA
|
||||||
|
pkFields.push({
|
||||||
|
key: "Curve Name",
|
||||||
|
value: pk.curveName
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "Length",
|
||||||
|
value: (((new r.BigInteger(pk.pubKeyHex, 16)).bitLength()-3) /2) + " bits"
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "pub",
|
||||||
|
value: formatByteStr(pk.pubKeyHex, 16, 18)
|
||||||
|
});
|
||||||
|
} else if (pk.type === "DSA") { // DSA
|
||||||
|
pkFields.push({
|
||||||
|
key: "pub",
|
||||||
|
value: formatByteStr(pk.y.toString(16), 16, 18)
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "P",
|
||||||
|
value: formatByteStr(pk.p.toString(16), 16, 18)
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "Q",
|
||||||
|
value: formatByteStr(pk.q.toString(16), 16, 18)
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "G",
|
||||||
|
value: formatByteStr(pk.g.toString(16), 16, 18)
|
||||||
|
});
|
||||||
|
} else if (pk.e) { // RSA
|
||||||
|
pkFields.push({
|
||||||
|
key: "Length",
|
||||||
|
value: pk.n.bitLength() + " bits"
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "Modulus",
|
||||||
|
value: formatByteStr(pk.n.toString(16), 16, 18)
|
||||||
|
});
|
||||||
|
pkFields.push({
|
||||||
|
key: "Exponent",
|
||||||
|
value: pk.e + " (0x" + pk.e.toString(16) + ")"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pkFields.push({
|
||||||
|
key: "Error",
|
||||||
|
value: "Unknown Public Key type"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format Public Key fields
|
||||||
|
for (let i = 0; i < pkFields.length; i++) {
|
||||||
|
pkStr += ` ${pkFields[i].key}:${(pkFields[i].value + "\n").padStart(
|
||||||
|
18 - (pkFields[i].key.length + 3) + pkFields[i].value.length + 1,
|
||||||
|
" "
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signature fields
|
||||||
|
let breakoutSig = false;
|
||||||
|
try {
|
||||||
|
breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0;
|
||||||
|
} catch (err) {
|
||||||
|
// Error processing signature, output without further breakout
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakoutSig) { // DSA or ECDSA
|
||||||
|
sigStr = ` r: ${formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18)}
|
||||||
|
s: ${formatByteStr(r.ASN1HEX.getV(sig, 48), 16, 18)}`;
|
||||||
|
} else { // RSA or unknown
|
||||||
|
sigStr = ` Signature: ${formatByteStr(sig, 16, 18)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
try {
|
||||||
|
extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0];
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
const issuerStr = formatDnStr(issuer, 2),
|
||||||
|
nbDate = formatDate(cert.getNotBefore()),
|
||||||
|
naDate = formatDate(cert.getNotAfter()),
|
||||||
|
subjectStr = formatDnStr(subject, 2);
|
||||||
|
|
||||||
|
return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)})
|
||||||
|
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
|
||||||
|
Algorithm ID: ${cert.getSignatureAlgorithmField()}
|
||||||
|
Validity
|
||||||
|
Not Before: ${nbDate} (dd-mm-yy hh:mm:ss) (${cert.getNotBefore()})
|
||||||
|
Not After: ${naDate} (dd-mm-yy hh:mm:ss) (${cert.getNotAfter()})
|
||||||
|
Issuer
|
||||||
|
${issuerStr}
|
||||||
|
Subject
|
||||||
|
${subjectStr}
|
||||||
|
Public Key
|
||||||
|
${pkStr.slice(0, -1)}
|
||||||
|
Certificate Signature
|
||||||
|
Algorithm: ${cert.getSignatureAlgorithmName()}
|
||||||
|
${sigStr}
|
||||||
|
|
||||||
|
Extensions
|
||||||
|
${extensions}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats dates.
|
||||||
|
*
|
||||||
|
* @param {string} dateStr
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function formatDate (dateStr) {
|
||||||
|
return dateStr[4] + dateStr[5] + "/" +
|
||||||
|
dateStr[2] + dateStr[3] + "/" +
|
||||||
|
dateStr[0] + dateStr[1] + " " +
|
||||||
|
dateStr[6] + dateStr[7] + ":" +
|
||||||
|
dateStr[8] + dateStr[9] + ":" +
|
||||||
|
dateStr[10] + dateStr[11];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParseX509Certificate;
|
|
@ -0,0 +1,262 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import XRegExp from "xregexp";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regular expression operation
|
||||||
|
*/
|
||||||
|
class RegularExpression extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegularExpression constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Regular expression";
|
||||||
|
this.module = "Regex";
|
||||||
|
this.description = "Define your own regular expression (regex) to search the input data with, optionally choosing from a list of pre-defined patterns.<br><br>Supports extended regex syntax including the 'dot matches all' flag, named capture groups, full unicode coverage (including <code>\\p{}</code> categories and scripts as well as astral codes) and recursive matching.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Built in regexes",
|
||||||
|
"type": "populateOption",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
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: "\\b(\\w[-.\\w]*)@([-\\w]+(?:\\.[-\\w]+)*)\\.([A-Za-z]{2,4})\\b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "URL",
|
||||||
|
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Domain",
|
||||||
|
value: "\\b((?=[a-z0-9-]{1,63}\\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}\\b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,}"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"target": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Regex",
|
||||||
|
"type": "text",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Case insensitive",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "^ and $ match at newlines",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dot matches all",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Unicode support",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Astral support",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Display total",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Highlight matches", "List matches", "List capture groups", "List matches with capture groups"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [,
|
||||||
|
userRegex,
|
||||||
|
i, m, s, u, a,
|
||||||
|
displayTotal,
|
||||||
|
outputFormat
|
||||||
|
] = args;
|
||||||
|
let modifiers = "g";
|
||||||
|
|
||||||
|
if (i) modifiers += "i";
|
||||||
|
if (m) modifiers += "m";
|
||||||
|
if (s) modifiers += "s";
|
||||||
|
if (u) modifiers += "u";
|
||||||
|
if (a) modifiers += "A";
|
||||||
|
|
||||||
|
if (userRegex && userRegex !== "^" && userRegex !== "$") {
|
||||||
|
try {
|
||||||
|
const regex = new XRegExp(userRegex, modifiers);
|
||||||
|
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "Highlight matches":
|
||||||
|
return regexHighlight(input, regex, displayTotal);
|
||||||
|
case "List matches":
|
||||||
|
return Utils.escapeHtml(regexList(input, regex, displayTotal, true, false));
|
||||||
|
case "List capture groups":
|
||||||
|
return Utils.escapeHtml(regexList(input, regex, displayTotal, false, true));
|
||||||
|
case "List matches with capture groups":
|
||||||
|
return Utils.escapeHtml(regexList(input, regex, displayTotal, true, true));
|
||||||
|
default:
|
||||||
|
return "Error: Invalid output format";
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Invalid regex. Details: " + err.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Utils.escapeHtml(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a string listing the matches within a string.
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @param {RegExp} regex
|
||||||
|
* @param {boolean} displayTotal
|
||||||
|
* @param {boolean} matches - Display full match
|
||||||
|
* @param {boolean} captureGroups - Display each of the capture groups separately
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function regexList (input, regex, displayTotal, matches, captureGroups) {
|
||||||
|
let output = "",
|
||||||
|
total = 0,
|
||||||
|
match;
|
||||||
|
|
||||||
|
while ((match = regex.exec(input))) {
|
||||||
|
// Moves pointer when an empty string is matched (prevents infinite loop)
|
||||||
|
if (match.index === regex.lastIndex) {
|
||||||
|
regex.lastIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
total++;
|
||||||
|
if (matches) {
|
||||||
|
output += match[0] + "\n";
|
||||||
|
}
|
||||||
|
if (captureGroups) {
|
||||||
|
for (let i = 1; i < match.length; i++) {
|
||||||
|
if (matches) {
|
||||||
|
output += " Group " + i + ": ";
|
||||||
|
}
|
||||||
|
output += match[i] + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayTotal)
|
||||||
|
output = "Total found: " + total + "\n\n" + output;
|
||||||
|
|
||||||
|
return output.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds HTML highlights to matches within a string.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {string} input
|
||||||
|
* @param {RegExp} regex
|
||||||
|
* @param {boolean} displayTotal
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function regexHighlight (input, regex, displayTotal) {
|
||||||
|
let output = "",
|
||||||
|
m,
|
||||||
|
hl = 1,
|
||||||
|
i = 0,
|
||||||
|
total = 0;
|
||||||
|
|
||||||
|
while ((m = regex.exec(input))) {
|
||||||
|
// Moves pointer when an empty string is matched (prevents infinite loop)
|
||||||
|
if (m.index === regex.lastIndex) {
|
||||||
|
regex.lastIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add up to match
|
||||||
|
output += Utils.escapeHtml(input.slice(i, m.index));
|
||||||
|
|
||||||
|
// Add match with highlighting
|
||||||
|
output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
||||||
|
|
||||||
|
// Switch highlight
|
||||||
|
hl = hl === 1 ? 2 : 1;
|
||||||
|
|
||||||
|
i = regex.lastIndex;
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all after final match
|
||||||
|
output += Utils.escapeHtml(input.slice(i, input.length));
|
||||||
|
|
||||||
|
if (displayTotal)
|
||||||
|
output = "Total found: " + total + "\n\n" + output;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RegularExpression;
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* @author tlwr [toby@toby.codes]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { removeEXIF } from "../vendor/remove-exif";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove EXIF operation
|
||||||
|
*/
|
||||||
|
class RemoveEXIF extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RemoveEXIF constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Remove EXIF";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = [
|
||||||
|
"Removes EXIF data from a JPEG image.",
|
||||||
|
"<br><br>",
|
||||||
|
"EXIF data embedded in photos usually contains information about the image file itself as well as the device used to create it.",
|
||||||
|
].join("\n");
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
// Do nothing if input is empty
|
||||||
|
if (input.length === 0) return input;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return removeEXIF(input);
|
||||||
|
} catch (err) {
|
||||||
|
// Simply return input if no EXIF data is found
|
||||||
|
if (err === "Exif not found.") return input;
|
||||||
|
throw new OperationError(`Could not remove EXIF data from image: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RemoveEXIF;
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* @author tlwr [toby@toby.codes]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromBase64, toBase64 } from "../lib/Base64";
|
||||||
|
import { fromHex } from "../lib/Hex";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
import Magic from "../lib/Magic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render Image operation
|
||||||
|
*/
|
||||||
|
class RenderImage extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RenderImage constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Render Image";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = "Displays the input as an image. Supports the following formats:<br><br><ul><li>jpg/jpeg</li><li>png</li><li>gif</li><li>webp</li><li>bmp</li><li>ico</li></ul>";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Input format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw", "Base64", "Hex"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.patterns = [
|
||||||
|
{
|
||||||
|
"match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
|
||||||
|
"flags": "",
|
||||||
|
"args": ["Raw"],
|
||||||
|
"useful": true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const inputFormat = args[0];
|
||||||
|
let dataURI = "data:";
|
||||||
|
|
||||||
|
if (!input.length) return "";
|
||||||
|
|
||||||
|
// Convert input to raw bytes
|
||||||
|
switch (inputFormat) {
|
||||||
|
case "Hex":
|
||||||
|
input = fromHex(input);
|
||||||
|
break;
|
||||||
|
case "Base64":
|
||||||
|
// Don't trust the Base64 entered by the user.
|
||||||
|
// Unwrap it first, then re-encode later.
|
||||||
|
input = fromBase64(input, undefined, "byteArray");
|
||||||
|
break;
|
||||||
|
case "Raw":
|
||||||
|
default:
|
||||||
|
input = Utils.strToByteArray(input);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine file type
|
||||||
|
const type = Magic.magicFileType(input);
|
||||||
|
if (type && type.mime.indexOf("image") === 0) {
|
||||||
|
dataURI += type.mime + ";";
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid file type");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add image data to URI
|
||||||
|
dataURI += "base64," + toBase64(input);
|
||||||
|
|
||||||
|
return "<img src='" + dataURI + "'>";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RenderImage;
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Beautify operation
|
||||||
|
*/
|
||||||
|
class SQLBeautify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQLBeautify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "SQL Beautify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Indents and prettifies Structured Query Language (SQL) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Indent string",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\t"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const indentStr = args[0];
|
||||||
|
return vkbeautify.sql(input, indentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SQLBeautify;
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL Minify operation
|
||||||
|
*/
|
||||||
|
class SQLMinify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQLMinify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "SQL Minify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Compresses Structured Query Language (SQL) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return vkbeautify.sqlmin(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SQLMinify;
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML Beautify operation
|
||||||
|
*/
|
||||||
|
class XMLBeautify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMLBeautify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "XML Beautify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Indents and prettifies eXtensible Markup Language (XML) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Indent string",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\t"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const indentStr = args[0];
|
||||||
|
return vkbeautify.xml(input, indentStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default XMLBeautify;
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import vkbeautify from "vkbeautify";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XML Minify operation
|
||||||
|
*/
|
||||||
|
class XMLMinify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMLMinify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "XML Minify";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Compresses eXtensible Markup Language (XML) code.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Preserve comments",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const preserveComments = args[0];
|
||||||
|
return vkbeautify.xmlmin(input, preserveComments);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default XMLMinify;
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
|
||||||
|
* @copyright Crown Copyright 2016
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import xmldom from "xmldom";
|
||||||
|
import xpath from "xpath";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XPath expression operation
|
||||||
|
*/
|
||||||
|
class XPathExpression extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XPathExpression constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "XPath expression";
|
||||||
|
this.module = "Code";
|
||||||
|
this.description = "Extract information from an XML document with an XPath query";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "XPath",
|
||||||
|
"type": "string",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Result delimiter",
|
||||||
|
"type": "binaryShortString",
|
||||||
|
"value": "\\n"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [query, delimiter] = args;
|
||||||
|
|
||||||
|
let doc;
|
||||||
|
try {
|
||||||
|
doc = new xmldom.DOMParser().parseFromString(input, "application/xml");
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Invalid input XML.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodes;
|
||||||
|
try {
|
||||||
|
nodes = xpath.select(query, doc);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Invalid XPath. Details:\n${err.message}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeToString = function(node) {
|
||||||
|
return node.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
return nodes.map(nodeToString).join(delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default XPathExpression;
|
|
@ -1,540 +0,0 @@
|
||||||
import {camelCase, kebabCase, snakeCase} from "lodash";
|
|
||||||
import vkbeautify from "vkbeautify";
|
|
||||||
import {DOMParser} from "xmldom";
|
|
||||||
import xpath from "xpath";
|
|
||||||
import jpath from "jsonpath";
|
|
||||||
import nwmatcher from "nwmatcher";
|
|
||||||
import hljs from "highlight.js";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Code operations.
|
|
||||||
*
|
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
|
||||||
* @copyright Crown Copyright 2016
|
|
||||||
* @license Apache-2.0
|
|
||||||
*
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
const Code = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
LANGUAGES: ["auto detect"].concat(hljs.listLanguages()),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syntax highlighter operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {html}
|
|
||||||
*/
|
|
||||||
runSyntaxHighlight: function(input, args) {
|
|
||||||
const language = args[0];
|
|
||||||
|
|
||||||
if (language === "auto detect") {
|
|
||||||
return hljs.highlightAuto(input).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hljs.highlight(language, input, true).value;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
BEAUTIFY_INDENT: "\\t",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML Beautify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runXmlBeautify: function(input, args) {
|
|
||||||
const indentStr = args[0];
|
|
||||||
return vkbeautify.xml(input, indentStr);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Beautify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runJsonBeautify: function(input, args) {
|
|
||||||
const indentStr = args[0];
|
|
||||||
if (!input) return "";
|
|
||||||
return vkbeautify.json(input, indentStr);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS Beautify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runCssBeautify: function(input, args) {
|
|
||||||
const indentStr = args[0];
|
|
||||||
return vkbeautify.css(input, indentStr);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL Beautify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runSqlBeautify: function(input, args) {
|
|
||||||
const indentStr = args[0];
|
|
||||||
return vkbeautify.sql(input, indentStr);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
PRESERVE_COMMENTS: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML Minify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runXmlMinify: function(input, args) {
|
|
||||||
const preserveComments = args[0];
|
|
||||||
return vkbeautify.xmlmin(input, preserveComments);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Minify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runJsonMinify: function(input, args) {
|
|
||||||
if (!input) return "";
|
|
||||||
return vkbeautify.jsonmin(input);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS Minify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runCssMinify: function(input, args) {
|
|
||||||
const preserveComments = args[0];
|
|
||||||
return vkbeautify.cssmin(input, preserveComments);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL Minify operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runSqlMinify: 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}
|
|
||||||
*/
|
|
||||||
runGenericBeautify: function(input, args) {
|
|
||||||
let code = input,
|
|
||||||
t = 0,
|
|
||||||
preservedTokens = [],
|
|
||||||
m;
|
|
||||||
|
|
||||||
// Remove strings
|
|
||||||
const sstrings = /'([^'\\]|\\.)*'/g;
|
|
||||||
while ((m = sstrings.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
sstrings.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dstrings = /"([^"\\]|\\.)*"/g;
|
|
||||||
while ((m = dstrings.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
dstrings.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove comments
|
|
||||||
const scomments = /\/\/[^\n\r]*/g;
|
|
||||||
while ((m = scomments.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
scomments.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mcomments = /\/\*[\s\S]*?\*\//gm;
|
|
||||||
while ((m = mcomments.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
mcomments.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hcomments = /(^|\n)#[^\n\r#]+/g;
|
|
||||||
while ((m = hcomments.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
hcomments.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove regexes
|
|
||||||
const regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
|
|
||||||
while ((m = regexes.exec(code))) {
|
|
||||||
code = preserveToken(code, m, t++);
|
|
||||||
regexes.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
code = code
|
|
||||||
// Create newlines after ;
|
|
||||||
.replace(/;/g, ";\n")
|
|
||||||
// Create newlines after { and around }
|
|
||||||
.replace(/{/g, "{\n")
|
|
||||||
.replace(/}/g, "\n}\n")
|
|
||||||
// Remove carriage returns
|
|
||||||
.replace(/\r/g, "")
|
|
||||||
// Remove all indentation
|
|
||||||
.replace(/^\s+/g, "")
|
|
||||||
.replace(/\n\s+/g, "\n")
|
|
||||||
// Remove trailing spaces
|
|
||||||
.replace(/\s*$/g, "")
|
|
||||||
.replace(/\n{/g, "{");
|
|
||||||
|
|
||||||
// Indent
|
|
||||||
let i = 0,
|
|
||||||
level = 0,
|
|
||||||
indent;
|
|
||||||
while (i < code.length) {
|
|
||||||
switch (code[i]) {
|
|
||||||
case "{":
|
|
||||||
level++;
|
|
||||||
break;
|
|
||||||
case "\n":
|
|
||||||
if (i+1 >= code.length) break;
|
|
||||||
|
|
||||||
if (code[i+1] === "}") level--;
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
code = code
|
|
||||||
// Add strategic spaces
|
|
||||||
.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
|
|
||||||
.replace(/\s*<([=]?)\s*/g, " <$1 ")
|
|
||||||
.replace(/\s*>([=]?)\s*/g, " >$1 ")
|
|
||||||
.replace(/([^+])\+([^+=])/g, "$1 + $2")
|
|
||||||
.replace(/([^-])-([^-=])/g, "$1 - $2")
|
|
||||||
.replace(/([^*])\*([^*=])/g, "$1 * $2")
|
|
||||||
.replace(/([^/])\/([^/=])/g, "$1 / $2")
|
|
||||||
.replace(/\s*,\s*/g, ", ")
|
|
||||||
.replace(/\s*{/g, " {")
|
|
||||||
.replace(/}\n/g, "}\n\n")
|
|
||||||
// Hacky horribleness
|
|
||||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3")
|
|
||||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
|
|
||||||
.replace(/else\s*\n([^{])/gim, "else\n $1")
|
|
||||||
.replace(/else\s+([^{])/gim, "else $1")
|
|
||||||
// Remove strategic spaces
|
|
||||||
.replace(/\s+;/g, ";")
|
|
||||||
.replace(/\{\s+\}/g, "{}")
|
|
||||||
.replace(/\[\s+\]/g, "[]")
|
|
||||||
.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
|
|
||||||
|
|
||||||
// Replace preserved tokens
|
|
||||||
const ptokens = /###preservedToken(\d+)###/g;
|
|
||||||
while ((m = ptokens.exec(code))) {
|
|
||||||
const ti = parseInt(m[1], 10);
|
|
||||||
code = code.substring(0, m.index) + preservedTokens[ti] + code.substring(m.index + m[0].length);
|
|
||||||
ptokens.lastIndex = m.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return code;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces a matched token with a placeholder value.
|
|
||||||
*/
|
|
||||||
function preserveToken(str, match, t) {
|
|
||||||
preservedTokens[t] = match[0];
|
|
||||||
return str.substring(0, match.index) +
|
|
||||||
"###preservedToken" + t + "###" +
|
|
||||||
str.substring(match.index + match[0].length);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
XPATH_INITIAL: "",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
XPATH_DELIMITER: "\\n",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XPath expression operation.
|
|
||||||
*
|
|
||||||
* @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runXpath: function(input, args) {
|
|
||||||
let query = args[0],
|
|
||||||
delimiter = args[1];
|
|
||||||
|
|
||||||
let doc;
|
|
||||||
try {
|
|
||||||
doc = new DOMParser().parseFromString(input, "application/xml");
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid input XML.";
|
|
||||||
}
|
|
||||||
|
|
||||||
let nodes;
|
|
||||||
try {
|
|
||||||
nodes = xpath.select(query, doc);
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid XPath. Details:\n" + err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nodeToString = function(node) {
|
|
||||||
return node.toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
return nodes.map(nodeToString).join(delimiter);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
JPATH_INITIAL: "",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
JPATH_DELIMITER: "\\n",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JPath expression operation.
|
|
||||||
*
|
|
||||||
* @author Matt C (matt@artemisbot.uk)
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runJpath: function(input, args) {
|
|
||||||
let query = args[0],
|
|
||||||
delimiter = args[1],
|
|
||||||
results,
|
|
||||||
obj;
|
|
||||||
|
|
||||||
try {
|
|
||||||
obj = JSON.parse(input);
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid input JSON: " + err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
results = jpath.query(obj, query);
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid JPath expression: " + err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
return results.map(result => JSON.stringify(result)).join(delimiter);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
CSS_SELECTOR_INITIAL: "",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
CSS_QUERY_DELIMITER: "\\n",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSS selector operation.
|
|
||||||
*
|
|
||||||
* @author Mikescher (https://github.com/Mikescher | https://mikescher.com)
|
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runCSSQuery: function(input, args) {
|
|
||||||
let query = args[0],
|
|
||||||
delimiter = args[1],
|
|
||||||
parser = new DOMParser(),
|
|
||||||
dom,
|
|
||||||
result;
|
|
||||||
|
|
||||||
if (!query.length || !input.length) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
dom = parser.parseFromString(input);
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid input HTML.";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const matcher = nwmatcher({document: dom});
|
|
||||||
result = matcher.select(query, dom);
|
|
||||||
} catch (err) {
|
|
||||||
return "Invalid CSS Selector. Details:\n" + err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nodeToString = function(node) {
|
|
||||||
return node.toString();
|
|
||||||
/* xmldom does not return the outerHTML value.
|
|
||||||
switch (node.nodeType) {
|
|
||||||
case node.ELEMENT_NODE: return node.outerHTML;
|
|
||||||
case node.ATTRIBUTE_NODE: return node.value;
|
|
||||||
case node.TEXT_NODE: return node.wholeText;
|
|
||||||
case node.COMMENT_NODE: return node.data;
|
|
||||||
case node.DOCUMENT_NODE: return node.outerHTML;
|
|
||||||
default: throw new Error("Unknown Node Type: " + node.nodeType);
|
|
||||||
}*/
|
|
||||||
};
|
|
||||||
|
|
||||||
return result
|
|
||||||
.map(nodeToString)
|
|
||||||
.join(delimiter);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This tries to rename variable names in a code snippet according to a function.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {function} replacer - this function will be fed the token which should be renamed.
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
_replaceVariableNames(input, replacer) {
|
|
||||||
const tokenRegex = /\\"|"(?:\\"|[^"])*"|(\b[a-z0-9\-_]+\b)/ig;
|
|
||||||
|
|
||||||
return input.replace(tokenRegex, (...args) => {
|
|
||||||
let match = args[0],
|
|
||||||
quotes = args[1];
|
|
||||||
|
|
||||||
if (!quotes) {
|
|
||||||
return match;
|
|
||||||
} else {
|
|
||||||
return replacer(match);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To Snake Case operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runToSnakeCase(input, args) {
|
|
||||||
const smart = args[0];
|
|
||||||
|
|
||||||
if (smart) {
|
|
||||||
return Code._replaceVariableNames(input, snakeCase);
|
|
||||||
} else {
|
|
||||||
return snakeCase(input);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To Camel Case operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runToCamelCase(input, args) {
|
|
||||||
const smart = args[0];
|
|
||||||
|
|
||||||
if (smart) {
|
|
||||||
return Code._replaceVariableNames(input, camelCase);
|
|
||||||
} else {
|
|
||||||
return camelCase(input);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To Kebab Case operation.
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runToKebabCase(input, args) {
|
|
||||||
const smart = args[0];
|
|
||||||
|
|
||||||
if (smart) {
|
|
||||||
return Code._replaceVariableNames(input, kebabCase);
|
|
||||||
} else {
|
|
||||||
return kebabCase(input);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Code;
|
|
|
@ -1,125 +0,0 @@
|
||||||
import * as ExifParser from "exif-parser";
|
|
||||||
import removeEXIF from "../vendor/remove-exif.js";
|
|
||||||
import Utils from "../Utils.js";
|
|
||||||
import FileType from "./FileType.js";
|
|
||||||
import {fromBase64, toBase64} from "../lib/Base64";
|
|
||||||
import {fromHex} from "../lib/Hex";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Image operations.
|
|
||||||
*
|
|
||||||
* @author tlwr [toby@toby.codes]
|
|
||||||
* @copyright Crown Copyright 2017
|
|
||||||
* @license Apache-2.0
|
|
||||||
*
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
const Image = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract EXIF operation.
|
|
||||||
*
|
|
||||||
* Extracts EXIF data from a byteArray, representing a JPG or a TIFF image.
|
|
||||||
*
|
|
||||||
* @param {ArrayBuffer} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
runExtractEXIF(input, args) {
|
|
||||||
try {
|
|
||||||
const parser = ExifParser.create(input);
|
|
||||||
const result = parser.parse();
|
|
||||||
|
|
||||||
let lines = [];
|
|
||||||
for (let tagName in result.tags) {
|
|
||||||
let value = result.tags[tagName];
|
|
||||||
lines.push(`${tagName}: ${value}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const numTags = lines.length;
|
|
||||||
lines.unshift(`Found ${numTags} tags.\n`);
|
|
||||||
return lines.join("\n");
|
|
||||||
} catch (err) {
|
|
||||||
throw "Could not extract EXIF data from image: " + err;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove EXIF operation.
|
|
||||||
*
|
|
||||||
* Removes EXIF data from a byteArray, representing a JPG.
|
|
||||||
*
|
|
||||||
* @author David Moodie [davidmoodie12@gmail.com]
|
|
||||||
* @param {byteArray} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {byteArray}
|
|
||||||
*/
|
|
||||||
runRemoveEXIF(input, args) {
|
|
||||||
// Do nothing if input is empty
|
|
||||||
if (input.length === 0) return input;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return removeEXIF(input);
|
|
||||||
} catch (err) {
|
|
||||||
// Simply return input if no EXIF data is found
|
|
||||||
if (err === "Exif not found.") return input;
|
|
||||||
throw "Could not remove EXIF data from image: " + err;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constant
|
|
||||||
* @default
|
|
||||||
*/
|
|
||||||
INPUT_FORMAT: ["Raw", "Base64", "Hex"],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render Image operation.
|
|
||||||
*
|
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {html}
|
|
||||||
*/
|
|
||||||
runRenderImage(input, args) {
|
|
||||||
const inputFormat = args[0];
|
|
||||||
let dataURI = "data:";
|
|
||||||
|
|
||||||
if (!input.length) return "";
|
|
||||||
|
|
||||||
// Convert input to raw bytes
|
|
||||||
switch (inputFormat) {
|
|
||||||
case "Hex":
|
|
||||||
input = fromHex(input);
|
|
||||||
break;
|
|
||||||
case "Base64":
|
|
||||||
// Don't trust the Base64 entered by the user.
|
|
||||||
// Unwrap it first, then re-encode later.
|
|
||||||
input = fromBase64(input, null, "byteArray");
|
|
||||||
break;
|
|
||||||
case "Raw":
|
|
||||||
default:
|
|
||||||
input = Utils.strToByteArray(input);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine file type
|
|
||||||
const type = FileType.magicType(input);
|
|
||||||
if (type && type.mime.indexOf("image") === 0) {
|
|
||||||
dataURI += type.mime + ";";
|
|
||||||
} else {
|
|
||||||
throw "Invalid file type";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add image data to URI
|
|
||||||
dataURI += "base64," + toBase64(input);
|
|
||||||
|
|
||||||
return "<img src='" + dataURI + "'>";
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Image;
|
|
|
@ -18,10 +18,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Utils from "../Utils.js";
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
// Param jpeg should be a binaryArray
|
// Param jpeg should be a binaryArray
|
||||||
function removeEXIF(jpeg) {
|
export function removeEXIF(jpeg) {
|
||||||
// Convert binaryArray to char string
|
// Convert binaryArray to char string
|
||||||
jpeg = Utils.byteArrayToChars(jpeg);
|
jpeg = Utils.byteArrayToChars(jpeg);
|
||||||
if (jpeg.slice(0, 2) != "\xff\xd8") {
|
if (jpeg.slice(0, 2) != "\xff\xd8") {
|
||||||
|
@ -149,5 +149,3 @@ function unpack(mark, str) {
|
||||||
|
|
||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default removeEXIF;
|
|
|
@ -34,7 +34,7 @@ import "./tests/operations/CartesianProduct";
|
||||||
import "./tests/operations/CharEnc";
|
import "./tests/operations/CharEnc";
|
||||||
import "./tests/operations/Ciphers";
|
import "./tests/operations/Ciphers";
|
||||||
import "./tests/operations/Checksum";
|
import "./tests/operations/Checksum";
|
||||||
// import "./tests/operations/Code";
|
import "./tests/operations/Code";
|
||||||
import "./tests/operations/Compress";
|
import "./tests/operations/Compress";
|
||||||
import "./tests/operations/Crypt";
|
import "./tests/operations/Crypt";
|
||||||
import "./tests/operations/DateTime";
|
import "./tests/operations/DateTime";
|
||||||
|
@ -45,16 +45,16 @@ import "./tests/operations/Register";
|
||||||
import "./tests/operations/Comment";
|
import "./tests/operations/Comment";
|
||||||
import "./tests/operations/Hash";
|
import "./tests/operations/Hash";
|
||||||
import "./tests/operations/Hexdump";
|
import "./tests/operations/Hexdump";
|
||||||
// import "./tests/operations/Image";
|
import "./tests/operations/Image";
|
||||||
import "./tests/operations/MorseCode";
|
import "./tests/operations/MorseCode";
|
||||||
import "./tests/operations/MS";
|
import "./tests/operations/MS";
|
||||||
import "./tests/operations/PHP";
|
import "./tests/operations/PHP";
|
||||||
import "./tests/operations/NetBIOS";
|
import "./tests/operations/NetBIOS";
|
||||||
import "./tests/operations/OTP";
|
import "./tests/operations/OTP";
|
||||||
import "./tests/operations/PowerSet";
|
import "./tests/operations/PowerSet";
|
||||||
// import "./tests/operations/Regex";
|
import "./tests/operations/Regex";
|
||||||
import "./tests/operations/Rotate";
|
import "./tests/operations/Rotate";
|
||||||
// import "./tests/operations/StrUtils";
|
import "./tests/operations/StrUtils";
|
||||||
import "./tests/operations/SeqUtils";
|
import "./tests/operations/SeqUtils";
|
||||||
import "./tests/operations/SetDifference";
|
import "./tests/operations/SetDifference";
|
||||||
import "./tests/operations/SetIntersection";
|
import "./tests/operations/SetIntersection";
|
||||||
|
|
|
@ -57,7 +57,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Extract EXIF: hello world text (error)",
|
name: "Extract EXIF: hello world text (error)",
|
||||||
input: "hello world",
|
input: "hello world",
|
||||||
expectedError: true,
|
expectedOutput: "Could not extract EXIF data from image: Error: Invalid JPEG section offset",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Extract EXIF",
|
op: "Extract EXIF",
|
||||||
|
@ -129,7 +129,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Remove EXIF: hello world text (error)",
|
name: "Remove EXIF: hello world text (error)",
|
||||||
input: "hello world",
|
input: "hello world",
|
||||||
expectedError: true,
|
expectedOutput: "Could not remove EXIF data from image: Given data is not jpeg.",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Remove EXIF",
|
op: "Remove EXIF",
|
||||||
|
|
Loading…
Reference in New Issue