11import * as nodeNet from 'node:net'
22import * as https from 'node:https'
3- import { PostgresConnection } from 'pg-gateway'
3+ import { BackendError , PostgresConnection } from 'pg-gateway'
4+ import { fromNodeSocket } from 'pg-gateway/node'
45import { WebSocketServer , type WebSocket } from 'ws'
56import makeDebug from 'debug'
67import * as tls from 'node:tls'
78import { extractDatabaseId , isValidServername } from './servername.ts'
8- import { getTls } from './tls.ts'
9+ import { getTls , setSecureContext } from './tls.ts'
910import { createStartupMessage } from './create-message.ts'
1011import { extractIP } from './extract-ip.ts'
1112
1213const debug = makeDebug ( 'browser-proxy' )
1314
14- const tcpConnections = new Map < string , nodeNet . Socket > ( )
15+ const tcpConnections = new Map < string , PostgresConnection > ( )
1516const websocketConnections = new Map < string , WebSocket > ( )
1617
17- let tlsOptions = await getTls ( )
18-
19- // refresh the TLS certificate every week
20- setInterval (
21- async ( ) => {
22- tlsOptions = await getTls ( )
23- httpsServer . setSecureContext ( tlsOptions )
24- } ,
25- 1000 * 60 * 60 * 24 * 7
26- )
27-
2818const httpsServer = https . createServer ( {
29- ...tlsOptions ,
3019 SNICallback : ( servername , callback ) => {
3120 debug ( 'SNICallback' , servername )
3221 if ( isValidServername ( servername ) ) {
3322 debug ( 'SNICallback' , 'valid' )
34- callback ( null , tls . createSecureContext ( tlsOptions ) )
23+ callback ( null )
3524 } else {
3625 debug ( 'SNICallback' , 'invalid' )
3726 callback ( new Error ( 'invalid SNI' ) )
3827 }
3928 } ,
4029} )
30+ await setSecureContext ( httpsServer )
31+ // reset the secure context every week to pick up any new TLS certificates
32+ setInterval ( ( ) => setSecureContext ( httpsServer ) , 1000 * 60 * 60 * 24 * 7 )
4133
4234const websocketServer = new WebSocketServer ( {
4335 server : httpsServer ,
@@ -70,8 +62,8 @@ websocketServer.on('connection', (socket, request) => {
7062
7163 socket . on ( 'message' , ( data : Buffer ) => {
7264 debug ( 'websocket message' , data . toString ( 'hex' ) )
73- const tcpSocket = tcpConnections . get ( databaseId )
74- tcpSocket ?. write ( data )
65+ const tcpConnection = tcpConnections . get ( databaseId )
66+ tcpConnection ?. streamWriter ?. write ( data )
7567 } )
7668
7769 socket . on ( 'close' , ( ) => {
@@ -86,50 +78,41 @@ const net = (
8678
8779const tcpServer = net . createServer ( )
8880
89- tcpServer . on ( 'connection' , ( socket ) => {
81+ tcpServer . on ( 'connection' , async ( socket ) => {
9082 let databaseId : string | undefined
9183
92- const connection = new PostgresConnection ( socket , {
93- tls : tlsOptions ,
84+ const connection = await fromNodeSocket ( socket , {
85+ tls : getTls ,
9486 onTlsUpgrade ( state ) {
95- if ( ! state . tlsInfo ?. sniServerName || ! isValidServername ( state . tlsInfo . sniServerName ) ) {
96- // connection.detach()
97- connection . sendError ( {
87+ if ( ! state . tlsInfo ?. serverName || ! isValidServername ( state . tlsInfo . serverName ) ) {
88+ throw BackendError . create ( {
9889 code : '08006' ,
9990 message : 'invalid SNI' ,
10091 severity : 'FATAL' ,
10192 } )
102- connection . end ( )
103- return
10493 }
10594
106- const _databaseId = extractDatabaseId ( state . tlsInfo . sniServerName ! )
95+ const _databaseId = extractDatabaseId ( state . tlsInfo . serverName ! )
10796
10897 if ( ! websocketConnections . has ( _databaseId ! ) ) {
109- // connection.detach()
110- connection . sendError ( {
98+ throw BackendError . create ( {
11199 code : 'XX000' ,
112100 message : 'the browser is not sharing the database' ,
113101 severity : 'FATAL' ,
114102 } )
115- connection . end ( )
116- return
117103 }
118104
119105 if ( tcpConnections . has ( _databaseId ) ) {
120- // connection.detach()
121- connection . sendError ( {
106+ throw BackendError . create ( {
122107 code : '53300' ,
123108 message : 'sorry, too many clients already' ,
124109 severity : 'FATAL' ,
125110 } )
126- connection . end ( )
127- return
128111 }
129112
130113 // only set the databaseId after we've verified the connection
131114 databaseId = _databaseId
132- tcpConnections . set ( databaseId ! , connection . socket )
115+ tcpConnections . set ( databaseId ! , connection )
133116 } ,
134117 serverVersion ( ) {
135118 return '16.3'
@@ -138,13 +121,11 @@ tcpServer.on('connection', (socket) => {
138121 const websocket = websocketConnections . get ( databaseId ! )
139122
140123 if ( ! websocket ) {
141- connection . sendError ( {
124+ throw BackendError . create ( {
142125 code : 'XX000' ,
143126 message : 'the browser is not sharing the database' ,
144127 severity : 'FATAL' ,
145128 } )
146- connection . end ( )
147- return
148129 }
149130
150131 const clientIpMessage = createStartupMessage ( 'postgres' , 'postgres' , {
@@ -160,13 +141,11 @@ tcpServer.on('connection', (socket) => {
160141 const websocket = websocketConnections . get ( databaseId ! )
161142
162143 if ( ! websocket ) {
163- connection . sendError ( {
144+ throw BackendError . create ( {
164145 code : 'XX000' ,
165146 message : 'the browser is not sharing the database' ,
166147 severity : 'FATAL' ,
167148 } )
168- connection . end ( )
169- return
170149 }
171150
172151 debug ( 'tcp message' , { message } )
0 commit comments