Chef.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import Dish from "./Dish.js";
  2. import Recipe from "./Recipe.js";
  3. /**
  4. * The main controller for CyberChef.
  5. *
  6. * @author n1474335 [n1474335@gmail.com]
  7. * @copyright Crown Copyright 2016
  8. * @license Apache-2.0
  9. *
  10. * @class
  11. */
  12. const Chef = function() {
  13. this.dish = new Dish();
  14. };
  15. /**
  16. * Runs the recipe over the input.
  17. *
  18. * @param {string} inputText - The input data as a string
  19. * @param {Object[]} recipeConfig - The recipe configuration object
  20. * @param {Object} options - The options object storing various user choices
  21. * @param {boolean} options.attempHighlight - Whether or not to attempt highlighting
  22. * @param {number} progress - The position in the recipe to start from
  23. * @param {number} [step] - Whether to only execute one operation in the recipe
  24. *
  25. * @returns {Object} response
  26. * @returns {string} response.result - The output of the recipe
  27. * @returns {string} response.type - The data type of the result
  28. * @returns {number} response.progress - The position that we have got to in the recipe
  29. * @returns {number} response.options - The app options object (which may have been changed)
  30. * @returns {number} response.duration - The number of ms it took to execute the recipe
  31. * @returns {number} response.error - The error object thrown by a failed operation (false if no error)
  32. */
  33. Chef.prototype.bake = async function(inputText, recipeConfig, options, progress, step) {
  34. let startTime = new Date().getTime(),
  35. recipe = new Recipe(recipeConfig),
  36. containsFc = recipe.containsFlowControl(),
  37. error = false;
  38. // Reset attemptHighlight flag
  39. if (options.hasOwnProperty("attemptHighlight")) {
  40. options.attemptHighlight = true;
  41. }
  42. if (containsFc) options.attemptHighlight = false;
  43. // Clean up progress
  44. if (progress >= recipeConfig.length) {
  45. progress = 0;
  46. }
  47. if (step) {
  48. // Unset breakpoint on this step
  49. recipe.setBreakpoint(progress, false);
  50. // Set breakpoint on next step
  51. recipe.setBreakpoint(progress + 1, true);
  52. }
  53. // If stepping with flow control, we have to start from the beginning
  54. // but still want to skip all previous breakpoints
  55. if (progress > 0 && containsFc) {
  56. recipe.removeBreaksUpTo(progress);
  57. progress = 0;
  58. }
  59. // If starting from scratch, load data
  60. if (progress === 0) {
  61. this.dish.set(inputText, Dish.STRING);
  62. }
  63. try {
  64. progress = await recipe.execute(this.dish, progress);
  65. } catch (err) {
  66. // Return the error in the result so that everything else gets correctly updated
  67. // rather than throwing it here and losing state info.
  68. error = err;
  69. progress = err.progress;
  70. }
  71. return {
  72. result: this.dish.type === Dish.HTML ?
  73. this.dish.get(Dish.HTML) :
  74. this.dish.get(Dish.STRING),
  75. type: Dish.enumLookup(this.dish.type),
  76. progress: progress,
  77. options: options,
  78. duration: new Date().getTime() - startTime,
  79. error: error
  80. };
  81. };
  82. /**
  83. * When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs,
  84. * it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a
  85. * minute, we run a silent bake which will force the browser to load and cache all the relevant
  86. * JavaScript code needed to do a real bake.
  87. *
  88. * This will stop baking taking a long time when the CyberChef browser tab has been unfocused for a
  89. * long time and the browser has swapped out all its memory.
  90. *
  91. * The output will not be modified (hence "silent" bake).
  92. *
  93. * This will only actually execute the recipe if auto-bake is enabled, otherwise it will just load
  94. * the recipe, ingredients and dish.
  95. *
  96. * @param {Object[]} recipeConfig - The recipe configuration object
  97. * @returns {number} The time it took to run the silent bake in milliseconds.
  98. */
  99. Chef.prototype.silentBake = function(recipeConfig) {
  100. let startTime = new Date().getTime(),
  101. recipe = new Recipe(recipeConfig),
  102. dish = new Dish("", Dish.STRING);
  103. try {
  104. recipe.execute(dish);
  105. } catch (err) {
  106. // Suppress all errors
  107. }
  108. return new Date().getTime() - startTime;
  109. };
  110. export default Chef;