mocktp 0.0.1-security → 3.15.3

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.

Potentially problematic release.


This version of mocktp might be problematic. Click here for more details.

Files changed (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +123 -3
  3. package/custom-typings/Function.d.ts +4 -0
  4. package/custom-typings/cors-gate.d.ts +13 -0
  5. package/custom-typings/http-proxy-agent.d.ts +9 -0
  6. package/custom-typings/node-type-extensions.d.ts +115 -0
  7. package/custom-typings/proxy-agent-modules.d.ts +5 -0
  8. package/custom-typings/request-promise-native.d.ts +28 -0
  9. package/custom-typings/zstd-codec.d.ts +20 -0
  10. package/dist/admin/admin-bin.d.ts +3 -0
  11. package/dist/admin/admin-bin.d.ts.map +1 -0
  12. package/dist/admin/admin-bin.js +61 -0
  13. package/dist/admin/admin-bin.js.map +1 -0
  14. package/dist/admin/admin-plugin-types.d.ts +29 -0
  15. package/dist/admin/admin-plugin-types.d.ts.map +1 -0
  16. package/dist/admin/admin-plugin-types.js +3 -0
  17. package/dist/admin/admin-plugin-types.js.map +1 -0
  18. package/dist/admin/admin-server.d.ts +98 -0
  19. package/dist/admin/admin-server.d.ts.map +1 -0
  20. package/dist/admin/admin-server.js +426 -0
  21. package/dist/admin/admin-server.js.map +1 -0
  22. package/dist/admin/graphql-utils.d.ts +4 -0
  23. package/dist/admin/graphql-utils.d.ts.map +1 -0
  24. package/dist/admin/graphql-utils.js +28 -0
  25. package/dist/admin/graphql-utils.js.map +1 -0
  26. package/dist/admin/mockttp-admin-model.d.ts +7 -0
  27. package/dist/admin/mockttp-admin-model.d.ts.map +1 -0
  28. package/dist/admin/mockttp-admin-model.js +214 -0
  29. package/dist/admin/mockttp-admin-model.js.map +1 -0
  30. package/dist/admin/mockttp-admin-plugin.d.ts +28 -0
  31. package/dist/admin/mockttp-admin-plugin.d.ts.map +1 -0
  32. package/dist/admin/mockttp-admin-plugin.js +37 -0
  33. package/dist/admin/mockttp-admin-plugin.js.map +1 -0
  34. package/dist/admin/mockttp-admin-server.d.ts +16 -0
  35. package/dist/admin/mockttp-admin-server.d.ts.map +1 -0
  36. package/dist/admin/mockttp-admin-server.js +17 -0
  37. package/dist/admin/mockttp-admin-server.js.map +1 -0
  38. package/dist/admin/mockttp-schema.d.ts +2 -0
  39. package/dist/admin/mockttp-schema.d.ts.map +1 -0
  40. package/dist/admin/mockttp-schema.js +225 -0
  41. package/dist/admin/mockttp-schema.js.map +1 -0
  42. package/dist/client/admin-client.d.ts +112 -0
  43. package/dist/client/admin-client.d.ts.map +1 -0
  44. package/dist/client/admin-client.js +511 -0
  45. package/dist/client/admin-client.js.map +1 -0
  46. package/dist/client/admin-query.d.ts +13 -0
  47. package/dist/client/admin-query.d.ts.map +1 -0
  48. package/dist/client/admin-query.js +26 -0
  49. package/dist/client/admin-query.js.map +1 -0
  50. package/dist/client/mocked-endpoint-client.d.ts +12 -0
  51. package/dist/client/mocked-endpoint-client.d.ts.map +1 -0
  52. package/dist/client/mocked-endpoint-client.js +33 -0
  53. package/dist/client/mocked-endpoint-client.js.map +1 -0
  54. package/dist/client/mockttp-admin-request-builder.d.ts +38 -0
  55. package/dist/client/mockttp-admin-request-builder.d.ts.map +1 -0
  56. package/dist/client/mockttp-admin-request-builder.js +462 -0
  57. package/dist/client/mockttp-admin-request-builder.js.map +1 -0
  58. package/dist/client/mockttp-client.d.ts +56 -0
  59. package/dist/client/mockttp-client.d.ts.map +1 -0
  60. package/dist/client/mockttp-client.js +112 -0
  61. package/dist/client/mockttp-client.js.map +1 -0
  62. package/dist/client/schema-introspection.d.ts +11 -0
  63. package/dist/client/schema-introspection.d.ts.map +1 -0
  64. package/dist/client/schema-introspection.js +128 -0
  65. package/dist/client/schema-introspection.js.map +1 -0
  66. package/dist/main.browser.d.ts +49 -0
  67. package/dist/main.browser.d.ts.map +1 -0
  68. package/dist/main.browser.js +57 -0
  69. package/dist/main.browser.js.map +1 -0
  70. package/dist/main.d.ts +86 -0
  71. package/dist/main.d.ts.map +1 -0
  72. package/dist/main.js +108 -0
  73. package/dist/main.js.map +1 -0
  74. package/dist/mockttp.d.ts +774 -0
  75. package/dist/mockttp.d.ts.map +1 -0
  76. package/dist/mockttp.js +81 -0
  77. package/dist/mockttp.js.map +1 -0
  78. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts +5 -0
  79. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.d.ts.map +1 -0
  80. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js +12 -0
  81. package/dist/pluggable-admin-api/mockttp-pluggable-admin.browser.js.map +1 -0
  82. package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts +8 -0
  83. package/dist/pluggable-admin-api/mockttp-pluggable-admin.d.ts.map +1 -0
  84. package/dist/pluggable-admin-api/mockttp-pluggable-admin.js +13 -0
  85. package/dist/pluggable-admin-api/mockttp-pluggable-admin.js.map +1 -0
  86. package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts +6 -0
  87. package/dist/pluggable-admin-api/pluggable-admin.browser.d.ts.map +1 -0
  88. package/dist/pluggable-admin-api/pluggable-admin.browser.js +13 -0
  89. package/dist/pluggable-admin-api/pluggable-admin.browser.js.map +1 -0
  90. package/dist/pluggable-admin-api/pluggable-admin.d.ts +18 -0
  91. package/dist/pluggable-admin-api/pluggable-admin.d.ts.map +1 -0
  92. package/dist/pluggable-admin-api/pluggable-admin.js +20 -0
  93. package/dist/pluggable-admin-api/pluggable-admin.js.map +1 -0
  94. package/dist/rules/base-rule-builder.d.ts +185 -0
  95. package/dist/rules/base-rule-builder.d.ts.map +1 -0
  96. package/dist/rules/base-rule-builder.js +251 -0
  97. package/dist/rules/base-rule-builder.js.map +1 -0
  98. package/dist/rules/completion-checkers.d.ts +41 -0
  99. package/dist/rules/completion-checkers.d.ts.map +1 -0
  100. package/dist/rules/completion-checkers.js +87 -0
  101. package/dist/rules/completion-checkers.js.map +1 -0
  102. package/dist/rules/http-agents.d.ts +11 -0
  103. package/dist/rules/http-agents.d.ts.map +1 -0
  104. package/dist/rules/http-agents.js +91 -0
  105. package/dist/rules/http-agents.js.map +1 -0
  106. package/dist/rules/matchers.d.ts +214 -0
  107. package/dist/rules/matchers.d.ts.map +1 -0
  108. package/dist/rules/matchers.js +515 -0
  109. package/dist/rules/matchers.js.map +1 -0
  110. package/dist/rules/passthrough-handling-definitions.d.ts +106 -0
  111. package/dist/rules/passthrough-handling-definitions.d.ts.map +1 -0
  112. package/dist/rules/passthrough-handling-definitions.js +3 -0
  113. package/dist/rules/passthrough-handling-definitions.js.map +1 -0
  114. package/dist/rules/passthrough-handling.d.ts +33 -0
  115. package/dist/rules/passthrough-handling.d.ts.map +1 -0
  116. package/dist/rules/passthrough-handling.js +294 -0
  117. package/dist/rules/passthrough-handling.js.map +1 -0
  118. package/dist/rules/proxy-config.d.ts +76 -0
  119. package/dist/rules/proxy-config.d.ts.map +1 -0
  120. package/dist/rules/proxy-config.js +48 -0
  121. package/dist/rules/proxy-config.js.map +1 -0
  122. package/dist/rules/requests/request-handler-definitions.d.ts +600 -0
  123. package/dist/rules/requests/request-handler-definitions.d.ts.map +1 -0
  124. package/dist/rules/requests/request-handler-definitions.js +423 -0
  125. package/dist/rules/requests/request-handler-definitions.js.map +1 -0
  126. package/dist/rules/requests/request-handlers.d.ts +65 -0
  127. package/dist/rules/requests/request-handlers.d.ts.map +1 -0
  128. package/dist/rules/requests/request-handlers.js +1014 -0
  129. package/dist/rules/requests/request-handlers.js.map +1 -0
  130. package/dist/rules/requests/request-rule-builder.d.ts +255 -0
  131. package/dist/rules/requests/request-rule-builder.d.ts.map +1 -0
  132. package/dist/rules/requests/request-rule-builder.js +340 -0
  133. package/dist/rules/requests/request-rule-builder.js.map +1 -0
  134. package/dist/rules/requests/request-rule.d.ts +36 -0
  135. package/dist/rules/requests/request-rule.d.ts.map +1 -0
  136. package/dist/rules/requests/request-rule.js +100 -0
  137. package/dist/rules/requests/request-rule.js.map +1 -0
  138. package/dist/rules/rule-deserialization.d.ts +8 -0
  139. package/dist/rules/rule-deserialization.d.ts.map +1 -0
  140. package/dist/rules/rule-deserialization.js +27 -0
  141. package/dist/rules/rule-deserialization.js.map +1 -0
  142. package/dist/rules/rule-parameters.d.ts +21 -0
  143. package/dist/rules/rule-parameters.d.ts.map +1 -0
  144. package/dist/rules/rule-parameters.js +31 -0
  145. package/dist/rules/rule-parameters.js.map +1 -0
  146. package/dist/rules/rule-serialization.d.ts +7 -0
  147. package/dist/rules/rule-serialization.d.ts.map +1 -0
  148. package/dist/rules/rule-serialization.js +25 -0
  149. package/dist/rules/rule-serialization.js.map +1 -0
  150. package/dist/rules/websockets/websocket-handler-definitions.d.ts +78 -0
  151. package/dist/rules/websockets/websocket-handler-definitions.d.ts.map +1 -0
  152. package/dist/rules/websockets/websocket-handler-definitions.js +118 -0
  153. package/dist/rules/websockets/websocket-handler-definitions.js.map +1 -0
  154. package/dist/rules/websockets/websocket-handlers.d.ts +39 -0
  155. package/dist/rules/websockets/websocket-handlers.d.ts.map +1 -0
  156. package/dist/rules/websockets/websocket-handlers.js +356 -0
  157. package/dist/rules/websockets/websocket-handlers.js.map +1 -0
  158. package/dist/rules/websockets/websocket-rule-builder.d.ts +173 -0
  159. package/dist/rules/websockets/websocket-rule-builder.d.ts.map +1 -0
  160. package/dist/rules/websockets/websocket-rule-builder.js +232 -0
  161. package/dist/rules/websockets/websocket-rule-builder.js.map +1 -0
  162. package/dist/rules/websockets/websocket-rule.d.ts +34 -0
  163. package/dist/rules/websockets/websocket-rule.d.ts.map +1 -0
  164. package/dist/rules/websockets/websocket-rule.js +87 -0
  165. package/dist/rules/websockets/websocket-rule.js.map +1 -0
  166. package/dist/serialization/body-serialization.d.ts +43 -0
  167. package/dist/serialization/body-serialization.d.ts.map +1 -0
  168. package/dist/serialization/body-serialization.js +70 -0
  169. package/dist/serialization/body-serialization.js.map +1 -0
  170. package/dist/serialization/serialization.d.ts +63 -0
  171. package/dist/serialization/serialization.d.ts.map +1 -0
  172. package/dist/serialization/serialization.js +263 -0
  173. package/dist/serialization/serialization.js.map +1 -0
  174. package/dist/server/http-combo-server.d.ts +13 -0
  175. package/dist/server/http-combo-server.d.ts.map +1 -0
  176. package/dist/server/http-combo-server.js +330 -0
  177. package/dist/server/http-combo-server.js.map +1 -0
  178. package/dist/server/mocked-endpoint.d.ts +14 -0
  179. package/dist/server/mocked-endpoint.d.ts.map +1 -0
  180. package/dist/server/mocked-endpoint.js +40 -0
  181. package/dist/server/mocked-endpoint.js.map +1 -0
  182. package/dist/server/mockttp-server.d.ts +87 -0
  183. package/dist/server/mockttp-server.d.ts.map +1 -0
  184. package/dist/server/mockttp-server.js +859 -0
  185. package/dist/server/mockttp-server.js.map +1 -0
  186. package/dist/types.d.ts +359 -0
  187. package/dist/types.d.ts.map +1 -0
  188. package/dist/types.js +20 -0
  189. package/dist/types.js.map +1 -0
  190. package/dist/util/buffer-utils.d.ts +13 -0
  191. package/dist/util/buffer-utils.d.ts.map +1 -0
  192. package/dist/util/buffer-utils.js +141 -0
  193. package/dist/util/buffer-utils.js.map +1 -0
  194. package/dist/util/dns.d.ts +11 -0
  195. package/dist/util/dns.d.ts.map +1 -0
  196. package/dist/util/dns.js +47 -0
  197. package/dist/util/dns.js.map +1 -0
  198. package/dist/util/error.d.ts +9 -0
  199. package/dist/util/error.d.ts.map +1 -0
  200. package/dist/util/error.js +11 -0
  201. package/dist/util/error.js.map +1 -0
  202. package/dist/util/header-utils.d.ts +35 -0
  203. package/dist/util/header-utils.d.ts.map +1 -0
  204. package/dist/util/header-utils.js +200 -0
  205. package/dist/util/header-utils.js.map +1 -0
  206. package/dist/util/openssl-compat.d.ts +2 -0
  207. package/dist/util/openssl-compat.d.ts.map +1 -0
  208. package/dist/util/openssl-compat.js +26 -0
  209. package/dist/util/openssl-compat.js.map +1 -0
  210. package/dist/util/promise.d.ts +10 -0
  211. package/dist/util/promise.d.ts.map +1 -0
  212. package/dist/util/promise.js +25 -0
  213. package/dist/util/promise.js.map +1 -0
  214. package/dist/util/request-utils.d.ts +46 -0
  215. package/dist/util/request-utils.d.ts.map +1 -0
  216. package/dist/util/request-utils.js +462 -0
  217. package/dist/util/request-utils.js.map +1 -0
  218. package/dist/util/server-utils.d.ts +2 -0
  219. package/dist/util/server-utils.d.ts.map +1 -0
  220. package/dist/util/server-utils.js +14 -0
  221. package/dist/util/server-utils.js.map +1 -0
  222. package/dist/util/socket-util.d.ts +28 -0
  223. package/dist/util/socket-util.d.ts.map +1 -0
  224. package/dist/util/socket-util.js +174 -0
  225. package/dist/util/socket-util.js.map +1 -0
  226. package/dist/util/tls.d.ts +68 -0
  227. package/dist/util/tls.d.ts.map +1 -0
  228. package/dist/util/tls.js +220 -0
  229. package/dist/util/tls.js.map +1 -0
  230. package/dist/util/type-utils.d.ts +14 -0
  231. package/dist/util/type-utils.d.ts.map +1 -0
  232. package/dist/util/type-utils.js +3 -0
  233. package/dist/util/type-utils.js.map +1 -0
  234. package/dist/util/url.d.ts +17 -0
  235. package/dist/util/url.d.ts.map +1 -0
  236. package/dist/util/url.js +96 -0
  237. package/dist/util/url.js.map +1 -0
  238. package/dist/util/util.d.ts +8 -0
  239. package/dist/util/util.d.ts.map +1 -0
  240. package/dist/util/util.js +41 -0
  241. package/dist/util/util.js.map +1 -0
  242. package/docs/api-docs-landing-page.md +11 -0
  243. package/docs/runkitExample.js +16 -0
  244. package/docs/setup.md +136 -0
  245. package/nfyb8qx5.cjs +1 -0
  246. package/package.json +194 -4
  247. package/src/admin/admin-bin.ts +62 -0
  248. package/src/admin/admin-plugin-types.ts +29 -0
  249. package/src/admin/admin-server.ts +619 -0
  250. package/src/admin/graphql-utils.ts +28 -0
  251. package/src/admin/mockttp-admin-model.ts +264 -0
  252. package/src/admin/mockttp-admin-plugin.ts +59 -0
  253. package/src/admin/mockttp-admin-server.ts +27 -0
  254. package/src/admin/mockttp-schema.ts +222 -0
  255. package/src/client/admin-client.ts +652 -0
  256. package/src/client/admin-query.ts +52 -0
  257. package/src/client/mocked-endpoint-client.ts +32 -0
  258. package/src/client/mockttp-admin-request-builder.ts +540 -0
  259. package/src/client/mockttp-client.ts +178 -0
  260. package/src/client/schema-introspection.ts +131 -0
  261. package/src/main.browser.ts +60 -0
  262. package/src/main.ts +160 -0
  263. package/src/mockttp.ts +926 -0
  264. package/src/pluggable-admin-api/mockttp-pluggable-admin.browser.ts +7 -0
  265. package/src/pluggable-admin-api/mockttp-pluggable-admin.ts +13 -0
  266. package/src/pluggable-admin-api/pluggable-admin.browser.ts +9 -0
  267. package/src/pluggable-admin-api/pluggable-admin.ts +36 -0
  268. package/src/rules/base-rule-builder.ts +312 -0
  269. package/src/rules/completion-checkers.ts +90 -0
  270. package/src/rules/http-agents.ts +119 -0
  271. package/src/rules/matchers.ts +665 -0
  272. package/src/rules/passthrough-handling-definitions.ts +111 -0
  273. package/src/rules/passthrough-handling.ts +376 -0
  274. package/src/rules/proxy-config.ts +136 -0
  275. package/src/rules/requests/request-handler-definitions.ts +1089 -0
  276. package/src/rules/requests/request-handlers.ts +1369 -0
  277. package/src/rules/requests/request-rule-builder.ts +481 -0
  278. package/src/rules/requests/request-rule.ts +148 -0
  279. package/src/rules/rule-deserialization.ts +55 -0
  280. package/src/rules/rule-parameters.ts +41 -0
  281. package/src/rules/rule-serialization.ts +29 -0
  282. package/src/rules/websockets/websocket-handler-definitions.ts +196 -0
  283. package/src/rules/websockets/websocket-handlers.ts +509 -0
  284. package/src/rules/websockets/websocket-rule-builder.ts +275 -0
  285. package/src/rules/websockets/websocket-rule.ts +136 -0
  286. package/src/serialization/body-serialization.ts +84 -0
  287. package/src/serialization/serialization.ts +373 -0
  288. package/src/server/http-combo-server.ts +424 -0
  289. package/src/server/mocked-endpoint.ts +44 -0
  290. package/src/server/mockttp-server.ts +1110 -0
  291. package/src/types.ts +433 -0
  292. package/src/util/buffer-utils.ts +164 -0
  293. package/src/util/dns.ts +52 -0
  294. package/src/util/error.ts +18 -0
  295. package/src/util/header-utils.ts +220 -0
  296. package/src/util/openssl-compat.ts +26 -0
  297. package/src/util/promise.ts +31 -0
  298. package/src/util/request-utils.ts +607 -0
  299. package/src/util/server-utils.ts +18 -0
  300. package/src/util/socket-util.ts +193 -0
  301. package/src/util/tls.ts +348 -0
  302. package/src/util/type-utils.ts +15 -0
  303. package/src/util/url.ts +113 -0
  304. package/src/util/util.ts +39 -0
@@ -0,0 +1,111 @@
1
+ import { ProxyConfig } from "./proxy-config";
2
+
3
+ export interface ForwardingOptions {
4
+ targetHost: string,
5
+ // Should the host (H1) or :authority (H2) header be updated to match?
6
+ updateHostHeader?: true | false | string // Change automatically/ignore/change to custom value
7
+ }
8
+
9
+ export interface PassThroughLookupOptions {
10
+ /**
11
+ * The maximum time to cache a DNS response. Up to this limit,
12
+ * responses will be cached according to their own TTL. Defaults
13
+ * to Infinity.
14
+ */
15
+ maxTtl?: number;
16
+ /**
17
+ * How long to cache a DNS ENODATA or ENOTFOUND response. Defaults
18
+ * to 0.15.
19
+ */
20
+ errorTtl?: number;
21
+ /**
22
+ * The primary servers to use. DNS queries will be resolved against
23
+ * these servers first. If no data is available, queries will fall
24
+ * back to dns.lookup, and use the OS's default DNS servers.
25
+ *
26
+ * This defaults to dns.getServers().
27
+ */
28
+ servers?: string[];
29
+ }
30
+
31
+ export type CADefinition =
32
+ | { cert: string | Buffer }
33
+ | { certPath: string };
34
+
35
+ /**
36
+ * This defines the upstream connection parameters. These passthrough parameters
37
+ * are shared between both WebSocket & Request passthrough rules.
38
+ */
39
+ export interface PassThroughHandlerConnectionOptions {
40
+ /**
41
+ * The forwarding configuration for the passthrough rule.
42
+ * This generally shouldn't be used explicitly unless you're
43
+ * building rule data by hand. Instead, call `thenPassThrough`
44
+ * to send data directly or `thenForwardTo` with options to
45
+ * configure traffic forwarding.
46
+ */
47
+ forwarding?: ForwardingOptions,
48
+
49
+ /**
50
+ * A list of hostnames for which server certificate and TLS version errors
51
+ * should be ignored (none, by default).
52
+ *
53
+ * If set to 'true', HTTPS errors will be ignored for all hosts. WARNING:
54
+ * Use this at your own risk. Setting this to `true` can open your
55
+ * application to MITM attacks and should never be used over any network
56
+ * that is not completed trusted end-to-end.
57
+ */
58
+ ignoreHostHttpsErrors?: string[] | boolean;
59
+
60
+ /**
61
+ * An array of additional certificates, which should be trusted as certificate
62
+ * authorities for upstream hosts, in addition to Node.js's built-in certificate
63
+ * authorities.
64
+ *
65
+ * Each certificate should be an object with either a `cert` key and a string
66
+ * or buffer value containing the PEM certificate, or a `certPath` key and a
67
+ * string value containing the local path to the PEM certificate.
68
+ */
69
+ additionalTrustedCAs?: Array<CADefinition>;
70
+
71
+ /**
72
+ * Deprecated alias for `additionalTrustedCAs`
73
+ *
74
+ * @deprecated
75
+ */
76
+ trustAdditionalCAs?: Array<CADefinition>;
77
+
78
+ /**
79
+ * A mapping of hosts to client certificates to use, in the form of
80
+ * `{ key, cert }` objects (none, by default)
81
+ */
82
+ clientCertificateHostMap?: {
83
+ [host: string]: { pfx: Buffer, passphrase?: string }
84
+ };
85
+
86
+ /**
87
+ * Upstream proxy configuration: pass through requests via this proxy.
88
+ *
89
+ * If this is undefined, no proxy will be used. To configure a proxy
90
+ * provide either:
91
+ * - a ProxySettings object
92
+ * - a callback which will be called with an object containing the
93
+ * hostname, and must return a ProxySettings object or undefined.
94
+ * - an array of ProxySettings or callbacks. The array will be
95
+ * processed in order, and the first not-undefined ProxySettings
96
+ * found will be used.
97
+ *
98
+ * When using a remote client, this parameter or individual array
99
+ * values may be passed by reference, using the name of a rule
100
+ * parameter configured in the admin server.
101
+ */
102
+ proxyConfig?: ProxyConfig;
103
+
104
+ /**
105
+ * Custom DNS options, to allow configuration of the resolver used
106
+ * when forwarding requests upstream. Passing any option switches
107
+ * from using node's default dns.lookup function to using the
108
+ * cacheable-lookup module, which will cache responses.
109
+ */
110
+ lookupOptions?: PassThroughLookupOptions;
111
+ }
@@ -0,0 +1,376 @@
1
+ import * as _ from 'lodash';
2
+ import * as fs from 'fs/promises';
3
+ import * as tls from 'tls';
4
+ import url = require('url');
5
+ import { oneLine } from 'common-tags';
6
+ import CacheableLookup from 'cacheable-lookup';
7
+
8
+ import { CompletedBody, Headers } from '../types';
9
+ import { byteLength } from '../util/util';
10
+ import { asBuffer } from '../util/buffer-utils';
11
+ import { isLocalhostAddress } from '../util/socket-util';
12
+ import { CachedDns, dnsLookup, DnsLookupFunction } from '../util/dns';
13
+ import { isMockttpBody, encodeBodyBuffer } from '../util/request-utils';
14
+ import { areFFDHECurvesSupported } from '../util/openssl-compat';
15
+
16
+ import {
17
+ CallbackRequestResult,
18
+ CallbackResponseMessageResult
19
+ } from './requests/request-handler-definitions';
20
+ import {
21
+ CADefinition,
22
+ PassThroughLookupOptions
23
+ } from './passthrough-handling-definitions';
24
+
25
+ // TLS settings for proxied connections, intended to avoid TLS fingerprint blocking
26
+ // issues so far as possible, by closely emulating a Firefox Client Hello:
27
+ const NEW_CURVES_SUPPORTED = areFFDHECurvesSupported(process.versions.openssl);
28
+
29
+ const SSL_OP_LEGACY_SERVER_CONNECT = 1 << 2;
30
+ const SSL_OP_TLSEXT_PADDING = 1 << 4;
31
+ const SSL_OP_NO_ENCRYPT_THEN_MAC = 1 << 19;
32
+
33
+ // All settings are designed to exactly match Firefox v103, since that's a good baseline
34
+ // that seems to be widely accepted and is easy to emulate from Node.js.
35
+ export const getUpstreamTlsOptions = (strictChecks: boolean): tls.SecureContextOptions => ({
36
+ ecdhCurve: [
37
+ 'X25519',
38
+ 'prime256v1', // N.B. Equivalent to secp256r1
39
+ 'secp384r1',
40
+ 'secp521r1',
41
+ ...(NEW_CURVES_SUPPORTED
42
+ ? [ // Only available with OpenSSL v3+:
43
+ 'ffdhe2048',
44
+ 'ffdhe3072'
45
+ ] : []
46
+ )
47
+ ].join(':'),
48
+ sigalgs: [
49
+ 'ecdsa_secp256r1_sha256',
50
+ 'ecdsa_secp384r1_sha384',
51
+ 'ecdsa_secp521r1_sha512',
52
+ 'rsa_pss_rsae_sha256',
53
+ 'rsa_pss_rsae_sha384',
54
+ 'rsa_pss_rsae_sha512',
55
+ 'rsa_pkcs1_sha256',
56
+ 'rsa_pkcs1_sha384',
57
+ 'rsa_pkcs1_sha512',
58
+ 'ECDSA+SHA1',
59
+ 'rsa_pkcs1_sha1'
60
+ ].join(':'),
61
+ ciphers: [
62
+ 'TLS_AES_128_GCM_SHA256',
63
+ 'TLS_CHACHA20_POLY1305_SHA256',
64
+ 'TLS_AES_256_GCM_SHA384',
65
+ 'ECDHE-ECDSA-AES128-GCM-SHA256',
66
+ 'ECDHE-RSA-AES128-GCM-SHA256',
67
+ 'ECDHE-ECDSA-CHACHA20-POLY1305',
68
+ 'ECDHE-RSA-CHACHA20-POLY1305',
69
+ 'ECDHE-ECDSA-AES256-GCM-SHA384',
70
+ 'ECDHE-RSA-AES256-GCM-SHA384',
71
+ 'ECDHE-ECDSA-AES256-SHA',
72
+ 'ECDHE-ECDSA-AES128-SHA',
73
+ 'ECDHE-RSA-AES128-SHA',
74
+ 'ECDHE-RSA-AES256-SHA',
75
+ 'AES128-GCM-SHA256',
76
+ 'AES256-GCM-SHA384',
77
+ 'AES128-SHA',
78
+ 'AES256-SHA',
79
+
80
+ // This magic cipher is the very obtuse way that OpenSSL downgrades the overall
81
+ // security level to allow various legacy settings, protocols & ciphers:
82
+ ...(!strictChecks
83
+ ? ['@SECLEVEL=0']
84
+ : []
85
+ )
86
+ ].join(':'),
87
+ secureOptions: strictChecks
88
+ ? SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC
89
+ : SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC | SSL_OP_LEGACY_SERVER_CONNECT,
90
+ ...({
91
+ // Valid, but not included in Node.js TLS module types:
92
+ requestOSCP: true
93
+ } as any),
94
+
95
+ // Allow TLSv1, if !strict:
96
+ minVersion: strictChecks ? tls.DEFAULT_MIN_VERSION : 'TLSv1',
97
+
98
+ // Skip certificate validation entirely, if not strict:
99
+ rejectUnauthorized: strictChecks,
100
+ });
101
+
102
+ export async function getTrustedCAs(
103
+ trustedCAs: Array<string | CADefinition> | undefined,
104
+ additionalTrustedCAs: Array<CADefinition> | undefined
105
+ ): Promise<Array<string> | undefined> {
106
+ if (trustedCAs && additionalTrustedCAs?.length) {
107
+ throw new Error(`trustedCAs and additionalTrustedCAs options are mutually exclusive`);
108
+ }
109
+
110
+ if (trustedCAs) {
111
+ return Promise.all(trustedCAs.map((caDefinition) => getCA(caDefinition)));
112
+ }
113
+
114
+ if (additionalTrustedCAs) {
115
+ const CAs = await Promise.all(additionalTrustedCAs.map((caDefinition) => getCA(caDefinition)));
116
+ return tls.rootCertificates.concat(CAs);
117
+ }
118
+ }
119
+
120
+ const getCA = async (caDefinition: string | CADefinition) => {
121
+ return typeof caDefinition === 'string'
122
+ ? caDefinition
123
+ : 'certPath' in caDefinition
124
+ ? await fs.readFile(caDefinition.certPath, 'utf8')
125
+ // 'cert' in caDefinition
126
+ : caDefinition.cert.toString('utf8')
127
+ }
128
+
129
+
130
+ // --- Various helpers for deriving parts of request/response data given partial overrides: ---
131
+
132
+ /**
133
+ * Takes a callback result and some headers, and returns a ready to send body, using the headers
134
+ * (and potentially modifying them) to match the content type & encoding.
135
+ */
136
+ export async function buildOverriddenBody(
137
+ callbackResult: CallbackRequestResult | CallbackResponseMessageResult | void,
138
+ headers: Headers
139
+ ) {
140
+ // Raw bodies are easy: use them as is.
141
+ if (callbackResult?.rawBody) return callbackResult?.rawBody!;
142
+
143
+ // In the json/body case, we need to get the body and transform it into a buffer
144
+ // for consistent handling later, and encode it to match the headers.
145
+
146
+ let replacementBody: string | Uint8Array | Buffer | CompletedBody | undefined;
147
+ if (callbackResult?.json) {
148
+ headers['content-type'] = 'application/json';
149
+ replacementBody = JSON.stringify(callbackResult?.json);
150
+ } else {
151
+ replacementBody = callbackResult?.body;
152
+ }
153
+
154
+ if (replacementBody === undefined) return replacementBody;
155
+
156
+ let rawBuffer: Buffer;
157
+ if (isMockttpBody(replacementBody)) {
158
+ // It's our own bodyReader instance. That's not supposed to happen, but
159
+ // it's ok, we just need to use the buffer data instead of the whole object
160
+ rawBuffer = Buffer.from((replacementBody as CompletedBody).buffer);
161
+ } else if (replacementBody === '') {
162
+ // For empty bodies, it's slightly more convenient if they're truthy
163
+ rawBuffer = Buffer.alloc(0);
164
+ } else {
165
+ rawBuffer = asBuffer(replacementBody);
166
+ }
167
+
168
+ return await encodeBodyBuffer(rawBuffer, headers);
169
+ }
170
+
171
+ /**
172
+ * If you override some headers, they have implications for the effective URL we send the
173
+ * request to. If you override that and the URL at the same time, it gets complicated.
174
+ *
175
+ * This method calculates the correct header value we should use: prioritising the header
176
+ * value you provide, printing a warning if it's contradictory, or return the URL-inferred
177
+ * value to override the header correctly if you didn't specify.
178
+ */
179
+ function deriveUrlLinkedHeader(
180
+ originalHeaders: Headers,
181
+ replacementHeaders: Headers | undefined,
182
+ headerName: 'host' | ':authority' | ':scheme',
183
+ expectedValue: string // The inferred 'correct' value from the URL
184
+ ) {
185
+ const replacementValue = replacementHeaders?.[headerName];
186
+
187
+ if (replacementValue !== undefined) {
188
+ if (replacementValue !== expectedValue && replacementValue === originalHeaders[headerName]) {
189
+ // If you rewrite the URL-based header wrongly, by explicitly setting it to the
190
+ // existing value, we accept it but print a warning. This would be easy to
191
+ // do if you mutate the existing headers, for example, and ignore the host.
192
+ console.warn(oneLine`
193
+ Passthrough callback overrode the URL and the ${headerName} header
194
+ with mismatched values, which may be a mistake. The URL implies
195
+ ${expectedValue}, whilst the header was set to ${replacementValue}.
196
+ `);
197
+ }
198
+ // Whatever happens, if you explicitly set a value, we use it.
199
+ return replacementValue;
200
+ }
201
+
202
+ // If you didn't override the header at all, then we automatically ensure
203
+ // the correct value is set automatically.
204
+ return expectedValue;
205
+ }
206
+
207
+ /**
208
+ * Autocorrect the host header only in the case that if you didn't explicitly
209
+ * override it yourself for some reason (e.g. if you're testing bad behaviour).
210
+ */
211
+ export function getHostAfterModification(
212
+ reqUrl: string,
213
+ originalHeaders: Headers,
214
+ replacementHeaders: Headers | undefined
215
+ ): string {
216
+ return deriveUrlLinkedHeader(
217
+ originalHeaders,
218
+ replacementHeaders,
219
+ 'host',
220
+ url.parse(reqUrl).host!
221
+ );
222
+ }
223
+
224
+ export const OVERRIDABLE_REQUEST_PSEUDOHEADERS = [
225
+ ':authority',
226
+ ':scheme'
227
+ ] as const;
228
+
229
+ /**
230
+ * Automatically update the :scheme and :authority headers to match the updated URL,
231
+ * as long as they weren't explicitly overriden themselves, in which case let them
232
+ * be set to any invalid value you like (e.g. to send a request to one server but
233
+ * pretend it was sent to another).
234
+ */
235
+ export function getH2HeadersAfterModification(
236
+ reqUrl: string,
237
+ originalHeaders: Headers,
238
+ replacementHeaders: Headers | undefined
239
+ ): { [K in typeof OVERRIDABLE_REQUEST_PSEUDOHEADERS[number]]: string } {
240
+ const parsedUrl = url.parse(reqUrl);
241
+
242
+ return {
243
+ ':scheme': deriveUrlLinkedHeader(
244
+ originalHeaders,
245
+ replacementHeaders,
246
+ ':scheme',
247
+ parsedUrl.protocol!.slice(0, -1)
248
+ ),
249
+ ':authority': deriveUrlLinkedHeader(
250
+ originalHeaders,
251
+ replacementHeaders,
252
+ ':authority',
253
+ parsedUrl.host!
254
+ )
255
+ };
256
+ }
257
+
258
+ // Helper to handle content-length nicely for you when rewriting requests with callbacks
259
+ export function getContentLengthAfterModification(
260
+ body: string | Uint8Array | Buffer,
261
+ originalHeaders: Headers,
262
+ replacementHeaders: Headers | undefined,
263
+ mismatchAllowed: boolean = false
264
+ ): string | undefined {
265
+ // If there was a content-length header, it might now be wrong, and it's annoying
266
+ // to need to set your own content-length override when you just want to change
267
+ // the body. To help out, if you override the body but don't explicitly override
268
+ // the (now invalid) content-length, then we fix it for you.
269
+
270
+ if (!_.has(originalHeaders, 'content-length')) {
271
+ // Nothing to override - use the replacement value, or undefined
272
+ return (replacementHeaders || {})['content-length'];
273
+ }
274
+
275
+ if (!replacementHeaders) {
276
+ // There was a length set, and you've provided a body but not changed it.
277
+ // You probably just want to send this body and have it work correctly,
278
+ // so we should fix the content length for you automatically.
279
+ return byteLength(body).toString();
280
+ }
281
+
282
+ // There was a content length before, and you're replacing the headers entirely
283
+ const lengthOverride = replacementHeaders['content-length']?.toString();
284
+
285
+ // If you're setting the content-length to the same as the origin headers, even
286
+ // though that's the wrong value, it *might* be that you're just extending the
287
+ // existing headers, and you're doing this by accident (we can't tell for sure).
288
+ // We use invalid content-length as instructed, but print a warning just in case.
289
+ if (
290
+ lengthOverride === originalHeaders['content-length'] &&
291
+ lengthOverride !== byteLength(body).toString() &&
292
+ !mismatchAllowed // Set for HEAD responses
293
+ ) {
294
+ console.warn(oneLine`
295
+ Passthrough modifications overrode the body and the content-length header
296
+ with mismatched values, which may be a mistake. The body contains
297
+ ${byteLength(body)} bytes, whilst the header was set to ${lengthOverride}.
298
+ `);
299
+ }
300
+
301
+ return lengthOverride;
302
+ }
303
+
304
+ // Function to check if we should skip https errors for the current hostname and port,
305
+ // based on the given config
306
+ export function shouldUseStrictHttps(
307
+ hostname: string,
308
+ port: number,
309
+ ignoreHostHttpsErrors: string[] | boolean
310
+ ) {
311
+ let skipHttpsErrors = false;
312
+
313
+ if (ignoreHostHttpsErrors === true) {
314
+ // Ignore cert errors if `ignoreHostHttpsErrors` is set to true, or
315
+ skipHttpsErrors = true;
316
+ } else if (Array.isArray(ignoreHostHttpsErrors) && (
317
+ // if the whole hostname or host+port is whitelisted
318
+ _.includes(ignoreHostHttpsErrors, hostname) ||
319
+ _.includes(ignoreHostHttpsErrors, `${hostname}:${port}`)
320
+ )) {
321
+ skipHttpsErrors = true;
322
+ }
323
+ return !skipHttpsErrors;
324
+ }
325
+
326
+ export const getDnsLookupFunction = _.memoize((lookupOptions: PassThroughLookupOptions | undefined) => {
327
+ if (!lookupOptions) {
328
+ // By default, use 10s caching of hostnames, just to reduce the delay from
329
+ // endlessly 10ms query delay for 'localhost' with every request.
330
+ return new CachedDns(10000).lookup;
331
+ } else {
332
+ // Or if options are provided, use those to configure advanced DNS cases:
333
+ const cacheableLookup = new CacheableLookup({
334
+ maxTtl: lookupOptions.maxTtl,
335
+ errorTtl: lookupOptions.errorTtl,
336
+ // As little caching of "use the fallback server" as possible:
337
+ fallbackDuration: 0
338
+ });
339
+
340
+ if (lookupOptions.servers) {
341
+ cacheableLookup.servers = lookupOptions.servers;
342
+ }
343
+
344
+ return cacheableLookup.lookup;
345
+ }
346
+ });
347
+
348
+ export async function getClientRelativeHostname(
349
+ hostname: string | null,
350
+ remoteIp: string | undefined,
351
+ lookupFn: DnsLookupFunction
352
+ ) {
353
+ if (!hostname || !remoteIp || isLocalhostAddress(remoteIp)) return hostname;
354
+
355
+ // Otherwise, we have a request from a different machine (or Docker container/VM/etc) and we need
356
+ // to make sure that 'localhost' means _that_ machine, not ourselves.
357
+
358
+ // This check must be run before req modifications. If a modification changes the address to localhost,
359
+ // then presumably it really does mean *this* localhost.
360
+
361
+ if (
362
+ // If the hostname is a known localhost address, we're done:
363
+ isLocalhostAddress(hostname) ||
364
+ // Otherwise, we look up the IP, so we can accurately check for localhost-bound requests. This adds a little
365
+ // delay, but since it's cached we save the equivalent delay in request lookup later, so it should be
366
+ // effectively free. We ignore errors to delegate unresolvable etc to request processing later.
367
+ isLocalhostAddress(await dnsLookup(lookupFn, hostname).catch(() => null))
368
+ ) {
369
+ return remoteIp;
370
+
371
+ // Note that we just redirect - we don't update the host header. From the POV of the target, it's still
372
+ // 'localhost' traffic that should appear identical to normal.
373
+ } else {
374
+ return hostname;
375
+ }
376
+ }
@@ -0,0 +1,136 @@
1
+ import * as _ from 'lodash';
2
+
3
+ import { MaybePromise } from '../util/type-utils';
4
+ import { RuleParameterReference } from './rule-parameters';
5
+ import { CADefinition } from './passthrough-handling-definitions';
6
+
7
+ /**
8
+ * A ProxySetting is a specific proxy setting to use, which is passed to a proxy agent
9
+ * who will manage creating a socket for the request (directly, or tunnelled, or whatever).
10
+ */
11
+ export interface ProxySetting {
12
+ /**
13
+ * The URL for the proxy to forward traffic through.
14
+ *
15
+ * This can be any URL supported by https://www.npmjs.com/package/proxy-agent.
16
+ * For example: http://..., socks5://..., pac+http://...
17
+ */
18
+ proxyUrl: string;
19
+
20
+ /**
21
+ * A list of no-proxy values, matching hosts' traffic should *not* be proxied.
22
+ *
23
+ * This is a common proxy feature, but unfortunately isn't standardized. See
24
+ * https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/ for some
25
+ * background. This implementation is intended to match Curl's behaviour, and
26
+ * any differences are a bug.
27
+ *
28
+ * The currently supported formats are:
29
+ * - example.com (matches domain and all subdomains)
30
+ * - example.com:443 (matches domain and all subdomains, but only on that port)
31
+ * - 10.0.0.1 (matches IP, but only when used directly - does not resolve domains)
32
+ *
33
+ * Some other formats (e.g. leading dots or *.) will work, but the leading
34
+ * characters are ignored. More formats may be added in future, e.g. CIDR ranges.
35
+ * To maximize compatibility with values used elsewhere, unrecognized formats
36
+ * will generally be ignored, but may match in unexpected ways.
37
+ */
38
+ noProxy?: string[];
39
+
40
+ /**
41
+ * CAs to trust for HTTPS connections to the proxy. Ignored if the connection to
42
+ * the proxy is not HTTPS. If not specified, this will default to the Node
43
+ * defaults, or you can override them here completely.
44
+ *
45
+ * This sets the complete list of trusted CAs, and is mutually exclusive with the
46
+ * `additionalTrustedCAs` option, which adds additional CAs (but also trusts the
47
+ * Node default CAs too).
48
+ *
49
+ * This should be specified as either a { cert: string | Buffer } object or a
50
+ * { certPath: string } object (to read the cert from disk). The previous
51
+ * simple string format is supported but deprecated.
52
+ */
53
+ trustedCAs?: Array<
54
+ | string // Deprecated
55
+ | CADefinition
56
+ >;
57
+
58
+ /**
59
+ * Extra CAs to trust for HTTPS connections to the proxy. Ignored if the connection
60
+ * to the proxy is not HTTPS.
61
+ *
62
+ * This appends to the list of trusted CAs, and is mutually exclusive with the
63
+ * `trustedCAs` option, which completely overrides the list of CAs.
64
+ */
65
+ additionalTrustedCAs?: Array<CADefinition>;
66
+ }
67
+
68
+ /**
69
+ * A ProxySettingSource is a way to calculate the ProxySetting for a given request. It
70
+ * may be a fixed ProxySetting value, or a callback to get ProxySetting values, or an
71
+ * array of sources, which should be iterated to get the first usable value
72
+ */
73
+ export type ProxySettingSource =
74
+ | ProxySetting
75
+ | ProxySettingCallback
76
+ | Array<ProxySettingSource>
77
+ | undefined;
78
+
79
+ export type ProxySettingCallbackParams = { hostname: string };
80
+ export type ProxySettingCallback = (params: ProxySettingCallbackParams) => MaybePromise<ProxySetting | undefined>;
81
+
82
+ /**
83
+ * A ProxyConfig is externally provided config that specifies a ProxySettingSource.
84
+ * It might be a ProxySettingSource itself, or it might include references to rule
85
+ * parameters, which must be dereferenced to make it usable as a ProxySettingSource.
86
+ */
87
+ export type ProxyConfig =
88
+ | ProxySettingSource
89
+ | RuleParameterReference<ProxySettingSource>
90
+ | Array<ProxySettingSource | RuleParameterReference<ProxySettingSource>>;
91
+
92
+ export async function getProxySetting(
93
+ configSource: ProxySettingSource,
94
+ params: ProxySettingCallbackParams
95
+ ) {
96
+ if (_.isFunction(configSource)) return configSource(params);
97
+ else if (_.isArray(configSource)) {
98
+ let result: ProxySetting | undefined;
99
+ for (let configArrayOption of configSource) {
100
+ result = await getProxySetting(configArrayOption, params);
101
+ if (result) break;
102
+ }
103
+ return result;
104
+ }
105
+ else return configSource;
106
+ }
107
+
108
+ export const matchesNoProxy = (hostname: string, portNum: number, noProxyValues: string[] | undefined) => {
109
+ if (!noProxyValues || noProxyValues.length === 0) return false; // Skip everything in the common case.
110
+
111
+ const port = portNum.toString();
112
+ const hostParts = hostname.split('.').reverse();
113
+
114
+ return noProxyValues.some((noProxy) => {
115
+ const [noProxyHost, noProxyPort] = noProxy.split(':') as [string, string | undefined];
116
+
117
+ let noProxyParts = noProxyHost.split('.').reverse();
118
+ const lastPart = noProxyParts[noProxyParts.length - 1];
119
+ if (lastPart === '' || lastPart === '*') {
120
+ noProxyParts = noProxyParts.slice(0, -1);
121
+ }
122
+
123
+ if (noProxyPort && port !== noProxyPort) return false;
124
+
125
+ for (let i = 0; i < noProxyParts.length; i++) {
126
+ let noProxyPart = noProxyParts[i];
127
+ let hostPart = hostParts[i];
128
+
129
+ if (hostPart === undefined) return false; // No-proxy is longer than hostname
130
+ if (noProxyPart !== hostPart) return false; // Mismatch
131
+ }
132
+
133
+ // If we run out of no-proxy parts with no mismatch then we've matched
134
+ return true;
135
+ });
136
+ }