@m2k-5f/pgtx 2.7.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,30 +38,19 @@ await pool.begin(async tx => {
38
38
  That's most of what you need to know to use it. The rest of this document is for when you want to know *why* it's fast, or you need one of the sharper tools.
39
39
 
40
40
  ## Benchmarks
41
-
41
+
42
42
  Benchmarks run on GitHub Actions (Ubuntu, 2 vCPUs), reproducible, sources in this repo. Take CI numbers with the usual grain of salt — noisy neighbors and all that — but the gap is wide enough that it holds.
43
-
44
- **8192 concurrent parameterized SELECTs, measured with mitata:**
45
-
46
- | Driver | Avg time | Relative | Memory (p75) |
47
- |---|---:|---:|---:|
48
- | Pgtx | **69.23 ms** | 1.00× | ≈10.00 MB |
49
- | Postgres.js | 201.69 ms | 2.91× slower | ≈12.25 MB |
50
- | node-postgres (`pg`) | 738.97 ms | 10.67× slower | ≈12.74 MB |
51
-
52
- **Real HTTP throughput, `node:http` serving a PG-backed route, `wrk`:**
53
-
54
- | Concurrency | Pgtx | Postgres.js | Speedup |
55
- |---:|---:|---:|---:|
56
- | 50 | **13,575 req/s** | 5,507 req/s | 2.47× |
57
- | 200 | **18,431 req/s** | 6,640 req/s | 2.78× |
58
- | 1000 | **16,992 req/s** | 8,099 req/s | 2.10× |
59
- | 10000 | **17,700 req/s** | 10,414 req/s | 1.70× |
60
-
61
- (`/users` route — `SELECT` returning 5 rows, single connection pool, 2 wrk threads, 10s runs)
62
-
63
- The gap is widest at low-to-mid concurrency, where per-request overhead dominates; it narrows past ~10k concurrent connections as both drivers start hitting OS/socket limits rather than protocol overhead.
64
-
43
+
44
+ **HTTP throughput against `postgres.js` and Bun's own native `Bun.sql` driver, on Bun:**
45
+
46
+ | Connections | Pgtx | Postgres.js | Bun.sql | vs Postgres.js | vs Bun.sql |
47
+ |---:|---:|---:|---:|---:|---:|
48
+ | 50 | **27,885 req/s** | 8,967 req/s | 10,170 req/s | 3.11× | 2.74× |
49
+ | 200 | **31,975 req/s** | 9,861 req/s | 11,725 req/s | 3.24× | 2.73× |
50
+ | 500 | **31,245 req/s** | 8,289 req/s | 11,005 req/s | 3.77× | 2.84× |
51
+
52
+ Bun.sql is Bun's own built-in driver, written in native code and generally treated as the speed baseline in that ecosystem. Pgtx stays 2.7-2.8× ahead of it at every concurrency level tested — the gap doesn't come from JS-vs-native, it comes from the protocol.
53
+
65
54
  **How:** everything you fire concurrently against the same connection gets folded into one pipelined write — Parse/Bind/Execute for every query in the batch goes out in a single `socket.write()`, and results get demuxed as they come back, in order, without buffering rows you haven't asked for yet. Prepared statements are cached and deduplicated automatically, row descriptions are cached alongside them, and the binary protocol skips text (de)serialization where it can. None of this requires you to change how you write queries.
66
55
 
67
56
  ## The parts worth knowing about
@@ -214,6 +203,8 @@ interface ConnectionPartialConfig {
214
203
  int8toBigint?: boolean // default false
215
204
  queryTimeout?: number // default 30000
216
205
  syncShedule?: 'beforeMicrotask' | 'afterMicrotask' | 'Immediate' // default 'afterMicrotask'
206
+ ssl?: 'disable' | 'prefer' | 'require' // defaut 'prefer'
207
+ caPath?: string // forces `ssl` to 'require' if provided
217
208
  }
218
209
  ```
219
210
 
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiC,uBAAuB,EAAmC,GAAG,EAAiB,MAAM,SAAS,CAAA;AACrI,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAA;AACjD,OAAO,EAAkD,aAAa,EAAE,MAAM,SAAS,CAAA;AAavF;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAsD;IACtE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,aAAa,CAA2C;IAChE,OAAO,CAAC,aAAa,CAAgC;IAErD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAA4B;IAE/C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAAsC;IAEtD,OAAO,CAAC,mBAAmB,CAAyD;IACpF,OAAO,CAAC,YAAY,CAAI;IAGxB,OAAO,CAAC,cAAc;IAKtB,OAAO;IAYP;;;OAGG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,uBAAuB;IAe1C,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,KAAK;IASb;;;;;;OAMG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAStE,OAAO,CAAC,aAAa;IA4CrB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IASzD,OAAO,CAAC,eAAe;IAsCvB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAoB7D,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAOhD,sFAAsF;IACtF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAe/D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAoB/F;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAyBvE,OAAO,CAAC,cAAc;IA2CtB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,iBAAiB;IA2BzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,aAAa;IAoIrB,OAAO,KAAK,WAAW,GAEtB;IAGD,kDAAkD;IAClD,IAAI,QAAQ,YAEX;IAGD,mDAAmD;IACnD,IAAI,QAAQ,YAEX;IAGD;;OAEG;IACH,KAAK;CAwBR"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiC,uBAAuB,EAAmC,GAAG,EAAiB,MAAM,SAAS,CAAA;AACrI,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAA;AACjD,OAAO,EAAkD,aAAa,EAAE,MAAM,SAAS,CAAA;AAcvF;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAsD;IACtE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,aAAa,CAA2C;IAChE,OAAO,CAAC,aAAa,CAAgC;IAErD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAA4B;IAE/C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAAsC;IAEtD,OAAO,CAAC,mBAAmB,CAAyD;IACpF,OAAO,CAAC,YAAY,CAAI;IAGxB,OAAO,CAAC,cAAc;IAKtB,OAAO;IAYP;;;OAGG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,uBAAuB;IAkB1C,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,KAAK;IASb;;;;;;OAMG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAStE,OAAO,CAAC,aAAa;IA4CrB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IASzD,OAAO,CAAC,eAAe;IAsCvB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAoB7D,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAOhD,sFAAsF;IACtF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAe/D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAoB/F;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAyBvE,OAAO,CAAC,cAAc;IA2CtB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,aAAa;IAoIrB,OAAO,KAAK,WAAW,GAEtB;IAGD,kDAAkD;IAClD,IAAI,QAAQ,YAEX;IAGD,mDAAmD;IACnD,IAAI,QAAQ,YAEX;IAGD;;OAEG;IACH,KAAK;CAwBR"}
@@ -1,5 +1,4 @@
1
1
  import { ConnectionRequestWriter } from "./protocol/connection-request-writer";
2
- import { createAuthorizedSocket } from "./protocol/socket-authorization";
3
2
  import { ResponseTypes } from "./protocol/constants";
4
3
  import { compileSqlTemplate } from "./utils/template-compiler";
5
4
  import { Transaction } from "./transaction";
@@ -11,6 +10,7 @@ import { Begin, Future, Ok } from 'fluent-future';
11
10
  import { ErrConnectionClosed, ErrConnectionReconnecting } from "./error";
12
11
  import { Batch } from "./batch";
13
12
  import { nextTick } from "process";
13
+ import { authorizeSocket, createSocket, upgradeSocket } from "./protocol/socket-authorization";
14
14
  const shedule = {
15
15
  Immediate: setImmediate,
16
16
  afterMicrotask: setTimeout,
@@ -30,7 +30,7 @@ export class Connection {
30
30
  _nextStatement() {
31
31
  return `s-${this._stmtCounter++}`;
32
32
  }
33
- constructor(config, socket) {
33
+ constructor(socket, config) {
34
34
  this._activeBatch = null;
35
35
  this._closing = null;
36
36
  this._closed = false;
@@ -42,7 +42,7 @@ export class Connection {
42
42
  this._listeningCallbacks = new Map();
43
43
  this._stmtCounter = 0;
44
44
  this.config = config;
45
- this._socket = new SocketConnector(socket, (type, length, reader) => this._handlePacket(type, reader, length), () => this._reconnect());
45
+ this._socket = new SocketConnector(socket, this._handlePacket.bind(this), () => this._reconnect());
46
46
  }
47
47
  /**
48
48
  * Opens a new connection and authenticates.
@@ -54,11 +54,13 @@ export class Connection {
54
54
  logLevel: config.logLevel || 'error',
55
55
  int8toBigint: config.int8toBigint || false,
56
56
  queryTimeout: config.queryTimeout || 30000,
57
- syncShedule: config.syncShedule || 'afterMicrotask'
57
+ syncShedule: config.syncShedule || 'afterMicrotask',
58
+ ssl: config.caPath ? 'require' : (config.ssl || 'prefer')
58
59
  };
59
- const writer = ConnectionRequestWriter.new();
60
- return createAuthorizedSocket(writer, conf)
61
- .andThen(socket => Ok(new Connection(conf, socket)));
60
+ return createSocket(conf)
61
+ .andThen(socket => upgradeSocket(socket, conf))
62
+ .andThen(socket => authorizeSocket(socket, conf))
63
+ .andThen(socket => Ok(new Connection(socket, conf)));
62
64
  }
63
65
  _registerBatch() {
64
66
  if (!this._activeBatch) {
@@ -277,9 +279,11 @@ export class Connection {
277
279
  while (this._batchQueue.hasMore) {
278
280
  this._batchQueue.shift.reject(ErrConnectionReconnecting);
279
281
  }
280
- return createAuthorizedSocket(ConnectionRequestWriter.new(), this.config)
282
+ return createSocket(this.config)
283
+ .andThen(socket => upgradeSocket(socket, this.config))
284
+ .andThen(socket => authorizeSocket(socket, this.config))
281
285
  .andThen(socket => {
282
- const connector = new SocketConnector(socket, (type, length, reader) => this._handlePacket(type, reader, length), () => this._reconnect());
286
+ const connector = new SocketConnector(socket, this._handlePacket.bind(this), () => this._reconnect());
283
287
  this._socket = connector;
284
288
  return Ok();
285
289
  });
@@ -295,7 +299,7 @@ export class Connection {
295
299
  _getCurrentQuery() {
296
300
  return this._batchQueue.current.current;
297
301
  }
298
- _handlePacket(type, reader, length) {
302
+ _handlePacket(type, length, reader) {
299
303
  switch (type) {
300
304
  case ResponseTypes.ParseComplete:
301
305
  {
package/dist/error.d.ts CHANGED
@@ -23,4 +23,8 @@ export declare const ErrPoolClosed: PostgresError;
23
23
  export declare const ErrTransactionClosed: PostgresError;
24
24
  export declare const ErrConnectionClosed: PostgresError;
25
25
  export declare const ErrConnectionReconnecting: PostgresError;
26
+ export declare const ErrSSLDenied: PostgresError;
27
+ export declare const ErrDatabaseNotFound: PostgresError;
28
+ export declare const ErrUntrustedCertificate: PostgresError;
29
+ export declare const ErrCertificateFileNotFound: PostgresError;
26
30
  //# sourceMappingURL=error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;IAEhB,OAAO,EAAE,MAAM;IACxB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,MAAM;gBART,OAAO,EAAE,MAAM,EACxB,IAAI,GAAE,MAAqB,EAC3B,MAAM,GAAE,MAAW,EACnB,QAAQ,GAAE,MAAW,EACrB,KAAK,GAAE,MAAW,EAClB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,MAAW,EACrB,QAAQ,GAAE,MAAW,EACrB,UAAU,GAAE,MAAW;IAQlC,IAAI,YAAY,IAAI,OAAO,CAE1B;IAID,IAAI,UAAU,IAAI,OAAO,CAExB;IAID,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAGD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAGD,IAAI,mBAAmB,IAAI,OAAO,CAEjC;CACJ;AAED,eAAO,MAAM,gBAAgB,eAAmF,CAAA;AAChH,eAAO,MAAM,mBAAmB,eAAqE,CAAA;AACrG,eAAO,MAAM,yBAAyB,eAAiD,CAAA;AAEvF,eAAO,MAAM,eAAe,eAA8C,CAAA;AAE1E,eAAO,MAAM,aAAa,eAAkE,CAAA;AAE5F,eAAO,MAAM,oBAAoB,eAA6E,CAAA;AAE9G,eAAO,MAAM,mBAAmB,eAA8E,CAAA;AAC9G,eAAO,MAAM,yBAAyB,eAA2F,CAAA"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;IAEhB,OAAO,EAAE,MAAM;IACxB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,MAAM;gBART,OAAO,EAAE,MAAM,EACxB,IAAI,GAAE,MAAqB,EAC3B,MAAM,GAAE,MAAW,EACnB,QAAQ,GAAE,MAAW,EACrB,KAAK,GAAE,MAAW,EAClB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,MAAW,EACrB,QAAQ,GAAE,MAAW,EACrB,UAAU,GAAE,MAAW;IAQlC,IAAI,YAAY,IAAI,OAAO,CAE1B;IAID,IAAI,UAAU,IAAI,OAAO,CAExB;IAID,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAGD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAGD,IAAI,mBAAmB,IAAI,OAAO,CAEjC;CACJ;AAED,eAAO,MAAM,gBAAgB,eAAmF,CAAA;AAChH,eAAO,MAAM,mBAAmB,eAAqE,CAAA;AACrG,eAAO,MAAM,yBAAyB,eAAiD,CAAA;AAEvF,eAAO,MAAM,eAAe,eAA8C,CAAA;AAE1E,eAAO,MAAM,aAAa,eAAkE,CAAA;AAE5F,eAAO,MAAM,oBAAoB,eAA6E,CAAA;AAE9G,eAAO,MAAM,mBAAmB,eAA8E,CAAA;AAC9G,eAAO,MAAM,yBAAyB,eAA2F,CAAA;AACjI,eAAO,MAAM,YAAY,eAA4D,CAAA;AACrF,eAAO,MAAM,mBAAmB,eAAwD,CAAA;AACxF,eAAO,MAAM,uBAAuB,eAA4E,CAAA;AAChH,eAAO,MAAM,0BAA0B,eAAkF,CAAA"}
package/dist/error.js CHANGED
@@ -39,3 +39,7 @@ export const ErrPoolClosed = new PostgresError("Pool is closed", 'pool_closed',
39
39
  export const ErrTransactionClosed = new PostgresError("Transaction closed", "transaction_closed", '', "ERROR");
40
40
  export const ErrConnectionClosed = new PostgresError("Connection is closed", 'connection_closed', "", "ERROR");
41
41
  export const ErrConnectionReconnecting = new PostgresError("Connection are reconnecting", "connection_reconnecting", "", "ERROR");
42
+ export const ErrSSLDenied = new PostgresError("SSL is required but server denied it");
43
+ export const ErrDatabaseNotFound = new PostgresError('Database with that dsn not found');
44
+ export const ErrUntrustedCertificate = new PostgresError("Database SSL certificate is untrusted or self-signed");
45
+ export const ErrCertificateFileNotFound = new PostgresError("The SSL certificate file specified in caPath was not found");
@@ -29,6 +29,7 @@ export declare class ConnectionRequestWriter {
29
29
  writeStartup(user: string, database: string): this;
30
30
  writeExecute(portName: string | ""): this;
31
31
  writeSync(): this;
32
+ writeSSLRequest(): this;
32
33
  writePassword(password: string): this;
33
34
  writeSaslInitial(mechanism: string, clientFirstMessage: string): this;
34
35
  writeSaslResponse(clientFinalMessage: string): this;
@@ -1 +1 @@
1
- {"version":3,"file":"connection-request-writer.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-request-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAA;AAGvD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,wBAAwB;IAHpC,OAAO;IAOP,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM;IAK3B,OAAO,CAAC,cAAc;IAoBtB,YAAY,CAAC,MAAM,EAAE,MAAM;IAY3B,WAAW,CAAC,MAAM,EAAE,MAAM;IAS1B,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,SAAS,CAAC,IAAI,EAAE,MAAM;IAStB,YAAY,CAAC,WAAW,EAAE,WAAW;IAQrC,YAAY;IAMZ,UAAU;IAYV,QAAQ;IAKR,KAAK;CAIR;AAGD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IADlB,OAAO;IAIP,MAAM,CAAC,GAAG;IAMV,UAAU,CAAC,IAAI,EAAE,MAAM;IASvB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM;IAW1C,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,EAAE;IAUxC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAmBtF,UAAU,CAAC,IAAI,EAAE,MAAM;IAUvB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAY3C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE;IAUlC,SAAS;IAOT,aAAa,CAAC,QAAQ,EAAE,MAAM;IAS9B,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM;IAW9D,iBAAiB,CAAC,kBAAkB,EAAE,MAAM;IAS5C,QAAQ;IAKR,KAAK;CAKR"}
1
+ {"version":3,"file":"connection-request-writer.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-request-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAA;AAGvD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,wBAAwB;IAHpC,OAAO;IAOP,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM;IAK3B,OAAO,CAAC,cAAc;IAoBtB,YAAY,CAAC,MAAM,EAAE,MAAM;IAY3B,WAAW,CAAC,MAAM,EAAE,MAAM;IAS1B,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,SAAS,CAAC,IAAI,EAAE,MAAM;IAStB,YAAY,CAAC,WAAW,EAAE,WAAW;IAQrC,YAAY;IAMZ,UAAU;IAYV,QAAQ;IAKR,KAAK;CAIR;AAGD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IADlB,OAAO;IAIP,MAAM,CAAC,GAAG;IAMV,UAAU,CAAC,IAAI,EAAE,MAAM;IASvB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM;IAW1C,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,EAAE;IAUxC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAmBtF,UAAU,CAAC,IAAI,EAAE,MAAM;IAUvB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAY3C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE;IAUlC,SAAS;IAOT,eAAe;IASf,aAAa,CAAC,QAAQ,EAAE,MAAM;IAS9B,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM;IAW9D,iBAAiB,CAAC,kBAAkB,EAAE,MAAM;IAS5C,QAAQ;IAKR,KAAK;CAKR"}
@@ -141,6 +141,12 @@ export class ConnectionRequestWriter {
141
141
  this.buffer.startRequest(RequestTypes.Sync).endRequest();
142
142
  return this;
143
143
  }
144
+ writeSSLRequest() {
145
+ this.buffer.startMessage()
146
+ .writeInt32(80877103)
147
+ .endRequest();
148
+ return this;
149
+ }
144
150
  writePassword(password) {
145
151
  this.buffer.startRequest(RequestTypes.Password)
146
152
  .writeCString(password)
@@ -1 +1 @@
1
- {"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAQxC,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAAI,MAAM;IAOlB,SAAS,IAAI,MAAM;IAOnB,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,MAAM;IAQrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOrC,OAAO,IAAI,OAAO;IAKlB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO3C,cAAc,IAAI,IAAI;IAOtB,mBAAmB,IAAI,IAAI;IAO3B,cAAc,IAAI,MAAM;IAaxB,SAAS,CAAC,SAAS,EAAE,MAAM;IAK3B,aAAa,IAAI,OAAO;IAaxB,iBAAiB;IAIjB,QAAQ;IAMR,YAAY,IAAI,MAAM;IAOtB,SAAS;IAST,WAAW;IAOX,WAAW,IAAI,MAAM;IAMrB,QAAQ;IAWR,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,aAAa,CAAC,MAAM,EAAE,MAAM;CAW/B;AAGD,qBAAa,wBAAwB;IAG7B,OAAO,CAAC,MAAM;IADlB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ;cACoC,YAAY;;;IAIxD,kBAAkB,IACoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAQnB,kBAAkB;;;;IAQlB,iBAAiB,IAAI,aAAa;IA4ClC,iBAAiB,IACoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKvC,kBAAkB;IAsBlB,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0G1F,wBAAwB;;;;IASxB,mBAAmB,IAAI,MAAM;IAK7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAGjB,gBAAgB;IAGhB,wBAAwB;IAOxB,UAAU;IAEV,IAAI,CAAC,KAAK,EAAE,MAAM;CAGrB"}
1
+ {"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAOxC,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAAI,MAAM;IAOlB,SAAS,IAAI,MAAM;IAOnB,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,MAAM;IAQrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOrC,OAAO,IAAI,OAAO;IAKlB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO3C,cAAc,IAAI,IAAI;IAOtB,mBAAmB,IAAI,IAAI;IAO3B,cAAc,IAAI,MAAM;IAaxB,SAAS,CAAC,SAAS,EAAE,MAAM;IAK3B,aAAa,IAAI,OAAO;IAaxB,iBAAiB;IAIjB,QAAQ;IAMR,YAAY,IAAI,MAAM;IAOtB,SAAS;IAST,WAAW;IAOX,WAAW,IAAI,MAAM;IAMrB,QAAQ;IAWR,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,aAAa,CAAC,MAAM,EAAE,MAAM;CAW/B;AAGD,qBAAa,wBAAwB;IAG7B,OAAO,CAAC,MAAM;IADlB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ;cACoC,YAAY;;;IAIxD,kBAAkB,IACoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAQnB,kBAAkB;;;;IAQlB,iBAAiB,IAAI,aAAa;IA4ClC,iBAAiB,IACoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKvC,kBAAkB;IAsBlB,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0G1F,wBAAwB;;;;IASxB,mBAAmB,IAAI,MAAM;IAK7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAGjB,gBAAgB;IAGhB,wBAAwB;IAOxB,UAAU;IAEV,IAAI,CAAC,KAAK,EAAE,MAAM;CAGrB"}
@@ -27,6 +27,8 @@ export declare const ResponseTypes: {
27
27
  readonly NoData: "n";
28
28
  readonly Notice: "N";
29
29
  readonly NotificationResponse: "A";
30
+ readonly SSLOk: "S";
31
+ readonly SSLDenied: "N";
30
32
  };
31
33
  export declare const DataTypeOids: {
32
34
  readonly Bool: 16;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;CAiBhB,CAAA;AAGV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAIzE,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;AAGxD,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAGpE,eAAO,MAAM,mBAAmB;;;;CAItB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;CAmBhB,CAAA;AAGV,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAIzE,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;AAGxD,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAGpE,eAAO,MAAM,mBAAmB;;;;CAItB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
@@ -24,7 +24,9 @@ export const ResponseTypes = {
24
24
  ParameterDescription: "t",
25
25
  NoData: "n",
26
26
  Notice: "N",
27
- NotificationResponse: "A"
27
+ NotificationResponse: "A",
28
+ SSLOk: "S",
29
+ SSLDenied: "N"
28
30
  };
29
31
  export const DataTypeOids = {
30
32
  Bool: 16,
@@ -1,7 +1,8 @@
1
- import { Socket } from "node:net";
2
- import { ConnectionRequestWriter } from "./connection-request-writer";
3
1
  import { PostgresError } from "../error";
4
2
  import { Future } from "fluent-future";
5
- import { AuthorizationParams } from "../types";
6
- export declare const createAuthorizedSocket: (writer: ConnectionRequestWriter, params: AuthorizationParams) => Future<Socket, PostgresError>;
3
+ import { Socket } from "node:net";
4
+ import { ConnectionConfig } from "../types";
5
+ export declare const createSocket: (config: ConnectionConfig) => Future<Socket, PostgresError>;
6
+ export declare const upgradeSocket: (socket: Socket, config: ConnectionConfig) => Future<Socket, PostgresError>;
7
+ export declare const authorizeSocket: (socket: Socket, config: ConnectionConfig) => Future<Socket, PostgresError>;
7
8
  //# sourceMappingURL=socket-authorization.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-authorization.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,MAAM,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AAKrE,OAAO,EAAoE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC1G,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C,eAAO,MAAM,sBAAsB,GAAI,QAAQ,uBAAuB,EAAE,QAAQ,mBAAmB,kCAoHlG,CAAA"}
1
+ {"version":3,"file":"socket-authorization.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-authorization.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4J,aAAa,EAAE,MAAM,UAAU,CAAA;AAClM,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,OAAO,EAAoB,MAAM,EAAE,MAAM,UAAU,CAAA;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAI3C,eAAO,MAAM,YAAY,GAAI,QAAQ,gBAAgB,kCASpD,CAAA;AAGD,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,EAAE,QAAQ,gBAAgB,kCA+ErE,CAAA;AAGD,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,QAAQ,gBAAgB,kCAyHvE,CAAA"}
@@ -1,93 +1,186 @@
1
- import { createConnection } from "node:net";
1
+ import { ConnectionRequestWriter } from "./connection-request-writer";
2
2
  import { calculateScramAuth, generateNonce } from "../security/sasl";
3
3
  import { SocketConnector } from "./socket-connector";
4
4
  import { AuthenticationCodes, ResponseTypes } from "./constants";
5
5
  import { encryptMd5 } from "../security/md5";
6
- import { ErrNonceMismatch, ErrPasswordRequired, ErrSocketFailedDuringAuth } from "../error";
6
+ import { ErrCertificateFileNotFound, ErrDatabaseNotFound, ErrNonceMismatch, ErrPasswordRequired, ErrSocketFailedDuringAuth, ErrSSLDenied, ErrUntrustedCertificate } from "../error";
7
7
  import { Future } from "fluent-future";
8
- export const createAuthorizedSocket = (writer, params) => {
8
+ import { connect } from "node:tls";
9
+ import { createConnection } from "node:net";
10
+ import { readFileSync } from "node:fs";
11
+ export const createSocket = (config) => {
12
+ const { future, resolve, reject } = Future.withResolvers();
13
+ const socket = createConnection({ host: config.host, port: config.port });
14
+ socket.once('connect', () => resolve(socket));
15
+ socket.once('error', () => reject(ErrDatabaseNotFound));
16
+ return future;
17
+ };
18
+ export const upgradeSocket = (socket, config) => {
19
+ if (config.ssl === 'disable')
20
+ return Future.resolve(socket);
21
+ const { future, reject, resolve } = Future.withResolvers();
22
+ const writer = ConnectionRequestWriter.new();
23
+ const onError = () => {
24
+ cleanup();
25
+ reject(ErrSocketFailedDuringAuth);
26
+ };
27
+ socket.once('error', onError);
28
+ const cleanup = () => {
29
+ socket.off('error', onError);
30
+ };
31
+ socket.once('data', (data) => {
32
+ cleanup();
33
+ const responseCode = data.toString('utf8', 0, 1);
34
+ if (responseCode === 'S') {
35
+ if (data.length > 1) {
36
+ socket.unshift(data.subarray(1));
37
+ }
38
+ let cert = undefined;
39
+ try {
40
+ cert = config.caPath ? readFileSync(config.caPath) : undefined;
41
+ }
42
+ catch {
43
+ socket.destroy();
44
+ return reject(ErrCertificateFileNotFound);
45
+ }
46
+ const tls = connect({
47
+ socket: socket,
48
+ host: config.host,
49
+ rejectUnauthorized: config.ssl === 'require',
50
+ ca: cert
51
+ });
52
+ const tlsCleanup = () => {
53
+ tls.off('secureConnect', onSecureConnect);
54
+ tls.off('error', onTlsError);
55
+ };
56
+ const onSecureConnect = () => {
57
+ tlsCleanup();
58
+ resolve(tls);
59
+ };
60
+ const onTlsError = () => {
61
+ tlsCleanup();
62
+ tls.destroy();
63
+ reject(ErrUntrustedCertificate);
64
+ };
65
+ tls.once('secureConnect', onSecureConnect);
66
+ tls.once('error', onTlsError);
67
+ }
68
+ else if (responseCode === 'N') {
69
+ if (config.ssl === 'require') {
70
+ socket.destroy();
71
+ reject(ErrSSLDenied);
72
+ return;
73
+ }
74
+ resolve(socket);
75
+ }
76
+ else {
77
+ socket.destroy();
78
+ reject(ErrSocketFailedDuringAuth);
79
+ }
80
+ });
81
+ socket.write(writer.writeSSLRequest().asBuffer());
82
+ writer.clear();
83
+ return future;
84
+ };
85
+ export const authorizeSocket = (socket, config) => {
9
86
  const { future, reject, resolve } = Future.withResolvers();
87
+ const writer = ConnectionRequestWriter.new();
10
88
  const nonce = generateNonce();
11
89
  let clientMessage = '';
12
90
  let serverMessage = '';
13
- const socket = createConnection({ host: params.host, port: params.port });
14
- const connector = new SocketConnector(socket, (type, length, reader) => {
15
- writer.clear();
91
+ const connector = new SocketConnector(socket, handle, () => reject(ErrSocketFailedDuringAuth));
92
+ function handle(type, length, reader) {
16
93
  switch (type) {
17
- case ResponseTypes.Authentication: {
18
- switch (reader.readAuthentication()) {
19
- case AuthenticationCodes.Ok: break;
20
- case AuthenticationCodes.CleartextPassword: {
21
- if (!params.password)
22
- throw ErrPasswordRequired;
23
- connector.write(writer.writePassword(params.password));
24
- break;
25
- }
26
- case AuthenticationCodes.MD5Password: {
27
- const salt = reader.readMD5Salt();
28
- if (!params.password)
29
- throw ErrPasswordRequired;
30
- const password = encryptMd5(params.password, params.user, salt);
31
- connector.write(writer.writePassword(password));
32
- break;
33
- }
34
- case AuthenticationCodes.SASL: {
35
- reader.readSaslMechanisms();
36
- if (!params.password)
37
- throw ErrPasswordRequired;
38
- clientMessage = `n=${params.user},r=${nonce}`;
39
- connector.write(writer.writeSaslInitial('SCRAM-SHA-256', `n,,${clientMessage}`));
40
- break;
41
- }
42
- case AuthenticationCodes.SASLContinue: {
43
- serverMessage = reader.readSaslMessage(length);
44
- if (!params.password)
45
- throw ErrPasswordRequired;
46
- const parts = Object.fromEntries(serverMessage.split(',').map(x => x.split('=')));
47
- const serverNonce = parts.r;
48
- const saltBase64 = parts.s;
49
- const iterations = parseInt(parts.i, 10);
50
- if (!serverNonce.startsWith(nonce)) {
51
- connector.destroy();
52
- return reject(ErrNonceMismatch);
53
- }
54
- const clientFinalMessageWithoutProof = `c=biws,r=${serverNonce}`;
55
- const authMessage = `${clientMessage},${serverMessage},${clientFinalMessageWithoutProof}`;
56
- const { clientProof } = calculateScramAuth(params.password, saltBase64, iterations, authMessage);
57
- const clientFinalMessage = `${clientFinalMessageWithoutProof},p=${clientProof}`;
58
- connector.write(writer.writeSaslResponse(clientFinalMessage));
59
- break;
60
- }
61
- case AuthenticationCodes.SASLFinal: {
62
- reader.readSaslMessage(length);
63
- break;
64
- }
94
+ case ResponseTypes.Authentication:
95
+ {
96
+ Authentication(length, reader);
65
97
  }
66
98
  break;
67
- }
68
- case ResponseTypes.ParamaterStatus: {
69
- reader.readParameterStatus();
99
+ case ResponseTypes.ParamaterStatus:
100
+ {
101
+ reader.readParameterStatus();
102
+ }
70
103
  break;
71
- }
72
- case ResponseTypes.ErrorResponse: {
73
- const error = reader.readErrorResponse();
74
- connector.destroy();
75
- reject(error);
104
+ case ResponseTypes.ErrorResponse:
105
+ {
106
+ const error = reader.readErrorResponse();
107
+ connector.destroy();
108
+ reject(error);
109
+ }
76
110
  return;
77
- }
78
- case ResponseTypes.BackendKeyData: {
79
- reader.readBackendKeyData();
80
- }
81
- case ResponseTypes.ReadyForQuery: {
82
- reader.readReadyForQuery();
83
- resolve(connector.unwrapSocket());
111
+ case ResponseTypes.BackendKeyData:
112
+ {
113
+ reader.readBackendKeyData();
114
+ }
115
+ break;
116
+ case ResponseTypes.ReadyForQuery:
117
+ {
118
+ reader.readReadyForQuery();
119
+ resolve(connector.unwrapSocket());
120
+ }
84
121
  return;
85
- }
86
122
  }
87
- }, error => {
88
- reject(ErrSocketFailedDuringAuth);
89
- });
90
- connector.write(writer.writeStartup(params.user, params.database));
123
+ }
124
+ function Authentication(length, reader) {
125
+ switch (reader.readAuthentication()) {
126
+ case AuthenticationCodes.Ok: break;
127
+ case AuthenticationCodes.CleartextPassword:
128
+ {
129
+ if (!config.password)
130
+ throw ErrPasswordRequired;
131
+ connector.write(writer.writePassword(config.password));
132
+ writer.clear();
133
+ }
134
+ break;
135
+ case AuthenticationCodes.MD5Password:
136
+ {
137
+ const salt = reader.readMD5Salt();
138
+ if (!config.password)
139
+ throw ErrPasswordRequired;
140
+ const password = encryptMd5(config.password, config.user, salt);
141
+ connector.write(writer.writePassword(password));
142
+ writer.clear();
143
+ }
144
+ break;
145
+ case AuthenticationCodes.SASL:
146
+ {
147
+ reader.readSaslMechanisms();
148
+ if (!config.password)
149
+ throw ErrPasswordRequired;
150
+ clientMessage = `n=${config.user},r=${nonce}`;
151
+ connector.write(writer.writeSaslInitial('SCRAM-SHA-256', `n,,${clientMessage}`));
152
+ writer.clear();
153
+ }
154
+ break;
155
+ case AuthenticationCodes.SASLContinue:
156
+ {
157
+ serverMessage = reader.readSaslMessage(length);
158
+ if (!config.password)
159
+ throw ErrPasswordRequired;
160
+ const parts = Object.fromEntries(serverMessage.split(',').map(x => x.split('=')));
161
+ const serverNonce = parts.r;
162
+ const saltBase64 = parts.s;
163
+ const iterations = parseInt(parts.i, 10);
164
+ if (!serverNonce.startsWith(nonce)) {
165
+ connector.destroy();
166
+ return reject(ErrNonceMismatch);
167
+ }
168
+ const clientFinalMessageWithoutProof = `c=biws,r=${serverNonce}`;
169
+ const authMessage = `${clientMessage},${serverMessage},${clientFinalMessageWithoutProof}`;
170
+ const { clientProof } = calculateScramAuth(config.password, saltBase64, iterations, authMessage);
171
+ const clientFinalMessage = `${clientFinalMessageWithoutProof},p=${clientProof}`;
172
+ connector.write(writer.writeSaslResponse(clientFinalMessage));
173
+ writer.clear();
174
+ }
175
+ break;
176
+ case AuthenticationCodes.SASLFinal:
177
+ {
178
+ reader.readSaslMessage(length);
179
+ }
180
+ break;
181
+ }
182
+ }
183
+ connector.write(writer.writeStartup(config.user, config.database));
91
184
  writer.clear();
92
185
  return future;
93
186
  };
package/dist/types.d.ts CHANGED
@@ -18,13 +18,7 @@ export type ColumnDescription = {
18
18
  name: string;
19
19
  typeOID: DataTypeOid;
20
20
  };
21
- export type AuthorizationParams = {
22
- host: string;
23
- port: number;
24
- user: string;
25
- database: string;
26
- password?: string;
27
- };
21
+ export type SSLMode = 'disable' | 'prefer' | 'require';
28
22
  type LogLevel = "none" | "error" | "notice" | "query";
29
23
  export type ConnectionPartialConfig = {
30
24
  user: string;
@@ -36,6 +30,8 @@ export type ConnectionPartialConfig = {
36
30
  int8toBigint?: boolean;
37
31
  queryTimeout?: number;
38
32
  syncShedule?: "beforeMicrotask" | "afterMicrotask" | "Immediate";
33
+ ssl?: SSLMode;
34
+ caPath?: string;
39
35
  };
40
36
  export type ConnectionConfig = {
41
37
  user: string;
@@ -47,6 +43,8 @@ export type ConnectionConfig = {
47
43
  int8toBigint: boolean;
48
44
  queryTimeout: number;
49
45
  syncShedule: "beforeMicrotask" | "afterMicrotask" | "Immediate";
46
+ ssl: SSLMode;
47
+ caPath?: string;
50
48
  };
51
49
  export type StatementName = Branded<string, 'StatementName'>;
52
50
  export type QueryText = Branded<string, 'QueryText'>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m2k-5f/pgtx",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "type": "module",
5
5
  "description": "Blazing-fast PostgreSQL driver with pipeline support.",
6
6
  "files": [