Skip to content

Commit

Permalink
Merge pull request #11146 from mbaluda-org/main
Browse files Browse the repository at this point in the history
JS: Improved Hapi support
  • Loading branch information
erik-krogh authored Nov 17, 2022
2 parents a6f6936 + a7dc29b commit ba894e2
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 4 deletions.
37 changes: 33 additions & 4 deletions javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,28 @@ module Hapi {
/**
* An expression that creates a new Hapi server.
*/
class ServerDefinition extends Http::Servers::StandardServerDefinition, DataFlow::NewNode {
class ServerDefinition extends Http::Servers::StandardServerDefinition, DataFlow::Node {
ServerDefinition() {
// `server = new Hapi.Server()`
this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation()
or
// `server = Glue.compose(manifest, composeOptions)`
this = DataFlow::moduleMember("@hapi/glue", "compose").getAnInvocation()
or
// `register (server, options)`
// `module.exports.plugin = {register, pkg};`
this =
any(Module m)
.getAnExportedValue("plugin")
.getALocalSource()
.getAPropertySource("register")
.getAFunctionValue()
.getParameter(0)
or
// `const after = function (server) {...};`
// `server.dependency('name', after);`
this =
any(ServerDefinition s).ref().getAMethodCall("dependency").getABoundCallbackParameter(1, 0)
}
}

Expand Down Expand Up @@ -123,15 +141,15 @@ module Hapi {
kind = "parameter" and
exists(DataFlow::PropRead query |
// `request.query.name`
query.accesses(request, "query") and
query.accesses(request, ["query", "params"]) and
this.(DataFlow::PropRead).accesses(query, _)
)
or
exists(DataFlow::PropRead url |
// `request.url.path`
kind = "url" and
url.accesses(request, "url") and
this.(DataFlow::PropRead).accesses(url, "path")
this.(DataFlow::PropRead).accesses(url, ["path", "origin"])
)
or
exists(DataFlow::PropRead state |
Expand Down Expand Up @@ -209,6 +227,17 @@ module Hapi {
// server.ext('/', fun)
this.getMethodName() = "ext" and
handler = this.getArgument(1)
or
// server.route([{ handler(request){}])
this.getMethodName() = "route" and
handler =
this.getArgument(0)
.getALocalSource()
.(DataFlow::ArrayCreationNode)
.getAnElement()
.getALocalSource()
.getAPropertySource("handler")
.getAFunctionValue()
)
}

Expand Down Expand Up @@ -240,7 +269,7 @@ module Hapi {
RouteHandlerCandidate() {
exists(string request, string responseToolkit |
(request = "request" or request = "req") and
responseToolkit = "h" and
responseToolkit = ["h", "hapi"] and
// heuristic: parameter names match the Hapi documentation
astNode.getNumParameter() = 2 and
astNode.getParameter(0).getName() = request and
Expand Down
4 changes: 4 additions & 0 deletions javascript/ql/src/change-notes/2022-11-08-hapi-glue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for @hapi/glue and Hapi plugins to the frameworks/Hapi.qll library.
50 changes: 50 additions & 0 deletions javascript/ql/test/library-tests/frameworks/hapi/src/hapiglue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
var server1 = new (require('@hapi/glue')).compose(require("./manifest"), composeOptions); // test_ServerDefinition

var Hapi = require('@hapi/glue');
var server2 = new Hapi.compose(require("./manifest"), composeOptions); // test_ServerDefinition

function handler1(){} // HTTP::RouteHandler
server2.route({
handler: handler1
});


server2.route({
handler: function handler2(request, reply){ // HTTP::RouteHandler
request.response.header('HEADER1', '') // HTTP::HeaderDefinition
}});

server2.ext('onPreResponse', function handler3(request, reply) { // HTTP::RouteHandler
})

function handler4(request, reply){
request.rawPayload;
request.payload.foo;
request.query.bar;
request.params.bar;
request.url.path;
request.url.origin;
request.headers.baz;
request.state.token;
}
var route = {handler: handler4};
server2.route(route);

server2.cache({ segment: 'countries', expiresIn: 60*60*1000 });

function getHandler() {
return function (req, hapi){}
}
server2.route({handler: getHandler()});

function after(server) {
};

function register(server, options) {// test_ServerDefinition
server.dependency(options.dependencies, server_ => after(server_, options)); // test_ServerDefinition
}

module.exports.plugin = {
register,
pkg
};
70 changes: 70 additions & 0 deletions javascript/ql/test/library-tests/frameworks/hapi/tests.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,62 @@ test_RouteSetup
| src/hapi.js:17:1:18:2 | server2 ... dler\\n}) |
| src/hapi.js:29:1:29:20 | server2.route(route) |
| src/hapi.js:36:1:36:38 | server2 ... ler()}) |
| src/hapiglue.js:7:1:9:2 | server2 ... ler1\\n}) |
| src/hapiglue.js:12:1:15:7 | server2 ... }}) |
| src/hapiglue.js:17:1:18:2 | server2 ... dler\\n}) |
| src/hapiglue.js:31:1:31:20 | server2.route(route) |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) |
test_RequestInputAccess
| src/hapi.js:21:3:21:20 | request.rawPayload | body | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:22:3:22:21 | request.payload.foo | body | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:23:3:23:19 | request.query.bar | parameter | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:24:3:24:18 | request.url.path | url | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:25:3:25:21 | request.headers.baz | header | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:26:3:26:21 | request.state.token | cookie | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapiglue.js:21:3:21:20 | request.rawPayload | body | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:22:3:22:21 | request.payload.foo | body | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:23:3:23:19 | request.query.bar | parameter | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:24:3:24:20 | request.params.bar | parameter | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:25:3:25:18 | request.url.path | url | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:26:3:26:20 | request.url.origin | url | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:27:3:27:21 | request.headers.baz | header | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:28:3:28:21 | request.state.token | cookie | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
test_RouteHandler_getAResponseHeader
| src/hapi.js:13:14:15:5 | functio ... n\\n } | header1 | src/hapi.js:14:9:14:46 | request ... 1', '') |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | header1 | src/hapiglue.js:14:9:14:46 | request ... 1', '') |
test_HeaderDefinition_defines
| src/hapi.js:14:9:14:46 | request ... 1', '') | header1 | |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | header1 | |
test_ResponseExpr
| src/hapi.js:14:9:14:24 | request.response | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:14:9:14:24 | request.response | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
test_HeaderDefinition
| src/hapi.js:14:9:14:46 | request ... 1', '') | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
test_RouteSetup_getServer
| src/hapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:12:1:15:7 | server2 ... }}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:17:1:18:2 | server2 ... dler\\n}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:29:1:29:20 | server2.route(route) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:36:1:36:38 | server2 ... ler()}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapiglue.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:12:1:15:7 | server2 ... }}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:17:1:18:2 | server2 ... dler\\n}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:31:1:31:20 | server2.route(route) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
test_HeaderDefinition_getAHeaderName
| src/hapi.js:14:9:14:46 | request ... 1', '') | header1 |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | header1 |
test_ServerDefinition
| src/hapi.js:1:15:1:44 | new (re ... erver() |
| src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapiglue.js:1:15:1:88 | new (re ... ptions) |
| src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:43:19:43:24 | server |
| src/hapiglue.js:44:45:44:51 | server_ |
test_HeaderAccess
| src/hapi.js:25:3:25:21 | request.headers.baz | baz |
| src/hapiglue.js:27:3:27:21 | request.headers.baz | baz |
test_RouteSetup_getARouteHandler
| src/hapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapi.js:6:1:6:21 | functio ... er1(){} |
| src/hapi.js:12:1:15:7 | server2 ... }}) | src/hapi.js:13:14:15:5 | functio ... n\\n } |
Expand All @@ -40,12 +68,24 @@ test_RouteSetup_getARouteHandler
| src/hapi.js:36:1:36:38 | server2 ... ler()}) | src/hapi.js:33:1:35:1 | return of function getHandler |
| src/hapi.js:36:1:36:38 | server2 ... ler()}) | src/hapi.js:34:12:34:30 | function (req, h){} |
| src/hapi.js:36:1:36:38 | server2 ... ler()}) | src/hapi.js:36:25:36:36 | getHandler() |
| src/hapiglue.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapiglue.js:6:1:6:21 | functio ... er1(){} |
| src/hapiglue.js:12:1:15:7 | server2 ... }}) | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:17:1:18:2 | server2 ... dler\\n}) | src/hapiglue.js:17:30:18:1 | functio ... ndler\\n} |
| src/hapiglue.js:31:1:31:20 | server2.route(route) | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:35:1:37:1 | return of function getHandler |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:36:12:36:33 | functio ... hapi){} |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:38:25:38:36 | getHandler() |
test_RouteHandler
| src/hapi.js:6:1:6:21 | functio ... er1(){} | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:17:30:18:1 | functio ... ndler\\n} | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:34:12:34:30 | function (req, h){} | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapiglue.js:6:1:6:21 | functio ... er1(){} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:17:30:18:1 | functio ... ndler\\n} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:36:12:36:33 | functio ... hapi){} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
test_RequestExpr
| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } |
Expand All @@ -60,6 +100,21 @@ test_RequestExpr
| src/hapi.js:25:3:25:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:26:3:26:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:34:22:34:24 | req | src/hapi.js:34:12:34:30 | function (req, h){} |
| src/hapiglue.js:13:32:13:38 | request | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:13:32:13:38 | request | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:14:9:14:15 | request | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:17:48:17:54 | request | src/hapiglue.js:17:30:18:1 | functio ... ndler\\n} |
| src/hapiglue.js:20:19:20:25 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:20:19:20:25 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:21:3:21:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:22:3:22:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:23:3:23:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:24:3:24:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:25:3:25:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:26:3:26:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:27:3:27:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:28:3:28:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:36:22:36:24 | req | src/hapiglue.js:36:12:36:33 | functio ... hapi){} |
test_RouteHandler_getARequestExpr
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request |
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request |
Expand All @@ -74,3 +129,18 @@ test_RouteHandler_getARequestExpr
| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:25:3:25:9 | request |
| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:26:3:26:9 | request |
| src/hapi.js:34:12:34:30 | function (req, h){} | src/hapi.js:34:22:34:24 | req |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | src/hapiglue.js:13:32:13:38 | request |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | src/hapiglue.js:13:32:13:38 | request |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | src/hapiglue.js:14:9:14:15 | request |
| src/hapiglue.js:17:30:18:1 | functio ... ndler\\n} | src/hapiglue.js:17:48:17:54 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:20:19:20:25 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:20:19:20:25 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:21:3:21:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:22:3:22:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:23:3:23:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:24:3:24:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:25:3:25:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:26:3:26:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:27:3:27:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:28:3:28:9 | request |
| src/hapiglue.js:36:12:36:33 | functio ... hapi){} | src/hapiglue.js:36:22:36:24 | req |

0 comments on commit ba894e2

Please sign in to comment.