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'
6- import * as tls from 'node:tls'
77import { extractDatabaseId , isValidServername } from './servername.ts'
8- import { getTls } from './tls.ts'
8+ import { getTls , setSecureContext } from './tls.ts'
99import { createStartupMessage } from './create-message.ts'
1010import { extractIP } from './extract-ip.ts'
1111
1212const debug = makeDebug ( 'browser-proxy' )
1313
14- const tcpConnections = new Map < string , nodeNet . Socket > ( )
14+ const tcpConnections = new Map < string , PostgresConnection > ( )
1515const websocketConnections = new Map < string , WebSocket > ( )
1616
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-
2817const httpsServer = https . createServer ( {
29- ...tlsOptions ,
3018 SNICallback : ( servername , callback ) => {
3119 debug ( 'SNICallback' , servername )
3220 if ( isValidServername ( servername ) ) {
3321 debug ( 'SNICallback' , 'valid' )
34- callback ( null , tls . createSecureContext ( tlsOptions ) )
22+ callback ( null )
3523 } else {
3624 debug ( 'SNICallback' , 'invalid' )
3725 callback ( new Error ( 'invalid SNI' ) )
3826 }
3927 } ,
4028} )
29+ await setSecureContext ( httpsServer )
30+ // reset the secure context every week to pick up any new TLS certificates
31+ setInterval ( ( ) => setSecureContext ( httpsServer ) , 1000 * 60 * 60 * 24 * 7 )
4132
4233const websocketServer = new WebSocketServer ( {
4334 server : httpsServer ,
@@ -70,8 +61,8 @@ websocketServer.on('connection', (socket, request) => {
7061
7162 socket . on ( 'message' , ( data : Buffer ) => {
7263 debug ( 'websocket message' , data . toString ( 'hex' ) )
73- const tcpSocket = tcpConnections . get ( databaseId )
74- tcpSocket ?. write ( data )
64+ const tcpConnection = tcpConnections . get ( databaseId )
65+ tcpConnection ?. streamWriter ?. write ( data )
7566 } )
7667
7768 socket . on ( 'close' , ( ) => {
@@ -86,50 +77,41 @@ const net = (
8677
8778const tcpServer = net . createServer ( )
8879
89- tcpServer . on ( 'connection' , ( socket ) => {
80+ tcpServer . on ( 'connection' , async ( socket ) => {
9081 let databaseId : string | undefined
9182
92- const connection = new PostgresConnection ( socket , {
93- tls : tlsOptions ,
83+ const connection = await fromNodeSocket ( socket , {
84+ tls : getTls ,
9485 onTlsUpgrade ( state ) {
95- if ( ! state . tlsInfo ?. sniServerName || ! isValidServername ( state . tlsInfo . sniServerName ) ) {
96- // connection.detach()
97- connection . sendError ( {
86+ if ( ! state . tlsInfo ?. serverName || ! isValidServername ( state . tlsInfo . serverName ) ) {
87+ throw BackendError . create ( {
9888 code : '08006' ,
9989 message : 'invalid SNI' ,
10090 severity : 'FATAL' ,
10191 } )
102- connection . end ( )
103- return
10492 }
10593
106- const _databaseId = extractDatabaseId ( state . tlsInfo . sniServerName ! )
94+ const _databaseId = extractDatabaseId ( state . tlsInfo . serverName ! )
10795
10896 if ( ! websocketConnections . has ( _databaseId ! ) ) {
109- // connection.detach()
110- connection . sendError ( {
97+ throw BackendError . create ( {
11198 code : 'XX000' ,
11299 message : 'the browser is not sharing the database' ,
113100 severity : 'FATAL' ,
114101 } )
115- connection . end ( )
116- return
117102 }
118103
119104 if ( tcpConnections . has ( _databaseId ) ) {
120- // connection.detach()
121- connection . sendError ( {
105+ throw BackendError . create ( {
122106 code : '53300' ,
123107 message : 'sorry, too many clients already' ,
124108 severity : 'FATAL' ,
125109 } )
126- connection . end ( )
127- return
128110 }
129111
130112 // only set the databaseId after we've verified the connection
131113 databaseId = _databaseId
132- tcpConnections . set ( databaseId ! , connection . socket )
114+ tcpConnections . set ( databaseId ! , connection )
133115 } ,
134116 serverVersion ( ) {
135117 return '16.3'
@@ -138,13 +120,11 @@ tcpServer.on('connection', (socket) => {
138120 const websocket = websocketConnections . get ( databaseId ! )
139121
140122 if ( ! websocket ) {
141- connection . sendError ( {
123+ throw BackendError . create ( {
142124 code : 'XX000' ,
143125 message : 'the browser is not sharing the database' ,
144126 severity : 'FATAL' ,
145127 } )
146- connection . end ( )
147- return
148128 }
149129
150130 const clientIpMessage = createStartupMessage ( 'postgres' , 'postgres' , {
@@ -160,13 +140,11 @@ tcpServer.on('connection', (socket) => {
160140 const websocket = websocketConnections . get ( databaseId ! )
161141
162142 if ( ! websocket ) {
163- connection . sendError ( {
143+ throw BackendError . create ( {
164144 code : 'XX000' ,
165145 message : 'the browser is not sharing the database' ,
166146 severity : 'FATAL' ,
167147 } )
168- connection . end ( )
169- return
170148 }
171149
172150 debug ( 'tcp message' , { message } )
0 commit comments