diff options
author | Ruben Rodriguez <ruben@gnu.org> | 2015-01-28 22:16:14 +0100 |
---|---|---|
committer | Ruben Rodriguez <ruben@gnu.org> | 2015-01-28 22:16:14 +0100 |
commit | 16f2defa530b36cae7da5e28b5eafef9138adba5 (patch) | |
tree | c1415ef31bf1e96da1674aec2fc2c580c87d9e08 /data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js | |
parent | 763c090c20c60c13f9b6f50b953323a237fd778a (diff) |
Updated to v31.4.0ESR
* Search form in about:icecat now searches in default search engine
* Disabled accessibility.blockautorefresh
* Replaced references to Open Source with Free Software where applicable
* Added html5-video-everywhere v0.1.1 extension: https://github.com/lejenome/html5-video-everywhere
* Updated LibreJS to 6.0.8
Build scripts updated to use pbuilder
Diffstat (limited to 'data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js')
-rw-r--r-- | data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js | 697 |
1 files changed, 342 insertions, 355 deletions
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js index 0f7332a..6a22992 100644 --- a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js +++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/js_checker/nontrivial_checker.js @@ -2,20 +2,22 @@ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript. * * * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros + * Copyright (C) 2014, 2015 Nik Nyby * - * This program is free software: you can redistribute it and/or modify + * This file is part of GNU LibreJS. + * + * GNU LibreJS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * GNU LibreJS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * along with GNU LibreJS. If not, see <http://www.gnu.org/licenses/>. */ const types = require("js_checker/constant_types"); @@ -27,363 +29,348 @@ const token = types.token; var checkTypes = types.checkTypes; var utils = { + /** + * nodeContains + * Checks that node contains both a type and a value. + * Shortcut to check for null/undefined. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if matching. + */ + nodeContains: function (n, type, value) { + if (n != undefined) { + return n.type === type && + n.value === value; + } + }, + + /** + * isType + * Checks that node is of a certain type. + * Shortcut to check for null/undefined. + * + * @param {object} n. The current node being studied. + * @return {boolean}. True if it's the right type. + */ + isType: function (n, type) { + return n != undefined && n.type === type; + }, + + isNotType: function (n, type) { + return n != undefined && n.type !== type; + }, + + /** + * hasChildren + * + * Checks the token on the left + * and on the right. + * + * @param {object} n. The current node being studied. + * @param {leftType} token constant. The type on the + * left. + * @param {rightType} token constant. The type of child + * on the right + * + */ + hasChildren: function (n, leftType, rightType) { + if (types == undefined) { + return false; + } + return this.isType(n.children[0], leftType) && + this.isType(n.children[1], rightType); + }, + + /** + * findScriptTag + * + * This method should probably be replaced with DOM testing + * as regex is rather insufficiant, and this wouldn't cover + * tricky constructs as shown in http://ha.ckers.org/xss.html. + */ + findScriptTag: function (n) { + return n.value != undefined && + /<script[^>]*?>/i.test(n.value); + } +}; - /** - * nodeContains - * Checks that node contains both a type and a value. - * Shortcut to check for null/undefined. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if matching. - */ - nodeContains: function (n, type, value) { - if (n != undefined) { - return n.type === type && - n.value === value; - } - }, - - - /** - * isType - * Checks that node is of a certain type. - * Shortcut to check for null/undefined. - * - * @param {object} n. The current node being studied. - * @return {boolean}. True if it's the right type. - */ - isType: function (n, type) { - return n != undefined && n.type === type; - }, - - isNotType: function (n, type) { - return n != undefined && n.type !== type; - }, - - - /** - * hasChildren - * - * Checks the token on the left - * and on the right. - * - * @param {object} n. The current node being studied. - * @param {leftType} token constant. The type on the - * left. - * @param {rightType} token constant. The type of child - * on the right - * - */ - hasChildren: function (n, leftType, rightType) { - if (types == undefined) { - return false; - } - return this.isType(n.children[0], leftType) && - this.isType(n.children[1], rightType); - }, - - - /** - * findScriptTag - * - * This method should probably be replaced with DOM testing - * as regex is rather insufficiant, and this wouldn't cover - * tricky constructs as shown in http://ha.ckers.org/xss.html. - */ - findScriptTag: function (n) { - return n.value != undefined && - /<script[^>]*?>/i.test(n.value); - } +var NonTrivialChecker = function() { + this.definesFunction = false; + this.hash = null; +}; +/** + * definesFunctionFound + * + * Returns true if it finds a node of type FUNCTION + * that isn't a callback or an IIFE. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.definesFunctionFound = function (n) { + var isFunction = false; + if (n.type === token.FUNCTION && + n.body != undefined) { + + if (n.functionForm !== token.DECLARED_FORM && + ((n.parent.type === token.LIST && + n.parent.parent.type === token.CALL) || + n.parent.type === token.CALL) && + n.name == undefined) { + // this is a callback or an immediately + // invoked function expression "IIFE". + isFunction = false; + } else { + // this is a regular function declaration or + // function expression assigned to a variable. + //console.log("THIS DEFINES FUNCTION"); + isFunction = true; + } + } + + // look for Function constructor. + if (n.type === token.IDENTIFIER && + n.value === 'Function' && + (n.parent.type === token.NEW_WITH_ARGS || + n.parent.type === token.CALL)) { + // this is a Function constructor. + //console.log("THIS DEFINES FUNCTION"); + isFunction = true; + } + + return isFunction; }; -var nonTrivialChecker = { - - definesFunction: false, - hash: null, - /** - * definesFunctionFound - * - * Returns true if it finds a node of type FUNCTION - * that isn't a callback or an IIFE. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ - definesFunctionFound: function (n) { - var isFunction = false; - if (n.type === token.FUNCTION && - n.body != undefined) { - - if (n.functionForm !== token.DECLARED_FORM && - ((n.parent.type === token.LIST && - n.parent.parent.type === token.CALL) || - n.parent.type === token.CALL) && - n.name == undefined) { - // this is a callback or an immediately - // invoked function expression "IIFE". - isFunction = false; - } else { - // this is a regular function declaration or - // function expression assigned to a variable. - //console.log("THIS DEFINES FUNCTION"); - isFunction = true; - } - - } - - // look for Function constructor. - if (n.type === token.IDENTIFIER && - n.value === 'Function' && - (n.parent.type === token.NEW_WITH_ARGS || - n.parent.type === token.CALL)) { - // this is a Function constructor. - //console.log("THIS DEFINES FUNCTION"); - isFunction = true; - } - - return isFunction; - }, - - - /** - * invokesEval - * - * Returns true (nontrivial) if it finds any use of - * the eval function. For simplicity, we assume any - * use of an identifier "eval" is the eval function. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ - invokesEval: function (n) { - return (n.type === token.CALL && - utils.nodeContains(n.children[0], token.IDENTIFIER, 'eval') || - n.type === token.IDENTIFIER && n.value === 'eval'); - }, - - /** - * evalIdentifier - * - * Returns true (nontrivial) if it finds any use of - * the eval function. For simplicity, we assume any - * use of an identifier "eval" is the eval function. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ - evalIdentifier: function (n) { - return n.type === token.IDENTIFIER && - n.value === 'eval'; - }, - - - /** - * invokesMethodBracketSuffix - * - * Finds a method being invoked using the bracket suffix notation - * rather than the dot notation. It is difficult without keeping track of - * variable values to check for what method is actually being called. - * So we're just flagging any use of this construct as nontrivial. - * e.g., should catch: xhr[a+b]('GET', 'http://www.example.com'); - * Should not catch other uses such as: myArray[num]; - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ - invokesMethodBracketSuffix: function (n) { - return n.type === token.CALL && utils.isType(n.children[0], token.INDEX); - }, - - - /** - * createsXhrObject - * - * Creates an xhr object. - * Since all "new XMLHttpRequest", "XMLHttpRequest()", - * and "new window.XMLHttpRequest" instantiate the xhr object, - * we assume (without further proof) that any use - * of the identifier "XMLHttpRequest" and "ActiveXObject" - * is an xhr object. - * Constructs like window[a+b]() are already caught by the - * bracket suffix check. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - */ - createsXhrObject: function (n) { - return (n.type === token.IDENTIFIER) && - (n.value === 'XMLHttpRequest' || - n.value === 'ActiveXObject'); - }, - - - /** - * invokesXhrOpen - * - * Here we assume the call of an open method must be an xhr request - * (and not some other object) by checking the number of arguments. - * In most cases this method won't be used since createsXhrObject - * will already have caught the xhr. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ - invokesXhrOpen: function (n) { - return n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'open') && - n.children[1].children.length > 1; - }, - - - /** - * createsScriptElement - * - * Checks for document.createElement() that create a script. In the case - * it creates an element from a variable, we assume it's a script. In the - * future we might want to check for the value of that string variable - * (e.g., if a variable is assigned 'script', raise a flag) - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - * - */ - createsScriptElement: function (n) { - return n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'createElement') && - (utils.nodeContains(n.children[1].children[0], token.STRING, 'script') || - utils.isType(n.children[1].children[0], token.IDENTIFIER)); - }, - - - /** - * writesScriptAsHtmlString - * - * catches myObj.write('<script></script>'); - * or any myObj.write(myStringVariable); - * or concatenation such as: - * myObj.write('<scri' + stringVariable); - * or 'something' + 'somethingelse'. - * - * To check for javascript here we might want to look at the list - * from ha.ckers.org/xss.html for the future. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ - writesScriptAsHtmlString: function (n) { - var listArg; - - if (n.type === token.CALL && - utils.hasChildren(n, token.DOT, token.LIST) && - utils.isType(n.children[0].children[0], token.IDENTIFIER) && - utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'write')) { - - if (utils.isNotType(n.children[1].children[0], token.STRING)) { - // return true if any operation or concatenation. - // We are cautious (as it could - // embed a script) and flag this as nontrivial. - - return true; - } - return utils.findScriptTag(n.children[1].children[0]); - } else { - return false; - } - }, - - /** - * nontrivial anytime we see an identifier as innerHTML - */ - innerHTMLIdentifier: function (n) { - if ((n.type === token.IDENTIFIER || - n.type === token.STRING) && - n.value === 'innerHTML') { - return true; - } - }, - - - /** - * checkNontrivial - * - * Contains all the conditionals that try to identify, - * step by step, all code that could be flagged as - * nontrivial. - * - * @param {object} n. The current node being studied. - * @return {boolean} . True if found. - * - */ - checkNontrivial: function (n, t) { - - if (n.type === token.IDENTIFIER && this.evalIdentifier(n)) { - //console.log("NONTRIVIAL: eval has been found in code"); - return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - - if (this.innerHTMLIdentifier(n)) { - //console.log("NONTRIVIAL: innerHTML identifier"); - return types.nontrivialWithComment("NONTRIVIAL: innerHTML identifier"); - } - - // the node is an identifier - if (n.type === token.IDENTIFIER && this.createsXhrObject(n)) { - //console.log('NONTRIVIAL: Creates an xhr object'); - return types.nontrivialWithComment('NONTRIVIAL: Creates an xhr object'); - } - - // this is a method/function call - if (n.type === token.CALL) { - - if (this.invokesEval(n)) { - //console.log("NONTRIVIAL: eval has been found in code"); - return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - if (this.invokesMethodBracketSuffix(n)) { - //console.log('NONTRIVIAL: square bracket suffix method call detected'); +/** + * invokesEval + * + * Returns true (nontrivial) if it finds any use of + * the eval function. For simplicity, we assume any + * use of an identifier "eval" is the eval function. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.invokesEval = function (n) { + return (n.type === token.CALL && + utils.nodeContains(n.children[0], token.IDENTIFIER, 'eval') || + n.type === token.IDENTIFIER && n.value === 'eval'); +}; + +/** + * evalIdentifier + * + * Returns true (nontrivial) if it finds any use of + * the eval function. For simplicity, we assume any + * use of an identifier "eval" is the eval function. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.evalIdentifier = function (n) { + return n.type === token.IDENTIFIER && n.value === 'eval'; +}; + + +/** + * invokesMethodBracketSuffix + * + * Finds a method being invoked using the bracket suffix notation + * rather than the dot notation. It is difficult without keeping track of + * variable values to check for what method is actually being called. + * So we're just flagging any use of this construct as nontrivial. + * e.g., should catch: xhr[a+b]('GET', 'http://www.example.com'); + * Should not catch other uses such as: myArray[num]; + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.invokesMethodBracketSuffix = function (n) { + return n.type === token.CALL && utils.isType(n.children[0], token.INDEX); +}; + +/** + * createsXhrObject + * + * Creates an xhr object. + * Since all "new XMLHttpRequest", "XMLHttpRequest()", + * and "new window.XMLHttpRequest" instantiate the xhr object, + * we assume (without further proof) that any use + * of the identifier "XMLHttpRequest" and "ActiveXObject" + * is an xhr object. + * Constructs like window[a+b]() are already caught by the + * bracket suffix check. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + */ +NonTrivialChecker.prototype.createsXhrObject = function (n) { + return (n.type === token.IDENTIFIER) && + (n.value === 'XMLHttpRequest' || + n.value === 'ActiveXObject'); +}; + +/** + * invokesXhrOpen + * + * Here we assume the call of an open method must be an xhr request + * (and not some other object) by checking the number of arguments. + * In most cases this method won't be used since createsXhrObject + * will already have caught the xhr. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.invokesXhrOpen = function (n) { + return n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'open') && + n.children[1].children.length > 1; +}; + +/** + * createsScriptElement + * + * Checks for document.createElement() that create a script. In the case + * it creates an element from a variable, we assume it's a script. In the + * future we might want to check for the value of that string variable + * (e.g., if a variable is assigned 'script', raise a flag) + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + * + */ +NonTrivialChecker.prototype.createsScriptElement = function (n) { + return n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'createElement') && + (utils.nodeContains(n.children[1].children[0], token.STRING, 'script') || + utils.isType(n.children[1].children[0], token.IDENTIFIER)); +}; + +/** + * writesScriptAsHtmlString + * + * catches myObj.write('<script></script>'); + * or any myObj.write(myStringVariable); + * or concatenation such as: + * myObj.write('<scri' + stringVariable); + * or 'something' + 'somethingelse'. + * + * To check for javascript here we might want to look at the list + * from ha.ckers.org/xss.html for the future. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.writesScriptAsHtmlString = function (n) { + var listArg; + + if (n.type === token.CALL && + utils.hasChildren(n, token.DOT, token.LIST) && + utils.isType(n.children[0].children[0], token.IDENTIFIER) && + utils.nodeContains(n.children[0].children[1], token.IDENTIFIER, 'write') + ) { + if (utils.isNotType(n.children[1].children[0], token.STRING)) { + // return true if any operation or concatenation. + // We are cautious (as it could + // embed a script) and flag this as nontrivial. + + return true; + } + return utils.findScriptTag(n.children[1].children[0]); + } else { + return false; + } +}; + +/** + * nontrivial anytime we see an identifier as innerHTML + */ +NonTrivialChecker.prototype.innerHTMLIdentifier = function (n) { + if ((n.type === token.IDENTIFIER || + n.type === token.STRING) && + n.value === 'innerHTML' + ) { + return true; + } +}; + +/** + * checkNontrivial + * + * Contains all the conditionals that try to identify, + * step by step, all code that could be flagged as + * nontrivial. + * + * @param {object} n. The current node being studied. + * @return {boolean} . True if found. + * + */ +NonTrivialChecker.prototype.checkNontrivial = function (n, t) { + + if (n.type === token.IDENTIFIER && this.evalIdentifier(n)) { + //console.log("NONTRIVIAL: eval has been found in code"); return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); - } - - if (this.invokesXhrOpen(n)) { - //console.log('NONTRIVIAL: an open method similar to xhr.open is used'); - return types.nontrivialWithComment('NONTRIVIAL: square bracket suffix method call detected'); - } - - if (this.createsScriptElement(n)) { - //console.log('NONTRIVIAL: creates script element dynamically.'); - return types.nontrivialWithComment('NONTRIVIAL: an open method similar to xhr.open is used'); - } - - if (this.writesScriptAsHtmlString(n)) { - //console.log('NONTRIVIAL: writes script as html dynamically.'); - return types.nontrivialWithComment('NONTRIVIAL: creates script element dynamically.'); - } - } - - // The node is a function definition. - // Most common occurence. - if (this.definesFunctionFound(n)) { - return types.trivialFuncWithComment("Script is trivial but defines one or more functions"); - } - - // found nothing else, so trivial. - return types.trivialWithComment("Script is trivial"); - - } + } + + if (this.innerHTMLIdentifier(n)) { + //console.log("NONTRIVIAL: innerHTML identifier"); + return types.nontrivialWithComment("NONTRIVIAL: innerHTML identifier"); + } + + // the node is an identifier + if (n.type === token.IDENTIFIER && this.createsXhrObject(n)) { + //console.log('NONTRIVIAL: Creates an xhr object'); + return types.nontrivialWithComment('NONTRIVIAL: Creates an xhr object'); + } + + // this is a method/function call + if (n.type === token.CALL) { + + if (this.invokesEval(n)) { + //console.log("NONTRIVIAL: eval has been found in code"); + return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); + } + + if (this.invokesMethodBracketSuffix(n)) { + //console.log('NONTRIVIAL: square bracket suffix method call detected'); + return types.nontrivialWithComment("NONTRIVIAL: eval has been found in code"); + } + + if (this.invokesXhrOpen(n)) { + //console.log('NONTRIVIAL: an open method similar to xhr.open is used'); + return types.nontrivialWithComment('NONTRIVIAL: square bracket suffix method call detected'); + } + + if (this.createsScriptElement(n)) { + //console.log('NONTRIVIAL: creates script element dynamically.'); + return types.nontrivialWithComment('NONTRIVIAL: an open method similar to xhr.open is used'); + } + + if (this.writesScriptAsHtmlString(n)) { + //console.log('NONTRIVIAL: writes script as html dynamically.'); + return types.nontrivialWithComment('NONTRIVIAL: creates script element dynamically.'); + } + } + + // The node is a function definition. + // Most common occurence. + if (this.definesFunctionFound(n)) { + return types.trivialFuncWithComment("Script is trivial but defines one or more functions"); + } + + // found nothing else, so trivial. + return types.trivialWithComment("Script is trivial"); }; exports.nonTrivialChecker = function () { - - var checker = Object.create(nonTrivialChecker); - - return checker; -};
\ No newline at end of file + return new NonTrivialChecker(); +}; |