Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ class CdsServeCall extends DataFlow::CallNode {

Expr getServiceRepresentation() { result = serviceRepresentation }

UserDefinedApplicationService getServiceDefinition() {
ServiceInstance getServiceDefinition() {
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
/* 1. The argument to cds.serve is "all" */
this.getServiceRepresentation().getStringValue() = "all" and
result = any(UserDefinedApplicationService service)
or
/* 2. The argument to cds.serve is a name of the service */
result.getUnqualifiedName() = this.getServiceRepresentation().getStringValue()
result.(UserDefinedApplicationService).getUnqualifiedName() =
this.getServiceRepresentation().getStringValue()
or
/* 3. The argument to cds.serve is a name by which the service is required */
exists(RequiredService requiredService |
Expand Down Expand Up @@ -217,27 +218,28 @@ class CdsServeWithCall extends MethodCallNode {
*/
class ServiceInstanceFromServeWithParameter extends ServiceInstance {
CdsServeCall cdsServe;
CdsServeWithCall cdsServeWith;

ServiceInstanceFromServeWithParameter() {
exists(CdsServeWithCall cdsServeWith |
/*
* cds.serve('./srv/some-service1').with ((srv) => { // Parameter `srv` is captured.
* srv.on ('READ','SomeEntity1', (req) => req.reply([...]))
* })
*/
/*
* cds.serve('./srv/some-service1').with ((srv) => { // Parameter `srv` is captured.
* srv.on ('READ','SomeEntity1', (req) => req.reply([...]))
* })
*/

this.(ThisNode).getBinder().asExpr() = cdsServeWith.getDecorator().(FunctionExpr)
or
/*
* cds.serve('./srv/some-service2').with (function() { // Parameter `this` is captured.
* this.on ('READ','SomeEntity2', (req) => req.reply([...]))
* })
*/
this.(ThisNode).getBinder().asExpr() = cdsServeWith.getDecorator().(FunctionExpr)
or
/*
* cds.serve('./srv/some-service2').with (function() { // Parameter `this` is captured.
* this.on ('READ','SomeEntity2', (req) => req.reply([...]))
* })
*/

this = cdsServeWith.getDecorator().(ArrowFunctionExpr).getParameter(0).flow()
)
this = cdsServeWith.getDecorator().(ArrowFunctionExpr).getParameter(0).flow()
}

HandlerRegistration getAHandlerRegistration() { result = cdsServeWith.getAHandlerRegistration() }

override UserDefinedApplicationService getDefinition() {
/* 1. The argument to cds.serve is "all" */
cdsServe.getServiceRepresentation().getStringValue() = "all" and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import advanced_security.javascript.frameworks.cap.CDS
* SomeService.after("SomeEvent", "SomeEntity", (msg) => { ... });
* ```
* All the parameters named `req` and `msg` are captured in the above example.
*
* REQUIRES that a `UserDefinedApplicationService` is explicitly defined
*/
class HandlerParameter extends ParameterNode, RemoteFlowSource {
Handler handler;
Expand Down Expand Up @@ -49,9 +51,11 @@ class HandlerParameter extends ParameterNode, RemoteFlowSource {
* }
* ```
* parameters named `req` are captured in the above example.
*
* REQUIRES that a cds file has compiled AND that a service name is explicitly provided in the handler registration
*/
class ServiceinCDSHandlerParameter extends ParameterNode, RemoteFlowSource {
ServiceinCDSHandlerParameter() {
class ServiceinCDSHandlerParameterWithName extends ParameterNode, RemoteFlowSource {
ServiceinCDSHandlerParameterWithName() {
exists(MethodCallNode m, CdlEntity entity, string entityName |
entity.getName().regexpReplaceAll(".*\\.", "") = entityName and
m.getArgument(1).asExpr().getStringValue().regexpReplaceAll("'", "") = entityName and
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
Expand All @@ -64,3 +68,46 @@ class ServiceinCDSHandlerParameter extends ParameterNode, RemoteFlowSource {
result = "Parameter of an event handler belonging to an exposed service defined in a cds file"
}
}

/**
* A parameter of a handler registered for a service on an event. e.g.
* ```javascript
* cds.serve('./test-service').with((srv) => {
* srv.before('READ', '*', (req) => req.reply([]))
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
* })
* ```
* The parameter named `req` is captured in the above example.
*
* DOES NOT REQUIRE that a `UserDefinedApplicationService` is explicitly defined
* DOES NOT REQUIRE that the name is provided explicitly
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
*/
class HandlerParameterImplicitService extends ParameterNode, RemoteFlowSource {
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
Handler handler;
HandlerRegistration handlerRegistration;

HandlerParameterImplicitService() {
exists(ServiceInstanceFromServeWithParameter service |
handler = handlerRegistration.getHandler() and
this = handler.getParameter(0) and
service.getAHandlerRegistration() = handlerRegistration and
//this will otherwise duplicate on the case where we do actually know the
//name from the cds file and it matches up
//only relevant if you are using the specific type anyhow (as opposed to RemoteFlowSource)
not this instanceof ServiceinCDSHandlerParameterWithName
Comment thread
knewbury01 marked this conversation as resolved.
Outdated
)
}

override string getSourceType() {
result = "Parameter of an event handler belonging to an implicitly defined service"
}

/**
* Gets the handler this is a parameter of.
*/
Handler getHandler() { result = handler }

/**
* Gets the handler registration registering the handler it is a parameter of.
*/
HandlerRegistration getHandlerRegistration() { result = handlerRegistration }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import javascript
import advanced_security.javascript.frameworks.cap.RemoteFlowSources

from RemoteFlowSource source
select source
select source
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//this service unit test is a replica of requesthandler.js
const cds = require("@sap/cds");
class BooksService extends cds.ApplicationService {
init() {
const { Books, Authors } = this.entities
this.on('READ', [Books, Authors], req => req.target.data) //req
this.on('UPDATE', Books, req => { //req
let [ID] = req.params
return Object.assign(Books.data[ID], req.data)
})
this.after('READ', req => req.target.data) //req
this.before('*', req => req.target.data) //req
return super.init()
}
}
module.exports = BooksService

cds.serve('./test-service').with((srv) => {
srv.before('READ', 'Books', (req) => req.reply([])) //req
})

cds.serve('./test-service').with((srv) => {
srv.before('READ', 'Test', (req) => req.reply([])) //req
})
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
| requesthandler.js:5:43:5:45 | req |
| requesthandler.js:6:34:6:36 | req |
| requesthandler.js:16:34:16:36 | req |
| requesthandler.js:10:28:10:30 | req |
| requesthandler.js:11:26:11:28 | req |
| requesthandler.js:18:34:18:36 | req |
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class BooksService extends cds.ApplicationService {
let [ID] = req.params
return Object.assign(Books.data[ID], req.data)
})
this.after('READ', req => req.target.data)
this.before('*', req => req.target.data)
return super.init()
}
}
Expand Down
Loading