From f74653be46eafacb559fe3ce6859804559bae570 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 17 Apr 2019 15:18:06 +0200 Subject: [PATCH] JS: extract `getDefaultNode` from `DefaultRange` --- javascript/ql/src/semmle/javascript/AMD.qll | 7 ++++ .../src/semmle/javascript/ES2015Modules.qll | 16 +++++++++ javascript/ql/src/semmle/javascript/Expr.qll | 2 ++ .../ql/src/semmle/javascript/Modules.qll | 5 +++ .../ql/src/semmle/javascript/NodeJS.qll | 2 ++ .../ql/src/semmle/javascript/TypeScript.qll | 2 ++ .../src/semmle/javascript/dataflow/Nodes.qll | 34 ++----------------- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index f0bc67170f6..0b8b7fcffd8 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -263,6 +263,13 @@ private class AmdDependencyImport extends Import { not exists(super.getImportedModule()) and result = resolveByAbsolutePath() } + + override DataFlow::Node getDefaultNode() { + exists(Parameter param | + any(AmdModuleDefinition def).dependencyParameter(this, param) and + result = DataFlow::parameterNode(param) + ) + } } /** diff --git a/javascript/ql/src/semmle/javascript/ES2015Modules.qll b/javascript/ql/src/semmle/javascript/ES2015Modules.qll index 39cd46d94a4..1a92509f3b2 100644 --- a/javascript/ql/src/semmle/javascript/ES2015Modules.qll +++ b/javascript/ql/src/semmle/javascript/ES2015Modules.qll @@ -43,6 +43,22 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration { /** Gets an import specifier of this import declaration. */ ImportSpecifier getASpecifier() { result = getSpecifier(_) } + + override DataFlow::Node getDefaultNode() { + // `import * as http from 'http'` or `import http from `http`' + exists(ImportSpecifier is | + is = getASpecifier() and + result = DataFlow::ssaDefinitionNode(SSA::definition(is)) + | + is instanceof ImportNamespaceSpecifier and + count(getASpecifier()) = 1 + or + is.getImportedName() = "default" + ) + or + // `import { createServer } from 'http'` + result = DataFlow::destructuredModuleImportNode(this) + } } /** A literal path expression appearing in an `import` declaration. */ diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index 705d7b3aec4..14744c69966 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -1562,6 +1562,8 @@ class DynamicImportExpr extends @dynamicimport, Expr, Import { override PathExpr getImportedPath() { result = getSource() } override Module getEnclosingModule() { result = getTopLevel() } + + override DataFlow::Node getDefaultNode() { result = DataFlow::valueNode(this) } } /** A literal path expression appearing in a dynamic import. */ diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index f4120ee481e..3a9753c2527 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -160,6 +160,11 @@ abstract class Import extends ASTNode { result = resolveFromTypeRoot() ) } + + /** + * Gets the data flow node that the default import of this import is available at. + */ + abstract DataFlow::Node getDefaultNode(); } /** diff --git a/javascript/ql/src/semmle/javascript/NodeJS.qll b/javascript/ql/src/semmle/javascript/NodeJS.qll index 4e3720f4cb1..fa8676a3cf2 100644 --- a/javascript/ql/src/semmle/javascript/NodeJS.qll +++ b/javascript/ql/src/semmle/javascript/NodeJS.qll @@ -234,6 +234,8 @@ class Require extends CallExpr, Import { priority - (prioritiesPerCandidate() * r + numberOfExtensions() + 1)) ) } + + override DataFlow::Node getDefaultNode() { result = DataFlow::valueNode(this) } } /** An argument to `require` or `require.resolve`, considered as a path expression. */ diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 4dece7f650f..8cf9fa6d91c 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -212,6 +212,8 @@ class ExternalModuleReference extends Expr, Import, @externalmodulereference { override ControlFlowNode getFirstControlFlowNode() { result = getExpression().getFirstControlFlowNode() } + + override DataFlow::Node getDefaultNode() { result = DataFlow::valueNode(this) } } /** A literal path expression appearing in an external module reference. */ diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index f308bb0bf5a..edd72ee0e40 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -461,37 +461,9 @@ module ModuleImportNode { string path; DefaultRange() { - // `require("http")` - exists(Require req | req.getImportedPath().getValue() = path | - this = DataFlow::valueNode(req) - ) - or - // `import http = require("http")` - exists(ExternalModuleReference req | req.getImportedPath().getValue() = path | - this = DataFlow::valueNode(req) - ) - or - // `import * as http from 'http'` or `import http from `http`' - exists(ImportDeclaration id, ImportSpecifier is | - id.getImportedPath().getValue() = path and - is = id.getASpecifier() and - this = DataFlow::ssaDefinitionNode(SSA::definition(is)) - | - is instanceof ImportNamespaceSpecifier and - count(id.getASpecifier()) = 1 - or - is.getImportedName() = "default" - ) - or - // `import { createServer } from 'http'` - exists(ImportDeclaration id | - this = DataFlow::destructuredModuleImportNode(id) and - id.getImportedPath().getValue() = path - ) - or - // declared AMD dependency - exists(AmdModuleDefinition amd | - this = DataFlow::parameterNode(amd.getDependencyParameter(path)) + exists(Import i | + this = i.getDefaultNode() and + i.getImportedPath().getValue() = path ) or // AMD require