22 * transport-tls.ts - handles low level communication with sqlitecloud server via tls socket and binary protocol
33 */
44
5- import { SQLiteCloudConfig , SQLCloudRowsetMetadata , SQLiteCloudError , SQLiteCloudDataTypes , ErrorCallback , ResultsCallback } from './types'
5+ import { SQLiteCloudConfig , SQLiteCloudError , ErrorCallback , ResultsCallback , SQLCloudRowsetMetadata , SQLiteCloudDataTypes } from './types'
66import { SQLiteCloudRowset } from './rowset'
7- import { ConnectionTransport , getInitializationCommands } from './connection'
8- import { anonimizeError , anonimizeCommand } from './connection'
7+ import { ConnectionTransport , getInitializationCommands , anonimizeError , anonimizeCommand } from './connection'
98
10- import tls , { TLSSocket } from 'tls'
9+ import net from 'net'
10+ import tls from 'tls'
1111const lz4 = require ( 'lz4js' )
1212
13- /**
14- * The server communicates with clients via commands defined
15- * in the SQLiteCloud Server Protocol (SCSP), see more at:
16- * https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md
17- */
13+ // The server communicates with clients via commands defined in
14+ // SQLiteCloud Server Protocol (SCSP), see more at:
15+ // https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md
16+
1817const CMD_STRING = '+'
1918const CMD_ZEROSTRING = '!'
2019const CMD_ERROR = '-'
@@ -34,6 +33,7 @@ const CMD_ARRAY = '='
3433
3534/**
3635 * Implementation of SQLiteCloudConnection that connects directly to the database via tls socket and raw, binary protocol.
36+ * Connects with plain socket with no encryption is the ?insecure=1 parameter is specified.
3737 * SQLiteCloud low-level connection, will do messaging, handle socket, authentication, etc.
3838 * A connection socket is established when the connection is created and closed when the connection is closed.
3939 * All operations are serialized by waiting for any pending operations to complete. Once a connection is closed,
@@ -43,7 +43,7 @@ export class TlsSocketTransport implements ConnectionTransport {
4343 /** Configuration passed to connect */
4444 private config ?: SQLiteCloudConfig
4545 /** Currently opened tls socket used to communicated with SQLiteCloud server */
46- private socket ?: tls . TLSSocket | null
46+ private socket ?: tls . TLSSocket | net . Socket | null
4747
4848 /** True if connection is open */
4949 get connected ( ) : boolean {
@@ -69,36 +69,51 @@ export class TlsSocketTransport implements ConnectionTransport {
6969
7070 this . config = config
7171
72- // connect to tls socket, initialize connection, setup event handlers
73- this . socket = tls . connect ( this . config . port as number , this . config . host , this . config . tlsOptions , ( ) => {
74- if ( ! this . socket ?. authorized ) {
75- const anonimizedError = anonimizeError ( ( this . socket as TLSSocket ) . authorizationError )
76- console . error ( 'Connection was not authorized' , anonimizedError )
77- this . close ( )
78- finish ( new SQLiteCloudError ( 'Connection was not authorized' , { cause : anonimizedError } ) )
79- } else {
80- // the connection was closed before it was even opened,
81- // eg. client closed the connection before the server accepted it
82- if ( this . socket === null ) {
83- finish ( new SQLiteCloudError ( 'Connection was closed before it was done opening' ) )
84- return
85- }
86-
87- // send initialization commands
88- console . assert ( this . socket , 'Connection already closed' )
89- const commands = getInitializationCommands ( config )
90- this . processCommands ( commands , error => {
91- if ( error && this . socket ) {
92- this . close ( )
93- }
94- if ( callback ) {
95- callback ?. call ( this , error )
96- callback = undefined
97- }
98- finish ( error )
99- } )
72+ if ( config . insecure ) {
73+ // connect to plain socket, without encryption, only if insecure parameter specified
74+ // this option is mainly for testing purposes and is not available on production nodes
75+ // which would need to connect using tls and proper certificates as per code below
76+ const connectionOptions : net . SocketConnectOpts = {
77+ host : config . host ,
78+ port : config . port as number
10079 }
101- } )
80+ this . socket = net . connect ( connectionOptions , ( ) => {
81+ console . warn ( `TlsTransport.connect - connected to ${ config . host } :${ config . port } using insecure protocol` )
82+ callback ?. call ( this , null )
83+ } )
84+ } else {
85+ // connect to tls socket, initialize connection, setup event handlers
86+ this . socket = tls . connect ( this . config . port as number , this . config . host , this . config . tlsOptions , ( ) => {
87+ const tlsSocket = this . socket as tls . TLSSocket
88+ if ( ! tlsSocket ?. authorized ) {
89+ const anonimizedError = anonimizeError ( tlsSocket . authorizationError )
90+ console . error ( 'Connection was not authorized' , anonimizedError )
91+ this . close ( )
92+ finish ( new SQLiteCloudError ( 'Connection was not authorized' , { cause : anonimizedError } ) )
93+ } else {
94+ // the connection was closed before it was even opened,
95+ // eg. client closed the connection before the server accepted it
96+ if ( this . socket === null ) {
97+ finish ( new SQLiteCloudError ( 'Connection was closed before it was done opening' ) )
98+ return
99+ }
100+
101+ // send initialization commands
102+ console . assert ( this . socket , 'Connection already closed' )
103+ const commands = getInitializationCommands ( config )
104+ this . processCommands ( commands , error => {
105+ if ( error && this . socket ) {
106+ this . close ( )
107+ }
108+ if ( callback ) {
109+ callback ?. call ( this , error )
110+ callback = undefined
111+ }
112+ finish ( error )
113+ } )
114+ }
115+ } )
116+ }
102117
103118 this . socket . on ( 'close' , ( ) => {
104119 this . socket = null
@@ -408,9 +423,9 @@ function parseRowset(buffer: Buffer, spaceIndex: number): SQLiteCloudRowset {
408423 * Parse a chunk of a chunked rowset command, eg:
409424 * *LEN 0:VERS NROWS NCOLS DATA
410425 */
411- function parseRowsetChunks ( buffers : Buffer [ ] ) {
426+ export function parseRowsetChunks ( buffers : Buffer [ ] ) {
412427 let metadata : SQLCloudRowsetMetadata = { version : 1 , numberOfColumns : 0 , numberOfRows : 0 , columns : [ ] }
413- const data = [ ]
428+ const data : any [ ] = [ ]
414429
415430 for ( let i = 0 ; i < buffers . length ; i ++ ) {
416431 let buffer : Buffer = buffers [ i ]
@@ -456,7 +471,7 @@ function popIntegers(buffer: Buffer, numberOfIntegers = 1): { data: number[]; fw
456471}
457472
458473/** Parse command, extract its data, return the data and the buffer moved to the first byte after the command */
459- function popData ( buffer : Buffer ) : { data : SQLiteCloudDataTypes | SQLiteCloudRowset ; fwdBuffer : Buffer } {
474+ export function popData ( buffer : Buffer ) : { data : SQLiteCloudDataTypes | SQLiteCloudRowset ; fwdBuffer : Buffer } {
460475 function popResults ( data : any ) {
461476 const fwdBuffer = buffer . subarray ( commandEnd )
462477 return { data, fwdBuffer }
@@ -511,7 +526,7 @@ function popData(buffer: Buffer): { data: SQLiteCloudDataTypes | SQLiteCloudRows
511526}
512527
513528/** Format a command to be sent via SCSP protocol */
514- function formatCommand ( command : string ) : string {
529+ export function formatCommand ( command : string ) : string {
515530 const commandLength = Buffer . byteLength ( command , 'utf-8' )
516531 return `+${ commandLength } ${ command } `
517532}
0 commit comments