/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
import HTMLIngredient from "./HTMLIngredient.mjs";
import Utils from "../core/Utils.mjs";
import url from "url";
/**
* Object to handle the creation of operations.
*/
class HTMLOperation {
/**
* HTMLOperation constructor.
*
* @param {string} name - The name of the operation.
* @param {Object} config - The configuration object for this operation.
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
constructor(name, config, app, manager) {
this.app = app;
this.manager = manager;
this.name = name;
this.description = config.description;
this.infoURL = config.infoURL;
this.manualBake = config.manualBake || false;
this.config = config;
this.ingList = [];
for (let i = 0; i < config.args.length; i++) {
const ing = new HTMLIngredient(config.args[i], this.app, this.manager);
this.ingList.push(ing);
}
}
/**
* Renders the operation in HTML as a stub operation with no ingredients.
*
* @returns {string}
*/
toStubHtml(removeIcon) {
let html = "
${titleFromWikiLink(this.infoURL)}` : "";
html += ` data-container='body' data-toggle='popover' data-placement='right'
data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover'
data-boundary='viewport'`;
}
html += ">" + this.name;
if (removeIcon) {
html += "delete";
}
html += "";
return html;
}
/**
* Renders the operation in HTML as a full operation with ingredients.
*
* @returns {string}
*/
toFullHtml() {
let html = `${Utils.escapeHtml(this.name)}
`;
for (let i = 0; i < this.ingList.length; i++) {
html += this.ingList[i].toHtml();
}
html += `
pause
not_interested
`;
return html;
}
/**
* Highlights searched strings in the name and description of the operation.
*
* @param {[[number]]} nameIdxs - Indexes of the search strings in the operation name [[start, length]]
* @param {[[number]]} descIdxs - Indexes of the search strings in the operation description [[start, length]]
*/
highlightSearchStrings(nameIdxs, descIdxs) {
if (nameIdxs.length && typeof nameIdxs[0][0] === "number") {
let opName = "",
pos = 0;
nameIdxs.forEach(idxs => {
const [start, length] = idxs;
if (typeof start !== "number") return;
opName += this.name.slice(pos, start) + "" +
this.name.slice(start, start + length) + "";
pos = start + length;
});
opName += this.name.slice(pos, this.name.length);
this.name = opName;
}
if (this.description && descIdxs.length && descIdxs[0][0] >= 0) {
// Find HTML tag offsets
const re = /<[^>]+>/g;
let match;
while ((match = re.exec(this.description))) {
// If the search string occurs within an HTML tag, return without highlighting it.
const inHTMLTag = descIdxs.reduce((acc, idxs) => {
const start = idxs[0];
return start >= match.index && start <= (match.index + match[0].length);
}, false);
if (inHTMLTag) return;
}
let desc = "",
pos = 0;
descIdxs.forEach(idxs => {
const [start, length] = idxs;
desc += this.description.slice(pos, start) + "" +
this.description.slice(start, start + length) + "";
pos = start + length;
});
desc += this.description.slice(pos, this.description.length);
this.description = desc;
}
}
}
/**
* Given a URL for a Wikipedia (or other wiki) page, this function returns a link to that page.
*
* @param {string} urlStr
* @returns {string}
*/
function titleFromWikiLink(urlStr) {
const urlObj = url.parse(urlStr);
let wikiName = "",
pageTitle = "";
switch (urlObj.host) {
case "forensicswiki.xyz":
wikiName = "Forensics Wiki";
pageTitle = urlObj.query.substr(6).replace(/_/g, " "); // Chop off 'title='
break;
case "wikipedia.org":
wikiName = "Wikipedia";
pageTitle = urlObj.pathname.substr(6).replace(/_/g, " "); // Chop off '/wiki/'
break;
default:
// Not a wiki link, return full URL
return `More Informationopen_in_new`;
}
return `${pageTitle}open_in_new on ${wikiName}`;
}
export default HTMLOperation;