|
1 | | -import type { SessionToken } from '../sessions/types'; |
2 | | -import type KeyRing from '../keys/KeyRing'; |
3 | | -import type SessionManager from '../sessions/SessionManager'; |
4 | 1 | import type { RPCRequestParams } from './types'; |
5 | | -import type { JsonRpcRequest } from '../RPC/types'; |
6 | | -import type { ReadableWritablePair } from 'stream/web'; |
7 | | -import type Logger from '@matrixai/logger'; |
8 | | -import type { ConnectionInfo, Host, Port } from '../network/types'; |
9 | | -import type RPCServer from '../RPC/RPCServer'; |
10 | | -import type { TLSSocket } from 'tls'; |
11 | | -import type { Server } from 'https'; |
12 | | -import type net from 'net'; |
13 | | -import type https from 'https'; |
14 | | -import { ReadableStream, WritableStream } from 'stream/web'; |
15 | | -import WebSocket, { WebSocketServer } from 'ws'; |
16 | | -import * as clientErrors from '../client/errors'; |
17 | | -import { promise } from '../utils'; |
| 2 | +import type SessionManager from 'sessions/SessionManager'; |
| 3 | +import type KeyRing from 'keys/KeyRing'; |
| 4 | +import type { JsonRpcRequest } from 'RPC/types'; |
| 5 | +import type { SessionToken } from 'sessions/types'; |
| 6 | +import * as clientErrors from './errors'; |
18 | 7 |
|
19 | 8 | async function authenticate( |
20 | 9 | sessionManager: SessionManager, |
@@ -65,201 +54,4 @@ function encodeAuthFromPassword(password: string): string { |
65 | 54 | return `Basic ${encoded}`; |
66 | 55 | } |
67 | 56 |
|
68 | | -function readableFromWebSocket( |
69 | | - ws: WebSocket, |
70 | | - logger: Logger, |
71 | | -): ReadableStream<Uint8Array> { |
72 | | - return new ReadableStream<Uint8Array>({ |
73 | | - start: (controller) => { |
74 | | - logger.info('starting'); |
75 | | - const messageHandler = (data) => { |
76 | | - logger.debug(`message: ${data.toString()}`); |
77 | | - ws.pause(); |
78 | | - const message = data as Buffer; |
79 | | - if (message.length === 0) { |
80 | | - logger.info('ENDING'); |
81 | | - ws.removeAllListeners('message'); |
82 | | - try { |
83 | | - controller.close(); |
84 | | - } catch { |
85 | | - // Ignore already closed |
86 | | - } |
87 | | - return; |
88 | | - } |
89 | | - controller.enqueue(message); |
90 | | - }; |
91 | | - ws.on('message', messageHandler); |
92 | | - ws.once('close', () => { |
93 | | - logger.info('closed'); |
94 | | - ws.removeListener('message', messageHandler); |
95 | | - try { |
96 | | - controller.close(); |
97 | | - } catch { |
98 | | - // Ignore already closed |
99 | | - } |
100 | | - }); |
101 | | - ws.once('error', (e) => { |
102 | | - controller.error(e); |
103 | | - }); |
104 | | - }, |
105 | | - cancel: () => { |
106 | | - logger.info('cancelled'); |
107 | | - ws.close(); |
108 | | - }, |
109 | | - pull: () => { |
110 | | - logger.debug('resuming'); |
111 | | - ws.resume(); |
112 | | - }, |
113 | | - }); |
114 | | -} |
115 | | - |
116 | | -function writeableFromWebSocket( |
117 | | - ws: WebSocket, |
118 | | - holdOpen: boolean, |
119 | | - logger: Logger, |
120 | | -): WritableStream<Uint8Array> { |
121 | | - return new WritableStream<Uint8Array>({ |
122 | | - start: (controller) => { |
123 | | - logger.info('starting'); |
124 | | - ws.once('error', (e) => { |
125 | | - logger.error(`error: ${e}`); |
126 | | - controller.error(e); |
127 | | - }); |
128 | | - ws.once('close', (code, reason) => { |
129 | | - logger.info( |
130 | | - `ws closing early! with code: ${code} and reason: ${reason.toString()}`, |
131 | | - ); |
132 | | - controller.error(Error('TMP WebSocket Closed early')); |
133 | | - }); |
134 | | - }, |
135 | | - close: () => { |
136 | | - logger.info('stream closing'); |
137 | | - ws.send(Buffer.from([])); |
138 | | - if (!holdOpen) ws.terminate(); |
139 | | - }, |
140 | | - abort: () => { |
141 | | - logger.info('aborting'); |
142 | | - ws.close(); |
143 | | - }, |
144 | | - write: async (chunk, controller) => { |
145 | | - logger.debug(`writing: ${chunk?.toString()}`); |
146 | | - const wait = promise<void>(); |
147 | | - ws.send(chunk, (e) => { |
148 | | - if (e != null) { |
149 | | - logger.error(`error: ${e}`); |
150 | | - controller.error(e); |
151 | | - } |
152 | | - wait.resolveP(); |
153 | | - }); |
154 | | - await wait.p; |
155 | | - }, |
156 | | - }); |
157 | | -} |
158 | | - |
159 | | -function webSocketToWebStreamPair( |
160 | | - ws: WebSocket, |
161 | | - holdOpen: boolean, |
162 | | - logger: Logger, |
163 | | -): ReadableWritablePair<Uint8Array, Uint8Array> { |
164 | | - return { |
165 | | - readable: readableFromWebSocket(ws, logger.getChild('readable')), |
166 | | - writable: writeableFromWebSocket(ws, holdOpen, logger.getChild('writable')), |
167 | | - }; |
168 | | -} |
169 | | - |
170 | | -function startConnection( |
171 | | - host: string, |
172 | | - port: number, |
173 | | - logger: Logger, |
174 | | -): Promise<ReadableWritablePair<Uint8Array, Uint8Array>> { |
175 | | - const ws = new WebSocket(`wss://${host}:${port}`, { |
176 | | - // CheckServerIdentity: ( |
177 | | - // servername: string, |
178 | | - // cert: WebSocket.CertMeta, |
179 | | - // ): boolean => { |
180 | | - // console.log('CHECKING IDENTITY'); |
181 | | - // console.log(servername); |
182 | | - // console.log(cert); |
183 | | - // return false; |
184 | | - // }, |
185 | | - rejectUnauthorized: false, |
186 | | - // Ca: tlsConfig.certChainPem |
187 | | - }); |
188 | | - ws.once('close', () => logger.info('CLOSED')); |
189 | | - // Ws.once('upgrade', () => { |
190 | | - // // Const tlsSocket = request.socket as TLSSocket; |
191 | | - // // Console.log(tlsSocket.getPeerCertificate()); |
192 | | - // logger.info('Test early cancellation'); |
193 | | - // // Request.destroy(Error('some error')); |
194 | | - // // tlsSocket.destroy(Error('some error')); |
195 | | - // // ws.close(12345, 'some reason'); |
196 | | - // // TODO: Use the existing verify method from the GRPC implementation |
197 | | - // // TODO: Have this emit an error on verification failure. |
198 | | - // // It's fine for the server side to close abruptly without error |
199 | | - // }); |
200 | | - const prom = promise<ReadableWritablePair<Uint8Array, Uint8Array>>(); |
201 | | - ws.once('open', () => { |
202 | | - logger.info('starting connection'); |
203 | | - prom.resolveP(webSocketToWebStreamPair(ws, true, logger)); |
204 | | - }); |
205 | | - return prom.p; |
206 | | -} |
207 | | - |
208 | | -function handleConnection(ws: WebSocket, logger: Logger): void { |
209 | | - ws.once('close', () => logger.info('CLOSED')); |
210 | | - const readable = readableFromWebSocket(ws, logger.getChild('readable')); |
211 | | - const writable = writeableFromWebSocket( |
212 | | - ws, |
213 | | - false, |
214 | | - logger.getChild('writable'), |
215 | | - ); |
216 | | - void readable.pipeTo(writable).catch((e) => logger.error(e)); |
217 | | -} |
218 | | - |
219 | | -function createClientServer( |
220 | | - server: Server, |
221 | | - rpcServer: RPCServer, |
222 | | - logger: Logger, |
223 | | -) { |
224 | | - logger.info('created server'); |
225 | | - const wss = new WebSocketServer({ |
226 | | - server, |
227 | | - }); |
228 | | - wss.on('error', (e) => logger.error(e)); |
229 | | - logger.info('created wss'); |
230 | | - wss.on('connection', (ws, req) => { |
231 | | - logger.info('connection!'); |
232 | | - const socket = req.socket as TLSSocket; |
233 | | - const streamPair = webSocketToWebStreamPair(ws, false, logger); |
234 | | - rpcServer.handleStream(streamPair, { |
235 | | - localHost: socket.localAddress! as Host, |
236 | | - localPort: socket.localPort! as Port, |
237 | | - remoteCertificates: socket.getPeerCertificate(), |
238 | | - remoteHost: socket.remoteAddress! as Host, |
239 | | - remotePort: socket.remotePort! as Port, |
240 | | - } as unknown as ConnectionInfo); |
241 | | - }); |
242 | | - wss.once('close', () => { |
243 | | - wss.removeAllListeners('error'); |
244 | | - wss.removeAllListeners('connection'); |
245 | | - }); |
246 | | - return wss; |
247 | | -} |
248 | | - |
249 | | -async function listen(server: https.Server, host?: string, port?: number) { |
250 | | - await new Promise<void>((resolve) => { |
251 | | - server.listen(port, host ?? '127.0.0.1', undefined, () => resolve()); |
252 | | - }); |
253 | | - const addressInfo = server.address() as net.AddressInfo; |
254 | | - return addressInfo.port; |
255 | | -} |
256 | | - |
257 | | -export { |
258 | | - authenticate, |
259 | | - decodeAuth, |
260 | | - encodeAuthFromPassword, |
261 | | - startConnection, |
262 | | - handleConnection, |
263 | | - createClientServer, |
264 | | - listen, |
265 | | -}; |
| 57 | +export { authenticate, decodeAuth, encodeAuthFromPassword }; |
0 commit comments