node-firebird 2.3.1 → 2.3.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.
Files changed (55) hide show
  1. package/README.md +218 -31
  2. package/lib/index.d.ts +22 -0
  3. package/lib/pool.js +97 -10
  4. package/lib/srp.js +12 -1
  5. package/lib/wire/connection.js +40 -7
  6. package/lib/wire/socket.js +13 -1
  7. package/lib/wire/xsqlvar.js +69 -6
  8. package/package.json +1 -1
  9. package/poc/README.md +160 -0
  10. package/poc/helpers.js +59 -0
  11. package/poc/node_modules/.package-lock.json +14 -0
  12. package/poc/node_modules/node-firebird/.eslintrc.json +12 -0
  13. package/poc/node_modules/node-firebird/.github/workflows/codeql.yml +76 -0
  14. package/poc/node_modules/node-firebird/.github/workflows/node.js.yml +95 -0
  15. package/poc/node_modules/node-firebird/BIGINT_MIGRATION.md +374 -0
  16. package/poc/node_modules/node-firebird/CI_DEBUGGING_GUIDE.md +148 -0
  17. package/poc/node_modules/node-firebird/ENCRYPTION_CALLBACK.md +152 -0
  18. package/poc/node_modules/node-firebird/FIREBIRD_LOG_FEATURE.md +145 -0
  19. package/poc/node_modules/node-firebird/LICENSE +373 -0
  20. package/poc/node_modules/node-firebird/MINIMAL_CHANGES_SUMMARY.md +136 -0
  21. package/poc/node_modules/node-firebird/PR_SUMMARY.md +96 -0
  22. package/poc/node_modules/node-firebird/README.md +794 -0
  23. package/poc/node_modules/node-firebird/ROADMAP.md +223 -0
  24. package/poc/node_modules/node-firebird/SRP_PROTOCOL.md +482 -0
  25. package/poc/node_modules/node-firebird/lib/callback.js +38 -0
  26. package/poc/node_modules/node-firebird/lib/firebird.msg +0 -0
  27. package/poc/node_modules/node-firebird/lib/firebird.msg.json +1371 -0
  28. package/poc/node_modules/node-firebird/lib/gdscodes.d.ts +1524 -0
  29. package/poc/node_modules/node-firebird/lib/gdscodes.js +1531 -0
  30. package/poc/node_modules/node-firebird/lib/ieee754-decimal.js +500 -0
  31. package/poc/node_modules/node-firebird/lib/index.d.ts +316 -0
  32. package/poc/node_modules/node-firebird/lib/index.js +128 -0
  33. package/poc/node_modules/node-firebird/lib/messages.js +162 -0
  34. package/poc/node_modules/node-firebird/lib/pool.js +108 -0
  35. package/poc/node_modules/node-firebird/lib/srp.js +299 -0
  36. package/poc/node_modules/node-firebird/lib/unix-crypt.js +343 -0
  37. package/poc/node_modules/node-firebird/lib/utils.js +164 -0
  38. package/poc/node_modules/node-firebird/lib/wire/connection.js +2510 -0
  39. package/poc/node_modules/node-firebird/lib/wire/const.js +807 -0
  40. package/poc/node_modules/node-firebird/lib/wire/database.js +378 -0
  41. package/poc/node_modules/node-firebird/lib/wire/eventConnection.js +118 -0
  42. package/poc/node_modules/node-firebird/lib/wire/fbEventManager.js +326 -0
  43. package/poc/node_modules/node-firebird/lib/wire/serialize.js +588 -0
  44. package/poc/node_modules/node-firebird/lib/wire/service.js +1058 -0
  45. package/poc/node_modules/node-firebird/lib/wire/socket.js +175 -0
  46. package/poc/node_modules/node-firebird/lib/wire/statement.js +48 -0
  47. package/poc/node_modules/node-firebird/lib/wire/transaction.js +206 -0
  48. package/poc/node_modules/node-firebird/lib/wire/xsqlvar.js +703 -0
  49. package/poc/node_modules/node-firebird/package.json +38 -0
  50. package/poc/node_modules/node-firebird/vitest.config.js +24 -0
  51. package/poc/package-lock.json +21 -0
  52. package/poc/package.json +12 -0
  53. package/poc/reproduce-fixed.js +150 -0
  54. package/poc/reproduce.js +133 -0
  55. package/vitest.config.js +4 -1
@@ -0,0 +1,175 @@
1
+ const net = require("net");
2
+ const zlib = require("zlib");
3
+
4
+ /**
5
+ * Arc4 stream cipher for Firebird wire encryption.
6
+ * Uses the SRP session key to create RC4 encryption/decryption streams.
7
+ */
8
+ class Arc4 {
9
+ constructor(key) {
10
+ this._s = new Uint8Array(256);
11
+ this._i = 0;
12
+ this._j = 0;
13
+
14
+ // KSA (Key-Scheduling Algorithm)
15
+ for (var i = 0; i < 256; i++) {
16
+ this._s[i] = i;
17
+ }
18
+
19
+ var j = 0;
20
+ for (var i = 0; i < 256; i++) {
21
+ j = (j + this._s[i] + key[i % key.length]) & 0xFF;
22
+ // Swap
23
+ var tmp = this._s[i];
24
+ this._s[i] = this._s[j];
25
+ this._s[j] = tmp;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Transform (encrypt/decrypt) data in place.
31
+ * RC4 is symmetric - encrypt and decrypt are the same operation.
32
+ */
33
+ transform(data) {
34
+ var out = Buffer.alloc(data.length);
35
+ for (var n = 0; n < data.length; n++) {
36
+ this._i = (this._i + 1) & 0xFF;
37
+ this._j = (this._j + this._s[this._i]) & 0xFF;
38
+
39
+ // Swap
40
+ var tmp = this._s[this._i];
41
+ this._s[this._i] = this._s[this._j];
42
+ this._s[this._j] = tmp;
43
+
44
+ var k = this._s[(this._s[this._i] + this._s[this._j]) & 0xFF];
45
+ out[n] = data[n] ^ k;
46
+ }
47
+ return out;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Socket proxy.
53
+ */
54
+ class Socket {
55
+ constructor(port, host) {
56
+ this._socket = net.createConnection(port, host);
57
+ this._socket.setNoDelay(true);
58
+ this.compressor = null;
59
+ this.compressorBuffer = [];
60
+ this.decompressor = null;
61
+ this.decompressorBuffer = [];
62
+ this.buffer = null;
63
+ this.encrypt = false;
64
+ this.encryptCipher = null;
65
+ this.decryptCipher = null;
66
+
67
+ return new Proxy(this._socket, this);
68
+ }
69
+
70
+ /**
71
+ * Decompress and/or decrypt data when received.
72
+ * Override on data event.
73
+ */
74
+ on(event, cb) {
75
+ if (event === 'data') {
76
+ const mainCb = cb;
77
+ cb = (data) => {
78
+ // Decrypt first if encryption is enabled
79
+ if (this.encrypt) {
80
+ data = this.decryptCipher.transform(data);
81
+ }
82
+
83
+ if (this.compress) {
84
+ this.decompressor.write(data, () => {
85
+ mainCb(Buffer.concat(this.decompressorBuffer));
86
+ this.decompressorBuffer = []; // Reset buffer
87
+ });
88
+ } else {
89
+ mainCb(data);
90
+ }
91
+ };
92
+ }
93
+
94
+ this._socket.on(event, cb);
95
+ }
96
+
97
+ /**
98
+ * Compress and/or encrypt data before sending to socket.
99
+ */
100
+ write(data, defer = false) {
101
+ if (defer) {
102
+ this.buffer = Buffer.from(data);
103
+ return;
104
+ }
105
+
106
+ if (!defer && this.buffer) {
107
+ data = Buffer.concat([this.buffer, data]);
108
+ this.buffer = null;
109
+ }
110
+
111
+ if (this.compress) {
112
+ this.compressor.write(data, () => {
113
+ var compressedData = Buffer.concat(this.compressorBuffer);
114
+ this.compressorBuffer = []; // Reset buffer
115
+
116
+ // Encrypt after compression if encryption is enabled
117
+ if (this.encrypt) {
118
+ compressedData = this.encryptCipher.transform(compressedData);
119
+ }
120
+
121
+ this._socket.write(compressedData);
122
+ });
123
+ } else if (this.encrypt) {
124
+ this._socket.write(this.encryptCipher.transform(data));
125
+ } else {
126
+ this._socket.write(data);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Enable compression/decompression on the fly.
132
+ */
133
+ enableCompression() {
134
+ this.compress = true;
135
+
136
+ // Create decompressor instance
137
+ this.decompressor = zlib.createInflate();
138
+ this.decompressor.on('data', (inflate) => {
139
+ this.decompressorBuffer.push(inflate);
140
+ });
141
+
142
+ // Create compressor instance
143
+ this.compressor = zlib.createDeflate({
144
+ flush: zlib.constants.Z_FULL_FLUSH,
145
+ finishFlush: zlib.constants.Z_SYNC_FLUSH
146
+ });
147
+ this.compressor.on('data', (deflate) => {
148
+ this.compressorBuffer.push(deflate);
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Enable encryption/decryption using Arc4 cipher.
154
+ * @param {Buffer} sessionKey - The session key from SRP authentication.
155
+ */
156
+ enableEncryption(sessionKey) {
157
+ this.encrypt = true;
158
+ this.encryptCipher = new Arc4(sessionKey);
159
+ this.decryptCipher = new Arc4(sessionKey);
160
+ }
161
+
162
+ /**
163
+ * Proxy trap.
164
+ */
165
+ get(target, field) {
166
+ if (field in this) {
167
+ return this[field].bind(this);
168
+ }
169
+
170
+ return target[field];
171
+ }
172
+ }
173
+
174
+ module.exports = Socket;
175
+ module.exports.Arc4 = Arc4;
@@ -0,0 +1,48 @@
1
+ /***************************************
2
+ *
3
+ * Statement
4
+ *
5
+ ***************************************/
6
+
7
+ class Statement {
8
+ constructor(connection) {
9
+ this.connection = connection;
10
+ }
11
+
12
+ close(callback) {
13
+ this.connection.closeStatement(this, callback);
14
+ }
15
+
16
+ drop(callback) {
17
+ this.connection.dropStatement(this, callback);
18
+ }
19
+
20
+ release(callback) {
21
+ var cache_query = this.connection.getCachedQuery(this.query);
22
+ if (cache_query)
23
+ this.connection.closeStatement(this, callback);
24
+ else
25
+ this.connection.dropStatement(this, callback);
26
+ }
27
+
28
+ execute(transaction, params, callback, options) {
29
+ if (params instanceof Function) {
30
+ options = callback;
31
+ callback = params;
32
+ params = undefined;
33
+ }
34
+
35
+ this.options = options;
36
+ this.connection.executeStatement(transaction, this, params, callback, options);
37
+ }
38
+
39
+ fetch(transaction, count, callback) {
40
+ this.connection.fetch(this, transaction, count, callback);
41
+ }
42
+
43
+ fetchAll(transaction, callback) {
44
+ this.connection.fetchAll(this, transaction, callback);
45
+ }
46
+ }
47
+
48
+ module.exports = Statement;
@@ -0,0 +1,206 @@
1
+ const {doCallback, doError} = require('../callback');
2
+ const Const = require('./const');
3
+
4
+ /***************************************
5
+ *
6
+ * Transaction
7
+ *
8
+ ***************************************/
9
+
10
+ class Transaction {
11
+ constructor(connection) {
12
+ this.connection = connection;
13
+ this.db = connection.db;
14
+ }
15
+
16
+ newStatement(query, callback) {
17
+ var cnx = this.connection;
18
+ var self = this;
19
+ var query_cache = cnx.getCachedQuery(query);
20
+
21
+ if (query_cache) {
22
+ callback(null, query_cache);
23
+ } else {
24
+ cnx.prepare(self, query, false, callback);
25
+ }
26
+ }
27
+
28
+ execute(query, params, callback, options) {
29
+ if (params instanceof Function) {
30
+ options = callback;
31
+ callback = params;
32
+ params = undefined;
33
+ }
34
+
35
+ var self = this;
36
+ this.newStatement(query, function(err, statement) {
37
+
38
+ if (err) {
39
+ doError(err, callback);
40
+ return;
41
+ }
42
+
43
+ function dropError(err) {
44
+ statement.release();
45
+ doCallback(err, callback);
46
+ }
47
+
48
+ statement.execute(self, params, function(err, ret) {
49
+ if (err) {
50
+ dropError(err);
51
+ return;
52
+ }
53
+
54
+ switch (statement.type) {
55
+ case Const.isc_info_sql_stmt_select:
56
+ statement.fetchAll(self, function(err, r) {
57
+ if (err) {
58
+ dropError(err);
59
+ return;
60
+ }
61
+
62
+ statement.release();
63
+
64
+ if (callback)
65
+ callback(undefined, r, statement.output, true);
66
+
67
+ });
68
+
69
+ break;
70
+
71
+ case Const.isc_info_sql_stmt_exec_procedure:
72
+ if (ret && ret.data && ret.data.length > 0) {
73
+ statement.release();
74
+
75
+ if (callback)
76
+ callback(undefined, ret.data[0], statement.output, true);
77
+
78
+ break;
79
+ } else if (statement.output.length) {
80
+ statement.fetch(self, 1, function(err, ret) {
81
+ if (err) {
82
+ dropError(err);
83
+ return;
84
+ }
85
+
86
+ statement.release();
87
+
88
+ if (callback)
89
+ callback(undefined, ret.data[0], statement.output, false);
90
+ });
91
+
92
+ break;
93
+ }
94
+
95
+ // Fall through is normal
96
+ default:
97
+ statement.release();
98
+ if (callback)
99
+ callback()
100
+ break;
101
+ }
102
+
103
+ }, options);
104
+ });
105
+ }
106
+
107
+ sequentially(query, params, on, callback, options = {}) {
108
+ if (params instanceof Function) {
109
+ options = callback;
110
+ callback = on;
111
+ on = params;
112
+ params = undefined;
113
+ }
114
+
115
+ if (on === undefined){
116
+ throw new Error('Expected "on" delegate.');
117
+ }
118
+
119
+ if (callback instanceof Boolean) {
120
+ options = callback;
121
+ callback = undefined;
122
+ }
123
+
124
+ var self = this;
125
+ var _on = function(row, i, meta, next) {
126
+ var done = false;
127
+ var finish = function(err) {
128
+ if (done) {
129
+ return;
130
+ }
131
+ done = true;
132
+ next(err);
133
+ };
134
+
135
+ try {
136
+ var ret;
137
+ if (on.length >= 3) {
138
+ ret = on(row, i, finish);
139
+ } else {
140
+ ret = on(row, i);
141
+ }
142
+
143
+ if (ret && typeof ret.then === 'function') {
144
+ ret.then(function() {
145
+ finish();
146
+ }).catch(finish);
147
+ } else if (on.length < 3) {
148
+ finish();
149
+ }
150
+ } catch (err) {
151
+ finish(err);
152
+ }
153
+ };
154
+
155
+ // back compatibility - options parameter is a boolean
156
+ if (typeof options === 'boolean') {
157
+ options = { asObject: !options, asStream: true, on: _on };
158
+ } else {
159
+ options = {
160
+ asStream: true,
161
+ asObject: true,
162
+ on: _on,
163
+ ...options,
164
+ };
165
+ }
166
+
167
+ self.execute(query, params, callback, options);
168
+ return self;
169
+ }
170
+
171
+ query(query, params, callback, options = {}) {
172
+ if (params instanceof Function) {
173
+ callback = params;
174
+ params = undefined;
175
+ }
176
+
177
+ if (callback === undefined)
178
+ callback = noop;
179
+
180
+ options = {
181
+ asObject: true,
182
+ asStream: callback === undefined || callback === null,
183
+ ...options,
184
+ };
185
+
186
+ this.execute(query, params, callback, options);
187
+ }
188
+
189
+ commit(callback) {
190
+ this.connection.commit(this, callback);
191
+ }
192
+
193
+ rollback(callback) {
194
+ this.connection.rollback(this, callback);
195
+ }
196
+
197
+ commitRetaining(callback) {
198
+ this.connection.commitRetaining(this, callback);
199
+ }
200
+
201
+ rollbackRetaining(callback) {
202
+ this.connection.rollbackRetaining(this, callback);
203
+ }
204
+ }
205
+
206
+ module.exports = Transaction;