pg 8.5.1 → 8.7.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2010 - 2020 Brian Carlson
3
+ Copyright (c) 2010 - 2021 Brian Carlson
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -53,6 +53,11 @@ node-postgres's continued development has been made possible in part by generous
53
53
  <a href="https://crate.io" target="_blank">
54
54
  <img height="80" src="https://node-postgres.com/crate-io.png" />
55
55
  </a>
56
+
57
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAQAAAB0m0auAAAADElEQVR42mNkIBIAAABSAAI2VLqiAAAAAElFTkSuQmCC" />
58
+ <a href="https://www.eaze.com" target="_blank">
59
+ <img height="80" src="https://node-postgres.com/eaze.png" />
60
+ </a>
56
61
  </div>
57
62
 
58
63
  If you or your company are benefiting from node-postgres and would like to help keep the project financially sustainable [please consider supporting](https://github.com/sponsors/brianc) its development.
package/lib/client.js CHANGED
@@ -577,6 +577,14 @@ class Client extends EventEmitter {
577
577
  return result
578
578
  }
579
579
 
580
+ ref() {
581
+ this.connection.ref()
582
+ }
583
+
584
+ unref() {
585
+ this.connection.unref()
586
+ }
587
+
580
588
  end(cb) {
581
589
  this._ending = true
582
590
 
package/lib/connection.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  var net = require('net')
4
4
  var EventEmitter = require('events').EventEmitter
5
- var util = require('util')
6
5
 
7
6
  const { parse, serialize } = require('pg-protocol')
8
7
 
@@ -178,6 +177,14 @@ class Connection extends EventEmitter {
178
177
  this._send(syncBuffer)
179
178
  }
180
179
 
180
+ ref() {
181
+ this.stream.ref()
182
+ }
183
+
184
+ unref() {
185
+ this.stream.unref()
186
+ }
187
+
181
188
  end() {
182
189
  // 0x58 = 'X'
183
190
  this._ending = true
package/lib/index.js CHANGED
@@ -4,6 +4,7 @@ var Client = require('./client')
4
4
  var defaults = require('./defaults')
5
5
  var Connection = require('./connection')
6
6
  var Pool = require('pg-pool')
7
+ const { DatabaseError } = require('pg-protocol')
7
8
 
8
9
  const poolFactory = (Client) => {
9
10
  return class BoundPool extends Pool {
@@ -21,6 +22,7 @@ var PG = function (clientConstructor) {
21
22
  this._pools = []
22
23
  this.Connection = Connection
23
24
  this.types = require('pg-types')
25
+ this.DatabaseError = DatabaseError
24
26
  }
25
27
 
26
28
  if (typeof process.env.NODE_PG_FORCE_NATIVE !== 'undefined') {
@@ -285,6 +285,9 @@ Client.prototype.cancel = function (query) {
285
285
  }
286
286
  }
287
287
 
288
+ Client.prototype.ref = function () {}
289
+ Client.prototype.unref = function () {}
290
+
288
291
  Client.prototype.setTypeParser = function (oid, format, parseFn) {
289
292
  return this._types.setTypeParser(oid, format, parseFn)
290
293
  }
package/lib/sasl.js CHANGED
@@ -20,19 +20,27 @@ function continueSession(session, password, serverData) {
20
20
  if (session.message !== 'SASLInitialResponse') {
21
21
  throw new Error('SASL: Last message was not SASLInitialResponse')
22
22
  }
23
+ if (typeof password !== 'string') {
24
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')
25
+ }
26
+ if (typeof serverData !== 'string') {
27
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: serverData must be a string')
28
+ }
23
29
 
24
- const sv = extractVariablesFromFirstServerMessage(serverData)
30
+ const sv = parseServerFirstMessage(serverData)
25
31
 
26
32
  if (!sv.nonce.startsWith(session.clientNonce)) {
27
33
  throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce')
34
+ } else if (sv.nonce.length === session.clientNonce.length) {
35
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce is too short')
28
36
  }
29
37
 
30
38
  var saltBytes = Buffer.from(sv.salt, 'base64')
31
39
 
32
40
  var saltedPassword = Hi(password, saltBytes, sv.iteration)
33
41
 
34
- var clientKey = createHMAC(saltedPassword, 'Client Key')
35
- var storedKey = crypto.createHash('sha256').update(clientKey).digest()
42
+ var clientKey = hmacSha256(saltedPassword, 'Client Key')
43
+ var storedKey = sha256(clientKey)
36
44
 
37
45
  var clientFirstMessageBare = 'n=*,r=' + session.clientNonce
38
46
  var serverFirstMessage = 'r=' + sv.nonce + ',s=' + sv.salt + ',i=' + sv.iteration
@@ -41,12 +49,12 @@ function continueSession(session, password, serverData) {
41
49
 
42
50
  var authMessage = clientFirstMessageBare + ',' + serverFirstMessage + ',' + clientFinalMessageWithoutProof
43
51
 
44
- var clientSignature = createHMAC(storedKey, authMessage)
52
+ var clientSignature = hmacSha256(storedKey, authMessage)
45
53
  var clientProofBytes = xorBuffers(clientKey, clientSignature)
46
54
  var clientProof = clientProofBytes.toString('base64')
47
55
 
48
- var serverKey = createHMAC(saltedPassword, 'Server Key')
49
- var serverSignatureBytes = createHMAC(serverKey, authMessage)
56
+ var serverKey = hmacSha256(saltedPassword, 'Server Key')
57
+ var serverSignatureBytes = hmacSha256(serverKey, authMessage)
50
58
 
51
59
  session.message = 'SASLResponse'
52
60
  session.serverSignature = serverSignatureBytes.toString('base64')
@@ -57,54 +65,87 @@ function finalizeSession(session, serverData) {
57
65
  if (session.message !== 'SASLResponse') {
58
66
  throw new Error('SASL: Last message was not SASLResponse')
59
67
  }
68
+ if (typeof serverData !== 'string') {
69
+ throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: serverData must be a string')
70
+ }
60
71
 
61
- var serverSignature
62
-
63
- String(serverData)
64
- .split(',')
65
- .forEach(function (part) {
66
- switch (part[0]) {
67
- case 'v':
68
- serverSignature = part.substr(2)
69
- break
70
- }
71
- })
72
+ const { serverSignature } = parseServerFinalMessage(serverData)
72
73
 
73
74
  if (serverSignature !== session.serverSignature) {
74
75
  throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature does not match')
75
76
  }
76
77
  }
77
78
 
78
- function extractVariablesFromFirstServerMessage(data) {
79
- var nonce, salt, iteration
80
-
81
- String(data)
82
- .split(',')
83
- .forEach(function (part) {
84
- switch (part[0]) {
85
- case 'r':
86
- nonce = part.substr(2)
87
- break
88
- case 's':
89
- salt = part.substr(2)
90
- break
91
- case 'i':
92
- iteration = parseInt(part.substr(2), 10)
93
- break
79
+ /**
80
+ * printable = %x21-2B / %x2D-7E
81
+ * ;; Printable ASCII except ",".
82
+ * ;; Note that any "printable" is also
83
+ * ;; a valid "value".
84
+ */
85
+ function isPrintableChars(text) {
86
+ if (typeof text !== 'string') {
87
+ throw new TypeError('SASL: text must be a string')
88
+ }
89
+ return text
90
+ .split('')
91
+ .map((_, i) => text.charCodeAt(i))
92
+ .every((c) => (c >= 0x21 && c <= 0x2b) || (c >= 0x2d && c <= 0x7e))
93
+ }
94
+
95
+ /**
96
+ * base64-char = ALPHA / DIGIT / "/" / "+"
97
+ *
98
+ * base64-4 = 4base64-char
99
+ *
100
+ * base64-3 = 3base64-char "="
101
+ *
102
+ * base64-2 = 2base64-char "=="
103
+ *
104
+ * base64 = *base64-4 [base64-3 / base64-2]
105
+ */
106
+ function isBase64(text) {
107
+ return /^(?:[a-zA-Z0-9+/]{4})*(?:[a-zA-Z0-9+/]{2}==|[a-zA-Z0-9+/]{3}=)?$/.test(text)
108
+ }
109
+
110
+ function parseAttributePairs(text) {
111
+ if (typeof text !== 'string') {
112
+ throw new TypeError('SASL: attribute pairs text must be a string')
113
+ }
114
+
115
+ return new Map(
116
+ text.split(',').map((attrValue) => {
117
+ if (!/^.=/.test(attrValue)) {
118
+ throw new Error('SASL: Invalid attribute pair entry')
94
119
  }
120
+ const name = attrValue[0]
121
+ const value = attrValue.substring(2)
122
+ return [name, value]
95
123
  })
124
+ )
125
+ }
96
126
 
127
+ function parseServerFirstMessage(data) {
128
+ const attrPairs = parseAttributePairs(data)
129
+
130
+ const nonce = attrPairs.get('r')
97
131
  if (!nonce) {
98
132
  throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')
133
+ } else if (!isPrintableChars(nonce)) {
134
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce must only contain printable characters')
99
135
  }
100
-
136
+ const salt = attrPairs.get('s')
101
137
  if (!salt) {
102
138
  throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing')
139
+ } else if (!isBase64(salt)) {
140
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt must be base64')
103
141
  }
104
-
105
- if (!iteration) {
142
+ const iterationText = attrPairs.get('i')
143
+ if (!iterationText) {
106
144
  throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing')
145
+ } else if (!/^[1-9][0-9]*$/.test(iterationText)) {
146
+ throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: invalid iteration count')
107
147
  }
148
+ const iteration = parseInt(iterationText, 10)
108
149
 
109
150
  return {
110
151
  nonce,
@@ -113,31 +154,48 @@ function extractVariablesFromFirstServerMessage(data) {
113
154
  }
114
155
  }
115
156
 
157
+ function parseServerFinalMessage(serverData) {
158
+ const attrPairs = parseAttributePairs(serverData)
159
+ const serverSignature = attrPairs.get('v')
160
+ if (!serverSignature) {
161
+ throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing')
162
+ } else if (!isBase64(serverSignature)) {
163
+ throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64')
164
+ }
165
+ return {
166
+ serverSignature,
167
+ }
168
+ }
169
+
116
170
  function xorBuffers(a, b) {
117
- if (!Buffer.isBuffer(a)) a = Buffer.from(a)
118
- if (!Buffer.isBuffer(b)) b = Buffer.from(b)
119
- var res = []
120
- if (a.length > b.length) {
121
- for (var i = 0; i < b.length; i++) {
122
- res.push(a[i] ^ b[i])
123
- }
124
- } else {
125
- for (var j = 0; j < a.length; j++) {
126
- res.push(a[j] ^ b[j])
127
- }
128
- }
129
- return Buffer.from(res)
171
+ if (!Buffer.isBuffer(a)) {
172
+ throw new TypeError('first argument must be a Buffer')
173
+ }
174
+ if (!Buffer.isBuffer(b)) {
175
+ throw new TypeError('second argument must be a Buffer')
176
+ }
177
+ if (a.length !== b.length) {
178
+ throw new Error('Buffer lengths must match')
179
+ }
180
+ if (a.length === 0) {
181
+ throw new Error('Buffers cannot be empty')
182
+ }
183
+ return Buffer.from(a.map((_, i) => a[i] ^ b[i]))
184
+ }
185
+
186
+ function sha256(text) {
187
+ return crypto.createHash('sha256').update(text).digest()
130
188
  }
131
189
 
132
- function createHMAC(key, msg) {
190
+ function hmacSha256(key, msg) {
133
191
  return crypto.createHmac('sha256', key).update(msg).digest()
134
192
  }
135
193
 
136
194
  function Hi(password, saltBytes, iterations) {
137
- var ui1 = createHMAC(password, Buffer.concat([saltBytes, Buffer.from([0, 0, 0, 1])]))
195
+ var ui1 = hmacSha256(password, Buffer.concat([saltBytes, Buffer.from([0, 0, 0, 1])]))
138
196
  var ui = ui1
139
197
  for (var i = 0; i < iterations - 1; i++) {
140
- ui1 = createHMAC(password, ui1)
198
+ ui1 = hmacSha256(password, ui1)
141
199
  ui = xorBuffers(ui, ui1)
142
200
  }
143
201
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg",
3
- "version": "8.5.1",
3
+ "version": "8.7.3",
4
4
  "description": "PostgreSQL client - pure javascript & libpq with the same API",
5
5
  "keywords": [
6
6
  "database",
@@ -14,16 +14,17 @@
14
14
  "homepage": "https://github.com/brianc/node-postgres",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "git://github.com/brianc/node-postgres.git"
17
+ "url": "git://github.com/brianc/node-postgres.git",
18
+ "directory": "packages/pg"
18
19
  },
19
20
  "author": "Brian Carlson <brian.m.carlson@gmail.com>",
20
21
  "main": "./lib",
21
22
  "dependencies": {
22
23
  "buffer-writer": "2.0.0",
23
24
  "packet-reader": "1.0.0",
24
- "pg-connection-string": "^2.4.0",
25
- "pg-pool": "^3.2.2",
26
- "pg-protocol": "^1.4.0",
25
+ "pg-connection-string": "^2.5.0",
26
+ "pg-pool": "^3.5.1",
27
+ "pg-protocol": "^1.5.0",
27
28
  "pg-types": "^2.1.0",
28
29
  "pgpass": "1.x"
29
30
  },
@@ -52,5 +53,5 @@
52
53
  "engines": {
53
54
  "node": ">= 8.0.0"
54
55
  },
55
- "gitHead": "0b9bb349dcb10f6473737001062082b65efc74be"
56
+ "gitHead": "4fa7ee891a456168a75695ac026792136f16577f"
56
57
  }