dd-trace 3.3.1 → 3.12.1

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.
Files changed (198) hide show
  1. package/LICENSE-3rdparty.csv +8 -0
  2. package/README.md +108 -43
  3. package/ci/init.js +6 -1
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +129 -36
  7. package/package.json +18 -9
  8. package/packages/datadog-instrumentations/src/body-parser.js +26 -0
  9. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  10. package/packages/datadog-instrumentations/src/child-process.js +30 -0
  11. package/packages/datadog-instrumentations/src/connect.js +15 -15
  12. package/packages/datadog-instrumentations/src/cucumber.js +1 -3
  13. package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
  14. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -0
  16. package/packages/datadog-instrumentations/src/helpers/register.js +5 -0
  17. package/packages/datadog-instrumentations/src/http/server.js +20 -12
  18. package/packages/datadog-instrumentations/src/http2/server.js +67 -1
  19. package/packages/datadog-instrumentations/src/jest.js +182 -25
  20. package/packages/datadog-instrumentations/src/koa.js +32 -32
  21. package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
  22. package/packages/datadog-instrumentations/src/mariadb.js +63 -0
  23. package/packages/datadog-instrumentations/src/memcached.js +1 -4
  24. package/packages/datadog-instrumentations/src/mocha.js +135 -24
  25. package/packages/datadog-instrumentations/src/next.js +10 -2
  26. package/packages/datadog-instrumentations/src/opensearch.js +10 -0
  27. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  28. package/packages/datadog-instrumentations/src/pg.js +7 -3
  29. package/packages/datadog-instrumentations/src/qs.js +24 -0
  30. package/packages/datadog-instrumentations/src/redis.js +12 -3
  31. package/packages/datadog-instrumentations/src/restify.js +5 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +29 -15
  33. package/packages/datadog-instrumentations/src/router.js +23 -23
  34. package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
  35. package/packages/datadog-plugin-amqp10/src/index.js +11 -101
  36. package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
  37. package/packages/datadog-plugin-amqp10/src/util.js +15 -0
  38. package/packages/datadog-plugin-amqplib/src/client.js +38 -0
  39. package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
  40. package/packages/datadog-plugin-amqplib/src/index.js +14 -102
  41. package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
  42. package/packages/datadog-plugin-amqplib/src/util.js +14 -0
  43. package/packages/datadog-plugin-cassandra-driver/src/index.js +22 -60
  44. package/packages/datadog-plugin-cucumber/src/index.js +14 -33
  45. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  46. package/packages/datadog-plugin-dns/src/index.js +16 -91
  47. package/packages/datadog-plugin-dns/src/lookup.js +40 -0
  48. package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
  49. package/packages/datadog-plugin-dns/src/resolve.js +24 -0
  50. package/packages/datadog-plugin-dns/src/reverse.js +21 -0
  51. package/packages/datadog-plugin-elasticsearch/src/index.js +24 -60
  52. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +24 -0
  53. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +41 -0
  54. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
  55. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +33 -0
  56. package/packages/datadog-plugin-graphql/src/execute.js +73 -0
  57. package/packages/datadog-plugin-graphql/src/index.js +14 -176
  58. package/packages/datadog-plugin-graphql/src/parse.js +32 -0
  59. package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
  60. package/packages/datadog-plugin-graphql/src/validate.js +28 -0
  61. package/packages/datadog-plugin-grpc/src/client.js +46 -55
  62. package/packages/datadog-plugin-grpc/src/index.js +7 -24
  63. package/packages/datadog-plugin-grpc/src/server.js +50 -52
  64. package/packages/datadog-plugin-grpc/src/util.js +15 -14
  65. package/packages/datadog-plugin-http/src/client.js +15 -5
  66. package/packages/datadog-plugin-http/src/index.js +7 -22
  67. package/packages/datadog-plugin-http/src/server.js +19 -3
  68. package/packages/datadog-plugin-http2/src/client.js +20 -1
  69. package/packages/datadog-plugin-http2/src/index.js +8 -26
  70. package/packages/datadog-plugin-http2/src/server.js +44 -0
  71. package/packages/datadog-plugin-jest/src/index.js +41 -65
  72. package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
  73. package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
  74. package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
  75. package/packages/datadog-plugin-mariadb/src/index.js +10 -0
  76. package/packages/datadog-plugin-memcached/src/index.js +17 -52
  77. package/packages/datadog-plugin-mocha/src/index.js +40 -60
  78. package/packages/datadog-plugin-moleculer/src/client.js +22 -36
  79. package/packages/datadog-plugin-moleculer/src/index.js +8 -26
  80. package/packages/datadog-plugin-moleculer/src/server.js +18 -30
  81. package/packages/datadog-plugin-mongodb-core/src/index.js +23 -51
  82. package/packages/datadog-plugin-mysql/src/index.js +23 -52
  83. package/packages/datadog-plugin-mysql2/src/index.js +1 -3
  84. package/packages/datadog-plugin-net/src/index.js +4 -0
  85. package/packages/datadog-plugin-net/src/ipc.js +21 -0
  86. package/packages/datadog-plugin-net/src/tcp.js +46 -0
  87. package/packages/datadog-plugin-next/src/index.js +3 -0
  88. package/packages/datadog-plugin-opensearch/src/index.js +11 -0
  89. package/packages/datadog-plugin-oracledb/src/index.js +29 -55
  90. package/packages/datadog-plugin-pg/src/index.js +27 -51
  91. package/packages/datadog-plugin-redis/src/index.js +29 -60
  92. package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
  93. package/packages/datadog-plugin-rhea/src/index.js +11 -96
  94. package/packages/datadog-plugin-rhea/src/producer.js +45 -0
  95. package/packages/datadog-plugin-router/src/index.js +13 -2
  96. package/packages/datadog-plugin-sharedb/src/index.js +22 -39
  97. package/packages/datadog-plugin-tedious/src/index.js +20 -41
  98. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  99. package/packages/dd-trace/src/appsec/blocking.js +44 -0
  100. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +8 -6
  101. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
  102. package/packages/dd-trace/src/appsec/gateway/engine/index.js +7 -2
  103. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
  104. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +4 -1
  105. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  106. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  107. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
  108. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  109. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +43 -5
  110. package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
  111. package/packages/dd-trace/src/appsec/iast/index.js +24 -8
  112. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
  113. package/packages/dd-trace/src/appsec/iast/path-line.js +17 -6
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
  115. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  116. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  117. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +98 -0
  118. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  119. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +67 -0
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
  122. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +98 -30
  123. package/packages/dd-trace/src/appsec/index.js +79 -25
  124. package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
  125. package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
  126. package/packages/dd-trace/src/appsec/recommended.json +134 -53
  127. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  128. package/packages/dd-trace/src/appsec/remote_config/index.js +56 -0
  129. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  130. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  131. package/packages/dd-trace/src/appsec/rule_manager.js +61 -1
  132. package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
  133. package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
  134. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +66 -0
  135. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +9 -5
  136. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +19 -51
  137. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +10 -5
  138. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +202 -0
  139. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +51 -62
  140. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +89 -0
  141. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +82 -0
  142. package/packages/dd-trace/src/config.js +119 -35
  143. package/packages/dd-trace/src/constants.js +9 -1
  144. package/packages/dd-trace/src/dogstatsd.js +42 -10
  145. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
  146. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  147. package/packages/dd-trace/src/exporter.js +3 -0
  148. package/packages/dd-trace/src/exporters/agent/index.js +10 -2
  149. package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
  150. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +82 -0
  151. package/packages/dd-trace/src/exporters/common/request.js +51 -1
  152. package/packages/dd-trace/src/exporters/span-stats/index.js +6 -2
  153. package/packages/dd-trace/src/format.js +29 -10
  154. package/packages/dd-trace/src/lambda/handler.js +72 -0
  155. package/packages/dd-trace/src/lambda/index.js +5 -0
  156. package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
  157. package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
  158. package/packages/dd-trace/src/lambda/runtime/ritm.js +138 -0
  159. package/packages/dd-trace/src/metrics.js +15 -2
  160. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  161. package/packages/dd-trace/src/opentracing/span.js +2 -1
  162. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  163. package/packages/dd-trace/src/plugin_manager.js +11 -17
  164. package/packages/dd-trace/src/plugins/cache.js +9 -0
  165. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -0
  166. package/packages/dd-trace/src/plugins/client.js +9 -0
  167. package/packages/dd-trace/src/plugins/composite.js +26 -0
  168. package/packages/dd-trace/src/plugins/consumer.js +9 -0
  169. package/packages/dd-trace/src/plugins/database.js +55 -0
  170. package/packages/dd-trace/src/plugins/incoming.js +7 -0
  171. package/packages/dd-trace/src/plugins/index.js +3 -0
  172. package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
  173. package/packages/dd-trace/src/plugins/outgoing.js +31 -0
  174. package/packages/dd-trace/src/plugins/plugin.js +3 -0
  175. package/packages/dd-trace/src/plugins/producer.js +9 -0
  176. package/packages/dd-trace/src/plugins/server.js +9 -0
  177. package/packages/dd-trace/src/plugins/storage.js +21 -0
  178. package/packages/dd-trace/src/plugins/tracing.js +94 -0
  179. package/packages/dd-trace/src/plugins/util/ci.js +40 -4
  180. package/packages/dd-trace/src/plugins/util/git.js +58 -18
  181. package/packages/dd-trace/src/plugins/util/test.js +71 -8
  182. package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
  183. package/packages/dd-trace/src/plugins/util/web.js +11 -114
  184. package/packages/dd-trace/src/priority_sampler.js +6 -2
  185. package/packages/dd-trace/src/profiling/config.js +11 -6
  186. package/packages/dd-trace/src/profiling/exporters/agent.js +4 -0
  187. package/packages/dd-trace/src/profiling/index.js +2 -2
  188. package/packages/dd-trace/src/profiling/profiler.js +43 -7
  189. package/packages/dd-trace/src/proxy.js +8 -16
  190. package/packages/dd-trace/src/ritm.js +25 -14
  191. package/packages/dd-trace/src/span_processor.js +17 -0
  192. package/packages/dd-trace/src/span_sampler.js +77 -0
  193. package/packages/dd-trace/src/span_stats.js +2 -2
  194. package/packages/dd-trace/src/telemetry/dependencies.js +21 -7
  195. package/packages/dd-trace/src/telemetry/index.js +7 -1
  196. package/packages/dd-trace/src/telemetry/send-data.js +3 -1
  197. package/packages/dd-trace/src/tracer.js +10 -5
  198. package/packages/dd-trace/src/util.js +43 -1
@@ -1,9 +1,34 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.4.0"
4
+ "rules_version": "1.4.3"
5
5
  },
6
6
  "rules": [
7
+ {
8
+ "id": "blk-001-001",
9
+ "name": "Block IP Addresses",
10
+ "tags": {
11
+ "type": "block_ip",
12
+ "category": "security_response"
13
+ },
14
+ "conditions": [
15
+ {
16
+ "parameters": {
17
+ "inputs": [
18
+ {
19
+ "address": "http.client_ip"
20
+ }
21
+ ],
22
+ "data": "blocked_ips"
23
+ },
24
+ "operator": "ip_match"
25
+ }
26
+ ],
27
+ "transformers": [],
28
+ "on_match": [
29
+ "block"
30
+ ]
31
+ },
7
32
  {
8
33
  "id": "crs-913-110",
9
34
  "name": "Acunetix",
@@ -1777,7 +1802,7 @@
1777
1802
  "address": "server.request.path_params"
1778
1803
  }
1779
1804
  ],
1780
- "regex": "^(?i:file|ftps?|https?).*?\\?+$",
1805
+ "regex": "^(?i:file|ftps?|http)://.*?\\?+$",
1781
1806
  "options": {
1782
1807
  "case_sensitive": true,
1783
1808
  "min_length": 4
@@ -2669,8 +2694,9 @@
2669
2694
  "address": "grpc.server.request.message"
2670
2695
  }
2671
2696
  ],
2672
- "regex": "\\b(?:s(?:e(?:t(?:_(?:e(?:xception|rror)_handler|magic_quotes_runtime|include_path)|defaultstub)|ssion_s(?:et_save_handler|tart))|qlite_(?:(?:(?:unbuffered|single|array)_)?query|create_(?:aggregate|function)|p?open|exec)|tr(?:eam_(?:context_create|socket_client)|ipc?slashes|rev)|implexml_load_(?:string|file)|ocket_c(?:onnect|reate)|h(?:ow_sourc|a1_fil)e|pl_autoload_register|ystem)|p(?:r(?:eg_(?:replace(?:_callback(?:_array)?)?|match(?:_all)?|split)|oc_(?:(?:terminat|clos|nic)e|get_status|open)|int_r)|o(?:six_(?:get(?:(?:e[gu]|g)id|login|pwnam)|mk(?:fifo|nod)|ttyname|kill)|pen)|hp(?:_(?:strip_whitespac|unam)e|version|info)|g_(?:(?:execut|prepar)e|connect|query)|a(?:rse_(?:ini_file|str)|ssthru)|utenv)|r(?:unkit_(?:function_(?:re(?:defin|nam)e|copy|add)|method_(?:re(?:defin|nam)e|copy|add)|constant_(?:redefine|add))|e(?:(?:gister_(?:shutdown|tick)|name)_function|ad(?:(?:gz)?file|_exif_data|dir))|awurl(?:de|en)code)|i(?:mage(?:createfrom(?:(?:jpe|pn)g|x[bp]m|wbmp|gif)|(?:jpe|pn)g|g(?:d2?|if)|2?wbmp|xbm)|s_(?:(?:(?:execut|write?|read)ab|fi)le|dir)|ni_(?:get(?:_all)?|set)|terator_apply|ptcembed)|g(?:et(?:_(?:c(?:urrent_use|fg_va)r|meta_tags)|my(?:[gpu]id|inode)|(?:lastmo|cw)d|imagesize|env)|z(?:(?:(?:defla|wri)t|encod|fil)e|compress|open|read)|lob)|a(?:rray_(?:u(?:intersect(?:_u?assoc)?|diff(?:_u?assoc)?)|intersect_u(?:assoc|key)|diff_u(?:assoc|key)|filter|reduce|map)|ssert(?:_options)?|lert|tob)|h(?:tml(?:specialchars(?:_decode)?|_entity_decode|entities)|(?:ash(?:_(?:update|hmac))?|ighlight)_file|e(?:ader_register_callback|x2bin))|f(?:i(?:le(?:(?:[acm]tim|inod)e|(?:_exist|perm)s|group)?|nfo_open)|tp_(?:nb_(?:ge|pu)|connec|ge|pu)t|(?:unction_exis|pu)ts|write|open)|o(?:b_(?:get_(?:c(?:ontents|lean)|flush)|end_(?:clean|flush)|clean|flush|start)|dbc_(?:result(?:_all)?|exec(?:ute)?|connect)|pendir)|m(?:b_(?:ereg(?:_(?:replace(?:_callback)?|match)|i(?:_replace)?)?|parse_str)|(?:ove_uploaded|d5)_file|ethod_exists|ysql_query|kdir)|e(?:x(?:if_(?:t(?:humbnail|agname)|imagetype|read_data)|ec)|scapeshell(?:arg|cmd)|rror_reporting|val)|c(?:url_(?:file_create|exec|init)|onvert_uuencode|reate_function|hr)|u(?:n(?:serialize|pack)|rl(?:de|en)code|[ak]?sort)|b(?:(?:son_(?:de|en)|ase64_en)code|zopen|toa)|(?:json_(?:de|en)cod|debug_backtrac|tmpfil)e|var_dump)(?:\\s|/\\*.*\\*/|//.*|#.*|\\\")*\\(.*\\)",
2697
+ "regex": "\\b(?:s(?:e(?:t(?:_(?:e(?:xception|rror)_handler|magic_quotes_runtime|include_path)|defaultstub)|ssion_s(?:et_save_handler|tart))|qlite_(?:(?:(?:unbuffered|single|array)_)?query|create_(?:aggregate|function)|p?open|exec)|tr(?:eam_(?:context_create|socket_client)|ipc?slashes|rev)|implexml_load_(?:string|file)|ocket_c(?:onnect|reate)|h(?:ow_sourc|a1_fil)e|pl_autoload_register|ystem)|p(?:r(?:eg_(?:replace(?:_callback(?:_array)?)?|match(?:_all)?|split)|oc_(?:(?:terminat|clos|nic)e|get_status|open)|int_r)|o(?:six_(?:get(?:(?:e[gu]|g)id|login|pwnam)|mk(?:fifo|nod)|ttyname|kill)|pen)|hp(?:_(?:strip_whitespac|unam)e|version|info)|g_(?:(?:execut|prepar)e|connect|query)|a(?:rse_(?:ini_file|str)|ssthru)|utenv)|r(?:unkit_(?:function_(?:re(?:defin|nam)e|copy|add)|method_(?:re(?:defin|nam)e|copy|add)|constant_(?:redefine|add))|e(?:(?:gister_(?:shutdown|tick)|name)_function|ad(?:(?:gz)?file|_exif_data|dir))|awurl(?:de|en)code)|i(?:mage(?:createfrom(?:(?:jpe|pn)g|x[bp]m|wbmp|gif)|(?:jpe|pn)g|g(?:d2?|if)|2?wbmp|xbm)|s_(?:(?:(?:execut|write?|read)ab|fi)le|dir)|ni_(?:get(?:_all)?|set)|terator_apply|ptcembed)|g(?:et(?:_(?:c(?:urrent_use|fg_va)r|meta_tags)|my(?:[gpu]id|inode)|(?:lastmo|cw)d|imagesize|env)|z(?:(?:(?:defla|wri)t|encod|fil)e|compress|open|read)|lob)|a(?:rray_(?:u(?:intersect(?:_u?assoc)?|diff(?:_u?assoc)?)|intersect_u(?:assoc|key)|diff_u(?:assoc|key)|filter|reduce|map)|ssert(?:_options)?|lert|tob)|h(?:tml(?:specialchars(?:_decode)?|_entity_decode|entities)|(?:ash(?:_(?:update|hmac))?|ighlight)_file|e(?:ader_register_callback|x2bin))|f(?:i(?:le(?:(?:[acm]tim|inod)e|(?:_exist|perm)s|group)?|nfo_open)|tp_(?:nb_(?:ge|pu)|connec|ge|pu)t|(?:unction_exis|pu)ts|write|open)|o(?:b_(?:get_(?:c(?:ontents|lean)|flush)|end_(?:clean|flush)|clean|flush|start)|dbc_(?:result(?:_all)?|exec(?:ute)?|connect)|pendir)|m(?:b_(?:ereg(?:_(?:replace(?:_callback)?|match)|i(?:_replace)?)?|parse_str)|(?:ove_uploaded|d5)_file|ethod_exists|ysql_query|kdir)|e(?:x(?:if_(?:t(?:humbnail|agname)|imagetype|read_data)|ec)|scapeshell(?:arg|cmd)|rror_reporting|val)|c(?:url_(?:file_create|exec|init)|onvert_uuencode|reate_function|hr)|u(?:n(?:serialize|pack)|rl(?:de|en)code|[ak]?sort)|b(?:(?:son_(?:de|en)|ase64_en)code|zopen|toa)|(?:json_(?:de|en)cod|debug_backtrac|tmpfil)e|var_dump)(?:\\s|/\\*.*\\*/|//.*|#.*|\\\"|')*\\((?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?,)*(?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?)?\\)",
2673
2698
  "options": {
2699
+ "case_sensitive": true,
2674
2700
  "min_length": 5
2675
2701
  }
2676
2702
  },
@@ -2828,51 +2854,6 @@
2828
2854
  ],
2829
2855
  "transformers": []
2830
2856
  },
2831
- {
2832
- "id": "crs-941-100",
2833
- "name": "XSS Attack Detected via libinjection",
2834
- "tags": {
2835
- "type": "xss",
2836
- "crs_id": "941100",
2837
- "category": "attack_attempt"
2838
- },
2839
- "conditions": [
2840
- {
2841
- "parameters": {
2842
- "inputs": [
2843
- {
2844
- "address": "server.request.headers.no_cookies",
2845
- "key_path": [
2846
- "user-agent"
2847
- ]
2848
- },
2849
- {
2850
- "address": "server.request.headers.no_cookies",
2851
- "key_path": [
2852
- "referer"
2853
- ]
2854
- },
2855
- {
2856
- "address": "server.request.query"
2857
- },
2858
- {
2859
- "address": "server.request.body"
2860
- },
2861
- {
2862
- "address": "server.request.path_params"
2863
- },
2864
- {
2865
- "address": "grpc.server.request.message"
2866
- }
2867
- ]
2868
- },
2869
- "operator": "is_xss"
2870
- }
2871
- ],
2872
- "transformers": [
2873
- "removeNulls"
2874
- ]
2875
- },
2876
2857
  {
2877
2858
  "id": "crs-941-110",
2878
2859
  "name": "XSS Filter - Category 1: Script Tag Vector",
@@ -3544,7 +3525,7 @@
3544
3525
  "address": "grpc.server.request.message"
3545
3526
  }
3546
3527
  ],
3547
- "regex": "\\b(?i:eval|settimeout|setinterval|new\\s+Function)\\s*\\(",
3528
+ "regex": "\\b(?i:eval|settimeout|setinterval|new\\s+Function|alert|prompt)\\s*\\([^\\)]",
3548
3529
  "options": {
3549
3530
  "case_sensitive": true,
3550
3531
  "min_length": 5
@@ -3790,7 +3771,7 @@
3790
3771
  "address": "grpc.server.request.message"
3791
3772
  }
3792
3773
  ],
3793
- "regex": "(?i:(?:\\[?\\$(?:(?:s(?:lic|iz)|wher)e|e(?:lemMatch|xists|q)|n(?:o[rt]|in?|e)|l(?:ike|te?)|t(?:ext|ype)|a(?:ll|nd)|jsonSchema|between|regex|x?or|div|mod)\\]?))",
3774
+ "regex": "(?i:(?:\\[?\\$(?:(?:s(?:lic|iz)|wher)e|e(?:lemMatch|xists|q)|n(?:o[rt]|in?|e)|l(?:ike|te?)|t(?:ext|ype)|a(?:ll|nd)|jsonSchema|between|regex|x?or|div|mod)\\]?)\\b)",
3794
3775
  "options": {
3795
3776
  "case_sensitive": true,
3796
3777
  "min_length": 3
@@ -3828,7 +3809,7 @@
3828
3809
  "address": "grpc.server.request.message"
3829
3810
  }
3830
3811
  ],
3831
- "regex": "(?:^[\\W\\d]+\\s*?(?:alter\\s*(?:a(?:(?:pplication\\s*rol|ggregat)e|s(?:ymmetric\\s*ke|sembl)y|u(?:thorization|dit)|vailability\\s*group)|c(?:r(?:yptographic\\s*provider|edential)|o(?:l(?:latio|um)|nversio)n|ertificate|luster)|s(?:e(?:rv(?:ice|er)|curity|quence|ssion|arch)|y(?:mmetric\\s*key|nonym)|togroup|chema)|m(?:a(?:s(?:ter\\s*key|k)|terialized)|e(?:ssage\\s*type|thod)|odule)|l(?:o(?:g(?:file\\s*group|in)|ckdown)|a(?:ngua|r)ge|ibrary)|t(?:(?:abl(?:espac)?|yp)e|r(?:igger|usted)|hreshold|ext)|p(?:a(?:rtition|ckage)|ro(?:cedur|fil)e|ermission)|d(?:i(?:mension|skgroup)|atabase|efault|omain)|r(?:o(?:l(?:lback|e)|ute)|e(?:sourc|mot)e)|f(?:u(?:lltext|nction)|lashback|oreign)|e(?:xte(?:nsion|rnal)|(?:ndpoi|ve)nt)|in(?:dex(?:type)?|memory|stance)|b(?:roker\\s*priority|ufferpool)|x(?:ml\\s*schema|srobject)|w(?:ork(?:load)?|rapper)|hi(?:erarchy|stogram)|o(?:perator|utline)|(?:nicknam|queu)e|us(?:age|er)|group|java|view)\\b|(?:(?:(?:trunc|cre)at|renam)e|d(?:e(?:lete|sc)|rop)|(?:inser|selec)t|load)\\s+\\w+|u(?:nion\\s*(?:(?:distin|sele)ct|all)\\b|pdate\\s+\\w+))|\\b(?:(?:(?:(?:trunc|cre|upd)at|renam)e|(?:inser|selec)t|de(?:lete|sc)|alter|load)\\s+(?:group_concat|load_file|char)\\b\\s*\\(?|end\\s*?\\);)|[\\\"'`\\w]\\s+as\\b\\s*[\\\"'`\\w]+\\s*\\bfrom|[\\s(?:]load_file\\s*?\\(|[\\\"'`]\\s+regexp\\W)",
3812
+ "regex": "(?:^[\\W\\d]+\\s*?(?:alter\\s*(?:a(?:(?:pplication\\s*rol|ggregat)e|s(?:ymmetric\\s*ke|sembl)y|u(?:thorization|dit)|vailability\\s*group)|c(?:r(?:yptographic\\s*provider|edential)|o(?:l(?:latio|um)|nversio)n|ertificate|luster)|s(?:e(?:rv(?:ice|er)|curity|quence|ssion|arch)|y(?:mmetric\\s*key|nonym)|togroup|chema)|m(?:a(?:s(?:ter\\s*key|k)|terialized)|e(?:ssage\\s*type|thod)|odule)|l(?:o(?:g(?:file\\s*group|in)|ckdown)|a(?:ngua|r)ge|ibrary)|t(?:(?:abl(?:espac)?|yp)e|r(?:igger|usted)|hreshold|ext)|p(?:a(?:rtition|ckage)|ro(?:cedur|fil)e|ermission)|d(?:i(?:mension|skgroup)|atabase|efault|omain)|r(?:o(?:l(?:lback|e)|ute)|e(?:sourc|mot)e)|f(?:u(?:lltext|nction)|lashback|oreign)|e(?:xte(?:nsion|rnal)|(?:ndpoi|ve)nt)|in(?:dex(?:type)?|memory|stance)|b(?:roker\\s*priority|ufferpool)|x(?:ml\\s*schema|srobject)|w(?:ork(?:load)?|rapper)|hi(?:erarchy|stogram)|o(?:perator|utline)|(?:nicknam|queu)e|us(?:age|er)|group|java|view)|union\\s*(?:(?:distin|sele)ct|all))\\b|\\b(?:(?:(?:trunc|cre|upd)at|renam)e|(?:inser|selec)t|de(?:lete|sc)|alter|load)\\s+(?:group_concat|load_file|char)\\b\\s*\\(?|[\\s(]load_file\\s*?\\(|[\\\"'`]\\s+regexp\\W)",
3832
3813
  "options": {
3833
3814
  "min_length": 5
3834
3815
  }
@@ -4197,7 +4178,7 @@
4197
4178
  "address": "grpc.server.request.message"
4198
4179
  }
4199
4180
  ],
4200
- "regex": "[#%$]{[^}]+[^\\w\\s][^}]+}",
4181
+ "regex": "[#%$]{(?:[^}]+[^\\w\\s}\\-_][^}]+|\\d+-\\d+)}",
4201
4182
  "options": {
4202
4183
  "case_sensitive": true
4203
4184
  }
@@ -4338,6 +4319,72 @@
4338
4319
  "keys_only"
4339
4320
  ]
4340
4321
  },
4322
+ {
4323
+ "id": "dog-000-007",
4324
+ "name": "Server side template injection: Velocity & Freemarker",
4325
+ "tags": {
4326
+ "type": "java_code_injection",
4327
+ "category": "attack_attempt"
4328
+ },
4329
+ "conditions": [
4330
+ {
4331
+ "parameters": {
4332
+ "inputs": [
4333
+ {
4334
+ "address": "server.request.query"
4335
+ },
4336
+ {
4337
+ "address": "server.request.body"
4338
+ },
4339
+ {
4340
+ "address": "server.request.path_params"
4341
+ },
4342
+ {
4343
+ "address": "server.request.headers.no_cookies"
4344
+ },
4345
+ {
4346
+ "address": "grpc.server.request.message"
4347
+ }
4348
+ ],
4349
+ "regex": "#(?:set|foreach|macro|parse|if)\\(.*\\)|<#assign.*>"
4350
+ },
4351
+ "operator": "match_regex"
4352
+ }
4353
+ ],
4354
+ "transformers": []
4355
+ },
4356
+ {
4357
+ "id": "dog-931-001",
4358
+ "name": "RFI: URL Payload to well known RFI target",
4359
+ "tags": {
4360
+ "type": "rfi",
4361
+ "category": "attack_attempt"
4362
+ },
4363
+ "conditions": [
4364
+ {
4365
+ "parameters": {
4366
+ "inputs": [
4367
+ {
4368
+ "address": "server.request.query"
4369
+ },
4370
+ {
4371
+ "address": "server.request.body"
4372
+ },
4373
+ {
4374
+ "address": "server.request.path_params"
4375
+ }
4376
+ ],
4377
+ "regex": "^(?i:file|ftps?|https?).*/rfiinc\\.txt\\?+$",
4378
+ "options": {
4379
+ "case_sensitive": true,
4380
+ "min_length": 17
4381
+ }
4382
+ },
4383
+ "operator": "match_regex"
4384
+ }
4385
+ ],
4386
+ "transformers": []
4387
+ },
4341
4388
  {
4342
4389
  "id": "nfd-000-001",
4343
4390
  "name": "Detect common directory discovery scans",
@@ -5146,7 +5193,7 @@
5146
5193
  "address": "grpc.server.request.message"
5147
5194
  }
5148
5195
  ],
5149
- "regex": "^(jar:)?(http|https):\\/\\/([0-9oq]{1,5}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|[0-9]{1,10}|localhost)(:[0-9]{1,5})?(\\/.*|)$"
5196
+ "regex": "^(jar:)?(http|https):\\/\\/([0-9oq]{1,5}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|[0-9]{1,10})(:[0-9]{1,5})?(\\/.*|)$"
5150
5197
  },
5151
5198
  "operator": "match_regex"
5152
5199
  }
@@ -6403,6 +6450,40 @@
6403
6450
  ],
6404
6451
  "transformers": []
6405
6452
  },
6453
+ {
6454
+ "id": "ua0-600-56x",
6455
+ "name": "Datadog test scanner - blocking version: user-agent",
6456
+ "tags": {
6457
+ "type": "security_scanner",
6458
+ "category": "attack_attempt"
6459
+ },
6460
+ "conditions": [
6461
+ {
6462
+ "parameters": {
6463
+ "inputs": [
6464
+ {
6465
+ "address": "server.request.headers.no_cookies",
6466
+ "key_path": [
6467
+ "user-agent"
6468
+ ]
6469
+ },
6470
+ {
6471
+ "address": "grpc.server.request.metadata",
6472
+ "key_path": [
6473
+ "dd-canary"
6474
+ ]
6475
+ }
6476
+ ],
6477
+ "regex": "^dd-test-scanner-log-block$"
6478
+ },
6479
+ "operator": "match_regex"
6480
+ }
6481
+ ],
6482
+ "transformers": [],
6483
+ "on_match": [
6484
+ "block"
6485
+ ]
6486
+ },
6406
6487
  {
6407
6488
  "id": "ua0-600-5xx",
6408
6489
  "name": "Blind SQL Injection Brute Forcer",
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ ASM_ACTIVATION: 1n << 1n,
5
+ ASM_IP_BLOCKING: 1n << 2n,
6
+ ASM_DD_RULES: 1n << 3n
7
+ }
@@ -0,0 +1,56 @@
1
+ 'use strict'
2
+
3
+ const RemoteConfigManager = require('./manager')
4
+ const RemoteConfigCapabilities = require('./capabilities')
5
+ const RuleManager = require('../rule_manager')
6
+
7
+ let rc
8
+
9
+ function enable (config) {
10
+ rc = new RemoteConfigManager(config)
11
+
12
+ if (config.appsec.enabled === undefined) { // only activate ASM_FEATURES when conf is not set locally
13
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
14
+
15
+ rc.on('ASM_FEATURES', (action, conf) => {
16
+ if (conf && conf.asm && typeof conf.asm.enabled === 'boolean') {
17
+ let shouldEnable
18
+
19
+ if (action === 'apply' || action === 'modify') {
20
+ shouldEnable = conf.asm.enabled // take control
21
+ } else {
22
+ shouldEnable = config.appsec.enabled // give back control to local config
23
+ }
24
+
25
+ if (shouldEnable) {
26
+ require('..').enableAsync(config).catch(() => {})
27
+ } else {
28
+ require('..').disable()
29
+ }
30
+ }
31
+ })
32
+ }
33
+ }
34
+
35
+ function enableAsmData (appsecConfig) {
36
+ if (rc && appsecConfig && appsecConfig.rules === undefined) {
37
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, true)
38
+ rc.on('ASM_DATA', _asmDataListener)
39
+ }
40
+ }
41
+
42
+ function disableAsmData () {
43
+ if (rc) {
44
+ rc.off('ASM_DATA', _asmDataListener)
45
+ }
46
+ }
47
+
48
+ function _asmDataListener (action, ruleData, ruleId) {
49
+ RuleManager.updateAsmData(action, ruleData, ruleId)
50
+ }
51
+
52
+ module.exports = {
53
+ enable,
54
+ enableAsmData,
55
+ disableAsmData
56
+ }
@@ -0,0 +1,264 @@
1
+ 'use strict'
2
+
3
+ const uuid = require('crypto-randomuuid')
4
+ const { EventEmitter } = require('events')
5
+ const Scheduler = require('./scheduler')
6
+ const tracerVersion = require('../../../../../package.json').version
7
+ const request = require('../../exporters/common/request')
8
+ const log = require('../../log')
9
+
10
+ const clientId = uuid()
11
+
12
+ const DEFAULT_CAPABILITY = Buffer.alloc(1).toString('base64') // 0x00
13
+
14
+ // There MUST NOT exist separate instances of RC clients in a tracer making separate ClientGetConfigsRequest
15
+ // with their own separated Client.ClientState.
16
+ class RemoteConfigManager extends EventEmitter {
17
+ constructor (config) {
18
+ super()
19
+
20
+ const pollInterval = config.remoteConfig.pollInterval * 1000
21
+ this.scheduler = new Scheduler((cb) => this.poll(cb), pollInterval)
22
+
23
+ this.requestOptions = {
24
+ url: config.url,
25
+ hostname: config.hostname,
26
+ port: config.port,
27
+ method: 'POST',
28
+ path: '/v0.7/config'
29
+ }
30
+
31
+ this.state = {
32
+ client: {
33
+ state: { // updated by `parseConfig()`
34
+ root_version: 1,
35
+ targets_version: 0,
36
+ config_states: [],
37
+ has_error: false,
38
+ error: '',
39
+ backend_client_state: ''
40
+ },
41
+ id: clientId,
42
+ products: [], // updated by `updateProducts()`
43
+ is_tracer: true,
44
+ client_tracer: {
45
+ runtime_id: config.tags['runtime-id'],
46
+ language: 'node',
47
+ tracer_version: tracerVersion,
48
+ service: config.service,
49
+ env: config.env,
50
+ app_version: config.version
51
+ },
52
+ capabilities: DEFAULT_CAPABILITY // updated by `updateCapabilities()`
53
+ },
54
+ cached_target_files: [] // updated by `parseConfig()`
55
+ }
56
+
57
+ this.appliedConfigs = new Map()
58
+ }
59
+
60
+ updateCapabilities (mask, value) {
61
+ const hex = Buffer.from(this.state.client.capabilities, 'base64').toString('hex')
62
+
63
+ let num = BigInt(`0x${hex}`)
64
+
65
+ if (value) {
66
+ num |= mask
67
+ } else {
68
+ num &= ~mask
69
+ }
70
+
71
+ let str = num.toString(16)
72
+
73
+ if (str.length % 2) str = `0${str}`
74
+
75
+ this.state.client.capabilities = Buffer.from(str, 'hex').toString('base64')
76
+ }
77
+
78
+ on (event, listener) {
79
+ super.on(event, listener)
80
+
81
+ this.state.client.products = this.eventNames()
82
+
83
+ this.scheduler.start()
84
+
85
+ return this
86
+ }
87
+
88
+ off (event, listener) {
89
+ super.off(event, listener)
90
+
91
+ this.state.client.products = this.eventNames()
92
+
93
+ if (!this.state.client.products.length) {
94
+ this.scheduler.stop()
95
+ }
96
+
97
+ return this
98
+ }
99
+
100
+ poll (cb) {
101
+ request(JSON.stringify(this.state), this.requestOptions, (err, data, statusCode) => {
102
+ // 404 means RC is disabled, ignore it
103
+ if (statusCode === 404) return cb()
104
+
105
+ if (err) {
106
+ log.error(err)
107
+ return cb()
108
+ }
109
+
110
+ // if error was just sent, reset the state
111
+ if (this.state.client.state.has_error) {
112
+ this.state.client.state.has_error = false
113
+ this.state.client.state.error = ''
114
+ }
115
+
116
+ if (data && data !== '{}') { // '{}' means the tracer is up to date
117
+ try {
118
+ this.parseConfig(JSON.parse(data))
119
+ } catch (err) {
120
+ log.error(`Could not parse remote config response: ${err}`)
121
+
122
+ this.state.client.state.has_error = true
123
+ this.state.client.state.error = err.toString()
124
+ }
125
+ }
126
+
127
+ cb()
128
+ })
129
+ }
130
+
131
+ // `client_configs` is the list of config paths to have applied
132
+ // `targets` is the signed index with metadata for config files
133
+ // `target_files` is the list of config files containing the actual config data
134
+ parseConfig ({
135
+ client_configs: clientConfigs = [],
136
+ targets,
137
+ target_files: targetFiles = []
138
+ }) {
139
+ const toUnapply = []
140
+ const toApply = []
141
+ const toModify = []
142
+
143
+ for (const appliedConfig of this.appliedConfigs.values()) {
144
+ if (!clientConfigs.includes(appliedConfig.path)) {
145
+ toUnapply.push(appliedConfig)
146
+ }
147
+ }
148
+
149
+ targets = fromBase64JSON(targets)
150
+
151
+ if (targets) {
152
+ for (const path of clientConfigs) {
153
+ const meta = targets.signed.targets[path]
154
+ if (!meta) throw new Error(`Unable to find target for path ${path}`)
155
+
156
+ const current = this.appliedConfigs.get(path)
157
+
158
+ const newConf = {}
159
+
160
+ if (current) {
161
+ if (current.hashes.sha256 === meta.hashes.sha256) continue
162
+
163
+ toModify.push(newConf)
164
+ } else {
165
+ toApply.push(newConf)
166
+ }
167
+
168
+ const file = targetFiles.find(file => file.path === path)
169
+ if (!file) throw new Error(`Unable to find file for path ${path}`)
170
+
171
+ // TODO: verify signatures
172
+ // verify length
173
+ // verify hash
174
+ // verify _type
175
+ // TODO: new Date(meta.signed.expires) ignore the Targets data if it has expired ?
176
+
177
+ const { product, id } = parseConfigPath(path)
178
+
179
+ Object.assign(newConf, {
180
+ path,
181
+ product,
182
+ id,
183
+ version: meta.custom.v,
184
+ apply_state: 1,
185
+ apply_error: '',
186
+ length: meta.length,
187
+ hashes: meta.hashes,
188
+ file: fromBase64JSON(file.raw)
189
+ })
190
+ }
191
+
192
+ this.state.client.state.targets_version = targets.signed.version
193
+ this.state.client.state.backend_client_state = targets.signed.custom.opaque_backend_state
194
+ }
195
+
196
+ if (toUnapply.length || toApply.length || toModify.length) {
197
+ this.dispatch(toUnapply, 'unapply')
198
+ this.dispatch(toApply, 'apply')
199
+ this.dispatch(toModify, 'modify')
200
+
201
+ this.state.client.state.config_states = []
202
+ this.state.cached_target_files = []
203
+
204
+ for (const conf of this.appliedConfigs.values()) {
205
+ this.state.client.state.config_states.push({
206
+ id: conf.id,
207
+ version: conf.version,
208
+ product: conf.product,
209
+ apply_state: conf.apply_state,
210
+ apply_error: conf.apply_error
211
+ })
212
+
213
+ this.state.cached_target_files.push({
214
+ path: conf.path,
215
+ length: conf.length,
216
+ hashes: Object.entries(conf.hashes).map((entry) => ({ algorithm: entry[0], hash: entry[1] }))
217
+ })
218
+ }
219
+ }
220
+ }
221
+
222
+ dispatch (list, action) {
223
+ for (const item of list) {
224
+ try {
225
+ // TODO: do we want to pass old and new config ?
226
+ this.emit(item.product, action, item.file, item.id)
227
+
228
+ item.apply_state = 2
229
+ } catch (err) {
230
+ item.apply_state = 3
231
+ item.apply_error = err.toString()
232
+ }
233
+
234
+ if (action === 'unapply') {
235
+ this.appliedConfigs.delete(item.path)
236
+ } else {
237
+ this.appliedConfigs.set(item.path, item)
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ function fromBase64JSON (str) {
244
+ if (!str) return null
245
+
246
+ return JSON.parse(Buffer.from(str, 'base64').toString())
247
+ }
248
+
249
+ const configPathRegex = /^(?:datadog\/\d+|employee)\/([^/]+)\/([^/]+)\/[^/]+$/
250
+
251
+ function parseConfigPath (configPath) {
252
+ const match = configPathRegex.exec(configPath)
253
+
254
+ if (!match || !match[1] || !match[2]) {
255
+ throw new Error(`Unable to parse path ${configPath}`)
256
+ }
257
+
258
+ return {
259
+ product: match[1],
260
+ id: match[2]
261
+ }
262
+ }
263
+
264
+ module.exports = RemoteConfigManager
@@ -8,21 +8,21 @@ class Scheduler {
8
8
  }
9
9
 
10
10
  start () {
11
- this._timer = setInterval(this._callback, this._interval)
12
- this._timer.unref && this._timer.unref()
11
+ if (this._timer) return
13
12
 
14
- process.once('beforeExit', this._callback)
13
+ this.runAfterDelay(0)
15
14
  }
16
15
 
17
- stop () {
18
- clearInterval(this._timer)
16
+ runAfterDelay (interval = this._interval) {
17
+ this._timer = setTimeout(this._callback, interval, () => this.runAfterDelay())
19
18
 
20
- process.removeListener('beforeExit', this._callback)
19
+ this._timer.unref && this._timer.unref()
21
20
  }
22
21
 
23
- reset () {
24
- this.stop()
25
- this.start()
22
+ stop () {
23
+ clearTimeout(this._timer)
24
+
25
+ this._timer = null
26
26
  }
27
27
  }
28
28