Outre la redéfinition console._commandLineAPI
, il existe d'autres façons de pénétrer dans InjectedScriptHost sur les navigateurs WebKit, pour empêcher ou modifier l'évaluation des expressions entrées dans la console du développeur.
Éditer:
Chrome a corrigé cela dans une version antérieure. - qui devait être avant février 2015, car j'ai créé l'essentiel à cette époque
Voici donc une autre possibilité. Cette fois, nous nous connectons, un niveau au-dessus, directement InjectedScript
plutôt que InjectedScriptHost
par opposition à la version précédente.
Ce qui est plutôt sympa, car vous pouvez directement corriger le singe InjectedScript._evaluateAndWrap
au lieu de devoir vous y fier InjectedScriptHost.evaluate
car cela vous donne un contrôle plus précis sur ce qui devrait arriver.
Une autre chose assez intéressante est que nous pouvons intercepter le résultat interne lorsqu'une expression est évaluée et renvoyer cela à l'utilisateur au lieu du comportement normal.
Voici le code, qui fait exactement cela, retourne le résultat interne lorsqu'un utilisateur évalue quelque chose dans la console.
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);
C'est un peu bavard, mais je pensais y mettre quelques commentaires
Donc normalement, si un utilisateur, par exemple, évalue, [1,2,3,4]
vous vous attendez à la sortie suivante:
Après InjectedScript._evaluateAndWrap
évaluation monkeypatch de la même expression, donne la sortie suivante:
Comme vous le voyez, la petite flèche à gauche, indiquant la sortie, est toujours là, mais cette fois, nous obtenons un objet. Lorsque le résultat de l'expression, le tableau [1,2,3,4]
est représenté comme un objet avec toutes ses propriétés décrites.
Je recommande d'essayer d'évaluer telle ou telle expression, y compris celles qui génèrent des erreurs. C'est assez intéressant.
De plus, jetez un œil à l' objet is
- InjectedScriptHost
- . Il fournit quelques méthodes pour jouer et obtenir un aperçu des éléments internes de l'inspecteur.
Bien sûr, vous pouvez intercepter toutes ces informations et renvoyer le résultat d'origine à l'utilisateur.
Remplacez simplement l'instruction return dans le chemin else par un console.log (res)
a return res
. Ensuite, vous vous retrouvez avec ce qui suit.
Fin du montage
Il s'agit de la version antérieure qui a été corrigée par Google. Ce n'est donc plus une voie possible.
L'un d'eux est accroché à Function.prototype.call
Chrome évalue l'expression entrée en call
ing sa fonction eval avec InjectedScriptHost
asthisArg
var result = evalFunction.call(object, expression);
Compte tenu de cela, vous pouvez écouter le thisArg
d' call
être evaluate
et d' obtenir une référence au premier argument ( 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);
}
};
}
Vous pouvez par exemple envoyer une erreur, que l'évaluation a été rejetée.
Voici un exemple où l'expression entrée est passée à un compilateur CoffeeScript avant de la passer à la evaluate
fonction.