@contrast/agent 4.5.1 → 4.7.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 (209) hide show
  1. package/bin/VERSION +1 -1
  2. package/bin/linux/contrast-service +0 -0
  3. package/bin/mac/contrast-service +0 -0
  4. package/bin/windows/contrast-service.exe +0 -0
  5. package/lib/assess/membrane/deserialization-membrane.js +4 -5
  6. package/lib/assess/membrane/source-membrane.js +16 -33
  7. package/lib/assess/models/call-context.js +1 -1
  8. package/lib/assess/policy/propagators.json +19 -21
  9. package/lib/assess/policy/rules.json +7 -2
  10. package/lib/assess/policy/signatures.json +42 -0
  11. package/lib/assess/policy/util.js +2 -1
  12. package/lib/assess/propagators/JSON/parse.js +1 -1
  13. package/lib/assess/propagators/JSON/stringify.js +3 -3
  14. package/lib/assess/propagators/array-prototype-join.js +7 -8
  15. package/lib/assess/propagators/common.js +7 -5
  16. package/lib/assess/propagators/dustjs/escape-html.js +22 -0
  17. package/lib/assess/propagators/dustjs/escape-js.js +22 -0
  18. package/lib/assess/propagators/encode-uri/encode-uri-component.js +22 -0
  19. package/lib/assess/propagators/encode-uri/encode-uri.js +22 -0
  20. package/lib/assess/propagators/handlebars-escape-expresssion.js +1 -1
  21. package/lib/assess/propagators/index.js +0 -2
  22. package/lib/assess/propagators/joi/boolean.js +1 -1
  23. package/lib/assess/propagators/joi/expression.js +1 -1
  24. package/lib/assess/propagators/joi/number.js +1 -1
  25. package/lib/assess/propagators/joi/string-base.js +1 -1
  26. package/lib/assess/propagators/joi/string-schema.js +12 -13
  27. package/lib/assess/propagators/joi/values.js +37 -22
  28. package/lib/assess/propagators/manager.js +12 -10
  29. package/lib/assess/propagators/mongoose/helpers.js +20 -0
  30. package/lib/assess/propagators/mongoose/index.js +18 -0
  31. package/lib/assess/propagators/mongoose/map.js +74 -0
  32. package/lib/assess/propagators/mongoose/string.js +104 -0
  33. package/lib/assess/propagators/mustache/escape.js +22 -0
  34. package/lib/assess/propagators/number.js +54 -0
  35. package/lib/assess/propagators/object.js +6 -7
  36. package/lib/assess/propagators/path/basename.js +14 -13
  37. package/lib/assess/propagators/path/common.js +156 -47
  38. package/lib/assess/propagators/path/dirname.js +14 -13
  39. package/lib/assess/propagators/path/extname.js +14 -13
  40. package/lib/assess/propagators/path/join.js +5 -1
  41. package/lib/assess/propagators/path/normalize.js +1 -2
  42. package/lib/assess/propagators/path/parse.js +1 -1
  43. package/lib/assess/propagators/path/relative.js +7 -5
  44. package/lib/assess/propagators/path/resolve.js +11 -2
  45. package/lib/assess/propagators/querystring/escape.js +20 -18
  46. package/lib/assess/propagators/querystring/parse.js +7 -5
  47. package/lib/assess/propagators/querystring/stringify.js +25 -24
  48. package/lib/assess/propagators/querystring/unescape.js +20 -18
  49. package/lib/assess/propagators/sequelize/sql-string-escape.js +1 -1
  50. package/lib/assess/propagators/sequelize/sql-string-format-named-parameters.js +1 -1
  51. package/lib/assess/propagators/sequelize/sql-string-format.js +3 -3
  52. package/lib/assess/propagators/sequelize/utils.js +2 -2
  53. package/lib/assess/propagators/string-prototype-replace.js +30 -28
  54. package/lib/assess/propagators/string-prototype-split.js +36 -36
  55. package/lib/assess/propagators/string-prototype-trim.js +15 -17
  56. package/lib/assess/propagators/string.js +12 -16
  57. package/lib/assess/propagators/template-escape.js +87 -0
  58. package/lib/assess/propagators/templates.js +10 -11
  59. package/lib/assess/propagators/url/url-prototype-parse.js +5 -6
  60. package/lib/assess/propagators/url/url-url.js +51 -43
  61. package/lib/assess/propagators/util/format.js +1 -1
  62. package/lib/assess/propagators/v8/init-hooks.js +3 -3
  63. package/lib/assess/propagators/validator/init-hooks.js +22 -22
  64. package/lib/assess/sinks/common.js +10 -5
  65. package/lib/assess/sinks/dustjs-linkedin-xss.js +131 -0
  66. package/lib/assess/sinks/libxmljs-xxe.js +1 -1
  67. package/lib/assess/sinks/mongodb.js +2 -1
  68. package/lib/assess/sinks/ssrf-url.js +1 -1
  69. package/lib/constants.js +4 -1
  70. package/lib/core/arch-components/dynamodb.js +1 -2
  71. package/lib/core/arch-components/dynamodbv3.js +44 -0
  72. package/lib/core/arch-components/index.js +1 -0
  73. package/lib/core/arch-components/rethinkdb.js +53 -0
  74. package/lib/core/config/options.js +3 -2
  75. package/lib/core/rewrite/injections.js +8 -0
  76. package/lib/core/stacktrace.js +2 -1
  77. package/lib/feature-set.js +1 -1
  78. package/lib/hooks/frameworks/base.js +8 -2
  79. package/lib/hooks/frameworks/http.js +23 -16
  80. package/lib/hooks/frameworks/http2.js +73 -0
  81. package/lib/hooks/frameworks/index.js +8 -3
  82. package/lib/hooks/http.js +112 -128
  83. package/lib/hooks/object-to-primitive.js +6 -7
  84. package/lib/hooks/patcher.js +75 -44
  85. package/lib/hooks/require.js +16 -22
  86. package/lib/instrumentation.js +0 -3
  87. package/lib/protect/rules/nosqli/nosql-injection-rule.js +228 -0
  88. package/lib/protect/rules/rule-factory.js +2 -2
  89. package/lib/protect/service.js +23 -11
  90. package/lib/protect/sinks/mongodb.js +56 -55
  91. package/lib/reporter/translations/to-protobuf/dtm/index.js +1 -1
  92. package/lib/reporter/translations/to-protobuf/dtm/ip-denylist-details.js +1 -1
  93. package/lib/reporter/translations/to-protobuf/dtm/rasp-rule-sample.js +1 -1
  94. package/lib/reporter/translations/to-protobuf/settings/defend-features.js +8 -6
  95. package/lib/reporter/translations/to-protobuf/settings/exclusions.js +5 -4
  96. package/lib/tracker.js +13 -65
  97. package/lib/util/some.js +27 -0
  98. package/lib/util/source-map.js +1 -1
  99. package/package.json +15 -16
  100. package/lib/hooks/frameworks/https.js +0 -42
  101. package/lib/protect/rules/nosqli/no-sql-injection-rule.js +0 -109
  102. package/node_modules/bindings/LICENSE.md +0 -22
  103. package/node_modules/bindings/README.md +0 -98
  104. package/node_modules/bindings/bindings.js +0 -221
  105. package/node_modules/bindings/package.json +0 -32
  106. package/node_modules/file-uri-to-path/.npmignore +0 -1
  107. package/node_modules/file-uri-to-path/.travis.yml +0 -30
  108. package/node_modules/file-uri-to-path/History.md +0 -21
  109. package/node_modules/file-uri-to-path/LICENSE +0 -20
  110. package/node_modules/file-uri-to-path/README.md +0 -74
  111. package/node_modules/file-uri-to-path/index.d.ts +0 -2
  112. package/node_modules/file-uri-to-path/index.js +0 -66
  113. package/node_modules/file-uri-to-path/package.json +0 -36
  114. package/node_modules/file-uri-to-path/test/test.js +0 -24
  115. package/node_modules/file-uri-to-path/test/tests.json +0 -13
  116. package/node_modules/glossy/LICENSE +0 -19
  117. package/node_modules/glossy/README.md +0 -129
  118. package/node_modules/glossy/index.js +0 -12
  119. package/node_modules/glossy/lib/glossy/parse.js +0 -520
  120. package/node_modules/glossy/lib/glossy/produce.js +0 -459
  121. package/node_modules/glossy/package.json +0 -47
  122. package/node_modules/glossy/test/decide.js +0 -7
  123. package/node_modules/glossy/test/decode_pri.js +0 -24
  124. package/node_modules/glossy/test/parse_3164.js +0 -104
  125. package/node_modules/glossy/test/parse_5424.js +0 -106
  126. package/node_modules/glossy/test/parse_5848.js +0 -40
  127. package/node_modules/glossy/test/parse_8601.js +0 -14
  128. package/node_modules/glossy/test/parse_rfc3339.js +0 -9
  129. package/node_modules/glossy/test/produce.js +0 -162
  130. package/node_modules/glossy/test/runner.js +0 -40
  131. package/node_modules/glossy/test/structure_data.js +0 -24
  132. package/node_modules/nan/CHANGELOG.md +0 -537
  133. package/node_modules/nan/LICENSE.md +0 -13
  134. package/node_modules/nan/README.md +0 -455
  135. package/node_modules/nan/doc/asyncworker.md +0 -146
  136. package/node_modules/nan/doc/buffers.md +0 -54
  137. package/node_modules/nan/doc/callback.md +0 -76
  138. package/node_modules/nan/doc/converters.md +0 -41
  139. package/node_modules/nan/doc/errors.md +0 -226
  140. package/node_modules/nan/doc/json.md +0 -62
  141. package/node_modules/nan/doc/maybe_types.md +0 -583
  142. package/node_modules/nan/doc/methods.md +0 -664
  143. package/node_modules/nan/doc/new.md +0 -147
  144. package/node_modules/nan/doc/node_misc.md +0 -123
  145. package/node_modules/nan/doc/object_wrappers.md +0 -263
  146. package/node_modules/nan/doc/persistent.md +0 -296
  147. package/node_modules/nan/doc/scopes.md +0 -73
  148. package/node_modules/nan/doc/script.md +0 -38
  149. package/node_modules/nan/doc/string_bytes.md +0 -62
  150. package/node_modules/nan/doc/v8_internals.md +0 -199
  151. package/node_modules/nan/doc/v8_misc.md +0 -85
  152. package/node_modules/nan/include_dirs.js +0 -1
  153. package/node_modules/nan/nan.h +0 -2898
  154. package/node_modules/nan/nan_callbacks.h +0 -88
  155. package/node_modules/nan/nan_callbacks_12_inl.h +0 -514
  156. package/node_modules/nan/nan_callbacks_pre_12_inl.h +0 -520
  157. package/node_modules/nan/nan_converters.h +0 -72
  158. package/node_modules/nan/nan_converters_43_inl.h +0 -68
  159. package/node_modules/nan/nan_converters_pre_43_inl.h +0 -42
  160. package/node_modules/nan/nan_define_own_property_helper.h +0 -29
  161. package/node_modules/nan/nan_implementation_12_inl.h +0 -430
  162. package/node_modules/nan/nan_implementation_pre_12_inl.h +0 -263
  163. package/node_modules/nan/nan_json.h +0 -166
  164. package/node_modules/nan/nan_maybe_43_inl.h +0 -356
  165. package/node_modules/nan/nan_maybe_pre_43_inl.h +0 -268
  166. package/node_modules/nan/nan_new.h +0 -340
  167. package/node_modules/nan/nan_object_wrap.h +0 -156
  168. package/node_modules/nan/nan_persistent_12_inl.h +0 -132
  169. package/node_modules/nan/nan_persistent_pre_12_inl.h +0 -242
  170. package/node_modules/nan/nan_private.h +0 -73
  171. package/node_modules/nan/nan_string_bytes.h +0 -305
  172. package/node_modules/nan/nan_typedarray_contents.h +0 -96
  173. package/node_modules/nan/nan_weak.h +0 -437
  174. package/node_modules/nan/package.json +0 -41
  175. package/node_modules/nan/tools/1to2.js +0 -412
  176. package/node_modules/nan/tools/README.md +0 -14
  177. package/node_modules/nan/tools/package.json +0 -19
  178. package/node_modules/unix-dgram/LICENSE +0 -13
  179. package/node_modules/unix-dgram/README.md +0 -107
  180. package/node_modules/unix-dgram/binding.gyp +0 -20
  181. package/node_modules/unix-dgram/build/Makefile +0 -324
  182. package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram/src/unix_dgram.o.d +0 -58
  183. package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram.node.d +0 -1
  184. package/node_modules/unix-dgram/build/Release/.deps/Release/unix_dgram.node.d +0 -1
  185. package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram/src/unix_dgram.o +0 -0
  186. package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram.node +0 -0
  187. package/node_modules/unix-dgram/build/Release/unix_dgram.node +0 -0
  188. package/node_modules/unix-dgram/build/binding.Makefile +0 -6
  189. package/node_modules/unix-dgram/build/config.gypi +0 -213
  190. package/node_modules/unix-dgram/build/unix_dgram.target.mk +0 -159
  191. package/node_modules/unix-dgram/lib/unix_dgram.js +0 -168
  192. package/node_modules/unix-dgram/package.json +0 -36
  193. package/node_modules/unix-dgram/src/unix_dgram.cc +0 -404
  194. package/node_modules/unix-dgram/src/win_dummy.cc +0 -7
  195. package/node_modules/unix-dgram/test/test-connect-callback.js +0 -68
  196. package/node_modules/unix-dgram/test/test-connect.js +0 -53
  197. package/node_modules/unix-dgram/test/test-dgram-unix.js +0 -58
  198. package/node_modules/unix-dgram/test/test-send-error.js +0 -26
  199. package/node_modules/winston-syslog/.eslintrc +0 -7
  200. package/node_modules/winston-syslog/.travis.yml +0 -14
  201. package/node_modules/winston-syslog/CHANGELOG.md +0 -9
  202. package/node_modules/winston-syslog/LICENSE +0 -20
  203. package/node_modules/winston-syslog/README.md +0 -135
  204. package/node_modules/winston-syslog/lib/utils.js +0 -26
  205. package/node_modules/winston-syslog/lib/winston-syslog.js +0 -385
  206. package/node_modules/winston-syslog/package.json +0 -56
  207. package/node_modules/winston-syslog/test/format-test.js +0 -122
  208. package/node_modules/winston-syslog/test/syslog-test.js +0 -95
  209. package/node_modules/winston-syslog/test/unix-connect-test.js +0 -133
@@ -212,7 +212,7 @@ class FeatureSet {
212
212
  */
213
213
  getIpDenylistPolicy() {
214
214
  const config = this.getProtectRuleConfig(RULES.IP_DENYLIST);
215
- const settings = _.get(this, 'serverFeatures.defend.ipBlacklistsList', []);
215
+ const settings = _.get(this, 'serverFeatures.defend.ipDenylistsList', []);
216
216
 
217
217
  return {
218
218
  id: RULES.IP_DENYLIST,
@@ -22,8 +22,14 @@ const RequestFactory = require('../../reporter/models/utils/request-factory');
22
22
  const CleanStack = require('../../util/clean-stack');
23
23
  const agentEmitter = require('../../agent-emitter');
24
24
 
25
+ /** @typedef {import('../../agent').ContrastAgent} Agent */
26
+
25
27
  class BaseFramework {
26
- // sets options
28
+ /**
29
+ * @param {Object} opts
30
+ * @param {string} opts.id
31
+ * @param {Agent} opts.agent
32
+ */
27
33
  constructor({ id, agent } = {}) {
28
34
  this.id = id;
29
35
  this.agent = agent;
@@ -46,7 +52,7 @@ class BaseFramework {
46
52
  * -- Note --
47
53
  * The current imlementation uses a CleanStack instance in order to generate
48
54
  * a stackframe from which to obtain the information. This can be expensive.
49
- * @returns {String}
55
+ * @returns {string}
50
56
  */
51
57
  getAppCodeLocation() {
52
58
  const limit = Error.stackTraceLimit;
@@ -19,39 +19,41 @@ const moduleHook = require('../require');
19
19
  const patcher = require('../patcher');
20
20
  const { HTTP_EVENTS, PATCH_TYPES } = require('../../constants');
21
21
 
22
- class HttpFramework extends BaseFramework {
23
- constructor(agent, id = 'http') {
24
- super({ id, agent });
25
-
26
- this.init();
27
- }
22
+ /** @typedef {import('../../agent').ContrastAgent} Agent */
23
+ /** @typedef {import('net').Server} Server */
28
24
 
25
+ class HttpFramework extends BaseFramework {
29
26
  /**
30
- * Initialization logic.
27
+ * @param {Agent} agent
28
+ * @param {string} id
31
29
  */
32
- init() {
30
+ constructor(agent, id = 'http') {
31
+ super({ agent, id });
33
32
  moduleHook.resolve({ name: this.id }, this.onRequire.bind(this));
34
33
  }
35
34
 
35
+ /**
36
+ * @template {import('http') | import('https')} T
37
+ * @param {T} xport
38
+ * @returns {T}
39
+ */
36
40
  onRequire(xport) {
37
- const { id } = this;
38
-
39
41
  patcher.patch(xport, 'Server', {
40
- name: `${id}.Server`,
42
+ name: `${this.id}.Server`,
41
43
  patchType: PATCH_TYPES.FRAMEWORK,
42
44
  alwaysRun: true,
43
45
  post: (fnData) => this.handleServerCreate(fnData.args, fnData.result)
44
46
  });
45
47
 
46
48
  patcher.patch(xport, 'createServer', {
47
- name: `${id}.createServer`,
49
+ name: `${this.id}.createServer`,
48
50
  patchType: PATCH_TYPES.FRAMEWORK,
49
51
  alwaysRun: true,
50
52
  post: (fnData) => this.handleServerCreate(fnData.args, fnData.result)
51
53
  });
52
54
 
53
55
  patcher.patch(xport.Server.prototype, 'listen', {
54
- name: `${id}.Server.prototype`,
56
+ name: `${this.id}.Server.prototype`,
55
57
  patchType: PATCH_TYPES.FRAMEWORK,
56
58
  alwaysRun: true,
57
59
  pre: (fnData) => this.handleServerListen(fnData.args, fnData.obj)
@@ -62,6 +64,7 @@ class HttpFramework extends BaseFramework {
62
64
 
63
65
  /**
64
66
  * Emits a listen event if one has not been pubished for the server instance.
67
+ * @param {any[]}
65
68
  * @param {Server} server Server on which `listen` was called
66
69
  */
67
70
  handleServerListen(args, server) {
@@ -70,12 +73,16 @@ class HttpFramework extends BaseFramework {
70
73
 
71
74
  /**
72
75
  * Emits a create event for the new Server instance.
73
- * @param {*[]} args The arguments passed to the Server constructor
76
+ * @param {any[]} args The arguments passed to the Server constructor
74
77
  * @param {Server} server The http Server instance
75
78
  */
76
79
  handleServerCreate(args, server) {
77
- const [callback] = args;
78
- this.emitter.emit(HTTP_EVENTS.SERVER_CREATE, callback, server);
80
+ const [options] = args;
81
+ let [, handler] = args;
82
+ if (typeof options === 'function') {
83
+ handler = options;
84
+ }
85
+ this.emitter.emit(HTTP_EVENTS.SERVER_CREATE, handler, server);
79
86
  }
80
87
  }
81
88
 
@@ -0,0 +1,73 @@
1
+ /**
2
+ Copyright: 2021 Contrast Security, Inc
3
+ Contact: support@contrastsecurity.com
4
+ License: Commercial
5
+
6
+ NOTICE: This Software and the patented inventions embodied within may only be
7
+ used as part of Contrast Security’s commercial offerings. Even though it is
8
+ made available through public repositories, use of this Software is subject to
9
+ the applicable End User Licensing Agreement found at
10
+ https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ between Contrast Security and the End User. The Software may not be reverse
12
+ engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ way not consistent with the End User License Agreement.
14
+ */
15
+ 'use strict';
16
+
17
+ const { PATCH_TYPES } = require('../../constants');
18
+ const patcher = require('../patcher');
19
+ const HttpFramework = require('./http');
20
+
21
+ /** @typedef {import('../../agent').ContrastAgent} Agent */
22
+
23
+ class Http2Framework extends HttpFramework {
24
+ /**
25
+ * @param {Agent} agent
26
+ */
27
+ constructor(agent) {
28
+ super(agent, 'http2');
29
+ }
30
+
31
+ /**
32
+ * @param {import('http2')} http2
33
+ * @returns {import('http2')}
34
+ */
35
+ onRequire(http2) {
36
+ patcher.patch(http2, 'createServer', {
37
+ name: `${this.id}.createServer`,
38
+ patchType: PATCH_TYPES.FRAMEWORK,
39
+ alwaysRun: true,
40
+ post: ({ args, result }) => this.handleServerCreate(args, result)
41
+ });
42
+
43
+ patcher.patch(http2, 'createSecureServer', {
44
+ name: `${this.id}.createSecureServer`,
45
+ patchType: PATCH_TYPES.FRAMEWORK,
46
+ alwaysRun: true,
47
+ post: ({ args, result }) => this.handleServerCreate(args, result)
48
+ });
49
+
50
+ return http2;
51
+ }
52
+
53
+ /**
54
+ * Emits a create event for the new Server instance.
55
+ * @param {any[]} args The arguments passed to the Server constructor
56
+ * @param {import('net').Server} server The http Server instance
57
+ */
58
+ handleServerCreate(args, server) {
59
+ super.handleServerCreate(args, server);
60
+
61
+ // Since the `Http2Server` class is not exported, we can patch it here after
62
+ // creation.
63
+ // NOTE: could we just patch `net.Server` here and in `http`?
64
+ patcher.patch(server, 'listen', {
65
+ name: `${this.id}.Http2Server.listen`,
66
+ patchType: PATCH_TYPES.FRAMEWORK,
67
+ alwaysRun: true,
68
+ pre: ({ args, obj }) => this.handleServerListen(args, obj)
69
+ });
70
+ }
71
+ }
72
+
73
+ module.exports = Http2Framework;
@@ -14,9 +14,14 @@ Copyright: 2021 Contrast Security, Inc
14
14
  */
15
15
  'use strict';
16
16
 
17
+ const Http = require('./http');
18
+ const Http2 = require('./http2');
19
+ const Hapi16 = require('./hapi16');
20
+
17
21
  module.exports = function(agent) {
18
22
  // load all the hooks
19
- new (require('./http'))(agent);
20
- new (require('./https'))(agent);
21
- new (require('./hapi16'))(agent);
23
+ new Http(agent);
24
+ new Http(agent, 'https');
25
+ new Http2(agent);
26
+ new Hapi16(agent);
22
27
  };
package/lib/hooks/http.js CHANGED
@@ -35,39 +35,45 @@ const logger = require('../core/logger')('contrast:hooks');
35
35
  const patcher = require('./patcher');
36
36
  const { PATCH_TYPES } = require('../constants');
37
37
 
38
- module.exports = function(agent) {
39
- logger.info('applying non-policy hook: http');
38
+ const flatten = (ary) => Array.prototype.join.apply(ary, [',']);
40
39
 
41
- moduleHook.resolve({ name: 'http' }, function(http) {
42
- hookServerPrototype(http.Server.prototype, agent);
43
- });
44
- moduleHook.resolve({ name: 'https' }, function(https) {
45
- hookServerPrototype(https.Server.prototype, agent);
40
+ /**
41
+ * Logs stack for every res.[end, writeHead, write] call
42
+ *
43
+ * @param {ServerResponse} response
44
+ * @param {string} method method to hook
45
+ */
46
+ const logHook = (response, method) => {
47
+ patcher.patch(response, method, {
48
+ alwaysRun: true,
49
+ name: 'req-log',
50
+ patchType: PATCH_TYPES.MISC,
51
+ post(data) {
52
+ const { stack } = new Error();
53
+ logger.info('res.%s(%s):%o', method, flatten(data.args), stack);
54
+ }
46
55
  });
47
56
  };
48
57
 
49
- module.exports.getId = getId;
50
- module.exports.hookServerPrototype = hookServerPrototype;
51
-
52
58
  /**
53
59
  * Hooks the Server prototype's <code>emit</code> method.
54
- * @param {Server} proto The Server prototype
60
+ * @param {Server} server The Server prototype
55
61
  */
56
- function hookServerPrototype(proto, agent) {
57
- patcher.patch(proto, 'listen', {
62
+ const hookServer = (server, agent, id) => {
63
+ patcher.patch(server, 'listen', {
58
64
  alwaysRun: true,
59
65
  name: 'server-listen-log-time',
60
66
  patchType: PATCH_TYPES.MISC,
61
- pre(data) {
67
+ pre() {
62
68
  logger.info(`${process.pid}: http listen after ${process.uptime()}`);
63
69
  }
64
70
  });
65
71
 
66
72
  // Wrap the request emit in a contrast domain to track non-dataflow hooks, and for storage.
67
- const { emit } = proto;
68
- proto.emit = function(...args) {
69
- const [event, req, res] = args;
73
+ const { emit } = server;
74
+ server.emit = function newEmit(...args) {
70
75
  const self = this;
76
+ const [event, req, res] = args;
71
77
 
72
78
  if (event === 'request') {
73
79
  logger.debug('Received request %s, method %s', req.url, req.method);
@@ -75,35 +81,77 @@ function hookServerPrototype(proto, agent) {
75
81
  agent,
76
82
  req,
77
83
  res,
78
- hookResponse,
79
- callback: () => {
84
+ hookResponse(response, agent) {
85
+ const { writeHead, end } = response;
86
+ // XXX(ehden): we keep the original method available to call when handling
87
+ // blocked requests because of MethodTampering or other rules whose sink
88
+ // type is RESPONSE_STATUS and which can block at perimeter. We call the original
89
+ // when we block to prevent recursing through blocks by setting our own 403.
90
+ response[WRITE_HEAD] = writeHead;
91
+ response[END] = end;
92
+
93
+ /**
94
+ * Patch writeHead to emit a sink event before calling writeHead
95
+ *
96
+ */
97
+ patcher.patch(response, 'writeHead', {
98
+ alwaysRun: true,
99
+ name: 'write-head',
100
+ patchType: PATCH_TYPES.PROTECT_SINK,
101
+ pre(data) {
102
+ const [statusCode, reason] = data.args;
103
+ let [, , obj] = data.args;
104
+ let contentType;
105
+ if (typeof reason !== 'string') {
106
+ obj = reason;
107
+ }
108
+ if (obj && typeof obj === 'object') {
109
+ for (const [key, value] of Object.entries(obj)) {
110
+ if (key.toLowerCase() === 'content-type') {
111
+ contentType = value;
112
+ }
113
+ }
114
+ }
115
+ if (contentType) {
116
+ AsyncStorage.set(KEYS.RESPONSE_CONTENT_TYPE, contentType);
117
+ }
118
+ emitSinkEvent(statusCode, SINK_TYPES.RESPONSE_STATUS, id, false);
119
+ }
120
+ });
121
+
122
+ patcher.patch(response, 'setHeader', {
123
+ alwaysRun: true,
124
+ name: 'set-header',
125
+ patchType: PATCH_TYPES.ASYNC_CONTEXT,
126
+ pre(data) {
127
+ const [name = '', value] = data.args;
128
+ if (name.toLowerCase() === 'content-type' && value) {
129
+ AsyncStorage.set(KEYS.RESPONSE_CONTENT_TYPE, value);
130
+ }
131
+ }
132
+ });
133
+
134
+ // special HTTP logging for responses.
135
+ if (agent.config.agent.logger.log_outbound_http) {
136
+ ['end', 'writeHead', 'write'].forEach((method) => {
137
+ logHook(response, method);
138
+ });
139
+ }
140
+ },
141
+ callback() {
80
142
  const ipEvent = createSourceEvent(
81
143
  req,
82
144
  req,
83
145
  res,
84
- 'connection.remoteAddress',
146
+ 'socket.remoteAddress',
85
147
  INPUT_TYPES.IP,
86
- getId(req)
148
+ id
87
149
  );
88
150
  agentEmitter.emit('http.requestStart', req, res, ipEvent);
89
151
 
90
- emitSourceEvent(
91
- req,
92
- req,
93
- res,
94
- 'method',
95
- INPUT_TYPES.METHOD,
96
- getId(req)
97
- );
98
- emitSourceEvent(
99
- req,
100
- req,
101
- res,
102
- 'headers',
103
- INPUT_TYPES.HEADER,
104
- getId(req)
105
- );
106
- emitSourceEvent(req, req, res, 'url', INPUT_TYPES.URL, getId(req));
152
+ emitSourceEvent(req, req, res, 'method', INPUT_TYPES.METHOD, id);
153
+ emitSourceEvent(req, req, res, 'headers', INPUT_TYPES.HEADER, id);
154
+ emitSourceEvent(req, req, res, 'url', INPUT_TYPES.URL, id);
107
155
 
108
156
  const rv = emit.apply(self, args);
109
157
 
@@ -115,101 +163,37 @@ function hookServerPrototype(proto, agent) {
115
163
  return emit.apply(self, args);
116
164
  }
117
165
  };
118
- }
166
+ };
119
167
 
120
- /**
121
- * Patches ServerResponse instances and runs in AsyncStorage
122
- * context.
123
- * @param {ServerResponse} res
124
- */
125
- function hookResponse(res, agent) {
126
- const flattenArgs = (args) => Array.prototype.join.apply(args, [',']);
127
-
128
- /*
129
- * Logs stack for every res.[end, writeHead, write] call
130
- *
131
- * @param {ServerResponse} res
132
- * @param {string} method method to hook
133
- */
134
- function logHook(res, method) {
135
- patcher.patch(res, method, {
136
- alwaysRun: true,
137
- name: 'req-log',
138
- patchType: PATCH_TYPES.MISC,
139
- post(data) {
140
- const { stack } = new Error();
141
- logger.info('res.%s(%s):%o', method, flattenArgs(data.args), stack);
142
- }
143
- });
144
- }
145
-
146
- const { writeHead, end } = res;
147
- // XXX(ehden): we keep the original method available to call when handling
148
- // blocked requests because of MethodTampering or other rules whose sink
149
- // type is RESPONSE_STATUS and which can block at perimeter. We call the original
150
- // when we block to prevent recursing through blocks by setting our own 403.
151
- res[WRITE_HEAD] = writeHead;
152
- res[END] = end;
153
-
154
- /**
155
- * Patch writeHead to emit a sink event before calling writeHead
156
- *
157
- */
158
- patcher.patch(res, 'writeHead', {
159
- alwaysRun: true,
160
- name: 'write-head',
161
- patchType: PATCH_TYPES.PROTECT_SINK,
162
- pre(data) {
163
- let contentType;
164
- if (data.args[1] && typeof data.args[1] === 'object') {
165
- for (const [key, value] of Object.entries(data.args[1])) {
166
- if (key.toLowerCase() === 'content-type') {
167
- contentType = value;
168
- }
169
- }
170
- }
168
+ module.exports = (agent) => {
169
+ logger.info('applying non-policy hook: http');
171
170
 
172
- if (contentType) {
173
- AsyncStorage.set(KEYS.RESPONSE_CONTENT_TYPE, contentType);
174
- }
175
- const [statusCode] = data.args;
176
- emitSinkEvent(statusCode, SINK_TYPES.RESPONSE_STATUS, getId(this), false);
177
- }
171
+ moduleHook.resolve({ name: 'http' }, (http) => {
172
+ hookServer(http.Server.prototype, agent, 'http');
178
173
  });
179
174
 
180
- patcher.patch(res, 'setHeader', {
181
- alwaysRun: true,
182
- name: 'set-header',
183
- patchType: PATCH_TYPES.ASYNC_CONTEXT,
184
- pre(data) {
185
- if (
186
- (data.args[0] || '').toLowerCase() === 'content-type' &&
187
- data.args[1]
188
- ) {
189
- AsyncStorage.set(KEYS.RESPONSE_CONTENT_TYPE, data.args[1]);
190
- }
191
- }
175
+ moduleHook.resolve({ name: 'https' }, (https) => {
176
+ hookServer(https.Server.prototype, agent, 'https');
192
177
  });
193
178
 
194
- // special HTTP logging for responses.
195
- if (agent.config.agent.logger.log_outbound_http) {
196
- ['end', 'writeHead', 'write'].forEach((method) => {
197
- logHook(res, method);
179
+ moduleHook.resolve({ name: 'http2' }, (http2) => {
180
+ patcher.patch(http2, 'createServer', {
181
+ name: `create-server-http2-hooks`,
182
+ patchType: PATCH_TYPES.MISC,
183
+ alwaysRun: true,
184
+ post({ result }) {
185
+ hookServer(result, agent);
186
+ }
198
187
  });
199
- }
200
- }
201
188
 
202
- /**
203
- * Returns http or https depending on information about the
204
- * incomingMessage
205
- *
206
- * @param {IncomingMessage} req
207
- * @return {string} http or https
208
- */
209
- function getId(req) {
210
- if (req == null || req.socket == null) {
211
- return 'http';
212
- } else {
213
- return req.socket.encrypted ? 'https' : 'http';
214
- }
215
- }
189
+ patcher.patch(http2, 'createSecureServer', {
190
+ name: `create-secure-server-http2-hooks`,
191
+ patchType: PATCH_TYPES.MISC,
192
+ alwaysRun: true,
193
+ post({ result }) {
194
+ hookServer(result, agent);
195
+ }
196
+ });
197
+ });
198
+ };
199
+ module.exports.hookServer = hookServer;
@@ -31,13 +31,12 @@ const tracker = require('../tracker');
31
31
  function wrapNativeMethod(origFn, str) {
32
32
  let s = Reflect.apply(origFn, str, []);
33
33
  const origProps = tracker.getData(str);
34
- if (origProps.tracked) {
35
- s = tracker.track(s);
36
-
37
- const contrastProps = tracker.getData(s);
38
- if (contrastProps.tracked) {
39
- contrastProps.tagRanges = origProps.tagRanges;
40
- contrastProps.event = origProps.event;
34
+ if (origProps) {
35
+ const tracked = tracker.track(s);
36
+ if (tracked) {
37
+ s = tracked.str;
38
+ tracked.props.tagRanges = origProps.tagRanges;
39
+ tracked.props.event = origProps.event;
41
40
  }
42
41
  }
43
42
  return s;