@nocobase/plugin-idp-oauth 2.1.0-alpha.17 → 2.1.0-alpha.19

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 (221) hide show
  1. package/build.config.ts +1 -1
  2. package/dist/externalVersion.js +6 -4
  3. package/dist/node_modules/light-my-request/package.json +1 -1
  4. package/dist/node_modules/undici/LICENSE +21 -0
  5. package/dist/node_modules/undici/README.md +741 -0
  6. package/dist/node_modules/undici/docs/docs/api/Agent.md +84 -0
  7. package/dist/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
  8. package/dist/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
  9. package/dist/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
  10. package/dist/node_modules/undici/docs/docs/api/Client.md +285 -0
  11. package/dist/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
  12. package/dist/node_modules/undici/docs/docs/api/Connector.md +115 -0
  13. package/dist/node_modules/undici/docs/docs/api/ContentType.md +57 -0
  14. package/dist/node_modules/undici/docs/docs/api/Cookies.md +101 -0
  15. package/dist/node_modules/undici/docs/docs/api/Debug.md +62 -0
  16. package/dist/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
  17. package/dist/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
  18. package/dist/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
  19. package/dist/node_modules/undici/docs/docs/api/Errors.md +49 -0
  20. package/dist/node_modules/undici/docs/docs/api/EventSource.md +45 -0
  21. package/dist/node_modules/undici/docs/docs/api/Fetch.md +60 -0
  22. package/dist/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
  23. package/dist/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
  24. package/dist/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
  25. package/dist/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
  26. package/dist/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
  27. package/dist/node_modules/undici/docs/docs/api/MockClient.md +81 -0
  28. package/dist/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
  29. package/dist/node_modules/undici/docs/docs/api/MockPool.md +555 -0
  30. package/dist/node_modules/undici/docs/docs/api/Pool.md +84 -0
  31. package/dist/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
  32. package/dist/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
  33. package/dist/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
  34. package/dist/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
  35. package/dist/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
  36. package/dist/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
  37. package/dist/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
  38. package/dist/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +274 -0
  39. package/dist/node_modules/undici/docs/docs/api/Util.md +25 -0
  40. package/dist/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
  41. package/dist/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
  42. package/dist/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
  43. package/dist/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
  44. package/dist/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
  45. package/dist/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
  46. package/dist/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
  47. package/dist/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
  48. package/dist/node_modules/undici/index-fetch.js +65 -0
  49. package/dist/node_modules/undici/index.d.ts +3 -0
  50. package/dist/node_modules/undici/index.js +234 -0
  51. package/dist/node_modules/undici/lib/api/abort-signal.js +59 -0
  52. package/dist/node_modules/undici/lib/api/api-connect.js +110 -0
  53. package/dist/node_modules/undici/lib/api/api-pipeline.js +252 -0
  54. package/dist/node_modules/undici/lib/api/api-request.js +214 -0
  55. package/dist/node_modules/undici/lib/api/api-stream.js +209 -0
  56. package/dist/node_modules/undici/lib/api/api-upgrade.js +111 -0
  57. package/dist/node_modules/undici/lib/api/index.js +7 -0
  58. package/dist/node_modules/undici/lib/api/readable.js +580 -0
  59. package/dist/node_modules/undici/lib/cache/memory-cache-store.js +234 -0
  60. package/dist/node_modules/undici/lib/cache/sqlite-cache-store.js +461 -0
  61. package/dist/node_modules/undici/lib/core/connect.js +137 -0
  62. package/dist/node_modules/undici/lib/core/constants.js +143 -0
  63. package/dist/node_modules/undici/lib/core/diagnostics.js +227 -0
  64. package/dist/node_modules/undici/lib/core/errors.js +477 -0
  65. package/dist/node_modules/undici/lib/core/request.js +438 -0
  66. package/dist/node_modules/undici/lib/core/socks5-client.js +407 -0
  67. package/dist/node_modules/undici/lib/core/socks5-utils.js +203 -0
  68. package/dist/node_modules/undici/lib/core/symbols.js +75 -0
  69. package/dist/node_modules/undici/lib/core/tree.js +160 -0
  70. package/dist/node_modules/undici/lib/core/util.js +992 -0
  71. package/dist/node_modules/undici/lib/dispatcher/agent.js +158 -0
  72. package/dist/node_modules/undici/lib/dispatcher/balanced-pool.js +219 -0
  73. package/dist/node_modules/undici/lib/dispatcher/client-h1.js +1610 -0
  74. package/dist/node_modules/undici/lib/dispatcher/client-h2.js +995 -0
  75. package/dist/node_modules/undici/lib/dispatcher/client.js +659 -0
  76. package/dist/node_modules/undici/lib/dispatcher/dispatcher-base.js +165 -0
  77. package/dist/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
  78. package/dist/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
  79. package/dist/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
  80. package/dist/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
  81. package/dist/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
  82. package/dist/node_modules/undici/lib/dispatcher/pool.js +118 -0
  83. package/dist/node_modules/undici/lib/dispatcher/proxy-agent.js +318 -0
  84. package/dist/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
  85. package/dist/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
  86. package/dist/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +249 -0
  87. package/dist/node_modules/undici/lib/encoding/index.js +33 -0
  88. package/dist/node_modules/undici/lib/global.js +50 -0
  89. package/dist/node_modules/undici/lib/handler/cache-handler.js +578 -0
  90. package/dist/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
  91. package/dist/node_modules/undici/lib/handler/decorator-handler.js +67 -0
  92. package/dist/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
  93. package/dist/node_modules/undici/lib/handler/redirect-handler.js +238 -0
  94. package/dist/node_modules/undici/lib/handler/retry-handler.js +394 -0
  95. package/dist/node_modules/undici/lib/handler/unwrap-handler.js +100 -0
  96. package/dist/node_modules/undici/lib/handler/wrap-handler.js +105 -0
  97. package/dist/node_modules/undici/lib/interceptor/cache.js +495 -0
  98. package/dist/node_modules/undici/lib/interceptor/decompress.js +259 -0
  99. package/dist/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
  100. package/dist/node_modules/undici/lib/interceptor/dns.js +571 -0
  101. package/dist/node_modules/undici/lib/interceptor/dump.js +112 -0
  102. package/dist/node_modules/undici/lib/interceptor/redirect.js +21 -0
  103. package/dist/node_modules/undici/lib/interceptor/response-error.js +95 -0
  104. package/dist/node_modules/undici/lib/interceptor/retry.js +19 -0
  105. package/dist/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  106. package/dist/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
  107. package/dist/node_modules/undici/lib/llhttp/constants.js +531 -0
  108. package/dist/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
  109. package/dist/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
  110. package/dist/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
  111. package/dist/node_modules/undici/lib/llhttp/utils.js +12 -0
  112. package/dist/node_modules/undici/lib/mock/mock-agent.js +232 -0
  113. package/dist/node_modules/undici/lib/mock/mock-call-history.js +248 -0
  114. package/dist/node_modules/undici/lib/mock/mock-client.js +68 -0
  115. package/dist/node_modules/undici/lib/mock/mock-errors.js +29 -0
  116. package/dist/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
  117. package/dist/node_modules/undici/lib/mock/mock-pool.js +68 -0
  118. package/dist/node_modules/undici/lib/mock/mock-symbols.js +32 -0
  119. package/dist/node_modules/undici/lib/mock/mock-utils.js +486 -0
  120. package/dist/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
  121. package/dist/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
  122. package/dist/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
  123. package/dist/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
  124. package/dist/node_modules/undici/lib/util/cache.js +407 -0
  125. package/dist/node_modules/undici/lib/util/date.js +653 -0
  126. package/dist/node_modules/undici/lib/util/promise.js +28 -0
  127. package/dist/node_modules/undici/lib/util/runtime-features.js +124 -0
  128. package/dist/node_modules/undici/lib/util/stats.js +32 -0
  129. package/dist/node_modules/undici/lib/util/timers.js +425 -0
  130. package/dist/node_modules/undici/lib/web/cache/cache.js +864 -0
  131. package/dist/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
  132. package/dist/node_modules/undici/lib/web/cache/util.js +45 -0
  133. package/dist/node_modules/undici/lib/web/cookies/constants.js +12 -0
  134. package/dist/node_modules/undici/lib/web/cookies/index.js +199 -0
  135. package/dist/node_modules/undici/lib/web/cookies/parse.js +322 -0
  136. package/dist/node_modules/undici/lib/web/cookies/util.js +282 -0
  137. package/dist/node_modules/undici/lib/web/eventsource/eventsource-stream.js +399 -0
  138. package/dist/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
  139. package/dist/node_modules/undici/lib/web/eventsource/util.js +29 -0
  140. package/dist/node_modules/undici/lib/web/fetch/LICENSE +21 -0
  141. package/dist/node_modules/undici/lib/web/fetch/body.js +509 -0
  142. package/dist/node_modules/undici/lib/web/fetch/constants.js +131 -0
  143. package/dist/node_modules/undici/lib/web/fetch/data-url.js +596 -0
  144. package/dist/node_modules/undici/lib/web/fetch/formdata-parser.js +575 -0
  145. package/dist/node_modules/undici/lib/web/fetch/formdata.js +259 -0
  146. package/dist/node_modules/undici/lib/web/fetch/global.js +40 -0
  147. package/dist/node_modules/undici/lib/web/fetch/headers.js +719 -0
  148. package/dist/node_modules/undici/lib/web/fetch/index.js +2397 -0
  149. package/dist/node_modules/undici/lib/web/fetch/request.js +1115 -0
  150. package/dist/node_modules/undici/lib/web/fetch/response.js +641 -0
  151. package/dist/node_modules/undici/lib/web/fetch/util.js +1520 -0
  152. package/dist/node_modules/undici/lib/web/infra/index.js +229 -0
  153. package/dist/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
  154. package/dist/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
  155. package/dist/node_modules/undici/lib/web/webidl/index.js +1006 -0
  156. package/dist/node_modules/undici/lib/web/websocket/connection.js +329 -0
  157. package/dist/node_modules/undici/lib/web/websocket/constants.js +126 -0
  158. package/dist/node_modules/undici/lib/web/websocket/events.js +331 -0
  159. package/dist/node_modules/undici/lib/web/websocket/frame.js +133 -0
  160. package/dist/node_modules/undici/lib/web/websocket/permessage-deflate.js +118 -0
  161. package/dist/node_modules/undici/lib/web/websocket/receiver.js +450 -0
  162. package/dist/node_modules/undici/lib/web/websocket/sender.js +109 -0
  163. package/dist/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
  164. package/dist/node_modules/undici/lib/web/websocket/stream/websocketstream.js +497 -0
  165. package/dist/node_modules/undici/lib/web/websocket/util.js +347 -0
  166. package/dist/node_modules/undici/lib/web/websocket/websocket.js +751 -0
  167. package/dist/node_modules/undici/package.json +152 -0
  168. package/dist/node_modules/undici/scripts/strip-comments.js +10 -0
  169. package/dist/node_modules/undici/types/README.md +6 -0
  170. package/dist/node_modules/undici/types/agent.d.ts +32 -0
  171. package/dist/node_modules/undici/types/api.d.ts +43 -0
  172. package/dist/node_modules/undici/types/balanced-pool.d.ts +30 -0
  173. package/dist/node_modules/undici/types/cache-interceptor.d.ts +179 -0
  174. package/dist/node_modules/undici/types/cache.d.ts +36 -0
  175. package/dist/node_modules/undici/types/client-stats.d.ts +15 -0
  176. package/dist/node_modules/undici/types/client.d.ts +123 -0
  177. package/dist/node_modules/undici/types/connector.d.ts +36 -0
  178. package/dist/node_modules/undici/types/content-type.d.ts +21 -0
  179. package/dist/node_modules/undici/types/cookies.d.ts +30 -0
  180. package/dist/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
  181. package/dist/node_modules/undici/types/dispatcher.d.ts +273 -0
  182. package/dist/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
  183. package/dist/node_modules/undici/types/errors.d.ts +177 -0
  184. package/dist/node_modules/undici/types/eventsource.d.ts +66 -0
  185. package/dist/node_modules/undici/types/fetch.d.ts +231 -0
  186. package/dist/node_modules/undici/types/formdata.d.ts +114 -0
  187. package/dist/node_modules/undici/types/global-dispatcher.d.ts +9 -0
  188. package/dist/node_modules/undici/types/global-origin.d.ts +7 -0
  189. package/dist/node_modules/undici/types/h2c-client.d.ts +73 -0
  190. package/dist/node_modules/undici/types/handlers.d.ts +14 -0
  191. package/dist/node_modules/undici/types/header.d.ts +160 -0
  192. package/dist/node_modules/undici/types/index.d.ts +91 -0
  193. package/dist/node_modules/undici/types/interceptors.d.ts +80 -0
  194. package/dist/node_modules/undici/types/mock-agent.d.ts +68 -0
  195. package/dist/node_modules/undici/types/mock-call-history.d.ts +111 -0
  196. package/dist/node_modules/undici/types/mock-client.d.ts +27 -0
  197. package/dist/node_modules/undici/types/mock-errors.d.ts +12 -0
  198. package/dist/node_modules/undici/types/mock-interceptor.d.ts +94 -0
  199. package/dist/node_modules/undici/types/mock-pool.d.ts +27 -0
  200. package/dist/node_modules/undici/types/patch.d.ts +29 -0
  201. package/dist/node_modules/undici/types/pool-stats.d.ts +19 -0
  202. package/dist/node_modules/undici/types/pool.d.ts +41 -0
  203. package/dist/node_modules/undici/types/proxy-agent.d.ts +29 -0
  204. package/dist/node_modules/undici/types/readable.d.ts +68 -0
  205. package/dist/node_modules/undici/types/retry-agent.d.ts +8 -0
  206. package/dist/node_modules/undici/types/retry-handler.d.ts +125 -0
  207. package/dist/node_modules/undici/types/round-robin-pool.d.ts +41 -0
  208. package/dist/node_modules/undici/types/snapshot-agent.d.ts +109 -0
  209. package/dist/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
  210. package/dist/node_modules/undici/types/util.d.ts +18 -0
  211. package/dist/node_modules/undici/types/utility.d.ts +7 -0
  212. package/dist/node_modules/undici/types/webidl.d.ts +347 -0
  213. package/dist/node_modules/undici/types/websocket.d.ts +188 -0
  214. package/dist/server/collections/oidcStates.d.ts +10 -0
  215. package/dist/server/collections/oidcStates.js +96 -0
  216. package/dist/server/db-adapter.d.ts +25 -0
  217. package/dist/server/db-adapter.js +156 -0
  218. package/dist/server/service.js +11 -10
  219. package/package.json +2 -2
  220. package/dist/server/cache-adapter.d.ts +0 -33
  221. package/dist/server/cache-adapter.js +0 -159
@@ -0,0 +1,450 @@
1
+ 'use strict'
2
+
3
+ const { Writable } = require('node:stream')
4
+ const assert = require('node:assert')
5
+ const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
6
+ const {
7
+ isValidStatusCode,
8
+ isValidOpcode,
9
+ websocketMessageReceived,
10
+ utf8Decode,
11
+ isControlFrame,
12
+ isTextBinaryFrame,
13
+ isContinuationFrame
14
+ } = require('./util')
15
+ const { failWebsocketConnection } = require('./connection')
16
+ const { WebsocketFrameSend } = require('./frame')
17
+ const { PerMessageDeflate } = require('./permessage-deflate')
18
+ const { MessageSizeExceededError } = require('../../core/errors')
19
+
20
+ // This code was influenced by ws released under the MIT license.
21
+ // Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
22
+ // Copyright (c) 2013 Arnout Kazemier and contributors
23
+ // Copyright (c) 2016 Luigi Pinca and contributors
24
+
25
+ class ByteParser extends Writable {
26
+ #buffers = []
27
+ #fragmentsBytes = 0
28
+ #byteOffset = 0
29
+ #loop = false
30
+
31
+ #state = parserStates.INFO
32
+
33
+ #info = {}
34
+ #fragments = []
35
+
36
+ /** @type {Map<string, PerMessageDeflate>} */
37
+ #extensions
38
+
39
+ /** @type {import('./websocket').Handler} */
40
+ #handler
41
+
42
+ /**
43
+ * @param {import('./websocket').Handler} handler
44
+ * @param {Map<string, string>|null} extensions
45
+ */
46
+ constructor (handler, extensions) {
47
+ super()
48
+
49
+ this.#handler = handler
50
+ this.#extensions = extensions == null ? new Map() : extensions
51
+
52
+ if (this.#extensions.has('permessage-deflate')) {
53
+ this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions))
54
+ }
55
+ }
56
+
57
+ /**
58
+ * @param {Buffer} chunk
59
+ * @param {() => void} callback
60
+ */
61
+ _write (chunk, _, callback) {
62
+ this.#buffers.push(chunk)
63
+ this.#byteOffset += chunk.length
64
+ this.#loop = true
65
+
66
+ this.run(callback)
67
+ }
68
+
69
+ /**
70
+ * Runs whenever a new chunk is received.
71
+ * Callback is called whenever there are no more chunks buffering,
72
+ * or not enough bytes are buffered to parse.
73
+ */
74
+ run (callback) {
75
+ while (this.#loop) {
76
+ if (this.#state === parserStates.INFO) {
77
+ // If there aren't enough bytes to parse the payload length, etc.
78
+ if (this.#byteOffset < 2) {
79
+ return callback()
80
+ }
81
+
82
+ const buffer = this.consume(2)
83
+ const fin = (buffer[0] & 0x80) !== 0
84
+ const opcode = buffer[0] & 0x0F
85
+ const masked = (buffer[1] & 0x80) === 0x80
86
+
87
+ const fragmented = !fin && opcode !== opcodes.CONTINUATION
88
+ const payloadLength = buffer[1] & 0x7F
89
+
90
+ const rsv1 = buffer[0] & 0x40
91
+ const rsv2 = buffer[0] & 0x20
92
+ const rsv3 = buffer[0] & 0x10
93
+
94
+ if (!isValidOpcode(opcode)) {
95
+ failWebsocketConnection(this.#handler, 1002, 'Invalid opcode received')
96
+ return callback()
97
+ }
98
+
99
+ if (masked) {
100
+ failWebsocketConnection(this.#handler, 1002, 'Frame cannot be masked')
101
+ return callback()
102
+ }
103
+
104
+ // MUST be 0 unless an extension is negotiated that defines meanings
105
+ // for non-zero values. If a nonzero value is received and none of
106
+ // the negotiated extensions defines the meaning of such a nonzero
107
+ // value, the receiving endpoint MUST _Fail the WebSocket
108
+ // Connection_.
109
+ // This document allocates the RSV1 bit of the WebSocket header for
110
+ // PMCEs and calls the bit the "Per-Message Compressed" bit. On a
111
+ // WebSocket connection where a PMCE is in use, this bit indicates
112
+ // whether a message is compressed or not.
113
+ if (rsv1 !== 0 && !this.#extensions.has('permessage-deflate')) {
114
+ failWebsocketConnection(this.#handler, 1002, 'Expected RSV1 to be clear.')
115
+ return
116
+ }
117
+
118
+ if (rsv2 !== 0 || rsv3 !== 0) {
119
+ failWebsocketConnection(this.#handler, 1002, 'RSV1, RSV2, RSV3 must be clear')
120
+ return
121
+ }
122
+
123
+ if (fragmented && !isTextBinaryFrame(opcode)) {
124
+ // Only text and binary frames can be fragmented
125
+ failWebsocketConnection(this.#handler, 1002, 'Invalid frame type was fragmented.')
126
+ return
127
+ }
128
+
129
+ // If we are already parsing a text/binary frame and do not receive either
130
+ // a continuation frame or close frame, fail the connection.
131
+ if (isTextBinaryFrame(opcode) && this.#fragments.length > 0) {
132
+ failWebsocketConnection(this.#handler, 1002, 'Expected continuation frame')
133
+ return
134
+ }
135
+
136
+ if (this.#info.fragmented && fragmented) {
137
+ // A fragmented frame can't be fragmented itself
138
+ failWebsocketConnection(this.#handler, 1002, 'Fragmented frame exceeded 125 bytes.')
139
+ return
140
+ }
141
+
142
+ // "All control frames MUST have a payload length of 125 bytes or less
143
+ // and MUST NOT be fragmented."
144
+ if ((payloadLength > 125 || fragmented) && isControlFrame(opcode)) {
145
+ failWebsocketConnection(this.#handler, 1002, 'Control frame either too large or fragmented')
146
+ return
147
+ }
148
+
149
+ if (isContinuationFrame(opcode) && this.#fragments.length === 0 && !this.#info.compressed) {
150
+ failWebsocketConnection(this.#handler, 1002, 'Unexpected continuation frame')
151
+ return
152
+ }
153
+
154
+ if (payloadLength <= 125) {
155
+ this.#info.payloadLength = payloadLength
156
+ this.#state = parserStates.READ_DATA
157
+ } else if (payloadLength === 126) {
158
+ this.#state = parserStates.PAYLOADLENGTH_16
159
+ } else if (payloadLength === 127) {
160
+ this.#state = parserStates.PAYLOADLENGTH_64
161
+ }
162
+
163
+ if (isTextBinaryFrame(opcode)) {
164
+ this.#info.binaryType = opcode
165
+ this.#info.compressed = rsv1 !== 0
166
+ }
167
+
168
+ this.#info.opcode = opcode
169
+ this.#info.masked = masked
170
+ this.#info.fin = fin
171
+ this.#info.fragmented = fragmented
172
+ } else if (this.#state === parserStates.PAYLOADLENGTH_16) {
173
+ if (this.#byteOffset < 2) {
174
+ return callback()
175
+ }
176
+
177
+ const buffer = this.consume(2)
178
+
179
+ this.#info.payloadLength = buffer.readUInt16BE(0)
180
+ this.#state = parserStates.READ_DATA
181
+ } else if (this.#state === parserStates.PAYLOADLENGTH_64) {
182
+ if (this.#byteOffset < 8) {
183
+ return callback()
184
+ }
185
+
186
+ const buffer = this.consume(8)
187
+ const upper = buffer.readUInt32BE(0)
188
+ const lower = buffer.readUInt32BE(4)
189
+
190
+ // 2^31 is the maximum bytes an arraybuffer can contain
191
+ // on 32-bit systems. Although, on 64-bit systems, this is
192
+ // 2^53-1 bytes.
193
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
194
+ // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
195
+ // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
196
+ if (upper !== 0 || lower > 2 ** 31 - 1) {
197
+ failWebsocketConnection(this.#handler, 1009, 'Received payload length > 2^31 bytes.')
198
+ return
199
+ }
200
+
201
+ this.#info.payloadLength = lower
202
+ this.#state = parserStates.READ_DATA
203
+ } else if (this.#state === parserStates.READ_DATA) {
204
+ if (this.#byteOffset < this.#info.payloadLength) {
205
+ return callback()
206
+ }
207
+
208
+ const body = this.consume(this.#info.payloadLength)
209
+
210
+ if (isControlFrame(this.#info.opcode)) {
211
+ this.#loop = this.parseControlFrame(body)
212
+ this.#state = parserStates.INFO
213
+ } else {
214
+ if (!this.#info.compressed) {
215
+ this.writeFragments(body)
216
+
217
+ // If the frame is not fragmented, a message has been received.
218
+ // If the frame is fragmented, it will terminate with a fin bit set
219
+ // and an opcode of 0 (continuation), therefore we handle that when
220
+ // parsing continuation frames, not here.
221
+ if (!this.#info.fragmented && this.#info.fin) {
222
+ websocketMessageReceived(this.#handler, this.#info.binaryType, this.consumeFragments())
223
+ }
224
+
225
+ this.#state = parserStates.INFO
226
+ } else {
227
+ this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
228
+ if (error) {
229
+ // Use 1009 (Message Too Big) for decompression size limit errors
230
+ const code = error instanceof MessageSizeExceededError ? 1009 : 1007
231
+ failWebsocketConnection(this.#handler, code, error.message)
232
+ return
233
+ }
234
+
235
+ this.writeFragments(data)
236
+
237
+ if (!this.#info.fin) {
238
+ this.#state = parserStates.INFO
239
+ this.#loop = true
240
+ this.run(callback)
241
+ return
242
+ }
243
+
244
+ websocketMessageReceived(this.#handler, this.#info.binaryType, this.consumeFragments())
245
+
246
+ this.#loop = true
247
+ this.#state = parserStates.INFO
248
+ this.run(callback)
249
+ })
250
+
251
+ this.#loop = false
252
+ break
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Take n bytes from the buffered Buffers
261
+ * @param {number} n
262
+ * @returns {Buffer}
263
+ */
264
+ consume (n) {
265
+ if (n > this.#byteOffset) {
266
+ throw new Error('Called consume() before buffers satiated.')
267
+ } else if (n === 0) {
268
+ return emptyBuffer
269
+ }
270
+
271
+ this.#byteOffset -= n
272
+
273
+ const first = this.#buffers[0]
274
+
275
+ if (first.length > n) {
276
+ // replace with remaining buffer
277
+ this.#buffers[0] = first.subarray(n, first.length)
278
+ return first.subarray(0, n)
279
+ } else if (first.length === n) {
280
+ // prefect match
281
+ return this.#buffers.shift()
282
+ } else {
283
+ let offset = 0
284
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
285
+ const buffer = Buffer.allocUnsafeSlow(n)
286
+ while (offset !== n) {
287
+ const next = this.#buffers[0]
288
+ const length = next.length
289
+
290
+ if (length + offset === n) {
291
+ buffer.set(this.#buffers.shift(), offset)
292
+ break
293
+ } else if (length + offset > n) {
294
+ buffer.set(next.subarray(0, n - offset), offset)
295
+ this.#buffers[0] = next.subarray(n - offset)
296
+ break
297
+ } else {
298
+ buffer.set(this.#buffers.shift(), offset)
299
+ offset += length
300
+ }
301
+ }
302
+
303
+ return buffer
304
+ }
305
+ }
306
+
307
+ writeFragments (fragment) {
308
+ this.#fragmentsBytes += fragment.length
309
+ this.#fragments.push(fragment)
310
+ }
311
+
312
+ consumeFragments () {
313
+ const fragments = this.#fragments
314
+
315
+ if (fragments.length === 1) {
316
+ // single fragment
317
+ this.#fragmentsBytes = 0
318
+ return fragments.shift()
319
+ }
320
+
321
+ let offset = 0
322
+ // If Buffer.allocUnsafe is used, extra copies will be made because the offset is non-zero.
323
+ const output = Buffer.allocUnsafeSlow(this.#fragmentsBytes)
324
+
325
+ for (let i = 0; i < fragments.length; ++i) {
326
+ const buffer = fragments[i]
327
+ output.set(buffer, offset)
328
+ offset += buffer.length
329
+ }
330
+
331
+ this.#fragments = []
332
+ this.#fragmentsBytes = 0
333
+
334
+ return output
335
+ }
336
+
337
+ parseCloseBody (data) {
338
+ assert(data.length !== 1)
339
+
340
+ // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
341
+ /** @type {number|undefined} */
342
+ let code
343
+
344
+ if (data.length >= 2) {
345
+ // _The WebSocket Connection Close Code_ is
346
+ // defined as the status code (Section 7.4) contained in the first Close
347
+ // control frame received by the application
348
+ code = data.readUInt16BE(0)
349
+ }
350
+
351
+ if (code !== undefined && !isValidStatusCode(code)) {
352
+ return { code: 1002, reason: 'Invalid status code', error: true }
353
+ }
354
+
355
+ // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
356
+ /** @type {Buffer} */
357
+ let reason = data.subarray(2)
358
+
359
+ // Remove BOM
360
+ if (reason[0] === 0xEF && reason[1] === 0xBB && reason[2] === 0xBF) {
361
+ reason = reason.subarray(3)
362
+ }
363
+
364
+ try {
365
+ reason = utf8Decode(reason)
366
+ } catch {
367
+ return { code: 1007, reason: 'Invalid UTF-8', error: true }
368
+ }
369
+
370
+ return { code, reason, error: false }
371
+ }
372
+
373
+ /**
374
+ * Parses control frames.
375
+ * @param {Buffer} body
376
+ */
377
+ parseControlFrame (body) {
378
+ const { opcode, payloadLength } = this.#info
379
+
380
+ if (opcode === opcodes.CLOSE) {
381
+ if (payloadLength === 1) {
382
+ failWebsocketConnection(this.#handler, 1002, 'Received close frame with a 1-byte body.')
383
+ return false
384
+ }
385
+
386
+ this.#info.closeInfo = this.parseCloseBody(body)
387
+
388
+ if (this.#info.closeInfo.error) {
389
+ const { code, reason } = this.#info.closeInfo
390
+
391
+ failWebsocketConnection(this.#handler, code, reason)
392
+ return false
393
+ }
394
+
395
+ // Upon receiving such a frame, the other peer sends a
396
+ // Close frame in response, if it hasn't already sent one.
397
+ if (!this.#handler.closeState.has(sentCloseFrameState.SENT) && !this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
398
+ // If an endpoint receives a Close frame and did not previously send a
399
+ // Close frame, the endpoint MUST send a Close frame in response. (When
400
+ // sending a Close frame in response, the endpoint typically echos the
401
+ // status code it received.)
402
+ let body = emptyBuffer
403
+ if (this.#info.closeInfo.code) {
404
+ body = Buffer.allocUnsafe(2)
405
+ body.writeUInt16BE(this.#info.closeInfo.code, 0)
406
+ }
407
+ const closeFrame = new WebsocketFrameSend(body)
408
+
409
+ this.#handler.socket.write(closeFrame.createFrame(opcodes.CLOSE))
410
+ this.#handler.closeState.add(sentCloseFrameState.SENT)
411
+ }
412
+
413
+ // Upon either sending or receiving a Close control frame, it is said
414
+ // that _The WebSocket Closing Handshake is Started_ and that the
415
+ // WebSocket connection is in the CLOSING state.
416
+ this.#handler.readyState = states.CLOSING
417
+ this.#handler.closeState.add(sentCloseFrameState.RECEIVED)
418
+
419
+ return false
420
+ } else if (opcode === opcodes.PING) {
421
+ // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
422
+ // response, unless it already received a Close frame.
423
+ // A Pong frame sent in response to a Ping frame must have identical
424
+ // "Application data"
425
+
426
+ if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
427
+ const frame = new WebsocketFrameSend(body)
428
+
429
+ this.#handler.socket.write(frame.createFrame(opcodes.PONG))
430
+
431
+ this.#handler.onPing(body)
432
+ }
433
+ } else if (opcode === opcodes.PONG) {
434
+ // A Pong frame MAY be sent unsolicited. This serves as a
435
+ // unidirectional heartbeat. A response to an unsolicited Pong frame is
436
+ // not expected.
437
+ this.#handler.onPong(body)
438
+ }
439
+
440
+ return true
441
+ }
442
+
443
+ get closingInfo () {
444
+ return this.#info.closeInfo
445
+ }
446
+ }
447
+
448
+ module.exports = {
449
+ ByteParser
450
+ }
@@ -0,0 +1,109 @@
1
+ 'use strict'
2
+
3
+ const { WebsocketFrameSend } = require('./frame')
4
+ const { opcodes, sendHints } = require('./constants')
5
+ const FixedQueue = require('../../dispatcher/fixed-queue')
6
+
7
+ /**
8
+ * @typedef {object} SendQueueNode
9
+ * @property {Promise<void> | null} promise
10
+ * @property {((...args: any[]) => any)} callback
11
+ * @property {Buffer | null} frame
12
+ */
13
+
14
+ class SendQueue {
15
+ /**
16
+ * @type {FixedQueue}
17
+ */
18
+ #queue = new FixedQueue()
19
+
20
+ /**
21
+ * @type {boolean}
22
+ */
23
+ #running = false
24
+
25
+ /** @type {import('node:net').Socket} */
26
+ #socket
27
+
28
+ constructor (socket) {
29
+ this.#socket = socket
30
+ }
31
+
32
+ add (item, cb, hint) {
33
+ if (hint !== sendHints.blob) {
34
+ if (!this.#running) {
35
+ // TODO(@tsctx): support fast-path for string on running
36
+ if (hint === sendHints.text) {
37
+ // special fast-path for string
38
+ const { 0: head, 1: body } = WebsocketFrameSend.createFastTextFrame(item)
39
+ this.#socket.cork()
40
+ this.#socket.write(head)
41
+ this.#socket.write(body, cb)
42
+ this.#socket.uncork()
43
+ } else {
44
+ // direct writing
45
+ this.#socket.write(createFrame(item, hint), cb)
46
+ }
47
+ } else {
48
+ /** @type {SendQueueNode} */
49
+ const node = {
50
+ promise: null,
51
+ callback: cb,
52
+ frame: createFrame(item, hint)
53
+ }
54
+ this.#queue.push(node)
55
+ }
56
+ return
57
+ }
58
+
59
+ /** @type {SendQueueNode} */
60
+ const node = {
61
+ promise: item.arrayBuffer().then((ab) => {
62
+ node.promise = null
63
+ node.frame = createFrame(ab, hint)
64
+ }),
65
+ callback: cb,
66
+ frame: null
67
+ }
68
+
69
+ this.#queue.push(node)
70
+
71
+ if (!this.#running) {
72
+ this.#run()
73
+ }
74
+ }
75
+
76
+ async #run () {
77
+ this.#running = true
78
+ const queue = this.#queue
79
+ while (!queue.isEmpty()) {
80
+ const node = queue.shift()
81
+ // wait pending promise
82
+ if (node.promise !== null) {
83
+ await node.promise
84
+ }
85
+ // write
86
+ this.#socket.write(node.frame, node.callback)
87
+ // cleanup
88
+ node.callback = node.frame = null
89
+ }
90
+ this.#running = false
91
+ }
92
+ }
93
+
94
+ function createFrame (data, hint) {
95
+ return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.text ? opcodes.TEXT : opcodes.BINARY)
96
+ }
97
+
98
+ function toBuffer (data, hint) {
99
+ switch (hint) {
100
+ case sendHints.text:
101
+ case sendHints.typedArray:
102
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
103
+ case sendHints.arrayBuffer:
104
+ case sendHints.blob:
105
+ return new Uint8Array(data)
106
+ }
107
+ }
108
+
109
+ module.exports = { SendQueue }
@@ -0,0 +1,104 @@
1
+ 'use strict'
2
+
3
+ const { webidl } = require('../../webidl')
4
+ const { validateCloseCodeAndReason } = require('../util')
5
+ const { kConstruct } = require('../../../core/symbols')
6
+ const { kEnumerableProperty } = require('../../../core/util')
7
+
8
+ function createInheritableDOMException () {
9
+ // https://github.com/nodejs/node/issues/59677
10
+ class Test extends DOMException {
11
+ get reason () {
12
+ return ''
13
+ }
14
+ }
15
+
16
+ if (new Test().reason !== undefined) {
17
+ return DOMException
18
+ }
19
+
20
+ return new Proxy(DOMException, {
21
+ construct (target, args, newTarget) {
22
+ const instance = Reflect.construct(target, args, target)
23
+ Object.setPrototypeOf(instance, newTarget.prototype)
24
+ return instance
25
+ }
26
+ })
27
+ }
28
+
29
+ class WebSocketError extends createInheritableDOMException() {
30
+ #closeCode
31
+ #reason
32
+
33
+ constructor (message = '', init = undefined) {
34
+ message = webidl.converters.DOMString(message, 'WebSocketError', 'message')
35
+
36
+ // 1. Set this 's name to " WebSocketError ".
37
+ // 2. Set this 's message to message .
38
+ super(message, 'WebSocketError')
39
+
40
+ if (init === kConstruct) {
41
+ return
42
+ } else if (init !== null) {
43
+ init = webidl.converters.WebSocketCloseInfo(init)
44
+ }
45
+
46
+ // 3. Let code be init [" closeCode "] if it exists , or null otherwise.
47
+ let code = init.closeCode ?? null
48
+
49
+ // 4. Let reason be init [" reason "] if it exists , or the empty string otherwise.
50
+ const reason = init.reason ?? ''
51
+
52
+ // 5. Validate close code and reason with code and reason .
53
+ validateCloseCodeAndReason(code, reason)
54
+
55
+ // 6. If reason is non-empty, but code is not set, then set code to 1000 ("Normal Closure").
56
+ if (reason.length !== 0 && code === null) {
57
+ code = 1000
58
+ }
59
+
60
+ // 7. Set this 's closeCode to code .
61
+ this.#closeCode = code
62
+
63
+ // 8. Set this 's reason to reason .
64
+ this.#reason = reason
65
+ }
66
+
67
+ get closeCode () {
68
+ return this.#closeCode
69
+ }
70
+
71
+ get reason () {
72
+ return this.#reason
73
+ }
74
+
75
+ /**
76
+ * @param {string} message
77
+ * @param {number|null} code
78
+ * @param {string} reason
79
+ */
80
+ static createUnvalidatedWebSocketError (message, code, reason) {
81
+ const error = new WebSocketError(message, kConstruct)
82
+ error.#closeCode = code
83
+ error.#reason = reason
84
+ return error
85
+ }
86
+ }
87
+
88
+ const { createUnvalidatedWebSocketError } = WebSocketError
89
+ delete WebSocketError.createUnvalidatedWebSocketError
90
+
91
+ Object.defineProperties(WebSocketError.prototype, {
92
+ closeCode: kEnumerableProperty,
93
+ reason: kEnumerableProperty,
94
+ [Symbol.toStringTag]: {
95
+ value: 'WebSocketError',
96
+ writable: false,
97
+ enumerable: false,
98
+ configurable: true
99
+ }
100
+ })
101
+
102
+ webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError)
103
+
104
+ module.exports = { WebSocketError, createUnvalidatedWebSocketError }