HTMLOperation.mjs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * @author n1474335 [n1474335@gmail.com]
  3. * @copyright Crown Copyright 2016
  4. * @license Apache-2.0
  5. */
  6. import HTMLIngredient from "./HTMLIngredient.mjs";
  7. import Utils from "../core/Utils.mjs";
  8. import url from "url";
  9. /**
  10. * Object to handle the creation of operations.
  11. */
  12. class HTMLOperation {
  13. /**
  14. * HTMLOperation constructor.
  15. *
  16. * @param {string} name - The name of the operation.
  17. * @param {Object} config - The configuration object for this operation.
  18. * @param {App} app - The main view object for CyberChef.
  19. * @param {Manager} manager - The CyberChef event manager.
  20. */
  21. constructor(name, config, app, manager) {
  22. this.app = app;
  23. this.manager = manager;
  24. this.name = name;
  25. this.description = config.description;
  26. this.infoURL = config.infoURL;
  27. this.manualBake = config.manualBake || false;
  28. this.config = config;
  29. this.ingList = [];
  30. for (let i = 0; i < config.args.length; i++) {
  31. const ing = new HTMLIngredient(config.args[i], this.app, this.manager);
  32. this.ingList.push(ing);
  33. }
  34. }
  35. /**
  36. * Renders the operation in HTML as a stub operation with no ingredients.
  37. *
  38. * @returns {string}
  39. */
  40. toStubHtml(removeIcon) {
  41. let html = "<li class='operation'";
  42. if (this.description) {
  43. const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
  44. html += ` data-container='body' data-toggle='popover' data-placement='right'
  45. data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover'
  46. data-boundary='viewport'`;
  47. }
  48. html += ">" + this.name;
  49. if (removeIcon) {
  50. html += "<i class='material-icons remove-icon op-icon'>delete</i>";
  51. }
  52. html += "</li>";
  53. return html;
  54. }
  55. /**
  56. * Renders the operation in HTML as a full operation with ingredients.
  57. *
  58. * @returns {string}
  59. */
  60. toFullHtml() {
  61. let html = `<div class="op-title">${Utils.escapeHtml(this.name)}</div>
  62. <div class="ingredients">`;
  63. for (let i = 0; i < this.ingList.length; i++) {
  64. html += this.ingList[i].toHtml();
  65. }
  66. html += `</div>
  67. <div class="recip-icons">
  68. <i class="material-icons breakpoint" title="Set breakpoint" break="false" data-help-title="Setting breakpoints" data-help="Setting a breakpoint on an operation will cause execution of the Recipe to pause when it reaches that operation.">pause</i>
  69. <i class="material-icons disable-icon" title="Disable operation" disabled="false" data-help-title="Disabling operations" data-help="Disabling an operation will prevent it from being executed when the Recipe is baked. Execution will skip over the disabled operation and continue with subsequent operations.">not_interested</i>
  70. </div>
  71. <div class="clearfix">&nbsp;</div>`;
  72. return html;
  73. }
  74. /**
  75. * Highlights searched strings in the name and description of the operation.
  76. *
  77. * @param {[[number]]} nameIdxs - Indexes of the search strings in the operation name [[start, length]]
  78. * @param {[[number]]} descIdxs - Indexes of the search strings in the operation description [[start, length]]
  79. */
  80. highlightSearchStrings(nameIdxs, descIdxs) {
  81. if (nameIdxs.length && typeof nameIdxs[0][0] === "number") {
  82. let opName = "",
  83. pos = 0;
  84. nameIdxs.forEach(idxs => {
  85. const [start, length] = idxs;
  86. if (typeof start !== "number") return;
  87. opName += this.name.slice(pos, start) + "<b>" +
  88. this.name.slice(start, start + length) + "</b>";
  89. pos = start + length;
  90. });
  91. opName += this.name.slice(pos, this.name.length);
  92. this.name = opName;
  93. }
  94. if (this.description && descIdxs.length && descIdxs[0][0] >= 0) {
  95. // Find HTML tag offsets
  96. const re = /<[^>]+>/g;
  97. let match;
  98. while ((match = re.exec(this.description))) {
  99. // If the search string occurs within an HTML tag, return without highlighting it.
  100. const inHTMLTag = descIdxs.reduce((acc, idxs) => {
  101. const start = idxs[0];
  102. return start >= match.index && start <= (match.index + match[0].length);
  103. }, false);
  104. if (inHTMLTag) return;
  105. }
  106. let desc = "",
  107. pos = 0;
  108. descIdxs.forEach(idxs => {
  109. const [start, length] = idxs;
  110. desc += this.description.slice(pos, start) + "<b><u>" +
  111. this.description.slice(start, start + length) + "</u></b>";
  112. pos = start + length;
  113. });
  114. desc += this.description.slice(pos, this.description.length);
  115. this.description = desc;
  116. }
  117. }
  118. }
  119. /**
  120. * Given a URL for a Wikipedia (or other wiki) page, this function returns a link to that page.
  121. *
  122. * @param {string} urlStr
  123. * @returns {string}
  124. */
  125. function titleFromWikiLink(urlStr) {
  126. const urlObj = url.parse(urlStr);
  127. let wikiName = "",
  128. pageTitle = "";
  129. switch (urlObj.host) {
  130. case "forensics.wiki":
  131. wikiName = "Forensics Wiki";
  132. pageTitle = Utils.toTitleCase(urlObj.path.replace(/\//g, "").replace(/_/g, " "));
  133. break;
  134. case "wikipedia.org":
  135. wikiName = "Wikipedia";
  136. pageTitle = urlObj.pathname.substr(6).replace(/_/g, " "); // Chop off '/wiki/'
  137. break;
  138. default:
  139. // Not a wiki link, return full URL
  140. return `<a href='${urlStr}' target='_blank'>More Information<i class='material-icons inline-icon'>open_in_new</i></a>`;
  141. }
  142. return `<a href='${urlObj.href}' target='_blank'>${pageTitle}<i class='material-icons inline-icon'>open_in_new</i></a> on ${wikiName}`;
  143. }
  144. export default HTMLOperation;