UNPKG

addons-linter

Version:
1,323 lines (1,102 loc) 638 kB
require("source-map-support").install(); module.exports = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 30); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _templateObject = _taggedTemplateLiteral(['Node version must be ', ' or\n greater. You are using ', '.'], ['Node version must be ', ' or\n greater. You are using ', '.']); exports.singleLineString = singleLineString; exports.getRootExpression = getRootExpression; exports.getNodeReference = getNodeReference; exports.getVariable = getVariable; exports.gettext = gettext; exports.checkMinNodeVersion = checkMinNodeVersion; exports.getPackageTypeAsString = getPackageTypeAsString; exports.ignorePrivateFunctions = ignorePrivateFunctions; exports.ensureFilenameExists = ensureFilenameExists; exports.isLocalUrl = isLocalUrl; exports.apiToMessage = apiToMessage; var _url = __webpack_require__(116); var _url2 = _interopRequireDefault(_url); var _semver = __webpack_require__(115); var _semver2 = _interopRequireDefault(_semver); var _const = __webpack_require__(1); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } /* * Template tag for removing whitespace and new lines * in order to be able to use multiline template strings * as a single string. * * Usage: singleLineString`foo bar baz * whatever`; * * Will output: 'foo bar baz whatever' * */ function singleLineString(strings) { // Interweave the strings with the // substitution vars first. var output = ''; for (var _len = arguments.length, vars = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { vars[_key - 1] = arguments[_key]; } for (var i = 0; i < vars.length; i++) { output += strings[i] + vars[i]; } output += strings[vars.length]; // Split on newlines. var lines = output.split(/(?:\r\n|\n|\r)/); // Rip out the leading whitespace. return lines.map(function (line) { return line.replace(/^\s+/gm, ''); }).join(' ').trim(); } /* * Takes an AST node and returns the root property. * * example: foo().bar.baz() will return the AST node for foo. */ function getRootExpression(node) { var root = node.callee; // If we encounter a member, grab the parent if (node.callee.type === 'MemberExpression') { var parent = node.callee.object; while (parent.type !== 'Identifier') { if (parent.callee.type === 'MemberExpression') { parent = parent.callee.object; } else { parent = parent.callee; } } root = parent; } return root; } /* * Returns the name of the reference node passed. * * example: var foo = document; * The node for foo will return 'document' */ function getNodeReference(context, node) { var variables = context.getScope().variables; var scopeVar; // Just return the value if the node passed in is a reference to a literal. if (typeof node === 'undefined' || node.type === 'Literal') { return node; } // Finds variable reference in current scope. var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = variables[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var variable = _step.value; if (variable.name === node.name) { scopeVar = variable; break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } if (scopeVar && scopeVar.defs && scopeVar.defs[0] && scopeVar.defs[0].parent && scopeVar.defs[0].parent.parent && scopeVar.defs[0].parent.parent.body) { // This represents all occurrences of the variable var occurances = scopeVar.defs[0].parent.parent.body; var lastAssignment = void 0; if (occurances instanceof Array) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = occurances[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var occurance = _step2.value; if (occurance.type === 'VariableDeclaration' && occurance.declarations[0].init !== null) { // Get what the name of what it was assigned to or the raw // value depending on the initalization lastAssignment = occurance.declarations[0].init; } else if (occurance.type === 'ExpressionStatement' && occurance.expression.type === 'AssignmentExpression') { // Get the right hand side of the assignment lastAssignment = occurance.expression.right; } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } // Return the name of the first definition of the variable which // corresponds to the node passed in. if (lastAssignment) { return lastAssignment; } } // If that variable doesn't exist in scope, then just return the node's // name. return node; } /* * Get a variable from a eslint context object if it exists, otherwise * undefined. */ function getVariable(context, name) { var variables = context.getScope().variables; var result; variables.forEach(function (variable) { if (variable.name === name && variable.defs && variable.defs[0] && variable.defs[0].name && variable.defs[0].name.parent) { result = variable.defs[0].name.parent.init; } }); return result; } /* * Gettext utils. No-op until we have proper * a proper l10n solution. * */ function gettext(str) { return str; } /* * Check the minimum node version is met */ function checkMinNodeVersion(minVersion) { var _process = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : process; return new Promise(function (resolve) { minVersion = minVersion || '0.12.0'; if (!_semver2.default.gte(_process.version, minVersion)) { throw new Error(singleLineString(_templateObject, minVersion, _process.version)); } else { resolve(); } }); } function getPackageTypeAsString(numericPackageType) { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = Object.keys(_const.PACKAGE_TYPES)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var packageType = _step3.value; if (parseInt(numericPackageType, 10) === _const.PACKAGE_TYPES[packageType]) { return packageType; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } throw new Error('Invalid package type constant "' + numericPackageType + '"'); } /* * Looks through all exported functions and returns only * "public" *functions* that aren't prefixed with an _ * * Used for ignoring private functions and constants in rules files. * Rules can have private functions we don't run; anything that * starts with an "_" shouldn't be returned. * * This exists because we export private functions in rule files * for testing. */ function ignorePrivateFunctions(list) { var filteredList = {}; for (var functionName in list) { if (functionName.startsWith('_') === false && typeof list[functionName] === 'function') { filteredList[functionName] = list[functionName]; } } return filteredList; } /* * Check a filename to make sure it's valid; used by scanners so we never * accept new scanners that don't specify which file they're referencing. */ function ensureFilenameExists(filename) { if (typeof filename !== 'string' || filename.length < 1) { throw new Error('Filename is required'); } } function isLocalUrl(urlInput) { var parsedUrl = _url2.default.parse(urlInput); var protocol = parsedUrl.protocol; var path = parsedUrl.path; // Check protocol is chrome: or resource: if set. // Details on the chrome protocol are here: https://goo.gl/W52T0Q // Details on resource protocol are here: https://goo.gl/HHqeJA if (protocol && !_const.LOCAL_PROTOCOLS.includes(protocol)) { return false; } // Disallow protocol-free remote urls. if (path.startsWith('//')) { return false; } return true; } function apiToMessage(string) { return string.replace(/^extension/, 'ext').replace(/\./g, '_').toUpperCase().substr(0, 25); } /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TEMPORARY_APIS = exports.DEPRECATED_APIS = exports.FLAGGED_FILE_MAGIC_NUMBERS_LENGTH = exports.FLAGGED_FILE_MAGIC_NUMBERS = exports.FLAGGED_FILE_EXTENSIONS = exports.ALREADY_SIGNED_REGEX = exports.FLAGGED_FILE_REGEX = exports.HIDDEN_FILE_REGEX = exports.MAX_FILE_SIZE_TO_PARSE_MB = exports.MAX_FILE_SIZE_MB = exports.VALID_MANIFEST_VERSION = exports.MANIFEST_JSON = exports.INSTALL_RDF = exports.LOCAL_PROTOCOLS = exports.ADDON_TYPE_MAP = exports.PACKAGE_TYPES = exports.PACKAGE_SUBPACKAGE = exports.PACKAGE_MULTI = exports.PACKAGE_SEARCHPROV = exports.PACKAGE_LANGPACK = exports.PACKAGE_DICTIONARY = exports.PACKAGE_THEME = exports.PACKAGE_EXTENSION = exports.PACKAGE_ANY = exports.RDF_OBSOLETE_TAGS = exports.RDF_UNALLOWED_IF_LISTED_TAGS = exports.RDF_UNALLOWED_TAGS = exports.RDF_DEFAULT_NAMESPACE = exports.MESSAGE_TYPES = exports.ESLINT_TYPES = exports.VALIDATION_WARNING = exports.VALIDATION_NOTICE = exports.VALIDATION_ERROR = exports.ESLINT_OVERWRITE_MESSAGE = exports.ESLINT_RULE_MAPPING = exports.EXTERNAL_RULE_MAPPING = exports.ESLINT_WARNING = exports.ESLINT_ERROR = exports.NO_COMPRESSION = exports.DEFLATE_COMPRESSION = undefined; var _javascript = __webpack_require__(6); var DEFLATE_COMPRESSION = exports.DEFLATE_COMPRESSION = 8; var NO_COMPRESSION = exports.NO_COMPRESSION = 0; var ESLINT_ERROR = exports.ESLINT_ERROR = 2; var ESLINT_WARNING = exports.ESLINT_WARNING = 1; // 3rd party / eslint-internal rules var EXTERNAL_RULE_MAPPING = exports.EXTERNAL_RULE_MAPPING = { 'no-eval': [ESLINT_WARNING, { allowIndirect: false }], 'no-implied-eval': ESLINT_WARNING, 'no-new-func': ESLINT_WARNING, 'no-unsafe-innerhtml/no-unsafe-innerhtml': ESLINT_WARNING }; var ESLINT_RULE_MAPPING = exports.ESLINT_RULE_MAPPING = Object.assign({ 'deprecated-entities': ESLINT_WARNING, 'event-listener-fourth': ESLINT_WARNING, 'global-require-arg': ESLINT_WARNING, 'mozindexeddb': ESLINT_WARNING, 'mozindexeddb-property': ESLINT_WARNING, 'opendialog-nonlit-uri': ESLINT_WARNING, 'opendialog-remote-uri': ESLINT_WARNING, 'webextension-api': ESLINT_WARNING, 'webextension-unsupported-api': ESLINT_WARNING }, EXTERNAL_RULE_MAPPING); var ESLINT_OVERWRITE_MESSAGE = exports.ESLINT_OVERWRITE_MESSAGE = { 'no-eval': _javascript.DANGEROUS_EVAL, 'no-implied-eval': _javascript.NO_IMPLIED_EVAL, 'no-new-func': _javascript.DANGEROUS_EVAL, 'no-unsafe-innerhtml/no-unsafe-innerhtml': _javascript.UNSAFE_DYNAMIC_VARIABLE_ASSIGNMENT, 'webextension-unsupported-api': _javascript.UNSUPPORTED_API }; var VALIDATION_ERROR = exports.VALIDATION_ERROR = 'error'; var VALIDATION_NOTICE = exports.VALIDATION_NOTICE = 'notice'; var VALIDATION_WARNING = exports.VALIDATION_WARNING = 'warning'; var ESLINT_TYPES = exports.ESLINT_TYPES = { 0: VALIDATION_NOTICE, 1: VALIDATION_WARNING, 2: VALIDATION_ERROR }; var MESSAGE_TYPES = exports.MESSAGE_TYPES = [VALIDATION_ERROR, VALIDATION_NOTICE, VALIDATION_WARNING]; var RDF_DEFAULT_NAMESPACE = exports.RDF_DEFAULT_NAMESPACE = 'http://www.mozilla.org/2004/em-rdf#'; var RDF_UNALLOWED_TAGS = exports.RDF_UNALLOWED_TAGS = ['hidden']; var RDF_UNALLOWED_IF_LISTED_TAGS = exports.RDF_UNALLOWED_IF_LISTED_TAGS = ['updateKey', 'updateURL']; var RDF_OBSOLETE_TAGS = exports.RDF_OBSOLETE_TAGS = ['file', 'requires', 'skin']; // Package type constants. var PACKAGE_ANY = exports.PACKAGE_ANY = 0; var PACKAGE_EXTENSION = exports.PACKAGE_EXTENSION = 1; var PACKAGE_THEME = exports.PACKAGE_THEME = 2; var PACKAGE_DICTIONARY = exports.PACKAGE_DICTIONARY = 3; var PACKAGE_LANGPACK = exports.PACKAGE_LANGPACK = 4; var PACKAGE_SEARCHPROV = exports.PACKAGE_SEARCHPROV = 5; var PACKAGE_MULTI = exports.PACKAGE_MULTI = 1; // A multi extension is an extension var PACKAGE_SUBPACKAGE = exports.PACKAGE_SUBPACKAGE = 7; var PACKAGE_TYPES = exports.PACKAGE_TYPES = { PACKAGE_ANY: PACKAGE_ANY, PACKAGE_EXTENSION: PACKAGE_EXTENSION, PACKAGE_THEME: PACKAGE_THEME, PACKAGE_DICTIONARY: PACKAGE_DICTIONARY, PACKAGE_LANGPACK: PACKAGE_LANGPACK, PACKAGE_SEARCHPROV: PACKAGE_SEARCHPROV, PACKAGE_MULTI: PACKAGE_MULTI, PACKAGE_SUBPACKAGE: PACKAGE_SUBPACKAGE }; // Types from install.rdf don't match the types // we use internally. This provides a mapping. var ADDON_TYPE_MAP = exports.ADDON_TYPE_MAP = { 2: PACKAGE_EXTENSION, 4: PACKAGE_THEME, 8: PACKAGE_LANGPACK, 32: PACKAGE_MULTI, 64: PACKAGE_DICTIONARY, // New "experiment" type: see bug 1220097 // https://bugzilla.mozilla.org/show_bug.cgi?id=1220583 128: PACKAGE_EXTENSION }; var LOCAL_PROTOCOLS = exports.LOCAL_PROTOCOLS = ['chrome:', 'resource:']; var INSTALL_RDF = exports.INSTALL_RDF = 'install.rdf'; var MANIFEST_JSON = exports.MANIFEST_JSON = 'manifest.json'; var VALID_MANIFEST_VERSION = exports.VALID_MANIFEST_VERSION = 2; // The max file size in MB that the // io classes will open as strings or streams. var MAX_FILE_SIZE_MB = exports.MAX_FILE_SIZE_MB = 100; // This is the limit in megabytes of a file we will parse (eg. CSS, JS, etc.) // A singular CSS/JS file over 4MB seems bad and may actually be full of data // best stored in JSON/some other data format rather than code. // https://github.com/mozilla/addons-linter/issues/730 // We increased this limit from 2MB to 4MB as per: // https://github.com/mozilla/addons/issues/181 // // We should be careful about increasing this any further. var MAX_FILE_SIZE_TO_PARSE_MB = exports.MAX_FILE_SIZE_TO_PARSE_MB = 4; var HIDDEN_FILE_REGEX = exports.HIDDEN_FILE_REGEX = /^__MACOSX\//; var FLAGGED_FILE_REGEX = exports.FLAGGED_FILE_REGEX = /thumbs\.db$|\.DS_Store$|\.orig$|\.old$|\~$/i; var ALREADY_SIGNED_REGEX = exports.ALREADY_SIGNED_REGEX = /^META\-INF\/manifest\.mf/; var FLAGGED_FILE_EXTENSIONS = exports.FLAGGED_FILE_EXTENSIONS = ['.class', '.dll', '.dylib', '.exe', '.jar', '.sh', '.so', '.swf']; // A list of magic numbers that we won't allow. var FLAGGED_FILE_MAGIC_NUMBERS = exports.FLAGGED_FILE_MAGIC_NUMBERS = [[0x4d, 0x5a], // EXE or DLL, [0x5a, 0x4d], // Alternative EXE or DLL [0x7f, 0x45, 0x4c, 0x46], // UNIX elf [0x23, 0x21], // Shell script [0xca, 0xfe, 0xba, 0xbe], // Java + Mach-O (dylib) [0xca, 0xfe, 0xd0, 0x0d], // Java packed [0x43, 0x57, 0x53]]; // Based on the above, this is how deep we need to look into a file. var FLAGGED_FILE_MAGIC_NUMBERS_LENGTH = exports.FLAGGED_FILE_MAGIC_NUMBERS_LENGTH = 4; var DEPRECATED_APIS = exports.DEPRECATED_APIS = ['app.getDetails', 'extension.onRequest', 'extension.onRequestExternal', 'extension.sendRequest', 'tabs.getAllInWindow', 'tabs.getSelected', 'tabs.onActiveChanged', 'tabs.onSelectionChanged', 'tabs.sendRequest']; // These are APIs that will cause problems when loaded temporarily // in about:debugging. var TEMPORARY_APIS = exports.TEMPORARY_APIS = ['identity.getRedirectURL', 'storage.local', 'storage.sync']; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _css = __webpack_require__(32); Object.keys(_css).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _css[key]; } }); }); var _html = __webpack_require__(33); Object.keys(_html).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _html[key]; } }); }); var _javascript = __webpack_require__(6); Object.keys(_javascript).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _javascript[key]; } }); }); var _json = __webpack_require__(34); Object.keys(_json).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _json[key]; } }); }); var _layout = __webpack_require__(35); Object.keys(_layout).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _layout[key]; } }); }); var _manifestjson = __webpack_require__(36); Object.keys(_manifestjson).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _manifestjson[key]; } }); }); var _rdf = __webpack_require__(37); Object.keys(_rdf).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _rdf[key]; } }); }); /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createLogger = createLogger; var _bunyan = __webpack_require__(105); var _bunyan2 = _interopRequireDefault(_bunyan); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function createLogger() { var _process = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : process; var level = _process.env.LOG_LEVEL || 'fatal'; var logLevels = Object.keys(_bunyan2.default.levelFromName); if (logLevels.indexOf(level) === -1) { throw new Error('LOG_LEVEL must be one of ' + logLevels.join(', ')); } return _bunyan2.default.createLogger({ name: 'AddonLinterJS', stream: process.stdout, level: level }); } exports.default = createLogger(); /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _utils = __webpack_require__(0); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var BaseScanner = function () { _createClass(BaseScanner, null, [{ key: 'fileResultType', get: function get() { /* Because each scanner expects a certain kind of data from the io libraries, a string or stream for example, we'll let the scanner define the type of data it expects. Most default to string. This can be overridden on the class. Because contents is passed to the constructor, we need to be able to access this before the constructor. */ return 'string'; } }, { key: 'scannerName', get: function get() { /* Each scanner has a unique name that identifies it. This value is currently being used to organize scanned files and report them. This must be overriden on the class. */ throw new Error('scannerName is not implemented'); } }]); function BaseScanner(contents, filename) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; _classCallCheck(this, BaseScanner); this.contents = contents; this.filename = filename; this.options = options; this.linterMessages = []; this.scannedFiles = []; this._defaultRules = []; this._parsedContent = null; this._rulesProcessed = 0; (0, _utils.ensureFilenameExists)(this.filename); } _createClass(BaseScanner, [{ key: 'scan', value: function scan() { var _this = this; var _rules = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._defaultRules; return new Promise(function (resolve, reject) { _this.getContents().then(function (contents) { var promises = []; // Ignore private functions exported in rule files. // // (These are exported for testing purposes, but we don't want // to include them in our linter's rules.) var rules = (0, _utils.ignorePrivateFunctions)(_rules); for (var rule in rules) { _this._rulesProcessed++; promises.push(rules[rule](contents, _this.filename, _this.options)); } return Promise.all(promises); }).then(function (ruleResults) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = ruleResults[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var messages = _step.value; _this.linterMessages = _this.linterMessages.concat(messages); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } resolve({ linterMessages: _this.linterMessages, scannedFiles: [_this.filename] }); }).catch(reject); }); } }, { key: 'getContents', value: function getContents() { var _this2 = this; return new Promise(function (resolve, reject) { if (_this2._parsedContent !== null) { return resolve(_this2._parsedContent); } _this2._getContents().then(function (contents) { _this2._parsedContent = contents; resolve(_this2._parsedContent); }).catch(reject); }); } }, { key: '_getContents', value: function _getContents() { return Promise.reject(new Error('_getContents is not implemented')); } }]); return BaseScanner; }(); exports.default = BaseScanner; /***/ }), /* 5 */ /***/ (function(module, exports) { module.exports = require("path"); /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IDENTITY_GETREDIRECTURL = exports.STORAGE_SYNC = exports.STORAGE_LOCAL = exports.TABS_SENDREQUEST = exports.TABS_ONSELECTIONCHANGED = exports.TABS_ONACTIVECHANGED = exports.TABS_GETSELECTED = exports.TABS_GETALLINWINDOW = exports.EXT_SENDREQUEST = exports.EXT_ONREQUESTEXTERNAL = exports.EXT_ONREQUEST = exports.APP_GETDETAILS = exports.UNSUPPORTED_API = exports.UNSAFE_DYNAMIC_VARIABLE_ASSIGNMENT = exports.KNOWN_LIBRARY = exports.UNADVISED_LIBRARY = exports.BANNED_LIBRARY = exports.NO_DOCUMENT_WRITE = exports.UNEXPECTED_GLOGAL_ARG = exports.NO_IMPLIED_EVAL = exports.DANGEROUS_EVAL = exports.OPENDIALOG_NONLIT_URI = exports.OPENDIALOG_REMOTE_URI = exports.MOZINDEXEDDB_PROPERTY = exports.MOZINDEXEDDB = exports.EVENT_LISTENER_FOURTH = exports.JS_SYNTAX_ERROR = undefined; var _templateObject = _taggedTemplateLiteral(['There is a JavaScript syntax error in your\n code; validation cannot continue on this file.'], ['There is a JavaScript syntax error in your\n code; validation cannot continue on this file.']), _templateObject2 = _taggedTemplateLiteral(['When called with a truthy forth argument,\n listeners can be triggered potentially unsafely by untrusted code. This\n requires careful review.'], ['When called with a truthy forth argument,\n listeners can be triggered potentially unsafely by untrusted code. This\n requires careful review.']), _templateObject3 = _taggedTemplateLiteral(['Calling \'', '\' with variable\n parameters can result in potential security vulnerabilities if the\n variable contains a remote URI. Consider using \'window.open\' with\n the \'chrome=no\' flag.'], ['Calling \'', '\' with variable\n parameters can result in potential security vulnerabilities if the\n variable contains a remote URI. Consider using \'window.open\' with\n the \'chrome=no\' flag.']), _templateObject4 = _taggedTemplateLiteral(['Calling \'', '\' with a non-local\n URI will result in the dialog being opened with chrome privileges.'], ['Calling \'', '\' with a non-local\n URI will result in the dialog being opened with chrome privileges.']), _templateObject5 = _taggedTemplateLiteral(['Evaluation of strings as code can lead to\n security vulnerabilities and performance issues, even in the\n most innocuous of circumstances. Please avoid using `eval` and the\n `Function` constructor when at all possible.\''], ['Evaluation of strings as code can lead to\n security vulnerabilities and performance issues, even in the\n most innocuous of circumstances. Please avoid using \\`eval\\` and the\n \\`Function\\` constructor when at all possible.\'']), _templateObject6 = _taggedTemplateLiteral(['setTimeout, setInterval and execScript\n functions should be called only with function expressions as their\n first argument'], ['setTimeout, setInterval and execScript\n functions should be called only with function expressions as their\n first argument']), _templateObject7 = _taggedTemplateLiteral(['Passing a global as an argument\n is not recommended. Please make this a var instead.'], ['Passing a global as an argument\n is not recommended. Please make this a var instead.']), _templateObject8 = _taggedTemplateLiteral(['document.write will fail in many\n circumstances when used in extensions, and has potentially severe security\n repercussions when used improperly. Therefore, it should not be used.'], ['document.write will fail in many\n circumstances when used in extensions, and has potentially severe security\n repercussions when used improperly. Therefore, it should not be used.']), _templateObject9 = _taggedTemplateLiteral(['Your add-on uses a JavaScript library we\n consider unsafe. Read more: https://bit.ly/1TRIyZY'], ['Your add-on uses a JavaScript library we\n consider unsafe. Read more: https://bit.ly/1TRIyZY']), _templateObject10 = _taggedTemplateLiteral(['Your add-on uses a JavaScript library we do\n not recommend. Read more: https://bit.ly/1TRIyZY'], ['Your add-on uses a JavaScript library we do\n not recommend. Read more: https://bit.ly/1TRIyZY']), _templateObject11 = _taggedTemplateLiteral(['JavaScript libraries are discouraged for\n simple add-ons, but are generally accepted.'], ['JavaScript libraries are discouraged for\n simple add-ons, but are generally accepted.']), _templateObject12 = _taggedTemplateLiteral(['Due to both security and performance\n concerns, this may not be set using dynamic values which have\n not been adequately sanitized. This can lead to security issues or fairly\n serious performance degradation.'], ['Due to both security and performance\n concerns, this may not be set using dynamic values which have\n not been adequately sanitized. This can lead to security issues or fairly\n serious performance degradation.']), _templateObject13 = _taggedTemplateLiteral(['This API has been deprecated by Chrome\n and has not been implemented by Firefox.'], ['This API has been deprecated by Chrome\n and has not been implemented by Firefox.']), _templateObject14 = _taggedTemplateLiteral(['This API can cause issues when loaded\n temporarily using about:debugging in Firefox unless you specify\n applications > gecko > id in the manifest. Please see:\n https://mzl.la/2hizK4a for more.'], ['This API can cause issues when loaded\n temporarily using about:debugging in Firefox unless you specify\n applications > gecko > id in the manifest. Please see:\n https://mzl.la/2hizK4a for more.']); exports._nonLiteralUri = _nonLiteralUri; exports._methodPassedRemoteUri = _methodPassedRemoteUri; var _utils = __webpack_require__(0); function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } var JS_SYNTAX_ERROR = exports.JS_SYNTAX_ERROR = { code: 'JS_SYNTAX_ERROR', legacyCode: ['testcases_scripting', 'test_js_file', 'syntax_error'], message: (0, _utils.gettext)('JavaScript syntax error'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject)) }; var EVENT_LISTENER_FOURTH = exports.EVENT_LISTENER_FOURTH = { code: 'EVENT_LISTENER_FOURTH', message: (0, _utils.gettext)('addEventListener` called with truthy fourth argument.'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject2)), legacyCode: ['js', 'instanceactions', 'addEventListener_fourth'] }; var MOZINDEXEDDB = exports.MOZINDEXEDDB = { code: 'MOZINDEXEDDB', // Original code appeared to have a non-unique err_id which is no // use for comparsions. ('testcases_regex', 'generic', '_generated') legacyCode: null, message: (0, _utils.gettext)('mozIndexedDB has been removed; use indexedDB instead'), description: (0, _utils.gettext)('mozIndexedDB has been removed; use indexedDB instead.') }; var MOZINDEXEDDB_PROPERTY = exports.MOZINDEXEDDB_PROPERTY = { code: 'MOZINDEXEDDB_PROPERTY', // Original code appeared to have a non-unique err_id which is no // use for comparsions. ('testcases_regex', 'generic', '_generated') legacyCode: null, message: (0, _utils.gettext)('mozIndexedDB used as an object key/property'), description: (0, _utils.gettext)('mozIndexedDB has been removed; use indexedDB instead.') }; function _nonLiteralUri(method) { return { code: (method + '_NONLIT_URI').toUpperCase(), legacyCode: ['js', 'instanceactions', method + '_nonliteral'], message: (0, _utils.gettext)('\'' + method + '\' called with a non-literal uri'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject3, method)) }; } function _methodPassedRemoteUri(method) { return { code: (method + '_REMOTE_URI').toUpperCase(), legacyCode: ['js', 'instanceactions', method + '_remote_uri'], message: (0, _utils.gettext)('\'' + method + '\' called with non-local URI'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject4, method)) }; } var OPENDIALOG_REMOTE_URI = exports.OPENDIALOG_REMOTE_URI = _methodPassedRemoteUri('openDialog'); var OPENDIALOG_NONLIT_URI = exports.OPENDIALOG_NONLIT_URI = _nonLiteralUri('openDialog'); var DANGEROUS_EVAL = exports.DANGEROUS_EVAL = { code: 'DANGEROUS_EVAL', message: null, description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject5)), legacyCode: null }; var NO_IMPLIED_EVAL = exports.NO_IMPLIED_EVAL = { code: 'NO_IMPLIED_EVAL', message: null, description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject6)), legacyCode: null }; var UNEXPECTED_GLOGAL_ARG = exports.UNEXPECTED_GLOGAL_ARG = { code: 'UNEXPECTED_GLOGAL_ARG', message: (0, _utils.gettext)('Unexpected global passed as an argument'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject7)), legacyCode: null }; var NO_DOCUMENT_WRITE = exports.NO_DOCUMENT_WRITE = { code: 'NO_DOCUMENT_WRITE', message: (0, _utils.gettext)('Use of document.write strongly discouraged.'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject8)), legacyCode: ['js', 'document.write', 'evil'] }; var BANNED_LIBRARY = exports.BANNED_LIBRARY = { code: 'BANNED_LIBRARY', message: (0, _utils.gettext)('Banned 3rd-party JS library'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject9)), legacyCode: null }; var UNADVISED_LIBRARY = exports.UNADVISED_LIBRARY = { code: 'UNADVISED_LIBRARY', message: (0, _utils.gettext)('Unadvised 3rd-party JS library'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject10)), legacyCode: null }; var KNOWN_LIBRARY = exports.KNOWN_LIBRARY = { code: 'KNOWN_LIBRARY', message: (0, _utils.gettext)('Known JS library detected'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject11)), legacyCode: ['testcases_content', 'test_packed_packages', 'blacklisted_js_library'] }; var UNSAFE_DYNAMIC_VARIABLE_ASSIGNMENT = exports.UNSAFE_DYNAMIC_VARIABLE_ASSIGNMENT = { code: 'UNSAFE_VAR_ASSIGNMENT', // Uses original message from eslint message: null, legacyCode: null, description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject12)) }; var UNSUPPORTED_API = exports.UNSUPPORTED_API = { code: 'UNSUPPORTED_API', message: null, messageFormat: (0, _utils.gettext)('{{api}} is not supported'), description: (0, _utils.gettext)('This API has not been implemented by Firefox.'), legacyCode: null }; function deprecatedAPI(api) { return { code: (0, _utils.apiToMessage)(api), legacyCode: ['js', 'deprecated', api], message: (0, _utils.gettext)('"' + api + '" is deprecated or unimplemented'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject13)) }; } var APP_GETDETAILS = exports.APP_GETDETAILS = deprecatedAPI('app.getDetails'); var EXT_ONREQUEST = exports.EXT_ONREQUEST = deprecatedAPI('extension.onRequest'); var EXT_ONREQUESTEXTERNAL = exports.EXT_ONREQUESTEXTERNAL = deprecatedAPI('extension.onRequestExternal'); var EXT_SENDREQUEST = exports.EXT_SENDREQUEST = deprecatedAPI('extension.sendRequest'); var TABS_GETALLINWINDOW = exports.TABS_GETALLINWINDOW = deprecatedAPI('tabs.getAllInWindow'); var TABS_GETSELECTED = exports.TABS_GETSELECTED = deprecatedAPI('tabs.getSelected'); var TABS_ONACTIVECHANGED = exports.TABS_ONACTIVECHANGED = deprecatedAPI('tabs.onActiveChanged'); var TABS_ONSELECTIONCHANGED = exports.TABS_ONSELECTIONCHANGED = deprecatedAPI('tabs.onSelectionChanged'); var TABS_SENDREQUEST = exports.TABS_SENDREQUEST = deprecatedAPI('tabs.sendRequest'); function temporaryAPI(api) { return { code: (0, _utils.apiToMessage)(api), legacyCode: ['js', 'temporary', api], message: (0, _utils.gettext)('"' + api + '" can cause issues when loaded temporarily'), description: (0, _utils.gettext)((0, _utils.singleLineString)(_templateObject14)) }; } var STORAGE_LOCAL = exports.STORAGE_LOCAL = temporaryAPI('storage.local'); var STORAGE_SYNC = exports.STORAGE_SYNC = temporaryAPI('storage.sync'); var IDENTITY_GETREDIRECTURL = exports.IDENTITY_GETREDIRECTURL = temporaryAPI('identity.getRedirectURL'); /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _templateObject = _taggedTemplateLiteral(['Config requested from CLI, but not in CLI mode.\n Please supply a config instead of relying on the getConfig() call.'], ['Config requested from CLI, but not in CLI mode.\n Please supply a config instead of relying on the getConfig() call.']); exports.getConfig = getConfig; exports.terminalWidth = terminalWidth; var _yargs = __webpack_require__(118); var _yargs2 = _interopRequireDefault(_yargs); var _logger = __webpack_require__(3); var _logger2 = _interopRequireDefault(_logger); var _utils = __webpack_require__(0); var _package = __webpack_require__(64); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } function getConfig() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$useCLI = _ref.useCLI, useCLI = _ref$useCLI === undefined ? true : _ref$useCLI; if (useCLI === false) { _logger2.default.error((0, _utils.singleLineString)(_templateObject)); throw new Error('Cannot request config from CLI in library mode'); } return _yargs2.default.usage('Usage: ./$0 [options] addon-package-or-dir \n\n\n Add-ons Linter (JS Edition) v' + _package.version).option('log-level', { describe: 'The log-level to generate', type: 'string', default: 'fatal', choices: ['fatal', 'error', 'warn', 'info', 'debug', 'trace'] }).option('warnings-as-errors', { describe: 'Treat warning as errors', type: 'boolean', default: false }).option('output', { alias: 'o', describe: 'The type of output to generate', type: 'string', default: 'text', choices: ['json', 'text'] }).option('metadata', { describe: 'Output only metadata as JSON', type: 'boolean', default: 'false' }).option('pretty', { describe: 'Prettify JSON output', type: 'boolean', default: false }).option('stack', { describe: 'Show stacktraces when errors are thrown', type: 'boolean', default: false }).option('boring', { describe: 'Disables colorful shell output', type: 'boolean', default: false }).option('self-hosted', { describe: 'Disables messages related to hosting on addons.mozilla.org.', type: 'boolean', default: false }).option('scan-file', { alias: ['f'], describe: 'Scan a selected file', type: 'string', requiresArg: true } // Require one non-option. ).demand(1).help('help').alias('h', 'help').wrap(terminalWidth()); } function terminalWidth() { var _process = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : process; if (_process && _process.stdout && _process.stdout.columns > 0) { var width = _process.stdout.columns - 2; // Terminals less than ten pixels wide seem silly. if (width < 10) { width = 10; } return width; } else { return 78; } } /***/ }), /* 8 */ /***/ (function(module, exports) { module.exports = require("fs"); /***/ }), /* 9 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IOBase = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _templateObject = _taggedTemplateLiteral(['Unexpected fileStreamType\n value "', '" should be one of "string",\n "stream" or "chunk"'], ['Unexpected fileStreamType\n value "', '" should be one of "string",\n "stream" or "chunk"']); var _utils = __webpack_require__(0); var _const = __webpack_require__(1); function _taggedTemplateLiteral(strings, raw) { return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* * Base class for io operations for both an Xpi or * a directory */ var IOBase = exports.IOBase = function () { function IOBase(packageOrDirPath) { _classCallCheck(this, IOBase); this.path = packageOrDirPath; this.files = {}; this.entries = []; // If this is too large the node process will hit a RangeError // when it runs out of memory. this.maxSizeBytes = 1024 * 1024 * _const.MAX_FILE_SIZE_MB; // A callback that accepts a relative file path and returns // true if the path should be included in results for scanning. this.shouldScanFile = function () { return true; }; } _createClass(IOBase, [{ key: 'setScanFileCallback', value: function setScanFileCallback(callback) { if (typeof callback === 'function') { this.shouldScanFile = callback; } } }, { key: 'getFile', value: function getFile(path) { var fileStreamType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'string'; switch (fileStreamType) { case 'stream': return this.getFileAsStream(path); case 'string': return this.getFileAsString(path); case 'chunk': // Assuming that chunk is going to be primarily used for finding magic // numbers in files, then there's no need to have the default be longer // than that. return this.getChunkAsBuffer(path, _const.FLAGGED_FILE_MAGIC_NUMBERS_LENGTH); default: throw new Error((0, _utils.singleLineString)(_templateObject, fileStreamType)); } } }, { key: 'getFilesByExt', value: function getFilesByExt() { for (var _len = arguments.length, extensions = Array(_len), _key = 0; _key < _len; _key++) { extensions[_key] = arguments[_key]; } var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = extensions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var ext = _step.value; if (ext.indexOf('.') !== 0) { // We use Promise.reject as we're not inside a `then()` or a // Promise constructor callback. // If we throw here it won't be caught. return Promise.reject(new Error("File extension must start with '.'")); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return this.getFiles().then(function (filesObject) { var files = []; for (var filename in filesObject) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = extensions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var ext = _step2.value; if (filename.endsWith(ext)) { files.push(filename); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } return files; }); } }, { key: 'getFiles', value: function getFiles() { return Promise.reject(new Error('getFiles is not implemented')); } }, { key: 'getFileAsStream', value: function getFileAsStream() { return Promise.reject(new Error('getFileAsStream is not implemented')); } }, { key: 'getFileAsString', value: function getFileAsString() { return Promise.reject(new Error('getFileAsString is not implemented')); } }, { key: 'getChunkAsBuffer', value: function getChunkAsBuffer() { return Promise.reject(new Error('getChunkAsBuffer is not implemented')); } }]); return IOBase; }(); /***/ }), /* 10 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdirPromise = exports.lstatPromise = undefined; exports.walkPromise = walkPromise; var _fs = __webpack_require__(8); var _path = __webpack_require__(5); var path = _interopRequireWildcard(_path); var _logger = __webpack_require__(3); var _logger2 = _interopRequireDefault(_logger); var _es6Promisify = __webpack_require__(111); var _es6Promisify2 = _interopRequireDefault(_es6Promisify); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } var lstatPromise = exports.lstatPromise = (0, _es6Promisify2.default)(_fs.lstat); var readdirPromise = exports.readdirPromise = (0, _es6Promisify2.default)(_fs.readdir); function walkPromise(curPath) { var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref$shouldIncludePat = _ref.shouldIncludePath, shouldIncludePath = _ref$shouldIncludePat === undefined ? function () { return true; } : _ref$shouldIncludePat; var result = {}; // Set a basePath var with the initial path // so all file paths (the result keys) can // be relative to the starting point. var base