@api-client/core 0.18.12 → 0.18.13

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 (259) hide show
  1. package/build/src/browser.d.ts +0 -3
  2. package/build/src/browser.d.ts.map +1 -1
  3. package/build/src/browser.js +0 -3
  4. package/build/src/browser.js.map +1 -1
  5. package/build/src/index.d.ts +2 -5
  6. package/build/src/index.d.ts.map +1 -1
  7. package/build/src/index.js +2 -5
  8. package/build/src/index.js.map +1 -1
  9. package/build/src/lib/logging/DefaultLogger.d.ts +14 -0
  10. package/build/src/lib/logging/DefaultLogger.d.ts.map +1 -1
  11. package/build/src/lib/logging/DefaultLogger.js +27 -0
  12. package/build/src/lib/logging/DefaultLogger.js.map +1 -1
  13. package/build/src/lib/logging/index.d.ts +4 -0
  14. package/build/src/lib/logging/index.d.ts.map +1 -0
  15. package/build/src/lib/logging/index.js +10 -0
  16. package/build/src/lib/logging/index.js.map +1 -0
  17. package/build/src/models/ClientCertificate.d.ts +1 -1
  18. package/build/src/models/ClientCertificate.js.map +1 -1
  19. package/build/src/models/RequestConfig.d.ts +1 -1
  20. package/build/src/models/RequestConfig.js.map +1 -1
  21. package/build/src/models/SerializableError.d.ts +1 -1
  22. package/build/src/models/SerializableError.d.ts.map +1 -1
  23. package/build/src/models/SerializableError.js.map +1 -1
  24. package/build/src/proxy/RequestProxy.d.ts.map +1 -1
  25. package/build/src/proxy/RequestProxy.js +2 -2
  26. package/build/src/proxy/RequestProxy.js.map +1 -1
  27. package/build/src/runtime/http-engine/CoreEngine.d.ts +218 -139
  28. package/build/src/runtime/http-engine/CoreEngine.d.ts.map +1 -1
  29. package/build/src/runtime/http-engine/CoreEngine.js +716 -870
  30. package/build/src/runtime/http-engine/CoreEngine.js.map +1 -1
  31. package/build/src/runtime/http-engine/PayloadSupport.d.ts.map +1 -1
  32. package/build/src/runtime/http-engine/PayloadSupport.js +2 -1
  33. package/build/src/runtime/http-engine/PayloadSupport.js.map +1 -1
  34. package/build/src/runtime/http-engine/auth/AuthManager.d.ts +73 -0
  35. package/build/src/runtime/http-engine/auth/AuthManager.d.ts.map +1 -0
  36. package/build/src/runtime/http-engine/auth/AuthManager.js +186 -0
  37. package/build/src/runtime/http-engine/auth/AuthManager.js.map +1 -0
  38. package/build/src/runtime/http-engine/auth/index.d.ts +2 -0
  39. package/build/src/runtime/http-engine/auth/index.d.ts.map +1 -0
  40. package/build/src/runtime/http-engine/auth/index.js +2 -0
  41. package/build/src/runtime/http-engine/auth/index.js.map +1 -0
  42. package/build/src/runtime/http-engine/certificates/CertificateManager.d.ts +11 -0
  43. package/build/src/runtime/http-engine/certificates/CertificateManager.d.ts.map +1 -0
  44. package/build/src/runtime/http-engine/certificates/CertificateManager.js +76 -0
  45. package/build/src/runtime/http-engine/certificates/CertificateManager.js.map +1 -0
  46. package/build/src/runtime/http-engine/certificates/index.d.ts +2 -0
  47. package/build/src/runtime/http-engine/certificates/index.d.ts.map +1 -0
  48. package/build/src/runtime/http-engine/certificates/index.js +2 -0
  49. package/build/src/runtime/http-engine/certificates/index.js.map +1 -0
  50. package/build/src/runtime/http-engine/compression/CompressionManager.d.ts +25 -0
  51. package/build/src/runtime/http-engine/compression/CompressionManager.d.ts.map +1 -0
  52. package/build/src/runtime/http-engine/compression/CompressionManager.js +89 -0
  53. package/build/src/runtime/http-engine/compression/CompressionManager.js.map +1 -0
  54. package/build/src/runtime/http-engine/compression/index.d.ts +2 -0
  55. package/build/src/runtime/http-engine/compression/index.d.ts.map +1 -0
  56. package/build/src/runtime/http-engine/compression/index.js +2 -0
  57. package/build/src/runtime/http-engine/compression/index.js.map +1 -0
  58. package/build/src/runtime/http-engine/connections/ConnectionManager.d.ts +57 -0
  59. package/build/src/runtime/http-engine/connections/ConnectionManager.d.ts.map +1 -0
  60. package/build/src/runtime/http-engine/connections/ConnectionManager.js +78 -0
  61. package/build/src/runtime/http-engine/connections/ConnectionManager.js.map +1 -0
  62. package/build/src/runtime/http-engine/connections/DigestAuthHandler.d.ts +70 -0
  63. package/build/src/runtime/http-engine/connections/DigestAuthHandler.d.ts.map +1 -0
  64. package/build/src/runtime/http-engine/connections/DigestAuthHandler.js +184 -0
  65. package/build/src/runtime/http-engine/connections/DigestAuthHandler.js.map +1 -0
  66. package/build/src/runtime/http-engine/connections/DirectConnection.d.ts +22 -0
  67. package/build/src/runtime/http-engine/connections/DirectConnection.d.ts.map +1 -0
  68. package/build/src/runtime/http-engine/connections/DirectConnection.js +105 -0
  69. package/build/src/runtime/http-engine/connections/DirectConnection.js.map +1 -0
  70. package/build/src/runtime/http-engine/connections/ProxyAuthHandler.d.ts +60 -0
  71. package/build/src/runtime/http-engine/connections/ProxyAuthHandler.d.ts.map +1 -0
  72. package/build/src/runtime/http-engine/connections/ProxyAuthHandler.js +138 -0
  73. package/build/src/runtime/http-engine/connections/ProxyAuthHandler.js.map +1 -0
  74. package/build/src/runtime/http-engine/connections/ProxyConnection.d.ts +14 -0
  75. package/build/src/runtime/http-engine/connections/ProxyConnection.d.ts.map +1 -0
  76. package/build/src/runtime/http-engine/connections/ProxyConnection.js +47 -0
  77. package/build/src/runtime/http-engine/connections/ProxyConnection.js.map +1 -0
  78. package/build/src/runtime/http-engine/connections/TunnelConnection.d.ts +13 -0
  79. package/build/src/runtime/http-engine/connections/TunnelConnection.d.ts.map +1 -0
  80. package/build/src/runtime/http-engine/connections/TunnelConnection.js +175 -0
  81. package/build/src/runtime/http-engine/connections/TunnelConnection.js.map +1 -0
  82. package/build/src/runtime/http-engine/connections/index.d.ts +7 -0
  83. package/build/src/runtime/http-engine/connections/index.d.ts.map +1 -0
  84. package/build/src/runtime/http-engine/connections/index.js +7 -0
  85. package/build/src/runtime/http-engine/connections/index.js.map +1 -0
  86. package/build/src/runtime/http-engine/constants.d.ts +69 -0
  87. package/build/src/runtime/http-engine/constants.d.ts.map +1 -0
  88. package/build/src/runtime/http-engine/constants.js +90 -0
  89. package/build/src/runtime/http-engine/constants.js.map +1 -0
  90. package/build/src/runtime/http-engine/cookies/CookieProcessor.d.ts +5 -0
  91. package/build/src/runtime/http-engine/cookies/CookieProcessor.d.ts.map +1 -0
  92. package/build/src/runtime/http-engine/cookies/CookieProcessor.js +20 -0
  93. package/build/src/runtime/http-engine/cookies/CookieProcessor.js.map +1 -0
  94. package/build/src/runtime/http-engine/cookies/index.d.ts +2 -0
  95. package/build/src/runtime/http-engine/cookies/index.d.ts.map +1 -0
  96. package/build/src/runtime/http-engine/cookies/index.js +2 -0
  97. package/build/src/runtime/http-engine/cookies/index.js.map +1 -0
  98. package/build/src/runtime/http-engine/errors/HttpEngineErrors.d.ts +156 -0
  99. package/build/src/runtime/http-engine/errors/HttpEngineErrors.d.ts.map +1 -0
  100. package/build/src/runtime/http-engine/errors/HttpEngineErrors.js +227 -0
  101. package/build/src/runtime/http-engine/errors/HttpEngineErrors.js.map +1 -0
  102. package/build/src/runtime/http-engine/errors/index.d.ts +2 -0
  103. package/build/src/runtime/http-engine/errors/index.d.ts.map +1 -0
  104. package/build/src/runtime/http-engine/errors/index.js +2 -0
  105. package/build/src/runtime/http-engine/errors/index.js.map +1 -0
  106. package/build/src/runtime/http-engine/message/MessageBuilder.d.ts +66 -0
  107. package/build/src/runtime/http-engine/message/MessageBuilder.d.ts.map +1 -0
  108. package/build/src/runtime/http-engine/message/MessageBuilder.js +161 -0
  109. package/build/src/runtime/http-engine/message/MessageBuilder.js.map +1 -0
  110. package/build/src/runtime/http-engine/message/MessageProcessor.d.ts +27 -0
  111. package/build/src/runtime/http-engine/message/MessageProcessor.d.ts.map +1 -0
  112. package/build/src/runtime/http-engine/message/MessageProcessor.js +51 -0
  113. package/build/src/runtime/http-engine/message/MessageProcessor.js.map +1 -0
  114. package/build/src/runtime/http-engine/message/index.d.ts +3 -0
  115. package/build/src/runtime/http-engine/message/index.d.ts.map +1 -0
  116. package/build/src/runtime/http-engine/message/index.js +3 -0
  117. package/build/src/runtime/http-engine/message/index.js.map +1 -0
  118. package/build/src/runtime/http-engine/ntlm/NtlmAuth.d.ts +2 -8
  119. package/build/src/runtime/http-engine/ntlm/NtlmAuth.d.ts.map +1 -1
  120. package/build/src/runtime/http-engine/ntlm/NtlmAuth.js +11 -5
  121. package/build/src/runtime/http-engine/ntlm/NtlmAuth.js.map +1 -1
  122. package/build/src/runtime/http-engine/ntlm/NtlmMessage.js +6 -6
  123. package/build/src/runtime/http-engine/ntlm/NtlmMessage.js.map +1 -1
  124. package/build/src/runtime/http-engine/parsers/BodyParser.d.ts +39 -0
  125. package/build/src/runtime/http-engine/parsers/BodyParser.d.ts.map +1 -0
  126. package/build/src/runtime/http-engine/parsers/BodyParser.js +145 -0
  127. package/build/src/runtime/http-engine/parsers/BodyParser.js.map +1 -0
  128. package/build/src/runtime/http-engine/parsers/HeadersParser.d.ts +29 -0
  129. package/build/src/runtime/http-engine/parsers/HeadersParser.d.ts.map +1 -0
  130. package/build/src/runtime/http-engine/parsers/HeadersParser.js +88 -0
  131. package/build/src/runtime/http-engine/parsers/HeadersParser.js.map +1 -0
  132. package/build/src/runtime/http-engine/parsers/HttpResponseParser.d.ts +91 -0
  133. package/build/src/runtime/http-engine/parsers/HttpResponseParser.d.ts.map +1 -0
  134. package/build/src/runtime/http-engine/parsers/HttpResponseParser.js +236 -0
  135. package/build/src/runtime/http-engine/parsers/HttpResponseParser.js.map +1 -0
  136. package/build/src/runtime/http-engine/parsers/StatusParser.d.ts +20 -0
  137. package/build/src/runtime/http-engine/parsers/StatusParser.d.ts.map +1 -0
  138. package/build/src/runtime/http-engine/parsers/StatusParser.js +51 -0
  139. package/build/src/runtime/http-engine/parsers/StatusParser.js.map +1 -0
  140. package/build/src/runtime/http-engine/parsers/index.d.ts +5 -0
  141. package/build/src/runtime/http-engine/parsers/index.d.ts.map +1 -0
  142. package/build/src/runtime/http-engine/parsers/index.js +5 -0
  143. package/build/src/runtime/http-engine/parsers/index.js.map +1 -0
  144. package/build/src/runtime/http-engine/response/ResponseProcessor.d.ts +22 -0
  145. package/build/src/runtime/http-engine/response/ResponseProcessor.d.ts.map +1 -0
  146. package/build/src/runtime/http-engine/response/ResponseProcessor.js +25 -0
  147. package/build/src/runtime/http-engine/response/ResponseProcessor.js.map +1 -0
  148. package/build/src/runtime/http-engine/response/index.d.ts +2 -0
  149. package/build/src/runtime/http-engine/response/index.d.ts.map +1 -0
  150. package/build/src/runtime/http-engine/response/index.js +2 -0
  151. package/build/src/runtime/http-engine/response/index.js.map +1 -0
  152. package/build/src/runtime/http-engine/statistics/StatisticsProcessor.d.ts +7 -0
  153. package/build/src/runtime/http-engine/statistics/StatisticsProcessor.d.ts.map +1 -0
  154. package/build/src/runtime/http-engine/statistics/StatisticsProcessor.js +40 -0
  155. package/build/src/runtime/http-engine/statistics/StatisticsProcessor.js.map +1 -0
  156. package/build/src/runtime/http-engine/statistics/index.d.ts +2 -0
  157. package/build/src/runtime/http-engine/statistics/index.d.ts.map +1 -0
  158. package/build/src/runtime/http-engine/statistics/index.js +2 -0
  159. package/build/src/runtime/http-engine/statistics/index.js.map +1 -0
  160. package/build/src/runtime/http-engine/url/UrlProcessor.d.ts +24 -0
  161. package/build/src/runtime/http-engine/url/UrlProcessor.d.ts.map +1 -0
  162. package/build/src/runtime/http-engine/url/UrlProcessor.js +50 -0
  163. package/build/src/runtime/http-engine/url/UrlProcessor.js.map +1 -0
  164. package/build/src/runtime/http-engine/url/index.d.ts +2 -0
  165. package/build/src/runtime/http-engine/url/index.d.ts.map +1 -0
  166. package/build/src/runtime/http-engine/url/index.js +2 -0
  167. package/build/src/runtime/http-engine/url/index.js.map +1 -0
  168. package/build/src/runtime/http-runner/HttpRequestRunner.d.ts +3 -3
  169. package/build/src/runtime/http-runner/HttpRequestRunner.d.ts.map +1 -1
  170. package/build/src/runtime/http-runner/HttpRequestRunner.js.map +1 -1
  171. package/build/src/runtime/node/InteropInterfaces.d.ts +3 -3
  172. package/build/src/runtime/node/InteropInterfaces.d.ts.map +1 -1
  173. package/build/src/runtime/node/InteropInterfaces.js.map +1 -1
  174. package/build/src/runtime/node/ProjectRequestRunner.d.ts +2 -2
  175. package/build/src/runtime/node/ProjectRequestRunner.d.ts.map +1 -1
  176. package/build/src/runtime/node/ProjectRequestRunner.js.map +1 -1
  177. package/build/src/runtime/node/ProjectRunner.d.ts.map +1 -1
  178. package/build/src/runtime/node/ProjectRunner.js +2 -2
  179. package/build/src/runtime/node/ProjectRunner.js.map +1 -1
  180. package/build/tsconfig.tsbuildinfo +1 -1
  181. package/data/models/example-generator-api.json +6 -6
  182. package/package.json +2 -2
  183. package/src/lib/logging/DefaultLogger.ts +32 -0
  184. package/src/models/ClientCertificate.ts +1 -1
  185. package/src/models/RequestConfig.ts +1 -1
  186. package/src/models/SerializableError.ts +1 -1
  187. package/src/proxy/RequestProxy.ts +2 -2
  188. package/src/runtime/http-engine/CoreEngine.ts +858 -893
  189. package/src/runtime/http-engine/PayloadSupport.ts +2 -1
  190. package/src/runtime/http-engine/auth/AuthManager.ts +242 -0
  191. package/src/runtime/http-engine/certificates/CertificateManager.ts +74 -0
  192. package/src/runtime/http-engine/compression/CompressionManager.ts +99 -0
  193. package/src/runtime/http-engine/connections/ConnectionManager.ts +123 -0
  194. package/src/runtime/http-engine/connections/DigestAuthHandler.ts +238 -0
  195. package/src/runtime/http-engine/connections/DirectConnection.ts +134 -0
  196. package/src/runtime/http-engine/connections/ProxyAuthHandler.ts +179 -0
  197. package/src/runtime/http-engine/connections/ProxyConnection.ts +55 -0
  198. package/src/runtime/http-engine/connections/TunnelConnection.ts +192 -0
  199. package/src/runtime/http-engine/constants.ts +103 -0
  200. package/src/runtime/http-engine/cookies/CookieProcessor.ts +25 -0
  201. package/src/runtime/http-engine/errors/HttpEngineErrors.ts +319 -0
  202. package/src/runtime/http-engine/message/MessageBuilder.ts +201 -0
  203. package/src/runtime/http-engine/message/MessageProcessor.ts +73 -0
  204. package/src/runtime/http-engine/ntlm/NtlmAuth.ts +16 -13
  205. package/src/runtime/http-engine/ntlm/NtlmMessage.ts +6 -6
  206. package/src/runtime/http-engine/parsers/BodyParser.ts +171 -0
  207. package/src/runtime/http-engine/parsers/HeadersParser.ts +103 -0
  208. package/src/runtime/http-engine/parsers/HttpResponseParser.ts +280 -0
  209. package/src/runtime/http-engine/parsers/StatusParser.ts +69 -0
  210. package/src/runtime/http-engine/response/ResponseProcessor.ts +46 -0
  211. package/src/runtime/http-engine/statistics/StatisticsProcessor.ts +52 -0
  212. package/src/runtime/http-engine/url/UrlProcessor.ts +55 -0
  213. package/src/runtime/http-runner/HttpRequestRunner.ts +3 -3
  214. package/src/runtime/node/InteropInterfaces.ts +3 -3
  215. package/src/runtime/node/ProjectRequestRunner.ts +2 -2
  216. package/src/runtime/node/ProjectRunner.ts +2 -2
  217. package/tests/servers/ProxyServer.ts +32 -19
  218. package/tests/servers/express-routes/ApiEndpoint.ts +24 -0
  219. package/tests/servers/express-routes/BasicAuthRoute.ts +36 -0
  220. package/tests/servers/express-routes/BearerAuthRoute.ts +35 -0
  221. package/tests/servers/express-routes/NTLMRoute.ts +2 -3
  222. package/tests/servers/express-routes/PostApi.ts +15 -2
  223. package/tests/servers/express-routes/RedirectsApi.ts +12 -1
  224. package/tests/servers/express-routes/ResponsesApi.ts +1 -1
  225. package/tests/servers/express-routes/StreamApi.ts +19 -0
  226. package/tests/servers/oauth2mock/ServerMock.js +1 -1
  227. package/tests/unit/runtime/http-engine/HttpResponseParser.spec.ts +337 -0
  228. package/tests/unit/runtime/http-engine/abort.spec.ts +4 -5
  229. package/tests/unit/runtime/http-engine/auth.spec.ts +7 -58
  230. package/tests/unit/runtime/http-engine/certificates/CertificateManager.spec.ts +482 -0
  231. package/tests/unit/runtime/http-engine/certificates.spec.ts +2 -2
  232. package/tests/unit/runtime/http-engine/compression/CompressionManager.spec.ts +498 -0
  233. package/tests/unit/runtime/http-engine/compression.spec.ts +3 -72
  234. package/tests/unit/runtime/http-engine/connections/ConnectionManager.spec.ts +379 -0
  235. package/tests/unit/runtime/http-engine/connections/DigestAuthHandler.spec.ts +164 -0
  236. package/tests/unit/runtime/http-engine/core_engine.spec.ts +561 -0
  237. package/tests/unit/runtime/http-engine/engine_statuses.spec.ts +2 -2
  238. package/tests/unit/runtime/http-engine/events.spec.ts +2 -2
  239. package/tests/unit/runtime/http-engine/headers.spec.ts +2 -88
  240. package/tests/unit/runtime/http-engine/hosts.spec.ts +2 -2
  241. package/tests/unit/runtime/http-engine/http-get.spec.ts +2 -2
  242. package/tests/unit/runtime/http-engine/http-post.spec.ts +2 -2
  243. package/tests/unit/runtime/http-engine/logger.spec.ts +0 -8
  244. package/tests/unit/runtime/http-engine/message.spec.ts +2 -194
  245. package/tests/unit/runtime/http-engine/params.spec.ts +4 -4
  246. package/tests/unit/runtime/http-engine/proxy.spec.ts +15 -14
  247. package/tests/unit/runtime/http-engine/redirects.spec.ts +2 -2
  248. package/tests/unit/runtime/http-engine/responses.spec.ts +170 -277
  249. package/tests/unit/runtime/http-engine/timeout.spec.ts +3 -3
  250. package/tests/unit/runtime/http-engine/timings.spec.ts +2 -2
  251. package/tests/unit/runtime/proxy/HttpProjectProxy.spec.ts +25 -28
  252. package/tests/unit/runtime/runners/project_runner.spec.ts +2 -2
  253. package/tests/unit/runtime/runners/request_runner.spec.ts +2 -2
  254. package/build/src/runtime/http-engine/HttpEngine.d.ts +0 -311
  255. package/build/src/runtime/http-engine/HttpEngine.d.ts.map +0 -1
  256. package/build/src/runtime/http-engine/HttpEngine.js +0 -802
  257. package/build/src/runtime/http-engine/HttpEngine.js.map +0 -1
  258. package/src/runtime/http-engine/HttpEngine.ts +0 -952
  259. package/tests/unit/runtime/http-engine/connecting.spec.ts +0 -140
@@ -0,0 +1,238 @@
1
+ import crypto from 'node:crypto'
2
+ import { type Logger, type ILogObj } from '../../../lib/logging/index.js'
3
+
4
+ export interface DigestChallenge {
5
+ realm: string
6
+ nonce: string
7
+ qop?: string
8
+ algorithm?: string
9
+ opaque?: string
10
+ stale?: string
11
+ domain?: string
12
+ }
13
+
14
+ export interface DigestResponse {
15
+ username: string
16
+ realm: string
17
+ nonce: string
18
+ uri: string
19
+ response: string
20
+ qop?: string
21
+ nc?: string
22
+ cnonce?: string
23
+ algorithm?: string
24
+ opaque?: string
25
+ }
26
+
27
+ /**
28
+ * Handles HTTP Digest authentication according to RFC 2617
29
+ */
30
+ export class DigestAuthHandler {
31
+ private logger: Logger<ILogObj>
32
+ private username: string
33
+ private password: string
34
+ private nc = 1
35
+ private cnonce: string
36
+
37
+ constructor(username: string, password: string, logger: Logger<ILogObj>) {
38
+ this.username = username
39
+ this.password = password
40
+ this.logger = logger
41
+ this.cnonce = this.generateCnonce()
42
+ }
43
+
44
+ /**
45
+ * Parse a WWW-Authenticate or Proxy-Authenticate header
46
+ */
47
+ parseChallenge(authenticateHeader: string): DigestChallenge {
48
+ const challenge: DigestChallenge = { realm: '', nonce: '' }
49
+
50
+ // Extract the method (Digest)
51
+ const methodMatch = authenticateHeader.match(/^(\w+)/)
52
+ if (!methodMatch || methodMatch[1].toLowerCase() !== 'digest') {
53
+ throw new Error('Not a Digest authentication challenge')
54
+ }
55
+
56
+ // Parse key-value pairs (both quoted and unquoted)
57
+ const paramRegex = /(\w+)=(?:"([^"]*)"|([^,\s]+))/g
58
+ let match
59
+ while ((match = paramRegex.exec(authenticateHeader)) !== null) {
60
+ const [, key, quotedValue, unquotedValue] = match
61
+ const value = quotedValue !== undefined ? quotedValue : unquotedValue
62
+
63
+ switch (key.toLowerCase()) {
64
+ case 'realm':
65
+ challenge.realm = value
66
+ break
67
+ case 'nonce':
68
+ challenge.nonce = value
69
+ break
70
+ case 'qop':
71
+ challenge.qop = value
72
+ break
73
+ case 'algorithm':
74
+ challenge.algorithm = value
75
+ break
76
+ case 'opaque':
77
+ challenge.opaque = value
78
+ break
79
+ case 'stale':
80
+ challenge.stale = value
81
+ break
82
+ case 'domain':
83
+ challenge.domain = value
84
+ break
85
+ }
86
+ }
87
+
88
+ // Validate required fields
89
+ if (!challenge.realm || !challenge.nonce) {
90
+ throw new Error('Invalid Digest challenge: missing realm or nonce')
91
+ }
92
+
93
+ this.logger.debug('Parsed Digest challenge:', challenge)
94
+ return challenge
95
+ }
96
+
97
+ /**
98
+ * Generate a Digest authentication response
99
+ */
100
+ generateResponse(challenge: DigestChallenge, method: string, uri: string): string {
101
+ const algorithm = challenge.algorithm?.toLowerCase() || 'md5'
102
+ const qop = challenge.qop?.toLowerCase()
103
+
104
+ // Generate HA1 = MD5(username:realm:password)
105
+ const ha1 = this.calculateHA1(challenge.realm, algorithm)
106
+
107
+ // Generate HA2 = MD5(method:uri)
108
+ const ha2 = this.calculateHA2(method, uri, algorithm)
109
+
110
+ let response: string
111
+
112
+ if (qop) {
113
+ // With quality of protection
114
+ const nc = this.formatNC(this.nc)
115
+ const cnonce = this.cnonce
116
+
117
+ if (qop === 'auth') {
118
+ // response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
119
+ const responseInput = `${ha1}:${challenge.nonce}:${nc}:${cnonce}:${qop}:${ha2}`
120
+ response = crypto.createHash(algorithm).update(responseInput).digest('hex')
121
+ } else {
122
+ throw new Error(`Unsupported qop value: ${qop}`)
123
+ }
124
+ } else {
125
+ // Without quality of protection
126
+ // response = MD5(HA1:nonce:HA2)
127
+ const responseInput = `${ha1}:${challenge.nonce}:${ha2}`
128
+ response = crypto.createHash(algorithm).update(responseInput).digest('hex')
129
+ }
130
+
131
+ // Build the response header
132
+ const responseParams: DigestResponse = {
133
+ username: this.username,
134
+ realm: challenge.realm,
135
+ nonce: challenge.nonce,
136
+ uri,
137
+ response,
138
+ }
139
+
140
+ if (challenge.algorithm) {
141
+ responseParams.algorithm = challenge.algorithm
142
+ }
143
+
144
+ if (challenge.opaque) {
145
+ responseParams.opaque = challenge.opaque
146
+ }
147
+
148
+ if (qop) {
149
+ responseParams.qop = qop
150
+ responseParams.nc = this.formatNC(this.nc)
151
+ responseParams.cnonce = this.cnonce
152
+ }
153
+
154
+ const responseHeader = this.buildResponseHeader(responseParams)
155
+ this.logger.debug('Generated Digest response:', responseHeader)
156
+
157
+ // Increment nonce count for next request
158
+ this.nc++
159
+
160
+ return responseHeader
161
+ }
162
+
163
+ /**
164
+ * Calculate HA1 = MD5(username:realm:password)
165
+ */
166
+ private calculateHA1(realm: string, algorithm: string): string {
167
+ const input = `${this.username}:${realm}:${this.password}`
168
+ return crypto.createHash(algorithm).update(input).digest('hex')
169
+ }
170
+
171
+ /**
172
+ * Calculate HA2 = MD5(method:uri)
173
+ */
174
+ private calculateHA2(method: string, uri: string, algorithm: string): string {
175
+ const input = `${method}:${uri}`
176
+ return crypto.createHash(algorithm).update(input).digest('hex')
177
+ }
178
+
179
+ /**
180
+ * Generate a client nonce
181
+ */
182
+ private generateCnonce(): string {
183
+ return crypto.randomBytes(16).toString('hex')
184
+ }
185
+
186
+ /**
187
+ * Format nonce count as 8-digit hex string
188
+ */
189
+ private formatNC(nc: number): string {
190
+ return nc.toString(16).padStart(8, '0')
191
+ }
192
+
193
+ /**
194
+ * Build the Authorization header string
195
+ */
196
+ private buildResponseHeader(params: DigestResponse): string {
197
+ const parts: string[] = ['Digest']
198
+
199
+ // Add required parameters
200
+ parts.push(`username="${params.username}"`)
201
+ parts.push(`realm="${params.realm}"`)
202
+ parts.push(`nonce="${params.nonce}"`)
203
+ parts.push(`uri="${params.uri}"`)
204
+ parts.push(`response="${params.response}"`)
205
+
206
+ // Add optional parameters
207
+ if (params.algorithm) {
208
+ parts.push(`algorithm="${params.algorithm}"`)
209
+ }
210
+
211
+ if (params.opaque) {
212
+ parts.push(`opaque="${params.opaque}"`)
213
+ }
214
+
215
+ if (params.qop) {
216
+ parts.push(`qop="${params.qop}"`)
217
+ parts.push(`nc="${params.nc}"`)
218
+ parts.push(`cnonce="${params.cnonce}"`)
219
+ }
220
+
221
+ return parts.join(', ')
222
+ }
223
+
224
+ /**
225
+ * Reset the nonce count (useful for new sessions)
226
+ */
227
+ reset(): void {
228
+ this.nc = 1
229
+ this.cnonce = this.generateCnonce()
230
+ }
231
+
232
+ /**
233
+ * Check if a challenge is stale
234
+ */
235
+ isStale(challenge: DigestChallenge): boolean {
236
+ return challenge.stale === 'true'
237
+ }
238
+ }
@@ -0,0 +1,134 @@
1
+ import net from 'net'
2
+ import tls from 'tls'
3
+ import { ConnectionOptions } from './ConnectionManager.js'
4
+ import type { HttpCertificate } from '../../../models/ClientCertificate.js'
5
+ import { addClientCertificate, checkServerIdentity } from '../certificates/index.js'
6
+ import { type Logger, type ILogObj } from '../../../lib/logging/index.js'
7
+ import type { RequestStats } from '../CoreEngine.js'
8
+
9
+ /**
10
+ * Handles direct HTTP and HTTPS connections
11
+ */
12
+ export class DirectConnection {
13
+ private options: ConnectionOptions
14
+
15
+ constructor(options: ConnectionOptions) {
16
+ this.options = options
17
+ }
18
+
19
+ /**
20
+ * Establish a connection to the target host
21
+ */
22
+ async connect(): Promise<net.Socket> {
23
+ const { host, port, timeout, validateCertificates, certificates, logger, stats } = this.options
24
+
25
+ let socket: net.Socket
26
+ // Check if this is an HTTPS connection based on port or protocol
27
+ const isHttps = port === 443 || port === 8443 || this.options.protocol === 'https:'
28
+ if (isHttps) {
29
+ socket = await this.createTlsConnection(host, port, validateCertificates, certificates, logger, stats)
30
+ } else {
31
+ socket = await this.createTcpConnection(host, port, logger, stats)
32
+ }
33
+
34
+ if (timeout && timeout > 0) {
35
+ socket.setTimeout(timeout)
36
+ }
37
+
38
+ return socket
39
+ }
40
+
41
+ /**
42
+ * Create a TCP connection for HTTP
43
+ */
44
+ private createTcpConnection(
45
+ host: string,
46
+ port: number,
47
+ logger: Logger<ILogObj>,
48
+ stats: RequestStats
49
+ ): Promise<net.Socket> {
50
+ logger.debug(`Opening HTTP connection to ${host} on port ${port}`)
51
+ return new Promise((resolve, reject) => {
52
+ stats.connectionTime = Date.now()
53
+ const isIp = net.isIP(host)
54
+ if (isIp) {
55
+ stats.lookupTime = Date.now()
56
+ }
57
+
58
+ const client = net.createConnection(port, host, () => {
59
+ stats.connectedTime = Date.now()
60
+ logger.debug('HTTP connection established.')
61
+ resolve(client)
62
+ })
63
+
64
+ client.pause()
65
+ if (!isIp) {
66
+ client.once('lookup', () => {
67
+ stats.lookupTime = Date.now()
68
+ })
69
+ }
70
+ client.once('error', (err: Error) => reject(err))
71
+ })
72
+ }
73
+
74
+ /**
75
+ * Create a TLS connection for HTTPS
76
+ */
77
+ private createTlsConnection(
78
+ host: string,
79
+ port: number,
80
+ validateCertificates: boolean | undefined,
81
+ certificates: HttpCertificate[] | undefined,
82
+ logger: Logger<ILogObj>,
83
+ stats: RequestStats
84
+ ): Promise<tls.TLSSocket> {
85
+ logger.debug('Opening an SSL connection...')
86
+ const options: tls.ConnectionOptions = {}
87
+ const isIp = net.isIP(host)
88
+
89
+ if (!isIp) {
90
+ options.servername = host
91
+ }
92
+
93
+ if (validateCertificates) {
94
+ options.checkServerIdentity = (hostname: string, cert: tls.PeerCertificate) => checkServerIdentity(hostname, cert)
95
+ } else {
96
+ options.rejectUnauthorized = false
97
+ options.checkServerIdentity = (): Error | undefined => {
98
+ return undefined
99
+ }
100
+ }
101
+
102
+ // Add client certificates if provided
103
+ if (Array.isArray(certificates)) {
104
+ certificates.forEach((cert) => addClientCertificate(cert, options))
105
+ }
106
+
107
+ return new Promise((resolve, reject) => {
108
+ const time = Date.now()
109
+ stats.connectionTime = time
110
+ if (isIp) {
111
+ stats.lookupTime = time
112
+ }
113
+
114
+ const client = tls.connect(port, host, options, () => {
115
+ logger.debug('SSL connection established.')
116
+ const connectTime = Date.now()
117
+ stats.connectedTime = connectTime
118
+ stats.secureStartTime = connectTime
119
+ resolve(client)
120
+ })
121
+
122
+ client.pause()
123
+ client.once('error', (e: Error) => reject(e))
124
+ if (!isIp) {
125
+ client.once('lookup', () => {
126
+ stats.lookupTime = Date.now()
127
+ })
128
+ }
129
+ client.once('secureConnect', () => {
130
+ stats.secureConnectedTime = Date.now()
131
+ })
132
+ })
133
+ }
134
+ }
@@ -0,0 +1,179 @@
1
+ import { SerializableError } from '../../../models/SerializableError.js'
2
+ import { type Logger, type ILogObj } from '../../../lib/logging/index.js'
3
+ import { DigestAuthHandler } from './DigestAuthHandler.js'
4
+
5
+ export interface ProxyAuthOptions {
6
+ proxyUsername?: string
7
+ proxyPassword?: string
8
+ /**
9
+ * The type of proxy authentication to use.
10
+ */
11
+ proxyAuthorization?: 'Basic'
12
+ logger: Logger<ILogObj>
13
+ }
14
+
15
+ export interface ProxyAuthChallenge {
16
+ method: string
17
+ realm?: string
18
+ nonce?: string
19
+ qop?: string
20
+ algorithm?: string
21
+ }
22
+
23
+ /**
24
+ * Handles proxy authentication challenges and responses
25
+ */
26
+ export class ProxyAuthHandler {
27
+ private options: ProxyAuthOptions
28
+ private authState: 'none' | 'challenged' | 'authenticated' = 'none'
29
+ private challenge?: ProxyAuthChallenge
30
+ private digestHandler?: DigestAuthHandler
31
+
32
+ constructor(options: ProxyAuthOptions) {
33
+ this.options = options
34
+ if (options.proxyUsername && options.proxyPassword) {
35
+ this.digestHandler = new DigestAuthHandler(options.proxyUsername, options.proxyPassword, options.logger)
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Check if we have proxy credentials configured
41
+ */
42
+ hasCredentials(): boolean {
43
+ const { proxyUsername, proxyPassword, proxyAuthorization } = this.options
44
+ return !!(proxyUsername && proxyPassword) || !!proxyAuthorization
45
+ }
46
+
47
+ /**
48
+ * Generate the initial proxy authorization header
49
+ */
50
+ generateAuthHeader(): string | undefined {
51
+ const { proxyUsername, proxyPassword, proxyAuthorization } = this.options
52
+
53
+ if (!proxyUsername || !proxyPassword) {
54
+ return undefined
55
+ }
56
+
57
+ if (!proxyAuthorization || proxyAuthorization === 'Basic') {
58
+ // Basic authentication
59
+ const token = Buffer.from(`${proxyUsername}:${proxyPassword}`).toString('base64')
60
+ return `Basic ${token}`
61
+ }
62
+
63
+ if (proxyAuthorization === 'Digest') {
64
+ // For Digest auth, we need a challenge first
65
+ if (this.authState === 'none') {
66
+ // Initial request without auth header
67
+ return undefined
68
+ }
69
+ return this.generateDigestResponse()
70
+ }
71
+
72
+ throw new SerializableError(`Unsupported proxy authorization type: ${proxyAuthorization}`)
73
+ }
74
+
75
+ /**
76
+ * Handle a proxy authentication challenge
77
+ */
78
+ handleChallenge(authenticateHeader: string): string | undefined {
79
+ this.authState = 'challenged'
80
+ this.challenge = this.parseChallenge(authenticateHeader)
81
+ this.options.logger.debug('Received proxy authentication challenge:', this.challenge)
82
+
83
+ if (this.challenge?.method === 'Basic') {
84
+ // For Basic auth, we can respond immediately
85
+ return this.generateAuthHeader()
86
+ } else if (this.challenge?.method === 'Digest') {
87
+ // For Digest auth, we need to generate a proper response
88
+ return this.generateDigestResponse()
89
+ }
90
+
91
+ throw new SerializableError(`Unsupported proxy authentication method: ${this.challenge?.method}`)
92
+ }
93
+
94
+ /**
95
+ * Parse the WWW-Authenticate or Proxy-Authenticate header
96
+ */
97
+ private parseChallenge(authenticateHeader: string): ProxyAuthChallenge {
98
+ const challenge: ProxyAuthChallenge = { method: '' }
99
+
100
+ // Extract the method (Basic, Digest, etc.)
101
+ const methodMatch = authenticateHeader.match(/^(\w+)/)
102
+ if (methodMatch) {
103
+ challenge.method = methodMatch[1]
104
+ }
105
+
106
+ // Parse key-value pairs
107
+ const paramRegex = /(\w+)="([^"]*)"/g
108
+ let match
109
+ while ((match = paramRegex.exec(authenticateHeader)) !== null) {
110
+ const [, key, value] = match
111
+ switch (key.toLowerCase()) {
112
+ case 'realm':
113
+ challenge.realm = value
114
+ break
115
+ case 'nonce':
116
+ challenge.nonce = value
117
+ break
118
+ case 'qop':
119
+ challenge.qop = value
120
+ break
121
+ case 'algorithm':
122
+ challenge.algorithm = value
123
+ break
124
+ }
125
+ }
126
+
127
+ return challenge
128
+ }
129
+
130
+ /**
131
+ * Generate a Digest authentication response
132
+ */
133
+ private generateDigestResponse(): string | undefined {
134
+ if (!this.digestHandler || !this.challenge) {
135
+ return undefined
136
+ }
137
+
138
+ try {
139
+ // Parse the full Digest challenge
140
+ const digestChallenge = this.digestHandler.parseChallenge(
141
+ `Digest realm="${this.challenge.realm}", nonce="${this.challenge.nonce}"${
142
+ this.challenge.qop ? `, qop="${this.challenge.qop}"` : ''
143
+ }${this.challenge.algorithm ? `, algorithm="${this.challenge.algorithm}"` : ''}`
144
+ )
145
+
146
+ // Generate the response for CONNECT method
147
+ const response = this.digestHandler.generateResponse(digestChallenge, 'CONNECT', '/')
148
+ return response
149
+ } catch (error) {
150
+ this.options.logger.error('Failed to generate Digest response:', error)
151
+ throw new SerializableError(`Digest authentication failed: ${(error as Error).message}`, 127)
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Check if authentication was successful
157
+ */
158
+ isAuthenticated(): boolean {
159
+ return this.authState === 'authenticated'
160
+ }
161
+
162
+ /**
163
+ * Mark authentication as successful
164
+ */
165
+ markAuthenticated(): void {
166
+ this.authState = 'authenticated'
167
+ }
168
+
169
+ /**
170
+ * Reset authentication state
171
+ */
172
+ reset(): void {
173
+ this.authState = 'none'
174
+ this.challenge = undefined
175
+ if (this.digestHandler) {
176
+ this.digestHandler.reset()
177
+ }
178
+ }
179
+ }
@@ -0,0 +1,55 @@
1
+ import net from 'net'
2
+ import { URL } from 'url'
3
+ import { ProxyConnectionOptions } from './ConnectionManager.js'
4
+ import { DirectConnection } from './DirectConnection.js'
5
+ import { SerializableError } from '../../../models/SerializableError.js'
6
+
7
+ /**
8
+ * Handles HTTP requests through a proxy server
9
+ */
10
+ export class ProxyConnection {
11
+ private options: ProxyConnectionOptions
12
+
13
+ constructor(options: ProxyConnectionOptions) {
14
+ this.options = options
15
+ }
16
+
17
+ /**
18
+ * Establish a connection to the proxy server
19
+ */
20
+ async connect(): Promise<net.Socket> {
21
+ const { proxy, proxyIsSsl, logger } = this.options
22
+
23
+ logger.debug('Proxying an HTTP request...')
24
+
25
+ if (!proxy) {
26
+ throw new Error('No proxy configuration found.')
27
+ }
28
+
29
+ let proxyUrl = proxy
30
+ if (proxyIsSsl && !proxyUrl.startsWith('https:')) {
31
+ proxyUrl = `https://${proxyUrl}`
32
+ } else if (!proxyIsSsl && !proxyUrl.startsWith('http:')) {
33
+ proxyUrl = `http://${proxyUrl}`
34
+ }
35
+
36
+ const proxyUri = new URL(proxyUrl)
37
+ const port = Number(proxyUri.port || (proxyIsSsl ? 443 : 80))
38
+ const host = proxyUri.hostname
39
+
40
+ // Create a direct connection to the proxy
41
+ const directConnection = new DirectConnection({
42
+ ...this.options,
43
+ host,
44
+ port,
45
+ protocol: proxyIsSsl ? 'https:' : 'http:',
46
+ })
47
+
48
+ try {
49
+ return await directConnection.connect()
50
+ } catch (error) {
51
+ const err = error as Error & { code?: string }
52
+ throw new SerializableError(`Failed to connect to proxy: ${err.message}`, err.code ? Number(err.code) : 112)
53
+ }
54
+ }
55
+ }