mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #241 from asger-semmle/host-header-forgery
JS: Add HostHeaderPoisoningInEmailGeneration query
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens.
|
||||
A malicious user can send an HTTP request to the targeted web site, but with a Host header that refers to his own web site.
|
||||
This means the emails will be sent out to potential victims, originating from a server they trust, but with
|
||||
links leading to a malicious web site.
|
||||
</p>
|
||||
<p>
|
||||
If the email contains a password reset link, and should the victim click the link, the secret reset token will be leaked to the attacker.
|
||||
Using the leaked token, the attacker can then construct the real reset link and use it to change the victim's password.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Obtain the server's host name from a configuration file and avoid relying on the Host header.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example uses the <code>req.host</code> to generate a password reset link.
|
||||
This value is derived from the Host header, and can thus be set to anything by an attacker:
|
||||
</p>
|
||||
<sample src="examples/HostHeaderPoisoningInEmailGeneration.js"/>
|
||||
|
||||
<p>
|
||||
To ensure the link refers to the correct web site, get the host name from a configuration file:
|
||||
</p>
|
||||
<sample src="examples/HostHeaderPoisoningInEmailGenerationGood.js"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Mitre:
|
||||
<a href="https://cwe.mitre.org/data/definitions/640.html">CWE-640: Weak Password Recovery Mechanism for Forgotten Password</a>.
|
||||
</li>
|
||||
<li>
|
||||
Ian Muscat:
|
||||
<a href="https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/">What is a Host Header Attack?</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @name Host header poisoning in email generation
|
||||
* @description Using the HTTP Host header to construct a link in an email can facilitate phishing attacks and leak password reset tokens.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id js/host-header-forgery-in-email-generation
|
||||
* @tags security
|
||||
* external/cwe/cwe-640
|
||||
*/
|
||||
import javascript
|
||||
|
||||
class TaintedHostHeader extends TaintTracking::Configuration {
|
||||
TaintedHostHeader() { this = "TaintedHostHeader" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
exists (HTTP::RequestHeaderAccess input | node = input |
|
||||
input.getKind() = "header" and
|
||||
input.getAHeaderName() = "host")
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
exists (EmailSender email | node = email.getABody())
|
||||
}
|
||||
}
|
||||
|
||||
from TaintedHostHeader taint, DataFlow::Node src, DataFlow::Node sink
|
||||
where taint.hasFlow(src, sink)
|
||||
select sink, "Links in this email can be hijacked by poisoning the HTTP host header $@.", src, "here"
|
||||
@@ -0,0 +1,19 @@
|
||||
let nodemailer = require('nodemailer');
|
||||
let express = require('express');
|
||||
let backend = require('./backend');
|
||||
|
||||
let app = express();
|
||||
|
||||
let config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
|
||||
|
||||
app.post('/resetpass', (req, res) => {
|
||||
let email = req.query.email;
|
||||
let transport = nodemailer.createTransport(config.smtp);
|
||||
let token = backend.getUserSecretResetToken(email);
|
||||
transport.sendMail({
|
||||
from: 'webmaster@example.com',
|
||||
to: email,
|
||||
subject: 'Forgot password',
|
||||
text: `Click to reset password: https://${req.host}/resettoken/${token}`,
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
let nodemailer = require('nodemailer');
|
||||
let express = require('express');
|
||||
let backend = require('./backend');
|
||||
|
||||
let app = express();
|
||||
|
||||
let config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
|
||||
|
||||
app.post('/resetpass', (req, res) => {
|
||||
let email = req.query.email;
|
||||
let transport = nodemailer.createTransport(config.smtp);
|
||||
let token = backend.getUserSecretResetToken(email);
|
||||
transport.sendMail({
|
||||
from: 'webmaster@example.com',
|
||||
to: email,
|
||||
subject: 'Forgot password',
|
||||
text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,7 @@ import semmle.javascript.Constants
|
||||
import semmle.javascript.DataFlow
|
||||
import semmle.javascript.DefUse
|
||||
import semmle.javascript.DOM
|
||||
import semmle.javascript.EmailClients
|
||||
import semmle.javascript.Errors
|
||||
import semmle.javascript.ES2015Modules
|
||||
import semmle.javascript.Expr
|
||||
|
||||
68
javascript/ql/src/semmle/javascript/EmailClients.qll
Normal file
68
javascript/ql/src/semmle/javascript/EmailClients.qll
Normal file
@@ -0,0 +1,68 @@
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* An operation that sends an email.
|
||||
*/
|
||||
abstract class EmailSender extends DataFlow::DefaultSourceNode {
|
||||
/**
|
||||
* Gets a data flow node holding the plaintext version of the email body.
|
||||
*/
|
||||
abstract DataFlow::Node getPlainTextBody();
|
||||
|
||||
/**
|
||||
* Gets a data flow node holding the HTML body of the email.
|
||||
*/
|
||||
abstract DataFlow::Node getHtmlBody();
|
||||
|
||||
/**
|
||||
* Gets a data flow node holding the address of the email recipient(s).
|
||||
*/
|
||||
abstract DataFlow::Node getTo();
|
||||
|
||||
/**
|
||||
* Gets a data flow node holding the address of the email sender.
|
||||
*/
|
||||
abstract DataFlow::Node getFrom();
|
||||
|
||||
/**
|
||||
* Gets a data flow node holding the email subject.
|
||||
*/
|
||||
abstract DataFlow::Node getSubject();
|
||||
|
||||
/**
|
||||
* Gets a data flow node that refers to the HTML body or plaintext body of the email.
|
||||
*/
|
||||
DataFlow::Node getABody() {
|
||||
result = getPlainTextBody() or
|
||||
result = getHtmlBody()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An email-sending call based on the `nodemailer` package.
|
||||
*/
|
||||
private class NodemailerEmailSender extends EmailSender, DataFlow::MethodCallNode {
|
||||
NodemailerEmailSender() {
|
||||
this = DataFlow::moduleMember("nodemailer", "createTransport").getACall().getAMethodCall("sendMail")
|
||||
}
|
||||
|
||||
override DataFlow::Node getPlainTextBody() {
|
||||
result = getOptionArgument(0, "text")
|
||||
}
|
||||
|
||||
override DataFlow::Node getHtmlBody() {
|
||||
result = getOptionArgument(0, "html")
|
||||
}
|
||||
|
||||
override DataFlow::Node getTo() {
|
||||
result = getOptionArgument(0, "to")
|
||||
}
|
||||
|
||||
override DataFlow::Node getFrom() {
|
||||
result = getOptionArgument(0, "from")
|
||||
}
|
||||
|
||||
override DataFlow::Node getSubject() {
|
||||
result = getOptionArgument(0, "subject")
|
||||
}
|
||||
}
|
||||
@@ -471,29 +471,14 @@ module Express {
|
||||
propName = "originalUrl"
|
||||
)
|
||||
or
|
||||
exists (string methodName |
|
||||
// `req.get(...)` or `req.header(...)`
|
||||
kind = "header" and
|
||||
this.(DataFlow::MethodCallNode).calls(request, methodName) |
|
||||
methodName = "get" or
|
||||
methodName = "header"
|
||||
)
|
||||
or
|
||||
exists (DataFlow::PropRead headers |
|
||||
// `req.headers.name`
|
||||
kind = "header" and
|
||||
headers.accesses(request, "headers") and
|
||||
this = headers.getAPropertyRead())
|
||||
or
|
||||
exists (string propName | propName = "host" or propName = "hostname" |
|
||||
// `req.host` and `req.hostname` are derived from headers
|
||||
kind = "header" and
|
||||
this.(DataFlow::PropRead).accesses(request, propName))
|
||||
or
|
||||
// `req.cookies`
|
||||
kind = "cookie" and
|
||||
this.(DataFlow::PropRef).accesses(request, "cookies")
|
||||
)
|
||||
or
|
||||
exists (RequestHeaderAccess access | this = access |
|
||||
rh = access.getRouteHandler() and
|
||||
kind = "header")
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
@@ -505,6 +490,53 @@ module Express {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to a header on an Express request.
|
||||
*/
|
||||
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
|
||||
RouteHandler rh;
|
||||
|
||||
RequestHeaderAccess() {
|
||||
exists (DataFlow::Node request | request = DataFlow::valueNode(rh.getARequestExpr()) |
|
||||
exists (string methodName |
|
||||
// `req.get(...)` or `req.header(...)`
|
||||
this.(DataFlow::MethodCallNode).calls(request, methodName) |
|
||||
methodName = "get" or
|
||||
methodName = "header"
|
||||
)
|
||||
or
|
||||
exists (DataFlow::PropRead headers |
|
||||
// `req.headers.name`
|
||||
headers.accesses(request, "headers") and
|
||||
this = headers.getAPropertyRead())
|
||||
or
|
||||
exists (string propName | propName = "host" or propName = "hostname" |
|
||||
// `req.host` and `req.hostname` are derived from headers
|
||||
this.(DataFlow::PropRead).accesses(request, propName))
|
||||
)
|
||||
}
|
||||
|
||||
override string getAHeaderName() {
|
||||
exists (string name |
|
||||
name = this.(DataFlow::PropRead).getPropertyName()
|
||||
or
|
||||
this.(DataFlow::CallNode).getArgument(0).mayHaveStringValue(name)
|
||||
|
|
||||
if name = "hostname" then
|
||||
result = "host"
|
||||
else
|
||||
result = name.toLowerCase())
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = rh
|
||||
}
|
||||
|
||||
override string getKind() {
|
||||
result = "header"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP headers created by Express calls
|
||||
*/
|
||||
@@ -600,9 +632,9 @@ module Express {
|
||||
astNode.getMethodName() = any(string n | n = "set" or n = "header") and
|
||||
astNode.getNumArgument() = 1
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a reference to the multiple headers object that is to be set.
|
||||
* Gets a reference to the multiple headers object that is to be set.
|
||||
*/
|
||||
private DataFlow::SourceNode getAHeaderSource() {
|
||||
result.flowsToExpr(astNode.getArgument(0))
|
||||
@@ -618,12 +650,12 @@ module Express {
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = rh
|
||||
}
|
||||
|
||||
|
||||
override Expr getNameExpr() {
|
||||
exists (DataFlow::PropWrite write |
|
||||
exists (DataFlow::PropWrite write |
|
||||
getAHeaderSource().flowsTo(write.getBase()) and
|
||||
result = write.getPropertyNameExpr()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,9 +72,9 @@ module HTTP {
|
||||
* Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`.
|
||||
*/
|
||||
abstract predicate definesExplicitly(string headerName, Expr headerValue);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the expression used to compute the header name.
|
||||
* Returns the expression used to compute the header name.
|
||||
*/
|
||||
abstract Expr getNameExpr();
|
||||
}
|
||||
@@ -354,9 +354,9 @@ module HTTP {
|
||||
headerName = getNameExpr().getStringValue().toLowerCase() and
|
||||
headerValue = astNode.getArgument(1)
|
||||
}
|
||||
|
||||
|
||||
override Expr getNameExpr() {
|
||||
result = astNode.getArgument(0)
|
||||
result = astNode.getArgument(0)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -400,7 +400,20 @@ module HTTP {
|
||||
*/
|
||||
abstract string getKind();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An access to a header on an incoming HTTP request.
|
||||
*/
|
||||
abstract class RequestHeaderAccess extends RequestInputAccess {
|
||||
/**
|
||||
* Gets the lower-case name of an HTTP header from which this input is derived,
|
||||
* if this can be determined.
|
||||
*
|
||||
* When the name of the header is unknown, this has no result.
|
||||
*/
|
||||
abstract string getAHeaderName();
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that looks like a route setup on a server.
|
||||
*
|
||||
|
||||
@@ -121,13 +121,6 @@ module Hapi {
|
||||
this.asExpr().(PropAccess).accesses(url, "path")
|
||||
)
|
||||
or
|
||||
exists (PropAccess headers |
|
||||
// `request.headers.<name>`
|
||||
kind = "header" and
|
||||
headers.accesses(request, "headers") and
|
||||
this.asExpr().(PropAccess).accesses(headers, _)
|
||||
)
|
||||
or
|
||||
exists (PropAccess state |
|
||||
// `request.state.<name>`
|
||||
kind = "cookie" and
|
||||
@@ -135,6 +128,10 @@ module Hapi {
|
||||
this.asExpr().(PropAccess).accesses(state, _)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists (RequestHeaderAccess access | this = access |
|
||||
rh = access.getRouteHandler() and
|
||||
kind = "header")
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
@@ -146,6 +143,35 @@ module Hapi {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to an HTTP header on a Hapi request.
|
||||
*/
|
||||
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
|
||||
RouteHandler rh;
|
||||
|
||||
RequestHeaderAccess() {
|
||||
exists (Expr request | request = rh.getARequestExpr() |
|
||||
exists (PropAccess headers |
|
||||
// `request.headers.<name>`
|
||||
headers.accesses(request, "headers") and
|
||||
this.asExpr().(PropAccess).accesses(headers, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override string getAHeaderName() {
|
||||
result = this.(DataFlow::PropRead).getPropertyName().toLowerCase()
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = rh
|
||||
}
|
||||
|
||||
override string getKind() {
|
||||
result = "header"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An HTTP header defined in a Hapi server.
|
||||
*/
|
||||
|
||||
@@ -182,19 +182,6 @@ module Koa {
|
||||
propName = "originalUrl" or
|
||||
propName = "href"
|
||||
)
|
||||
or
|
||||
exists (string propName, PropAccess headers |
|
||||
// `ctx.request.header.<name>`, `ctx.request.headers.<name>`
|
||||
kind = "header" and
|
||||
headers.accesses(request, propName) and
|
||||
this.asExpr().(PropAccess).accesses(headers, _) |
|
||||
propName = "header" or
|
||||
propName = "headers"
|
||||
)
|
||||
or
|
||||
// `ctx.request.get(<name>)`
|
||||
kind = "header" and
|
||||
this.asExpr().(MethodCallExpr).calls(request, "get")
|
||||
)
|
||||
or
|
||||
exists (PropAccess cookies |
|
||||
@@ -203,6 +190,10 @@ module Koa {
|
||||
cookies.accesses(rh.getAContextExpr(), "cookies") and
|
||||
this.asExpr().(MethodCallExpr).calls(cookies, "get")
|
||||
)
|
||||
or
|
||||
exists (RequestHeaderAccess access | access = this |
|
||||
rh = access.getRouteHandler() and
|
||||
kind = "header")
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
@@ -214,6 +205,44 @@ module Koa {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to an HTTP header on a Koa request.
|
||||
*/
|
||||
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
|
||||
RouteHandler rh;
|
||||
|
||||
RequestHeaderAccess() {
|
||||
exists (Expr request | request = rh.getARequestExpr() |
|
||||
exists (string propName, PropAccess headers |
|
||||
// `ctx.request.header.<name>`, `ctx.request.headers.<name>`
|
||||
headers.accesses(request, propName) and
|
||||
this.asExpr().(PropAccess).accesses(headers, _) |
|
||||
propName = "header" or
|
||||
propName = "headers"
|
||||
)
|
||||
or
|
||||
// `ctx.request.get(<name>)`
|
||||
this.asExpr().(MethodCallExpr).calls(request, "get")
|
||||
)
|
||||
}
|
||||
|
||||
override string getAHeaderName() {
|
||||
result = this.(DataFlow::PropRead).getPropertyName().toLowerCase()
|
||||
or
|
||||
exists (string name |
|
||||
this.(DataFlow::CallNode).getArgument(0).mayHaveStringValue(name) and
|
||||
result = name.toLowerCase())
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = rh
|
||||
}
|
||||
|
||||
override string getKind() {
|
||||
result = "header"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a Koa method that sets up a route.
|
||||
*/
|
||||
|
||||
@@ -146,12 +146,16 @@ module NodeJSLib {
|
||||
kind = "url" and
|
||||
this.asExpr().(PropAccess).accesses(request, "url")
|
||||
or
|
||||
exists (PropAccess headers, string name |
|
||||
// `req.headers.<name>`
|
||||
if name = "cookie" then kind = "cookie" else kind= "header" |
|
||||
exists (PropAccess headers |
|
||||
// `req.headers.cookie`
|
||||
kind = "cookie" and
|
||||
headers.accesses(request, "headers") and
|
||||
this.asExpr().(PropAccess).accesses(headers, name)
|
||||
this.asExpr().(PropAccess).accesses(headers, "cookie")
|
||||
)
|
||||
or
|
||||
exists (RequestHeaderAccess access | this = access |
|
||||
request = access.getRequest() and
|
||||
kind = "header")
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
@@ -163,6 +167,38 @@ module NodeJSLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to an HTTP header (other than "Cookie") on an incoming Node.js request object.
|
||||
*/
|
||||
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
|
||||
RequestExpr request;
|
||||
|
||||
RequestHeaderAccess() {
|
||||
exists (PropAccess headers, string name |
|
||||
// `req.headers.<name>`
|
||||
name != "cookie" and
|
||||
headers.accesses(request, "headers") and
|
||||
this.asExpr().(PropAccess).accesses(headers, name)
|
||||
)
|
||||
}
|
||||
|
||||
override string getAHeaderName() {
|
||||
result = this.(DataFlow::PropRead).getPropertyName().toLowerCase()
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() {
|
||||
result = request.getRouteHandler()
|
||||
}
|
||||
|
||||
override string getKind() {
|
||||
result = "header"
|
||||
}
|
||||
|
||||
RequestExpr getRequest() {
|
||||
result = request
|
||||
}
|
||||
}
|
||||
|
||||
class RouteSetup extends CallExpr, HTTP::Servers::StandardRouteSetup {
|
||||
ServerDefinition server;
|
||||
Expr handler;
|
||||
@@ -380,7 +416,7 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A call to a method from module `child_process`.
|
||||
*/
|
||||
@@ -476,21 +512,21 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A call to a method from module `vm`
|
||||
*/
|
||||
class VmModuleMethodCall extends DataFlow::CallNode {
|
||||
string methodName;
|
||||
|
||||
|
||||
VmModuleMethodCall() {
|
||||
this = DataFlow::moduleMember("vm", methodName).getACall()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the code to be executed as part of this call.
|
||||
*/
|
||||
DataFlow::Node getACodeArgument() {
|
||||
DataFlow::Node getACodeArgument() {
|
||||
(
|
||||
methodName = "runInContext" or
|
||||
methodName = "runInNewContext" or
|
||||
@@ -543,7 +579,7 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A model of a URL request in the Node.js `http` library.
|
||||
*/
|
||||
@@ -569,7 +605,7 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the parameter of a result callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `https.request(url, (res) => {})`.
|
||||
*/
|
||||
@@ -579,12 +615,12 @@ module NodeJSLib {
|
||||
this = req.(DataFlow::MethodCallNode).getCallback(1).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "NodeJSClientRequest callback parameter"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the parameter of a data callback for an HTTP or HTTPS request made by a Node.js process, for example `body` in `http.request(url, (res) => {res.on('data', (body) => {})})`.
|
||||
*/
|
||||
@@ -596,20 +632,20 @@ module NodeJSLib {
|
||||
this = mcn.getCallback(1).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "http.request data parameter"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is registered as a callback for an HTTP or HTTPS request made by a Node.js process, for example the function `handler` in `http.request(url).on(message, handler)`.
|
||||
*/
|
||||
class ClientRequestHandler extends DataFlow::FunctionNode {
|
||||
string handledEvent;
|
||||
NodeJSClientRequest clientRequest;
|
||||
|
||||
|
||||
ClientRequestHandler() {
|
||||
exists(DataFlow::MethodCallNode mcn |
|
||||
clientRequest.getAMethodCall("on") = mcn and
|
||||
@@ -617,14 +653,14 @@ module NodeJSLib {
|
||||
flowsTo(mcn.getArgument(1))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the name of an event this callback is registered for.
|
||||
*/
|
||||
string getAHandledEvent() {
|
||||
result = handledEvent
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a request this callback is registered for.
|
||||
*/
|
||||
@@ -632,7 +668,7 @@ module NodeJSLib {
|
||||
result = clientRequest
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the parameter of a response callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `http.request(url).on('response', (res) => {})`.
|
||||
*/
|
||||
@@ -643,12 +679,12 @@ module NodeJSLib {
|
||||
handler.getAHandledEvent() = "response"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "NodeJSClientRequest response event"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the parameter of a data callback for an HTTP or HTTPS request made by a Node.js process, for example `chunk` in `http.request(url).on('response', (res) => {res.on('data', (chunk) => {})})`.
|
||||
*/
|
||||
@@ -660,12 +696,12 @@ module NodeJSLib {
|
||||
this = mcn.getCallback(1).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "NodeJSClientRequest data event"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is a login callback for an HTTP or HTTPS request made by a Node.js process.
|
||||
*/
|
||||
@@ -674,7 +710,7 @@ module NodeJSLib {
|
||||
getAHandledEvent() = "login"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is a parameter of a login callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `http.request(url).on('login', (res, callback) => {})`.
|
||||
*/
|
||||
@@ -684,12 +720,12 @@ module NodeJSLib {
|
||||
this = handler.getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "NodeJSClientRequest login event"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `callback` in `http.request(url).on('login', (res, callback) => {})`.
|
||||
*/
|
||||
@@ -700,7 +736,7 @@ module NodeJSLib {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the username passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `username` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
|
||||
*/
|
||||
@@ -710,14 +746,14 @@ module NodeJSLib {
|
||||
this = callback.getACall().getArgument(0).asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getCredentialsKind() {
|
||||
result = "Node.js http(s) client login username"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
|
||||
* A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
|
||||
*/
|
||||
private class ClientRequestLoginPassword extends CredentialsExpr {
|
||||
ClientRequestLoginPassword() {
|
||||
@@ -725,13 +761,13 @@ module NodeJSLib {
|
||||
this = callback.getACall().getArgument(1).asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getCredentialsKind() {
|
||||
result = "Node.js http(s) client login password"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A data flow node that is the parameter of an error callback for an HTTP or HTTPS request made by a Node.js process, for example `err` in `http.request(url).on('error', (err) => {})`.
|
||||
*/
|
||||
@@ -742,7 +778,7 @@ module NodeJSLib {
|
||||
handler.getAHandledEvent() = "error"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override string getSourceType() {
|
||||
result = "NodeJSClientRequest error event"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user