/** * The main controller for CyberChef. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 * @license Apache-2.0 * * @class */ var Chef = function() { this.dish = new Dish(); }; /** * Runs the recipe over the input. * * @param {string} input_text - The input data as a string * @param {Object[]} recipe_config - The recipe configuration object * @param {Object} options - The options object storing various user choices * @param {boolean} options.attemp_highlight - Whether or not to attempt highlighting * @param {number} progress - The position in the recipe to start from * @param {number} [step] - The number of operations to execute * * @returns {Object} response * @returns {string} response.result - The output of the recipe * @returns {string} response.type - The data type of the result * @returns {number} response.progress - The position that we have got to in the recipe * @returns {number} response.options - The app options object (which may have been changed) * @returns {number} response.duration - The number of ms it took to execute the recipe * @returns {number} response.error - The error object thrown by a failed operation (false if no error) */ Chef.prototype.bake = function(input_text, recipe_config, options, progress, step) { var start_time = new Date().getTime(), recipe = new Recipe(recipe_config), contains_fc = recipe.contains_flow_control(), error = false; // Reset attempt_highlight flag if (options.hasOwnProperty("attempt_highlight")) { options.attempt_highlight = true; } if (contains_fc) options.attempt_highlight = false; // Clean up progress if (progress >= recipe_config.length) { progress = 0; } if (step) { // Unset breakpoint on this step recipe.set_breakpoint(progress, false); // Set breakpoint on next step recipe.set_breakpoint(progress + 1, true); } // If stepping with flow control, we have to start from the beginning // but still want to skip all previous breakpoints if (progress > 0 && contains_fc) { recipe.remove_breaks_up_to(progress); progress = 0; } // If starting from scratch, load data if (progress === 0) { this.dish.set(input_text, Dish.STRING); } try { progress = recipe.execute(this.dish, progress); } catch (err) { // We can't throw the error from here as we will return in the finally block and ignore it // so we return the error in the result instead. error = err; progress = err.progress; } finally { return { result: this.dish.type == Dish.HTML ? this.dish.get(Dish.HTML) : this.dish.get(Dish.STRING), type: Dish.enum_lookup(this.dish.type), progress: progress, options: options, duration: new Date().getTime() - start_time, error: error }; } }; /** * When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs, * it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a * minute, we run a silent bake which will force the browser to load and cache all the relevant * JavaScript code needed to do a real bake. * * This will stop baking taking a long time when the CyberChef browser tab has been unfocused for a * long time and the browser has swapped out all its memory. * * The output will not be modified (hence "silent" bake). * * This will only actually execute the recipe if auto-bake is enabled, otherwise it will just load * the recipe, ingredients and dish. * * @param {Object[]} recipe_config - The recipe configuration object * @returns {number} The time it took to run the silent bake in milliseconds. */ Chef.prototype.silent_bake = function(recipe_config) { var start_time = new Date().getTime(), recipe = new Recipe(recipe_config), dish = new Dish("", Dish.STRING); try { recipe.execute(dish); } catch(err) { // Suppress all errors } return new Date().getTime() - start_time; };