mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-06 22:47:11 -04:00
Merge 5f1870a6c8
into 6bb6363b0f
This commit is contained in:
commit
b2814a5740
9 changed files with 356 additions and 118 deletions
|
@ -430,3 +430,35 @@ span.btn img {
|
|||
border-top: none;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@-moz-keyframes spinner {
|
||||
from { -moz-transform: rotate(0deg); }
|
||||
to { -moz-transform: rotate(359deg); }
|
||||
}
|
||||
@-webkit-keyframes spinner {
|
||||
from { -webkit-transform: rotate(0deg); }
|
||||
to { -webkit-transform: rotate(359deg); }
|
||||
}
|
||||
@keyframes spinner {
|
||||
from {transform:rotate(0deg);}
|
||||
to {transform:rotate(359deg);}
|
||||
}
|
||||
|
||||
.loading-icon::before {
|
||||
content: "\21bb";
|
||||
}
|
||||
|
||||
.loading-icon {
|
||||
-webkit-animation-name: spinner;
|
||||
-webkit-animation-duration: 1000ms;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
-webkit-animation-timing-function: linear;
|
||||
-moz-animation-name: spinner;
|
||||
-moz-animation-duration: 1000ms;
|
||||
-moz-animation-iteration-count: infinite;
|
||||
-moz-animation-timing-function: linear;
|
||||
-ms-animation-name: spinner;
|
||||
-ms-animation-duration: 1000ms;
|
||||
-ms-animation-iteration-count: infinite;
|
||||
-ms-animation-timing-function: linear;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@
|
|||
<div id="input" class="split no-select">
|
||||
<div class="title no-select">
|
||||
Input
|
||||
<div class="loading-icon"
|
||||
style="display: none">
|
||||
</div>
|
||||
<div class="btn-group io-btn-group">
|
||||
<button type="button" class="btn btn-default btn-sm" id="clr-io"><img src="images/recycle-16x16.png" /> Clear I/O</button>
|
||||
<button type="button" class="btn btn-default btn-sm" id="reset-layout"><img src="images/layout-16x16.png" /> Reset layout</button>
|
||||
|
@ -113,6 +116,9 @@
|
|||
<div id="output" class="split">
|
||||
<div class="title no-select">
|
||||
Output
|
||||
<div class="loading-icon"
|
||||
style="display: none">
|
||||
</div>
|
||||
<div class="btn-group io-btn-group">
|
||||
<button type="button" class="btn btn-default btn-sm" id="save-to-file" title="Save to file"><img src="images/save_as-16x16.png" /> Save to file</button>
|
||||
<button type="button" class="btn btn-default btn-sm" id="switch" title="Move output to input"><img src="images/switch-16x16.png" /> Move output to input</button>
|
||||
|
|
|
@ -287,6 +287,7 @@ var Categories = [
|
|||
"Jump",
|
||||
"Conditional Jump",
|
||||
"Return",
|
||||
"Wait",
|
||||
]
|
||||
},
|
||||
];
|
||||
|
|
|
@ -3120,5 +3120,19 @@ var OperationConfig = {
|
|||
outputType: "html",
|
||||
args: [
|
||||
]
|
||||
}
|
||||
},
|
||||
"Wait": {
|
||||
description: "Waits for a number of milliseconds.",
|
||||
run: FlowControl.runWait,
|
||||
inputType: "string",
|
||||
outputType: "string",
|
||||
flowControl: true,
|
||||
args: [
|
||||
{
|
||||
name: "Sleep time in milliseconds",
|
||||
type: "number",
|
||||
value: FlowControl.SLEEP_TIME,
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step)
|
|||
var startTime = new Date().getTime(),
|
||||
recipe = new Recipe(recipeConfig),
|
||||
containsFc = recipe.containsFlowControl(),
|
||||
error = false;
|
||||
chef = this;
|
||||
|
||||
// Reset attemptHighlight flag
|
||||
if (options.hasOwnProperty("attemptHighlight")) {
|
||||
|
@ -64,28 +64,41 @@ Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step)
|
|||
|
||||
// If starting from scratch, load data
|
||||
if (progress === 0) {
|
||||
this.dish.set(inputText, Dish.STRING);
|
||||
chef.dish.set(inputText, Dish.STRING);
|
||||
}
|
||||
|
||||
try {
|
||||
progress = recipe.execute(this.dish, progress);
|
||||
} catch (err) {
|
||||
// Return the error in the result so that everything else gets correctly updated
|
||||
// rather than throwing it here and losing state info.
|
||||
error = err;
|
||||
progress = err.progress;
|
||||
}
|
||||
|
||||
return {
|
||||
result: this.dish.type === Dish.HTML ?
|
||||
this.dish.get(Dish.HTML) :
|
||||
this.dish.get(Dish.STRING),
|
||||
type: Dish.enumLookup(this.dish.type),
|
||||
progress: progress,
|
||||
var ret = {
|
||||
options: options,
|
||||
duration: new Date().getTime() - startTime,
|
||||
error: error
|
||||
error: false,
|
||||
};
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
recipe.execute(chef.dish, progress)
|
||||
.then(function(progress) {
|
||||
ret.result = chef.dish.type === Dish.HTML ?
|
||||
chef.dish.get(Dish.HTML) :
|
||||
chef.dish.get(Dish.STRING);
|
||||
ret.type = Dish.enumLookup(chef.dish.type);
|
||||
|
||||
ret.duration = new Date().getTime() - startTime;
|
||||
ret.progress = progress;
|
||||
|
||||
resolve(ret);
|
||||
})
|
||||
.catch(function(err) {
|
||||
ret.result = chef.dish.type === Dish.HTML ?
|
||||
chef.dish.get(Dish.HTML) :
|
||||
chef.dish.get(Dish.STRING);
|
||||
ret.type = Dish.enumLookup(chef.dish.type);
|
||||
|
||||
ret.duration = new Date().getTime() - startTime;
|
||||
ret.progress = err.progress;
|
||||
ret.error = err;
|
||||
|
||||
// Resolve not reject: we are packaging the error as a value.
|
||||
resolve(ret);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -59,29 +59,53 @@ var FlowControl = {
|
|||
}
|
||||
}
|
||||
|
||||
var recipe = new Recipe(),
|
||||
output = "",
|
||||
progress = 0;
|
||||
|
||||
var recipe = new Recipe();
|
||||
recipe.addOperations(subOpList);
|
||||
|
||||
// Run recipe over each tranche
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
var dish = new Dish(inputs[i], inputType);
|
||||
try {
|
||||
progress = recipe.execute(dish, 0);
|
||||
} catch (err) {
|
||||
if (!ignoreErrors) {
|
||||
throw err;
|
||||
}
|
||||
progress = err.progress + 1;
|
||||
}
|
||||
output += dish.get(outputType) + mergeDelim;
|
||||
}
|
||||
return new Promise(function(resolve, reject) {
|
||||
var promises = inputs.map(function(input, i) {
|
||||
var forkDish = new Dish(input, inputType);
|
||||
|
||||
state.dish.set(output, outputType);
|
||||
state.progress += progress;
|
||||
return state;
|
||||
return new Promise(function(resolve, reject) {
|
||||
recipe.execute(forkDish, 0)
|
||||
.then(function(progress) {
|
||||
resolve({
|
||||
progress: progress,
|
||||
dish: forkDish,
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
if (ignoreErrors) {
|
||||
resolve({
|
||||
progress: err.progress + 1,
|
||||
dish: forkDish,
|
||||
});
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Promise.all(promises)
|
||||
.then(function(values) {
|
||||
var progress;
|
||||
|
||||
var output = values.map(function(value) {
|
||||
progress = value.progress;
|
||||
return value.dish.get(outputType);
|
||||
}).join(mergeDelim);
|
||||
|
||||
state.progress += progress;
|
||||
state.dish.set(output, outputType);
|
||||
|
||||
resolve(state);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
@ -183,4 +207,32 @@ var FlowControl = {
|
|||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SLEEP_TIME: 2500,
|
||||
|
||||
|
||||
/**
|
||||
* Wait operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runWait: function(state) {
|
||||
var ings = state.opList[state.progress].getIngValues(),
|
||||
sleepTime = ings[0];
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
setTimeout(function() {
|
||||
resolve(state);
|
||||
}, sleepTime);
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
|
|
@ -138,58 +138,112 @@ Recipe.prototype.lastOpIndex = function(startIndex) {
|
|||
* Executes each operation in the recipe over the given Dish.
|
||||
*
|
||||
* @param {Dish} dish
|
||||
* @param {number} [startFrom=0] - The index of the Operation to start executing from
|
||||
* @param {number} [currentStep=0] - The index of the Operation to start executing from
|
||||
* @returns {number} - The final progress through the recipe
|
||||
*/
|
||||
Recipe.prototype.execute = function(dish, startFrom) {
|
||||
startFrom = startFrom || 0;
|
||||
var op, input, output, numJumps = 0;
|
||||
Recipe.prototype.execute = function(dish, currentStep, state) {
|
||||
var recipe = this;
|
||||
|
||||
for (var i = startFrom; i < this.opList.length; i++) {
|
||||
op = this.opList[i];
|
||||
if (op.isDisabled()) {
|
||||
continue;
|
||||
}
|
||||
if (op.isBreakpoint()) {
|
||||
return i;
|
||||
var formatErrMsg = function(err, step, op) {
|
||||
var e = typeof err == "string" ? { message: err } : err;
|
||||
|
||||
e.progress = step;
|
||||
if (e.fileName) {
|
||||
e.displayStr = op.name + " - " + e.name + " in " +
|
||||
e.fileName + " on line " + e.lineNumber +
|
||||
".<br><br>Message: " + (e.displayStr || e.message);
|
||||
} else {
|
||||
e.displayStr = op.name + " - " + (e.displayStr || e.message);
|
||||
}
|
||||
|
||||
try {
|
||||
return e;
|
||||
};
|
||||
|
||||
// Operations can be asynchronous so we have to return a Promise to a
|
||||
// future value.
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Helper function to clean up recursing to the next recipe step.
|
||||
// It is a closure to avoid having to pass in resolve and reject.
|
||||
var execRecipe = function(recipe, dish, step, state) {
|
||||
return recipe.execute(dish, step, state)
|
||||
.then(function(progress) {
|
||||
resolve(progress);
|
||||
})
|
||||
.catch(function(err) {
|
||||
// Pass back the error to the previous caller.
|
||||
// We don't want to handle the error here as the current
|
||||
// operation did not cause the error, and so it should
|
||||
// not appear in the error message.
|
||||
reject(err);
|
||||
});
|
||||
};
|
||||
|
||||
currentStep = currentStep || 0;
|
||||
|
||||
if (currentStep === recipe.opList.length) {
|
||||
resolve(currentStep);
|
||||
return;
|
||||
}
|
||||
|
||||
var op = recipe.opList[currentStep],
|
||||
input = dish.get(op.inputType);
|
||||
|
||||
if (op.isDisabled()) {
|
||||
// Skip to next operation
|
||||
var nextStep = currentStep + 1;
|
||||
execRecipe(recipe, dish, nextStep, state);
|
||||
} else if (op.isBreakpoint()) {
|
||||
// We are at a breakpoint, we shouldn't recurse to the next op.
|
||||
resolve(currentStep);
|
||||
} else {
|
||||
var operationResult;
|
||||
|
||||
// We must try/catch here because op.run can either return
|
||||
// A) a value
|
||||
// B) a promise
|
||||
// Promise.resolve -> .catch will handle errors from promises
|
||||
// try/catch will handle errors from values
|
||||
try {
|
||||
if (op.isFlowControl()) {
|
||||
state = {
|
||||
progress: currentStep,
|
||||
dish: dish,
|
||||
opList: recipe.opList,
|
||||
numJumps: (state && state.numJumps) || 0,
|
||||
};
|
||||
operationResult = op.run(state);
|
||||
} else {
|
||||
operationResult = op.run(input, op.getIngValues());
|
||||
}
|
||||
} catch (err) {
|
||||
reject(formatErrMsg(err, currentStep, op));
|
||||
return;
|
||||
}
|
||||
|
||||
if (op.isFlowControl()) {
|
||||
// Package up the current state
|
||||
var state = {
|
||||
"progress" : i,
|
||||
"dish" : dish,
|
||||
"opList" : this.opList,
|
||||
"numJumps" : numJumps
|
||||
};
|
||||
|
||||
state = op.run(state);
|
||||
i = state.progress;
|
||||
numJumps = state.numJumps;
|
||||
Promise.resolve(operationResult)
|
||||
.then(function(state) {
|
||||
return recipe.execute(state.dish, state.progress + 1);
|
||||
})
|
||||
.then(function(progress) {
|
||||
resolve(progress);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(formatErrMsg(err, currentStep, op));
|
||||
});
|
||||
} else {
|
||||
output = op.run(input, op.getIngValues());
|
||||
dish.set(output, op.outputType);
|
||||
Promise.resolve(operationResult)
|
||||
.then(function(output) {
|
||||
dish.set(output, op.outputType);
|
||||
var nextStep = currentStep + 1;
|
||||
execRecipe(recipe, dish, nextStep, state);
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(formatErrMsg(err, currentStep, op));
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
var e = typeof err == "string" ? { message: err } : err;
|
||||
|
||||
e.progress = i;
|
||||
if (e.fileName) {
|
||||
e.displayStr = op.name + " - " + e.name + " in " +
|
||||
e.fileName + " on line " + e.lineNumber +
|
||||
".<br><br>Message: " + (e.displayStr || e.message);
|
||||
} else {
|
||||
e.displayStr = op.name + " - " + (e.displayStr || e.message);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return this.opList.length;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ var HTMLApp = function(categories, operations, defaultFavourites, defaultOptions
|
|||
this.progress = 0;
|
||||
this.ingId = 0;
|
||||
|
||||
this.baking = false;
|
||||
this.rebake = false;
|
||||
|
||||
window.chef = this.chef;
|
||||
};
|
||||
|
||||
|
@ -61,6 +64,36 @@ HTMLApp.prototype.handleError = function(err) {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the UI to show if baking is in process or not.
|
||||
*
|
||||
* @param {bakingStatus}
|
||||
*/
|
||||
HTMLApp.prototype.setBakingStatus = function(bakingStatus) {
|
||||
var inputLoadingIcon = document.querySelector("#input .title .loading-icon");
|
||||
var outputLoadingIcon = document.querySelector("#output .title .loading-icon");
|
||||
|
||||
var inputElement = document.querySelector("#input-text");
|
||||
var outputElement = document.querySelector("#output-text");
|
||||
|
||||
if (bakingStatus) {
|
||||
inputLoadingIcon.style.display = "inline-block";
|
||||
outputLoadingIcon.style.display = "inline-block";
|
||||
inputElement.classList.add("disabled");
|
||||
outputElement.classList.add("disabled");
|
||||
inputElement.disabled = true;
|
||||
outputElement.disabled = true;
|
||||
} else {
|
||||
inputLoadingIcon.style.display = "none";
|
||||
outputLoadingIcon.style.display = "none";
|
||||
inputElement.classList.remove("disabled");
|
||||
outputElement.classList.remove("disabled");
|
||||
inputElement.disabled = false;
|
||||
outputElement.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the Chef to bake the current input using the current recipe.
|
||||
*
|
||||
|
@ -68,37 +101,70 @@ HTMLApp.prototype.handleError = function(err) {
|
|||
* whole recipe.
|
||||
*/
|
||||
HTMLApp.prototype.bake = function(step) {
|
||||
var response;
|
||||
var app = this;
|
||||
|
||||
if (app.baking) {
|
||||
if (!app.rebake) {
|
||||
// We do not want to keep autobaking
|
||||
// Say that we will rebake and then try again later
|
||||
app.rebake = true;
|
||||
setTimeout(function() {
|
||||
app.bake(step);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
app.rebake = false;
|
||||
app.baking = true;
|
||||
app.setBakingStatus(true);
|
||||
|
||||
try {
|
||||
response = this.chef.bake(
|
||||
this.getInput(), // The user's input
|
||||
this.getRecipeConfig(), // The configuration of the recipe
|
||||
this.options, // Options set by the user
|
||||
this.progress, // The current position in the recipe
|
||||
app.chef.bake(
|
||||
app.getInput(), // The user's input
|
||||
app.getRecipeConfig(), // The configuration of the recipe
|
||||
app.options, // Options set by the user
|
||||
app.progress, // The current position in the recipe
|
||||
step // Whether or not to take one step or execute the whole recipe
|
||||
);
|
||||
)
|
||||
.then(function(response) {
|
||||
app.baking = false;
|
||||
app.setBakingStatus(false);
|
||||
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
if (response.error) {
|
||||
app.handleError(response.error);
|
||||
}
|
||||
|
||||
app.options = response.options;
|
||||
|
||||
if (response.type === "html") {
|
||||
app.dishStr = Utils.stripHtmlTags(response.result, true);
|
||||
} else {
|
||||
app.dishStr = response.result;
|
||||
}
|
||||
|
||||
app.progress = response.progress;
|
||||
app.manager.recipe.updateBreakpointIndicator(response.progress);
|
||||
app.manager.output.set(response.result, response.type, response.duration);
|
||||
|
||||
// If baking took too long, disable auto-bake
|
||||
if (response.duration > app.options.autoBakeThreshold && app.autoBake_) {
|
||||
app.manager.controls.setAutoBake(false);
|
||||
app.alert("Baking took longer than " + app.options.autoBakeThreshold +
|
||||
"ms, Auto Bake has been disabled.", "warning", 5000);
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error("Chef's promise was rejected, should never occur");
|
||||
});
|
||||
} catch (err) {
|
||||
this.handleError(err);
|
||||
}
|
||||
|
||||
if (!response) return;
|
||||
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
}
|
||||
|
||||
this.options = response.options;
|
||||
this.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result;
|
||||
this.progress = response.progress;
|
||||
this.manager.recipe.updateBreakpointIndicator(response.progress);
|
||||
this.manager.output.set(response.result, response.type, response.duration);
|
||||
|
||||
// If baking took too long, disable auto-bake
|
||||
if (response.duration > this.options.autoBakeThreshold && this.autoBake_) {
|
||||
this.manager.controls.setAutoBake(false);
|
||||
this.alert("Baking took longer than " + this.options.autoBakeThreshold +
|
||||
"ms, Auto Bake has been disabled.", "warning", 5000);
|
||||
app.baking = false;
|
||||
app.setBakingStatus(false);
|
||||
app.handleError(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
214 source files
|
||||
115904 lines
|
||||
4.3M size
|
||||
116142 lines
|
||||
size
|
||||
|
||||
144 JavaScript source files
|
||||
106712 lines
|
||||
3.8M size
|
||||
106912 lines
|
||||
4.9M size
|
||||
|
||||
83 third party JavaScript source files
|
||||
86259 lines
|
||||
3.0M size
|
||||
3.7M size
|
||||
|
||||
61 first party JavaScript source files
|
||||
20453 lines
|
||||
764K size
|
||||
20653 lines
|
||||
1.3M size
|
||||
|
||||
3.5M uncompressed JavaScript size
|
||||
1.9M compressed JavaScript size
|
||||
uncompressed JavaScript size
|
||||
compressed JavaScript size
|
||||
|
||||
15 categories
|
||||
176 operations
|
||||
177 operations
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue