temporal solution to observable proxy crashes on self hosted mysql

problem

  • OS : windows 10
  • nodejs : 20, 22 both tested

About two month ago, observable proxy started to crash with my self hosted mysql, but I used it about 3 years now with no problems.

C:\mypath>observable-database-proxy start mydbname
Database proxy mydbname (mysql) running at http://127.0.0.1:2899
node:events:496
      throw er; // Unhandled 'error' event
      ^

Error: Server does not support secure connection
    at ClientHandshake.handshakeInit (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\commands\client_handshake.js:140:21)
    at ClientHandshake.execute (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\commands\command.js:45:22)
    at Connection.handlePacket (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:475:34)
    at PacketParser.onPacket (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:93:12)
    at PacketParser.executeStart (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\packet_parser.js:75:16)
    at Socket.<anonymous> (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:100:25)
    at Socket.emit (node:events:518:28)
    at addChunk (node:internal/streams/readable:561:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
    at Readable.push (node:internal/streams/readable:392:5)
Emitted 'error' event on Connection instance at:
    at Connection._notifyError (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:247:12)
    at Connection._handleFatalError (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:178:10)
    at Connection.handlePacket (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:485:12)
    at PacketParser.onPacket (C:\Users\heosd\AppData\Roaming\npm\node_modules\@observablehq\database-proxy\node_modules\mysql2\lib\base\connection.js:93:12)
    [... lines matching original stack trace ...]
    at Readable.push (node:internal/streams/readable:392:5) {
  code: 'HANDSHAKE_NO_SSL_SUPPORT',
  fatal: true
}

Node.js v20.18.2

C:\mypath>

observable database settings

  • type : Mysql
  • connection hosted by : self-hosted proxy
  • proxy host : 127.0.0.1
  • port : 2899
  • required SSL/TLS : NO!
  • allow guest access : NO!

I do not use secured connection to my database

debug 1

  • mysql2@3.12.0
  • mysql2/lib/command/client_handshake.js
  • console.log around line 138 “if (connection.config.ssl) {}”
C:\mypath>observable-database-proxy start mydbname
Database proxy mydbname (mysql) running at http://127.0.0.1:2899
## connection.config
ConnectionConfig {
...
  pool: undefined,
  ssl: { rejectUnauthorized: true },
  multipleStatements: false,
...
  connectAttributes: { _client_name: 'Node-MySQL-2', _client_version: '3.12.0' },
  maxPreparedStatements: 16000,
  jsonStrings: false
}
node:events:496

debug 2

  • connection.config.ssl.rejectUnauthorized = true
  • code checks
    if (connection.config.ssl) {
      // client requires SSL but server does not support it
      if (!serverSSLSupport) {
        const err = new Error('Server does not support secure connection');
        err.code = 'HANDSHAKE_NO_SSL_SUPPORT';
        err.fatal = true;
        this.emit('error', err);
        return false;
      }
    ...

result

  • connection.config.ssl should be false but have ‘rejectUnauthorized’

temporal solution

  • modify ‘client_handshake.js’
  • c:\Users\username\AppData\Roaming\npm\node_modules@observablehq\database-proxy\node_modules\mysql2\lib\commands\client_handshake.js
  • comment whole ssl connection and just connect with below
connection.config.compress =
  connection.config.compress &&
  this.handshake.capabilityFlags & ClientConstants.COMPRESS;
this.clientFlags = this.clientFlags | connection.config.compress;

// force connection
this.sendCredentials(connection);

// comment ssl check
/*
if (connection.config.ssl) {
  ...
}
*/

guest access check

  • checked Allow guest access
  • still have
connection.config.ssl.rejectUnauthorized = true