Além de redefinir console._commandLineAPI
, existem outras maneiras de invadir o InjectedScriptHost nos navegadores WebKit, para impedir ou alterar a avaliação das expressões inseridas no console do desenvolvedor.
Editar:
O Chrome corrigiu isso em uma versão anterior. - que deve ter sido antes de fevereiro de 2015, como eu criei a essência na época
Então aqui está outra possibilidade. Desta vez, conectamos um nível acima diretamente InjectedScript
ao invés InjectedScriptHost
da versão anterior.
O que é legal, pois você pode usar o patch diretamente em InjectedScript._evaluateAndWrap
vez de precisar confiar, InjectedScriptHost.evaluate
pois isso oferece um controle mais detalhado sobre o que deve acontecer.
Outra coisa bem interessante é que podemos interceptar o resultado interno quando uma expressão é avaliada e devolvê-lo ao usuário em vez do comportamento normal.
Aqui está o código, que faz exatamente isso, retorna o resultado interno quando um usuário avalia algo no 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);
É um pouco detalhado, mas pensei em colocar alguns comentários
Portanto, normalmente, se um usuário, por exemplo, avaliar [1,2,3,4]
você esperaria a seguinte saída:
Após o monkeypatching InjectedScript._evaluateAndWrap
avaliar a mesma expressão, fornece a seguinte saída:
Como você vê a pequena seta esquerda, indicando a saída, ainda está lá, mas desta vez obtemos um objeto. Onde o resultado da expressão, a matriz [1,2,3,4]
é representada como um objeto com todas as suas propriedades descritas.
Eu recomendo tentar avaliar esta e aquela expressão, incluindo aquelas que geram erros. É bem interessante.
Além disso, dê uma olhada no objeto is
- InjectedScriptHost
- . Ele fornece alguns métodos para brincar e obter algumas informações sobre as partes internas do inspetor.
Obviamente, você pode interceptar todas essas informações e ainda assim devolver o resultado original ao usuário.
Apenas substitua a instrução de retorno no caminho else por um console.log (res)
seguinte a return res
. Então você terminaria com o seguinte.
Fim da Edição
Esta é a versão anterior que foi corrigida pelo Google. Portanto, não existe mais um caminho possível.
Uma delas é ligar Function.prototype.call
Chrome avalia a expressão introduzida pelo call
ing sua função eval com InjectedScriptHost
comothisArg
var result = evalFunction.call(object, expression);
Diante disso, você pode ouvir o thisArg
de call
estar evaluate
e obter uma referência para o primeiro argumento ( 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);
}
};
}
Você poderia, por exemplo, lançar um erro, que a avaliação foi rejeitada.
Aqui está um exemplo em que a expressão inserida é passada para um compilador CoffeeScript antes de passá-la para a evaluate
função.