dd-trace 2.30.1 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -1
- package/esbuild.js +3 -0
- package/index.d.ts +10 -9
- package/package.json +12 -12
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-esbuild/index.js +9 -2
- package/packages/datadog-instrumentations/src/body-parser.js +15 -9
- package/packages/datadog-instrumentations/src/cucumber.js +11 -1
- package/packages/datadog-instrumentations/src/express.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/http/server.js +2 -1
- package/packages/datadog-instrumentations/src/jest.js +6 -3
- package/packages/datadog-instrumentations/src/mocha.js +19 -2
- package/packages/datadog-instrumentations/src/playwright.js +5 -2
- package/packages/datadog-plugin-amqp10/src/consumer.js +1 -3
- package/packages/datadog-plugin-amqp10/src/producer.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +4 -3
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -3
- package/packages/datadog-plugin-cucumber/src/index.js +6 -4
- package/packages/datadog-plugin-cypress/src/plugin.js +5 -1
- package/packages/datadog-plugin-cypress/src/support.js +4 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -3
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +2 -2
- package/packages/datadog-plugin-http2/src/server.js +0 -5
- package/packages/datadog-plugin-jest/src/index.js +10 -5
- package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -4
- package/packages/datadog-plugin-kafkajs/src/producer.js +1 -3
- package/packages/datadog-plugin-mocha/src/index.js +9 -4
- package/packages/datadog-plugin-playwright/src/index.js +6 -5
- package/packages/datadog-plugin-redis/src/index.js +16 -5
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
- package/packages/datadog-plugin-rhea/src/producer.js +1 -5
- package/packages/dd-trace/src/appsec/addresses.js +0 -3
- package/packages/dd-trace/src/appsec/blocked_templates.js +2 -9
- package/packages/dd-trace/src/appsec/blocking.js +1 -1
- package/packages/dd-trace/src/appsec/{gateway/channels.js → channels.js} +4 -4
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +21 -13
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/logs.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +87 -79
- package/packages/dd-trace/src/appsec/recommended.json +448 -121
- package/packages/dd-trace/src/appsec/remote_config/apply_states.js +7 -0
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +30 -11
- package/packages/dd-trace/src/appsec/remote_config/manager.js +33 -12
- package/packages/dd-trace/src/appsec/reporter.js +27 -58
- package/packages/dd-trace/src/appsec/rule_manager.js +160 -32
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -12
- package/packages/dd-trace/src/appsec/waf/index.js +75 -0
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +57 -0
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +66 -0
- package/packages/dd-trace/src/config.js +18 -1
- package/packages/dd-trace/src/dcitm.js +2 -0
- package/packages/dd-trace/src/encode/0.4.js +12 -4
- package/packages/dd-trace/src/encode/tags-processors.js +40 -68
- package/packages/dd-trace/src/exporters/common/request.js +2 -2
- package/packages/dd-trace/src/format.js +2 -1
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +11 -12
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/client.js +3 -2
- package/packages/dd-trace/src/plugins/consumer.js +17 -2
- package/packages/dd-trace/src/plugins/inbound.js +7 -0
- package/packages/dd-trace/src/plugins/{outgoing.js → outbound.js} +2 -2
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/producer.js +17 -2
- package/packages/dd-trace/src/plugins/server.js +2 -2
- package/packages/dd-trace/src/plugins/tracing.js +11 -0
- package/packages/dd-trace/src/plugins/util/test.js +19 -1
- package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/service-naming/index.js +41 -0
- package/packages/dd-trace/src/service-naming/schemas/definition.js +28 -0
- package/packages/dd-trace/src/service-naming/schemas/index.js +6 -0
- package/packages/dd-trace/src/service-naming/schemas/v0.js +66 -0
- package/packages/dd-trace/src/service-naming/schemas/v1.js +58 -0
- package/packages/dd-trace/src/span_stats.js +1 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/index.js +1 -1
- package/packages/diagnostics_channel/index.js +3 -0
- package/packages/diagnostics_channel/src/index.js +57 -0
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +0 -137
- package/packages/dd-trace/src/appsec/callbacks/index.js +0 -7
- package/packages/dd-trace/src/appsec/gateway/als.js +0 -6
- package/packages/dd-trace/src/appsec/gateway/engine/engine.js +0 -140
- package/packages/dd-trace/src/appsec/gateway/engine/index.js +0 -51
- package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -42
- package/packages/dd-trace/src/instrumenter.js +0 -203
- package/packages/dd-trace/src/loader.js +0 -131
- package/packages/dd-trace/src/plugins/incoming.js +0 -7
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { schemaDefinitions } = require('./schemas')
|
|
2
|
+
|
|
3
|
+
const kindMap = {
|
|
4
|
+
messaging: {
|
|
5
|
+
client: 'controlPlane',
|
|
6
|
+
consumer: 'inbound',
|
|
7
|
+
producer: 'outbound'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class SchemaManager {
|
|
12
|
+
constructor () {
|
|
13
|
+
this.schemas = schemaDefinitions
|
|
14
|
+
this.config = { spanAttributeSchema: 'v0' }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get schema () {
|
|
18
|
+
return this.schemas[this.version]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get version () {
|
|
22
|
+
return this.config.spanAttributeSchema
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
opName (type, kind, plugin, opNameArgs) {
|
|
26
|
+
return this.schema.getOpName(type, kindMap[type][kind], plugin, opNameArgs)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
serviceName (type, kind, plugin, serviceNameArgs) {
|
|
30
|
+
return this.schema.getServiceName(type, kindMap[type][kind], plugin, serviceNameArgs)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
configure (config = {}) {
|
|
34
|
+
this.config = config
|
|
35
|
+
Object.values(this.schemas).forEach(schemaDef => {
|
|
36
|
+
schemaDef.configure(config)
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = new SchemaManager()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class SchemaDefinition {
|
|
2
|
+
constructor (schema) {
|
|
3
|
+
this.schema = schema
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
getSchemaItem (type, subType, plugin) {
|
|
7
|
+
const schema = this.schema
|
|
8
|
+
if (schema && schema[type] && schema[type][subType] && schema[type][subType][plugin]) {
|
|
9
|
+
return schema[type][subType][plugin]
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getOpName (type, subType, plugin, opNameArgs) {
|
|
14
|
+
const item = this.getSchemaItem(type, subType, plugin)
|
|
15
|
+
return item.opName(opNameArgs)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getServiceName (type, subType, plugin, serviceNameArgs) {
|
|
19
|
+
const item = this.getSchemaItem(type, subType, plugin)
|
|
20
|
+
return item.serviceName(this.service, serviceNameArgs)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
configure ({ service }) {
|
|
24
|
+
this.service = service
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = SchemaDefinition
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const SchemaDefinition = require('./definition')
|
|
2
|
+
|
|
3
|
+
function amqpServiceName (service) {
|
|
4
|
+
return `${service}-amqp`
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const schema = {
|
|
8
|
+
messaging: {
|
|
9
|
+
outbound: {
|
|
10
|
+
amqplib: {
|
|
11
|
+
opName: () => 'amqp.command',
|
|
12
|
+
serviceName: amqpServiceName
|
|
13
|
+
},
|
|
14
|
+
amqp10: {
|
|
15
|
+
opName: () => 'amqp.send',
|
|
16
|
+
serviceName: amqpServiceName
|
|
17
|
+
},
|
|
18
|
+
'google-cloud-pubsub': {
|
|
19
|
+
opName: () => 'pubsub.request',
|
|
20
|
+
serviceName: service => `${service}-pubsub`
|
|
21
|
+
},
|
|
22
|
+
kafkajs: {
|
|
23
|
+
opName: () => 'kafka.produce',
|
|
24
|
+
serviceName: service => `${service}-kafka`
|
|
25
|
+
},
|
|
26
|
+
rhea: {
|
|
27
|
+
opName: () => 'amqp.send',
|
|
28
|
+
serviceName: service => `${service}-amqp-producer`
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
inbound: {
|
|
32
|
+
amqplib: {
|
|
33
|
+
opName: () => 'amqp.command',
|
|
34
|
+
serviceName: amqpServiceName
|
|
35
|
+
},
|
|
36
|
+
amqp10: {
|
|
37
|
+
opName: () => 'amqp.receive',
|
|
38
|
+
serviceName: amqpServiceName
|
|
39
|
+
},
|
|
40
|
+
'google-cloud-pubsub': {
|
|
41
|
+
opName: () => 'pubsub.receive',
|
|
42
|
+
serviceName: service => service
|
|
43
|
+
},
|
|
44
|
+
kafkajs: {
|
|
45
|
+
opName: () => 'kafka.consume',
|
|
46
|
+
serviceName: service => `${service}-kafka`
|
|
47
|
+
},
|
|
48
|
+
rhea: {
|
|
49
|
+
opName: () => 'amqp.receive',
|
|
50
|
+
serviceName: service => service
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
controlPlane: {
|
|
54
|
+
amqplib: {
|
|
55
|
+
opName: () => 'amqp.command',
|
|
56
|
+
serviceName: amqpServiceName
|
|
57
|
+
},
|
|
58
|
+
'google-cloud-pubsub': {
|
|
59
|
+
opName: () => 'pubsub.request',
|
|
60
|
+
serviceName: service => `${service}-pubsub`
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = new SchemaDefinition(schema)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const SchemaDefinition = require('./definition')
|
|
2
|
+
|
|
3
|
+
function identityService (service) {
|
|
4
|
+
return service
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const amqpInbound = {
|
|
8
|
+
opName: () => 'amqp.process',
|
|
9
|
+
serviceName: identityService
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const amqpOutbound = {
|
|
13
|
+
opName: () => 'amqp.send',
|
|
14
|
+
serviceName: identityService
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const schema = {
|
|
18
|
+
messaging: {
|
|
19
|
+
outbound: {
|
|
20
|
+
amqplib: amqpOutbound,
|
|
21
|
+
amqp10: amqpOutbound,
|
|
22
|
+
'google-cloud-pubsub': {
|
|
23
|
+
opName: () => 'gcp.pubsub.send',
|
|
24
|
+
serviceName: identityService
|
|
25
|
+
},
|
|
26
|
+
kafkajs: {
|
|
27
|
+
opName: () => 'kafka.send',
|
|
28
|
+
serviceName: identityService
|
|
29
|
+
},
|
|
30
|
+
rhea: amqpOutbound
|
|
31
|
+
},
|
|
32
|
+
inbound: {
|
|
33
|
+
amqplib: amqpInbound,
|
|
34
|
+
amqp10: amqpInbound,
|
|
35
|
+
'google-cloud-pubsub': {
|
|
36
|
+
opName: () => 'gcp.pubsub.process',
|
|
37
|
+
serviceName: identityService
|
|
38
|
+
},
|
|
39
|
+
kafkajs: {
|
|
40
|
+
opName: () => 'kafka.process',
|
|
41
|
+
serviceName: identityService
|
|
42
|
+
},
|
|
43
|
+
rhea: amqpInbound
|
|
44
|
+
},
|
|
45
|
+
controlPlane: {
|
|
46
|
+
amqplib: {
|
|
47
|
+
opName: () => 'amqp.command',
|
|
48
|
+
serviceName: identityService
|
|
49
|
+
},
|
|
50
|
+
'google-cloud-pubsub': {
|
|
51
|
+
opName: () => 'gcp.pubsub.request',
|
|
52
|
+
serviceName: identityService
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = new SchemaDefinition(schema)
|
|
@@ -4,7 +4,7 @@ const path = require('path')
|
|
|
4
4
|
const parse = require('module-details-from-path')
|
|
5
5
|
const requirePackageJson = require('../require-package-json')
|
|
6
6
|
const { sendData } = require('./send-data')
|
|
7
|
-
const dc = require('diagnostics_channel')
|
|
7
|
+
const dc = require('../../../diagnostics_channel')
|
|
8
8
|
const { fileURLToPath } = require('url')
|
|
9
9
|
|
|
10
10
|
const savedDependencies = new Set()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const tracerVersion = require('../../../../package.json').version
|
|
4
|
-
const dc = require('diagnostics_channel')
|
|
4
|
+
const dc = require('../../../diagnostics_channel')
|
|
5
5
|
const os = require('os')
|
|
6
6
|
const dependencies = require('./dependencies')
|
|
7
7
|
const { sendData } = require('./send-data')
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
Channel,
|
|
5
|
+
channel
|
|
6
|
+
} = require('diagnostics_channel') // eslint-disable-line n/no-restricted-require
|
|
7
|
+
|
|
8
|
+
const [major, minor] = process.versions.node.split('.')
|
|
9
|
+
const channels = new WeakSet()
|
|
10
|
+
|
|
11
|
+
// Our own DC with a limited subset of functionality stable across Node versions.
|
|
12
|
+
// TODO: Move the rest of the polyfill here.
|
|
13
|
+
// TODO: Switch to using global subscribe/unsubscribe/hasSubscribers.
|
|
14
|
+
const dc = { channel }
|
|
15
|
+
|
|
16
|
+
// Prevent going to 0 subscribers to avoid bug in Node.
|
|
17
|
+
// See https://github.com/nodejs/node/pull/47520
|
|
18
|
+
if (major === '19' && minor === '9') {
|
|
19
|
+
dc.channel = function () {
|
|
20
|
+
const ch = channel.apply(this, arguments)
|
|
21
|
+
|
|
22
|
+
if (!channels.has(ch)) {
|
|
23
|
+
const subscribe = ch.subscribe
|
|
24
|
+
const unsubscribe = ch.unsubscribe
|
|
25
|
+
|
|
26
|
+
ch.subscribe = function () {
|
|
27
|
+
delete ch.subscribe
|
|
28
|
+
delete ch.unsubscribe
|
|
29
|
+
|
|
30
|
+
const result = subscribe.apply(this, arguments)
|
|
31
|
+
|
|
32
|
+
this.subscribe(() => {}) // Keep it active forever.
|
|
33
|
+
|
|
34
|
+
return result
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (ch.unsubscribe === Channel.prototype.unsubscribe) {
|
|
38
|
+
// Needed because another subscriber could have subscribed to something
|
|
39
|
+
// that we unsubscribe to before the library is loaded.
|
|
40
|
+
ch.unsubscribe = function () {
|
|
41
|
+
delete ch.subscribe
|
|
42
|
+
delete ch.unsubscribe
|
|
43
|
+
|
|
44
|
+
this.subscribe(() => {}) // Keep it active forever.
|
|
45
|
+
|
|
46
|
+
return unsubscribe.apply(this, arguments)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
channels.add(ch)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return ch
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = dc
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const log = require('../../log')
|
|
4
|
-
const addresses = require('../addresses')
|
|
5
|
-
const Gateway = require('../gateway/engine')
|
|
6
|
-
const Reporter = require('../reporter')
|
|
7
|
-
|
|
8
|
-
const validAddressSet = new Set(Object.values(addresses))
|
|
9
|
-
|
|
10
|
-
// TODO: put reusable code in a base class
|
|
11
|
-
class WAFCallback {
|
|
12
|
-
static loadDDWAF (rules, config) {
|
|
13
|
-
try {
|
|
14
|
-
// require in `try/catch` because this can throw at require time
|
|
15
|
-
const { DDWAF } = require('@datadog/native-appsec')
|
|
16
|
-
|
|
17
|
-
return new DDWAF(rules, config)
|
|
18
|
-
} catch (err) {
|
|
19
|
-
log.error('AppSec could not load native package. In-app WAF features will not be available.')
|
|
20
|
-
|
|
21
|
-
throw err
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
constructor (rules, config) {
|
|
26
|
-
const { wafTimeout, obfuscatorKeyRegex, obfuscatorValueRegex } = config
|
|
27
|
-
|
|
28
|
-
this.ddwaf = WAFCallback.loadDDWAF(rules, { obfuscatorKeyRegex, obfuscatorValueRegex })
|
|
29
|
-
|
|
30
|
-
this.wafTimeout = wafTimeout
|
|
31
|
-
|
|
32
|
-
Reporter.metricsQueue.set('_dd.appsec.waf.version', this.ddwaf.constructor.version())
|
|
33
|
-
|
|
34
|
-
const { loaded, failed, errors } = this.ddwaf.rulesInfo
|
|
35
|
-
|
|
36
|
-
Reporter.metricsQueue.set('_dd.appsec.event_rules.loaded', loaded)
|
|
37
|
-
Reporter.metricsQueue.set('_dd.appsec.event_rules.error_count', failed)
|
|
38
|
-
if (failed) Reporter.metricsQueue.set('_dd.appsec.event_rules.errors', JSON.stringify(errors))
|
|
39
|
-
|
|
40
|
-
Reporter.metricsQueue.set('manual.keep', 'true')
|
|
41
|
-
|
|
42
|
-
this.wafContextCache = new WeakMap()
|
|
43
|
-
|
|
44
|
-
// closures are faster than binds
|
|
45
|
-
const self = this
|
|
46
|
-
const method = (params, store) => {
|
|
47
|
-
return self.action(params, store)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// might be its own class with more info later
|
|
51
|
-
const callback = { method }
|
|
52
|
-
|
|
53
|
-
const subscribedAddresses = new Set()
|
|
54
|
-
|
|
55
|
-
for (const rule of rules.rules) {
|
|
56
|
-
for (const condition of rule.conditions) {
|
|
57
|
-
for (const input of condition.parameters.inputs) {
|
|
58
|
-
const address = input.address.split(':', 2)[0]
|
|
59
|
-
|
|
60
|
-
if (!validAddressSet.has(address) || subscribedAddresses.has(address)) continue
|
|
61
|
-
|
|
62
|
-
subscribedAddresses.add(address)
|
|
63
|
-
|
|
64
|
-
Gateway.manager.addSubscription({ addresses: [address], callback })
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
action (params, store) {
|
|
71
|
-
let wafContext
|
|
72
|
-
|
|
73
|
-
if (store) {
|
|
74
|
-
const key = store.get('context')
|
|
75
|
-
|
|
76
|
-
if (key) {
|
|
77
|
-
if (this.wafContextCache.has(key)) {
|
|
78
|
-
wafContext = this.wafContextCache.get(key)
|
|
79
|
-
} else {
|
|
80
|
-
wafContext = this.ddwaf.createContext()
|
|
81
|
-
this.wafContextCache.set(key, wafContext)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!wafContext || wafContext.disposed) {
|
|
87
|
-
wafContext = this.ddwaf.createContext()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// cast status code to string
|
|
91
|
-
if (params[addresses.HTTP_INCOMING_RESPONSE_CODE]) {
|
|
92
|
-
params[addresses.HTTP_INCOMING_RESPONSE_CODE] = params[addresses.HTTP_INCOMING_RESPONSE_CODE] + ''
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
// TODO: possible optimizaion: only send params that haven't already been sent to this wafContext
|
|
97
|
-
const start = process.hrtime.bigint()
|
|
98
|
-
|
|
99
|
-
const result = wafContext.run(params, this.wafTimeout)
|
|
100
|
-
|
|
101
|
-
result.durationExt = parseInt(process.hrtime.bigint() - start)
|
|
102
|
-
|
|
103
|
-
return this.applyResult(result, store)
|
|
104
|
-
} catch (err) {
|
|
105
|
-
log.error('Error while running the AppSec WAF')
|
|
106
|
-
log.error(err)
|
|
107
|
-
} finally {
|
|
108
|
-
wafContext.dispose()
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
applyResult (result, store) {
|
|
113
|
-
Reporter.reportMetrics({
|
|
114
|
-
duration: result.totalRuntime / 1e3,
|
|
115
|
-
durationExt: result.durationExt / 1e3,
|
|
116
|
-
rulesVersion: this.ddwaf.rulesInfo.version
|
|
117
|
-
}, store)
|
|
118
|
-
|
|
119
|
-
if (result.data && result.data !== '[]') {
|
|
120
|
-
Reporter.reportAttack(result.data, store)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return result.actions
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
updateRuleData (ruleData) {
|
|
127
|
-
this.ddwaf.updateRuleData(ruleData)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
clear () {
|
|
131
|
-
this.ddwaf.dispose()
|
|
132
|
-
|
|
133
|
-
this.wafContextCache = new WeakMap()
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
module.exports = WAFCallback
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const Runner = require('./runner')
|
|
4
|
-
|
|
5
|
-
const MAX_CONTEXT_SIZE = 1024
|
|
6
|
-
|
|
7
|
-
class SubscriptionManager {
|
|
8
|
-
constructor () {
|
|
9
|
-
this.addressToSubscriptions = new Map()
|
|
10
|
-
this.addresses = new Set()
|
|
11
|
-
this.subscriptions = new Set()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
clear () {
|
|
15
|
-
this.addressToSubscriptions = new Map()
|
|
16
|
-
this.addresses = new Set()
|
|
17
|
-
this.subscriptions = new Set()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
addSubscription (subscription) {
|
|
21
|
-
if (!subscription.addresses.length || this.subscriptions.has(subscription)) return
|
|
22
|
-
|
|
23
|
-
for (let i = 0; i < subscription.addresses.length; ++i) {
|
|
24
|
-
const address = subscription.addresses[i]
|
|
25
|
-
|
|
26
|
-
this.addresses.add(address)
|
|
27
|
-
|
|
28
|
-
const list = this.addressToSubscriptions.get(address)
|
|
29
|
-
|
|
30
|
-
if (list === undefined) {
|
|
31
|
-
this.addressToSubscriptions.set(address, [subscription])
|
|
32
|
-
} else {
|
|
33
|
-
list.push(subscription)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
this.subscriptions.add(subscription)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
matchSubscriptions (newAddresses, allAddresses) {
|
|
41
|
-
const addresses = new Set()
|
|
42
|
-
const subscriptions = new Set()
|
|
43
|
-
const knownSubscriptions = new Set()
|
|
44
|
-
|
|
45
|
-
// TODO: possible optimization: collect matchedSubscriptions on the fly in Context#setValue
|
|
46
|
-
newAddresses.forEach((newAddress) => {
|
|
47
|
-
const matchedSubscriptions = this.addressToSubscriptions.get(newAddress)
|
|
48
|
-
|
|
49
|
-
if (matchedSubscriptions === undefined) return
|
|
50
|
-
|
|
51
|
-
for (let j = 0; j < matchedSubscriptions.length; ++j) {
|
|
52
|
-
const subscription = matchedSubscriptions[j]
|
|
53
|
-
|
|
54
|
-
if (knownSubscriptions.has(subscription) === true) continue
|
|
55
|
-
knownSubscriptions.add(subscription)
|
|
56
|
-
|
|
57
|
-
const isFulfilled = subscription.addresses.every(allAddresses.has, allAddresses)
|
|
58
|
-
|
|
59
|
-
if (isFulfilled === true) {
|
|
60
|
-
for (let k = 0; k < subscription.addresses.length; ++k) {
|
|
61
|
-
addresses.add(subscription.addresses[k])
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
subscriptions.add(subscription)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
return { addresses, subscriptions }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
dispatch (newAddresses, allAddresses, context) {
|
|
73
|
-
const matches = this.matchSubscriptions(newAddresses, allAddresses)
|
|
74
|
-
|
|
75
|
-
// TODO: possible optimization
|
|
76
|
-
// check if matches.subscriptions is empty here instead of in runner.js
|
|
77
|
-
|
|
78
|
-
const params = {}
|
|
79
|
-
|
|
80
|
-
matches.addresses.forEach((address) => {
|
|
81
|
-
params[address] = context.resolve(address)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
return Runner.runSubscriptions(matches.subscriptions, params)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
class Context {
|
|
89
|
-
static setManager (manager) {
|
|
90
|
-
this.manager = manager
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
constructor () {
|
|
94
|
-
// TODO: this probably don't need to be a Map()
|
|
95
|
-
this.store = new Map()
|
|
96
|
-
this.allAddresses = new Set()
|
|
97
|
-
this.newAddresses = new Set()
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
clear () {
|
|
101
|
-
this.store = new Map()
|
|
102
|
-
this.allAddresses = new Set()
|
|
103
|
-
this.newAddresses = new Set()
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
setValue (address, value) {
|
|
107
|
-
if (this.allAddresses.size >= MAX_CONTEXT_SIZE) return this
|
|
108
|
-
|
|
109
|
-
// cannot optimize for objects because they're pointers
|
|
110
|
-
if (typeof value !== 'object') {
|
|
111
|
-
const oldValue = this.store.get(address)
|
|
112
|
-
if (oldValue === value) return this
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
this.store.set(address, value)
|
|
116
|
-
this.allAddresses.add(address)
|
|
117
|
-
this.newAddresses.add(address)
|
|
118
|
-
|
|
119
|
-
return this
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
dispatch () {
|
|
123
|
-
if (this.newAddresses.size === 0) return []
|
|
124
|
-
|
|
125
|
-
const result = Context.manager.dispatch(this.newAddresses, this.allAddresses, this)
|
|
126
|
-
|
|
127
|
-
this.newAddresses.clear()
|
|
128
|
-
|
|
129
|
-
return result
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
resolve (address) {
|
|
133
|
-
return this.store.get(address)
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
module.exports = {
|
|
138
|
-
SubscriptionManager,
|
|
139
|
-
Context
|
|
140
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { SubscriptionManager, Context } = require('./engine')
|
|
4
|
-
const als = require('../als')
|
|
5
|
-
|
|
6
|
-
const manager = new SubscriptionManager()
|
|
7
|
-
Context.setManager(manager)
|
|
8
|
-
|
|
9
|
-
function startContext () {
|
|
10
|
-
const store = new Map()
|
|
11
|
-
|
|
12
|
-
store.set('context', new Context())
|
|
13
|
-
|
|
14
|
-
als.enterWith(store)
|
|
15
|
-
|
|
16
|
-
return store
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getContext () {
|
|
20
|
-
const store = als.getStore()
|
|
21
|
-
|
|
22
|
-
return store && store.get('context')
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function needsAddress (address) {
|
|
26
|
-
return manager.addresses.has(address)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function propagate (data, context = getContext()) {
|
|
30
|
-
if (!context) return
|
|
31
|
-
|
|
32
|
-
const keys = Object.keys(data)
|
|
33
|
-
|
|
34
|
-
for (let i = 0; i < keys.length; ++i) {
|
|
35
|
-
const key = keys[i]
|
|
36
|
-
|
|
37
|
-
if (needsAddress(key)) {
|
|
38
|
-
context.setValue(key, data[key])
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return context.dispatch()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
module.exports = {
|
|
46
|
-
manager,
|
|
47
|
-
startContext,
|
|
48
|
-
getContext,
|
|
49
|
-
needsAddress,
|
|
50
|
-
propagate
|
|
51
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const als = require('../als')
|
|
4
|
-
const log = require('../../../log')
|
|
5
|
-
|
|
6
|
-
let lock = false // lock to prevent recursive calls to runSubscriptions
|
|
7
|
-
|
|
8
|
-
function runSubscriptions (subscriptions, params) {
|
|
9
|
-
const results = []
|
|
10
|
-
|
|
11
|
-
if (lock || !subscriptions.size) return results
|
|
12
|
-
lock = true
|
|
13
|
-
|
|
14
|
-
const store = als.getStore()
|
|
15
|
-
|
|
16
|
-
// TODO: possible optimization
|
|
17
|
-
// can we deduplicate those before ?
|
|
18
|
-
const executedCallbacks = new Set()
|
|
19
|
-
|
|
20
|
-
for (const subscription of subscriptions) {
|
|
21
|
-
if (executedCallbacks.has(subscription.callback)) continue
|
|
22
|
-
executedCallbacks.add(subscription.callback)
|
|
23
|
-
|
|
24
|
-
let result
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
result = subscription.callback.method(params, store)
|
|
28
|
-
} catch (err) {
|
|
29
|
-
log.warn(`Error running subscription ${err}`)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
results.push(result)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
lock = false
|
|
36
|
-
|
|
37
|
-
return results
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = {
|
|
41
|
-
runSubscriptions
|
|
42
|
-
}
|