node-firebird 1.1.9 → 2.0.0

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.
@@ -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;
@@ -4,44 +4,45 @@
4
4
  *
5
5
  ***************************************/
6
6
 
7
- function Statement(connection) {
8
- this.connection = connection;
9
- }
10
-
11
- Statement.prototype.close = function(callback) {
12
- this.connection.closeStatement(this, callback);
13
- };
14
-
15
- Statement.prototype.drop = function(callback) {
16
- this.connection.dropStatement(this, callback);
17
- };
7
+ class Statement {
8
+ constructor(connection) {
9
+ this.connection = connection;
10
+ }
18
11
 
19
- Statement.prototype.release = function(callback) {
20
- var cache_query = this.connection.getCachedQuery(this.query);
21
- if (cache_query)
12
+ close(callback) {
22
13
  this.connection.closeStatement(this, callback);
23
- else
24
- this.connection.dropStatement(this, callback);
25
- };
14
+ }
26
15
 
27
- Statement.prototype.execute = function(transaction, params, callback, custom) {
16
+ drop(callback) {
17
+ this.connection.dropStatement(this, callback);
18
+ }
28
19
 
29
- if (params instanceof Function) {
30
- custom = callback;
31
- callback = params;
32
- params = undefined;
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);
33
26
  }
34
27
 
35
- this.custom = custom;
36
- this.connection.executeStatement(transaction, this, params, callback, custom);
37
- };
28
+ execute(transaction, params, callback, custom) {
29
+ if (params instanceof Function) {
30
+ custom = callback;
31
+ callback = params;
32
+ params = undefined;
33
+ }
34
+
35
+ this.custom = custom;
36
+ this.connection.executeStatement(transaction, this, params, callback, custom);
37
+ }
38
38
 
39
- Statement.prototype.fetch = function(transaction, count, callback) {
40
- this.connection.fetch(this, transaction, count, callback);
41
- };
39
+ fetch(transaction, count, callback) {
40
+ this.connection.fetch(this, transaction, count, callback);
41
+ }
42
42
 
43
- Statement.prototype.fetchAll = function(transaction, callback) {
44
- this.connection.fetchAll(this, transaction, callback);
45
- };
43
+ fetchAll(transaction, callback) {
44
+ this.connection.fetchAll(this, transaction, callback);
45
+ }
46
+ }
46
47
 
47
48
  module.exports = Statement;
@@ -7,77 +7,53 @@ const Const = require('./const');
7
7
  *
8
8
  ***************************************/
9
9
 
10
- function Transaction(connection) {
11
- this.connection = connection;
12
- this.db = connection.db;
13
- }
14
-
15
- Transaction.prototype.newStatement = function(query, callback) {
16
- var cnx = this.connection;
17
- var self = this;
18
- var query_cache = cnx.getCachedQuery(query);
19
-
20
- if (query_cache) {
21
- callback(null, query_cache);
22
- } else {
23
- cnx.prepare(self, query, false, callback);
10
+ class Transaction {
11
+ constructor(connection) {
12
+ this.connection = connection;
13
+ this.db = connection.db;
24
14
  }
25
- };
26
15
 
27
- Transaction.prototype.execute = function(query, params, callback, custom) {
16
+ newStatement(query, callback) {
17
+ var cnx = this.connection;
18
+ var self = this;
19
+ var query_cache = cnx.getCachedQuery(query);
28
20
 
29
- if (params instanceof Function) {
30
- custom = callback;
31
- callback = params;
32
- params = undefined;
21
+ if (query_cache) {
22
+ callback(null, query_cache);
23
+ } else {
24
+ cnx.prepare(self, query, false, callback);
25
+ }
33
26
  }
34
27
 
35
- var self = this;
36
- this.newStatement(query, function(err, statement) {
37
-
38
- if (err) {
39
- doError(err, callback);
40
- return;
28
+ execute(query, params, callback, custom) {
29
+ if (params instanceof Function) {
30
+ custom = callback;
31
+ callback = params;
32
+ params = undefined;
41
33
  }
42
34
 
43
- function dropError(err) {
44
- statement.release();
45
- doCallback(err, callback);
46
- }
35
+ var self = this;
36
+ this.newStatement(query, function(err, statement) {
47
37
 
48
- statement.execute(self, params, function(err, ret) {
49
38
  if (err) {
50
- dropError(err);
39
+ doError(err, callback);
51
40
  return;
52
41
  }
53
42
 
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();
43
+ function dropError(err) {
44
+ statement.release();
45
+ doCallback(err, callback);
46
+ }
74
47
 
75
- if (callback)
76
- callback(undefined, ret.data[0], statement.output, true);
48
+ statement.execute(self, params, function(err, ret) {
49
+ if (err) {
50
+ dropError(err);
51
+ return;
52
+ }
77
53
 
78
- break;
79
- } else if (statement.output.length) {
80
- statement.fetch(self, 1, function(err, ret) {
54
+ switch (statement.type) {
55
+ case Const.isc_info_sql_stmt_select:
56
+ statement.fetchAll(self, function(err, r) {
81
57
  if (err) {
82
58
  dropError(err);
83
59
  return;
@@ -86,75 +62,127 @@ Transaction.prototype.execute = function(query, params, callback, custom) {
86
62
  statement.release();
87
63
 
88
64
  if (callback)
89
- callback(undefined, ret.data[0], statement.output, false);
65
+ callback(undefined, r, statement.output, true);
66
+
90
67
  });
91
68
 
92
69
  break;
93
- }
94
-
95
- // Fall through is normal
96
- default:
97
- statement.release();
98
- if (callback)
99
- callback()
100
- break;
101
- }
102
70
 
103
- }, custom);
104
- });
105
- };
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);
106
77
 
107
- Transaction.prototype.sequentially = function (query, params, on, callback, asArray) {
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
+ }
108
85
 
109
- if (params instanceof Function) {
110
- asArray = callback;
111
- callback = on;
112
- on = params;
113
- params = undefined;
114
- }
86
+ statement.release();
115
87
 
116
- if (on === undefined){
117
- throw new Error('Expected "on" delegate.');
118
- }
88
+ if (callback)
89
+ callback(undefined, ret.data[0], statement.output, false);
90
+ });
119
91
 
120
- if (callback instanceof Boolean) {
121
- asArray = callback;
122
- callback = undefined;
92
+ break;
93
+ }
94
+
95
+ // Fall through is normal
96
+ default:
97
+ statement.release();
98
+ if (callback)
99
+ callback()
100
+ break;
101
+ }
102
+
103
+ }, custom);
104
+ });
123
105
  }
124
106
 
125
- var self = this;
126
- self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: on });
127
- return self;
128
- };
107
+ sequentially(query, params, on, callback, asArray) {
108
+ if (params instanceof Function) {
109
+ asArray = 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
+ asArray = callback;
121
+ callback = undefined;
122
+ }
129
123
 
130
- Transaction.prototype.query = function(query, params, callback) {
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
+ };
131
154
 
132
- if (params instanceof Function) {
133
- callback = params;
134
- params = undefined;
155
+ self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: _on });
156
+ return self;
135
157
  }
136
158
 
137
- if (callback === undefined)
138
- callback = noop;
159
+ query(query, params, callback) {
160
+ if (params instanceof Function) {
161
+ callback = params;
162
+ params = undefined;
163
+ }
139
164
 
140
- this.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null });
165
+ if (callback === undefined)
166
+ callback = noop;
141
167
 
142
- };
168
+ this.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null });
169
+ }
143
170
 
144
- Transaction.prototype.commit = function(callback) {
145
- this.connection.commit(this, callback);
146
- };
171
+ commit(callback) {
172
+ this.connection.commit(this, callback);
173
+ }
147
174
 
148
- Transaction.prototype.rollback = function(callback) {
149
- this.connection.rollback(this, callback);
150
- };
175
+ rollback(callback) {
176
+ this.connection.rollback(this, callback);
177
+ }
151
178
 
152
- Transaction.prototype.commitRetaining = function(callback) {
153
- this.connection.commitRetaining(this, callback);
154
- };
179
+ commitRetaining(callback) {
180
+ this.connection.commitRetaining(this, callback);
181
+ }
155
182
 
156
- Transaction.prototype.rollbackRetaining = function(callback) {
157
- this.connection.rollbackRetaining(this, callback);
158
- };
183
+ rollbackRetaining(callback) {
184
+ this.connection.rollbackRetaining(this, callback);
185
+ }
186
+ }
159
187
 
160
188
  module.exports = Transaction;