Merge pull request #208 from muffinresearch/add-widget-js-rule

Detect require() of deprecated widget module
This commit is contained in:
Stuart Colville 2015-11-05 11:59:22 +00:00
Родитель 6b4fd536a6 882cf03a54
Коммит bc57807cd7
5 изменённых файлов: 138 добавлений и 3 удалений

Просмотреть файл

@ -19,9 +19,10 @@ To update it edit `docs/rules.md` in the
| :x: | warning | called_dangerous_global | | `%s` called in potentially dangerous manner' | | | | |
| :white_check_mark: | error? | eval | | In order to prevent vulnerabilities, the `setTimeout` 'and `setInterval` functions should be called only with function expressions as their first argument. | | [testcases/javascript/actions.py](https://github.com/mozilla/amo-validator/blob/7a8011aba8bf8c665aef2b51eb26d0697b3e19c3/validator/testcases/javascript/actions.py#L488) | | EVAL_STRING_ARG |
| :x: | warning | low_level_module (not from src) | | Usage of low-level or non-SDK interface | | | | |
| :x: | warning | widget | | Use of deprecated SDK module | | | | |
| :white_check_mark: | warning | widget | | Use of deprecated SDK module | | | null | DEPREC_SDK_MOD_WIDGET |
| :negative_squared_cross_mark: | notice | \_readonly_top | | window.top is a reserved variable | | | ('testcases_javascript_actions', '_readonly_top' | **Removed** |
| :x: | warning | global_overwrite | | Global variable overwrite | | | | |
| :white_check_mark: | warning | unexpected_global_arg [NEW] | | Unexpected global passed as an argument | | | null | UNEXPECTED_GLOGAL_ARG |
### Call definitions
| Done? | MsgType | Rule name | Addon type | Description | File Type | Source ref | Old Code | New Code |

Просмотреть файл

@ -107,3 +107,23 @@ export const EVAL_STRING_ARG = {
called only with function expressions as their first argument`),
legacyCode: ['javascript', 'dangerous_global', 'eval'],
};
export const DEPREC_SDK_MOD_WIDGET = {
code: 'DEPREC_SDK_MOD_WIDGET',
message: _('Use of deprecated SDK module'),
description: _(singleLineString`The 'widget' module has been deprecated
due to a number of performance and usability issues, and has been
removed from the SDK as of Firefox 40. Please use the
'sdk/ui/button/action' or 'sdk/ui/button/toggle' module instead.
See https://developer.mozilla.org/Add-ons/SDK/High-Level_APIs/ui
for more information.`),
legacyCode: null,
};
export const UNEXPECTED_GLOGAL_ARG = {
code: 'UNEXPECTED_GLOGAL_ARG',
message: _('Unexpected global passed as an argument'),
description: _(singleLineString`Passing a global as an argument
is not recommended. Please make this a var instead.`),
legacyCode: null,
};

Просмотреть файл

@ -2,10 +2,11 @@ import { ESLINT_ERROR, ESLINT_WARNING } from 'const';
export default {
banned_identifiers: ESLINT_WARNING,
eval_string_arg: ESLINT_ERROR,
mozindexeddb: ESLINT_ERROR,
mozindexeddb_property: ESLINT_WARNING,
opendialog_remote_uri: ESLINT_WARNING,
opendialog_nonlit_uri: ESLINT_WARNING,
opendialog_remote_uri: ESLINT_WARNING,
shallow_wrapper: ESLINT_WARNING,
eval_string_arg: ESLINT_ERROR,
widget_module: ESLINT_WARNING,
};

Просмотреть файл

@ -0,0 +1,52 @@
import { DEPREC_SDK_MOD_WIDGET, UNEXPECTED_GLOGAL_ARG } from 'messages';
import { getVariable } from 'utils';
const WIDGET_PATH = 'sdk/widget';
/*
* This rule will detect use of `require()` with the first arg being either
* a literal that matches the widget module or var pointing at a literal.
*
* TODO: This rule looks to be related to compat - based on the old tests.
* TODO: This rule should only be run for jetpack.
*
*/
export default function(context) {
return {
CallExpression: function(node) {
var requiresWidgetMod = false;
if (node.callee.name === 'require' &&
node.arguments &&
node.arguments.length) {
var firstArg = node.arguments[0];
// Find a literal string value passed to the
// the require function.
if (firstArg.type === 'Literal' &&
firstArg.value === WIDGET_PATH) {
requiresWidgetMod = true;
}
// Detect a var matching the widget module
// being passed as the first arg of require().
if (firstArg.type === 'Identifier') {
var pathVar = getVariable(context, firstArg.name);
if (pathVar && pathVar.type === 'Literal' &&
pathVar.value === WIDGET_PATH) {
requiresWidgetMod = true;
}
if (typeof pathVar === 'undefined') {
// We infer this is probably a global.
return context.report(node, UNEXPECTED_GLOGAL_ARG.code);
}
}
if (requiresWidgetMod) {
return context.report(node, DEPREC_SDK_MOD_WIDGET.code);
}
}
},
};
}

Просмотреть файл

@ -0,0 +1,61 @@
import { VALIDATION_WARNING } from 'const';
import JavaScriptScanner from 'scanners/javascript';
import * as messages from 'messages';
describe('widget_module', () => {
it('should catch require of sdk/widget as literal', () => {
var code = `require("sdk/widget").Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico"
});`;
var jsScanner = new JavaScriptScanner(code, 'badcode.js');
return jsScanner.scan()
.then((validationMessages) => {
assert.equal(validationMessages.length, 1);
assert.equal(validationMessages[0].code,
messages.DEPREC_SDK_MOD_WIDGET.code);
assert.equal(validationMessages[0].type, VALIDATION_WARNING);
});
});
it('should catch require of sdk/widget as var', () => {
var code = `var path = 'sdk/widget';
require(path).Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico"
});`;
var jsScanner = new JavaScriptScanner(code, 'badcode.js');
return jsScanner.scan()
.then((validationMessages) => {
assert.equal(validationMessages.length, 1);
assert.equal(validationMessages[0].code,
messages.DEPREC_SDK_MOD_WIDGET.code);
assert.equal(validationMessages[0].type, VALIDATION_WARNING);
});
});
it('should catch require() first arg being a global', () => {
var code = `widgetPath = 'sdk/widget';
require(widgetPath).Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico"
});`;
var jsScanner = new JavaScriptScanner(code, 'badcode.js');
return jsScanner.scan()
.then((validationMessages) => {
assert.equal(validationMessages.length, 1);
assert.equal(validationMessages[0].code,
messages.UNEXPECTED_GLOGAL_ARG.code);
assert.equal(validationMessages[0].type, VALIDATION_WARNING);
});
});
});