Neben der Neudefinition console._commandLineAPI
gibt es einige andere Möglichkeiten, in InjectedScriptHost in WebKit-Browsern einzudringen, um die Auswertung von in die Entwicklerkonsole eingegebenen Ausdrücken zu verhindern oder zu ändern.
Bearbeiten:
Chrome hat dies in einer früheren Version behoben. - das muss vor Februar 2015 gewesen sein, als ich das Wesentliche zu dieser Zeit erstellt habe
Also hier ist eine andere Möglichkeit. Dieses Mal schließen wir uns ein Level höher direkt an InjectedScript
und nicht InjectedScriptHost
im Gegensatz zur vorherigen Version.
Das ist ein bisschen nett, da Sie Affen-Patches direkt ausführen können, InjectedScript._evaluateAndWrap
anstatt sich darauf verlassen zu müssen, InjectedScriptHost.evaluate
da Sie dadurch eine genauere Kontrolle darüber haben, was passieren soll.
Eine andere ziemlich interessante Sache ist, dass wir das interne Ergebnis abfangen können, wenn ein Ausdruck ausgewertet wird, und dieses anstelle des normalen Verhaltens an den Benutzer zurückgeben können.
Hier ist der Code, der genau das tut und das interne Ergebnis zurückgibt, wenn ein Benutzer etwas in der Konsole auswertet.
var is;
Object.defineProperty(Object.prototype,"_lastResult",{
get:function(){
return this._lR;
},
set:function(v){
if (typeof this._commandLineAPIImpl=="object") is=this;
this._lR=v;
}
});
setTimeout(function(){
var ev=is._evaluateAndWrap;
is._evaluateAndWrap=function(){
var res=ev.apply(is,arguments);
console.log();
if (arguments[2]==="completion") {
//This is the path you end up when a user types in the console and autocompletion get's evaluated
//Chrome expects a wrapped result to be returned from evaluateAndWrap.
//You can use `ev` to generate an object yourself.
//In case of the autocompletion chrome exptects an wrapped object with the properties that can be autocompleted. e.g.;
//{iGetAutoCompleted: true}
//You would then go and return that object wrapped, like
//return ev.call (is, '', '({test:true})', 'completion', true, false, true);
//Would make `test` pop up for every autocompletion.
//Note that syntax as well as every Object.prototype property get's added to that list later,
//so you won't be able to exclude things like `while` from the autocompletion list,
//unless you wou'd find a way to rewrite the getCompletions function.
//
return res; //Return the autocompletion result. If you want to break that, return nothing or an empty object
} else {
//This is the path where you end up when a user actually presses enter to evaluate an expression.
//In order to return anything as normal evaluation output, you have to return a wrapped object.
//In this case, we want to return the generated remote object.
//Since this is already a wrapped object it would be converted if we directly return it. Hence,
//`return result` would actually replicate the very normal behaviour as the result is converted.
//to output what's actually in the remote object, we have to stringify it and `evaluateAndWrap` that object again.`
//This is quite interesting;
return ev.call (is, null, '(' + JSON.stringify (res) + ')', "console", true, false, true)
}
};
},0);
Es ist ein bisschen ausführlich, aber ich dachte, ich habe ein paar Kommentare hinzugefügt
Wenn ein Benutzer beispielsweise auswertet [1,2,3,4]
, erwarten Sie normalerweise die folgende Ausgabe:
Nach dem Monkeypatching InjectedScript._evaluateAndWrap
, das denselben Ausdruck auswertet, wird die folgende Ausgabe ausgegeben:
Wie Sie sehen, ist der kleine linke Pfeil, der die Ausgabe anzeigt, immer noch vorhanden, aber dieses Mal erhalten wir ein Objekt. Wenn das Ergebnis des Ausdrucks ist, wird das Array [1,2,3,4]
als Objekt mit allen beschriebenen Eigenschaften dargestellt.
Ich empfehle, diesen und jenen Ausdruck zu bewerten, einschließlich derer, die Fehler erzeugen. Es ist ziemlich interessant.
Schauen Sie sich außerdem das is
- InjectedScriptHost
- Objekt an. Es bietet einige Methoden zum Spielen und um einen Einblick in die Interna des Inspektors zu erhalten.
Natürlich können Sie all diese Informationen abfangen und trotzdem das ursprüngliche Ergebnis an den Benutzer zurückgeben.
Ersetzen Sie einfach die return-Anweisung im else-Pfad durch ein console.log (res)
folgendes a return res
. Dann würden Sie am Ende mit dem folgenden enden.
Ende der Bearbeitung
Dies ist die vorherige Version, die von Google behoben wurde. Daher kein möglicher Weg mehr.
Eines davon hakt sich ein Function.prototype.call
Chrome wertet den eingegebenen Ausdruck aus, indem es call
seine Bewertungsfunktion mit InjectedScriptHost
as angibtthisArg
var result = evalFunction.call(object, expression);
Vor diesem Hintergrund können Sie für das hören thisArg
von call
Wesen evaluate
und einen Verweis auf das erste Argument bekommen ( InjectedScriptHost
)
if (window.URL) {
var ish, _call = Function.prototype.call;
Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
ish = arguments[0];
ish.evaluate = function (e) { //Redefine the evaluation behaviour
throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
};
Function.prototype.call = _call; //Reset the Function.prototype.call
return _call.apply(this, arguments);
}
};
}
Sie könnten zB einen Fehler auslösen, dass die Auswertung abgelehnt wurde.
Hier ist ein Beispiel, in dem der eingegebene Ausdruck an einen CoffeeScript-Compiler übergeben wird, bevor er an die evaluate
Funktion übergeben wird.