UNPKG

tslint-config-security

Version:
109 lines (108 loc) 5.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var Lint = require("tslint"); var ts = require("typescript"); var node_kind_1 = require("../node-kind"); var keywordMask = new RegExp('^.*((' + ['password', 'secret', 'api', 'apiKey', 'token', 'auth', 'pass', 'hash'].join(')|(') + ')).*$', 'im'); function containsKeyword(node) { switch (node.kind) { case ts.SyntaxKind.CallExpression: return containsKeywordCallExpression(node); case ts.SyntaxKind.ElementAccessExpression: return containsKeywordElementAccessExpression(node); case ts.SyntaxKind.Identifier: return containsKeywordIdentifier(node); case ts.SyntaxKind.PropertyAccessExpression: return containsKeywordPropertyAccessExpression(node); default: return false; } } function containsKeywordCallExpression(node) { return containsKeyword(node.expression); } function containsKeywordElementAccessExpression(node) { if (node_kind_1.stringLiteralKinds.includes(node.argumentExpression.kind)) { var argumentExpression = node.argumentExpression; return containsKeyword(node.expression) || Boolean(keywordMask.test(argumentExpression.text)); } return containsKeyword(node.expression) || containsKeyword(node.argumentExpression); } function containsKeywordIdentifier(node) { return Boolean(keywordMask.test(node.text)); } function containsKeywordPropertyAccessExpression(node) { return containsKeyword(node.expression) || containsKeyword(node.name); } function isVulnerableType(node) { if (node_kind_1.stringLiteralKinds.includes(node.kind)) { return true; } switch (node.kind) { case ts.SyntaxKind.CallExpression: return isVulnerableCallExpression(node); case ts.SyntaxKind.ElementAccessExpression: return isVulnerableElementAccessExpression(node); case ts.SyntaxKind.Identifier: return true; case ts.SyntaxKind.PropertyAccessExpression: return isVulnerablePropertyAccessExpression(node); default: return false; } } function isVulnerableCallExpression(node) { return isVulnerableType(node.expression); } function isVulnerableElementAccessExpression(node) { return isVulnerableType(node.expression) || isVulnerableType(node.argumentExpression); } function isVulnerablePropertyAccessExpression(node) { return isVulnerableType(node.expression) || isVulnerableType(node.name); } var Rule = (function (_super) { tslib_1.__extends(Rule, _super); function Rule() { return _super !== null && _super.apply(this, arguments) || this; } Rule.prototype.apply = function (sourceFile) { return this.applyWithFunction(sourceFile, walk); }; Rule.metadata = { ruleName: 'tsr-detect-possible-timing-attacks', description: 'Warns when possible timing attack is found', descriptionDetails: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["Any usage of unsafe comparisons ('==', '!=', '!==' and '===')\n that check input sequentially will trigger a warning.\n See https://github.com/webschik/tslint-config-security#tsr-detect-possible-timing-attacks"], ["Any usage of unsafe comparisons ('==', '!=', '!==' and '===')\n that check input sequentially will trigger a warning.\n See https://github.com/webschik/tslint-config-security#tsr-detect-possible-timing-attacks"]))), optionsDescription: '', options: null, type: 'functionality', requiresTypeInfo: false, typescriptOnly: false }; return Rule; }(Lint.Rules.AbstractRule)); exports.Rule = Rule; function walk(ctx) { function visitNode(node) { if (node.kind === ts.SyntaxKind.BinaryExpression) { var _a = node, left = _a.left, right = _a.right, operatorToken = _a.operatorToken; var operatorTokenKind = operatorToken.kind; if (operatorTokenKind === ts.SyntaxKind.EqualsEqualsToken || operatorTokenKind === ts.SyntaxKind.EqualsEqualsEqualsToken || operatorTokenKind === ts.SyntaxKind.ExclamationEqualsToken || operatorTokenKind === ts.SyntaxKind.ExclamationEqualsEqualsToken) { if (isVulnerableType(left) && isVulnerableType(right)) { if (containsKeyword(left)) { ctx.addFailureAtNode(node, 'Potential timing attack on the left side of expression'); } else if (containsKeyword(right)) { ctx.addFailureAtNode(node, 'Potential timing attack on the right side of expression'); } } } } return ts.forEachChild(node, visitNode); } return ts.forEachChild(ctx.sourceFile, visitNode); } var templateObject_1;