node-firebird 0.9.6 → 1.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.
- package/.github/workflows/node.js.yml +78 -0
- package/README.md +45 -8
- package/lib/gdscodes.d.ts +1524 -0
- package/lib/gdscodes.js +1531 -0
- package/lib/index.d.ts +218 -16
- package/lib/index.js +298 -105
- package/lib/messages.js +1 -1
- package/lib/serialize.js +13 -19
- package/lib/srp.js +281 -0
- package/package.json +2 -1
- package/.github/workflows/npmpublish.yml +0 -47
package/lib/index.js
CHANGED
|
@@ -11,7 +11,9 @@ var
|
|
|
11
11
|
BitSet = serialize.BitSet,
|
|
12
12
|
messages = require('./messages.js'),
|
|
13
13
|
crypt = require('./unix-crypt.js'),
|
|
14
|
-
path = require('path')
|
|
14
|
+
path = require('path'),
|
|
15
|
+
srp = require('./srp'),
|
|
16
|
+
BigInt = require('big-integer');
|
|
15
17
|
|
|
16
18
|
if (typeof(setImmediate) === 'undefined') {
|
|
17
19
|
global.setImmediate = function(cb) {
|
|
@@ -274,7 +276,9 @@ const
|
|
|
274
276
|
ptype_rpc = 2, // Simple remote procedure call
|
|
275
277
|
ptype_batch_send = 3, // Batch sends, no asynchrony
|
|
276
278
|
ptype_out_of_band = 4, // Batch sends w/ out of band notification
|
|
277
|
-
ptype_lazy_send = 5
|
|
279
|
+
ptype_lazy_send = 5, // Deferred packets delivery;
|
|
280
|
+
ptype_mask = 0xFF, // Mask - up to 255 types of protocol
|
|
281
|
+
pflag_compress = 0x100; // Turn on compression if possible
|
|
278
282
|
|
|
279
283
|
const SUPPORTED_PROTOCOL = [
|
|
280
284
|
[PROTOCOL_VERSION10, ARCHITECTURE_GENERIC, ptype_rpc, ptype_batch_send, 1],
|
|
@@ -790,11 +794,25 @@ const
|
|
|
790
794
|
DEFAULT_PAGE_SIZE = 4096,
|
|
791
795
|
DEFAULT_SVC_NAME = 'service_mgr';
|
|
792
796
|
|
|
793
|
-
const AUTH_PLUGIN_LEGACY = 'Legacy_Auth'
|
|
797
|
+
const AUTH_PLUGIN_LEGACY = 'Legacy_Auth',
|
|
798
|
+
AUTH_PLUGIN_SRP = 'Srp';
|
|
799
|
+
// AUTH_PLUGIN_SRP256 = 'Srp256';
|
|
794
800
|
|
|
795
801
|
const
|
|
796
|
-
AUTH_PLUGIN_LIST = [AUTH_PLUGIN_LEGACY],
|
|
797
|
-
|
|
802
|
+
// AUTH_PLUGIN_LIST = [AUTH_PLUGIN_SRP256, AUTH_PLUGIN_SRP, AUTH_PLUGIN_LEGACY],
|
|
803
|
+
AUTH_PLUGIN_LIST = [AUTH_PLUGIN_SRP, AUTH_PLUGIN_LEGACY],
|
|
804
|
+
// AUTH_PLUGIN_SRP_LIST = [AUTH_PLUGIN_SRP256, AUTH_PLUGIN_SRP],
|
|
805
|
+
AUTH_PLUGIN_SRP_LIST = [AUTH_PLUGIN_SRP],
|
|
806
|
+
LEGACY_AUTH_SALT = '9z',
|
|
807
|
+
WIRE_CRYPT_DISABLE = 0,
|
|
808
|
+
WIRE_CRYPT_ENABLE = 1;
|
|
809
|
+
|
|
810
|
+
exports.AUTH_PLUGIN_LEGACY = AUTH_PLUGIN_LEGACY;
|
|
811
|
+
exports.AUTH_PLUGIN_SRP = AUTH_PLUGIN_SRP;
|
|
812
|
+
// exports.AUTH_PLUGIN_SRP256 = AUTH_PLUGIN_SRP256;
|
|
813
|
+
|
|
814
|
+
exports.WIRE_CRYPT_DISABLE = WIRE_CRYPT_DISABLE;
|
|
815
|
+
exports.WIRE_CRYPT_ENABLE = WIRE_CRYPT_ENABLE;
|
|
798
816
|
|
|
799
817
|
exports.ISOLATION_READ_UNCOMMITTED = ISOLATION_READ_UNCOMMITTED;
|
|
800
818
|
exports.ISOLATION_READ_COMMITED = ISOLATION_READ_COMMITED;
|
|
@@ -812,16 +830,20 @@ if (!String.prototype.padLeft) {
|
|
|
812
830
|
/**
|
|
813
831
|
* Escape value
|
|
814
832
|
* @param {Object} value
|
|
833
|
+
* @param {Number} protocolVersion (optional, default: PROTOCOL_VERSION13)
|
|
815
834
|
* @return {String}
|
|
816
835
|
*/
|
|
817
|
-
exports.escape = function(value) {
|
|
836
|
+
exports.escape = function(value, protocolVersion) {
|
|
818
837
|
|
|
819
838
|
if (value === null || value === undefined)
|
|
820
839
|
return 'NULL';
|
|
821
840
|
|
|
822
841
|
switch (typeof(value)) {
|
|
823
842
|
case 'boolean':
|
|
824
|
-
|
|
843
|
+
if ((protocolVersion || PROTOCOL_VERSION13) >= PROTOCOL_VERSION13)
|
|
844
|
+
return value ? 'true' : 'false';
|
|
845
|
+
else
|
|
846
|
+
return value ? '1' : '0';
|
|
825
847
|
case 'number':
|
|
826
848
|
return value.toString();
|
|
827
849
|
case 'string':
|
|
@@ -1280,7 +1302,9 @@ SQLParamBool.prototype.calcBlr = function(blr) {
|
|
|
1280
1302
|
***************************************/
|
|
1281
1303
|
|
|
1282
1304
|
function isError(obj) {
|
|
1283
|
-
return (
|
|
1305
|
+
return Boolean(
|
|
1306
|
+
obj != null && typeof obj === "object" && !Array.isArray(obj) && obj.status
|
|
1307
|
+
);
|
|
1284
1308
|
}
|
|
1285
1309
|
|
|
1286
1310
|
function doCallback(obj, callback) {
|
|
@@ -1294,7 +1318,11 @@ function doCallback(obj, callback) {
|
|
|
1294
1318
|
}
|
|
1295
1319
|
|
|
1296
1320
|
if (isError(obj)) {
|
|
1297
|
-
|
|
1321
|
+
var error = new Error(obj.message);
|
|
1322
|
+
var status = obj.status && obj.status.length && obj.status[0] || {};
|
|
1323
|
+
error.gdscode = status.gdscode; // main error gds code
|
|
1324
|
+
error.gdsparams = status.params; // parameters (constraint name, table, etc.)
|
|
1325
|
+
callback(error);
|
|
1298
1326
|
return;
|
|
1299
1327
|
}
|
|
1300
1328
|
|
|
@@ -1379,6 +1407,7 @@ Transaction.prototype.newStatement = function(query, callback) {
|
|
|
1379
1407
|
Transaction.prototype.execute = function(query, params, callback, custom) {
|
|
1380
1408
|
|
|
1381
1409
|
if (params instanceof Function) {
|
|
1410
|
+
custom = callback;
|
|
1382
1411
|
callback = params;
|
|
1383
1412
|
params = undefined;
|
|
1384
1413
|
}
|
|
@@ -1454,6 +1483,29 @@ Transaction.prototype.execute = function(query, params, callback, custom) {
|
|
|
1454
1483
|
});
|
|
1455
1484
|
};
|
|
1456
1485
|
|
|
1486
|
+
Transaction.prototype.sequentially = function (query, params, on, callback, asArray) {
|
|
1487
|
+
|
|
1488
|
+
if (params instanceof Function) {
|
|
1489
|
+
asArray = callback;
|
|
1490
|
+
callback = on;
|
|
1491
|
+
on = params;
|
|
1492
|
+
params = undefined;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (on === undefined){
|
|
1496
|
+
throw new Error('Expected "on" delegate.');
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
if (callback instanceof Boolean) {
|
|
1500
|
+
asArray = callback;
|
|
1501
|
+
callback = undefined;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
var self = this;
|
|
1505
|
+
self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: on });
|
|
1506
|
+
return self;
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1457
1509
|
Transaction.prototype.query = function(query, params, callback) {
|
|
1458
1510
|
|
|
1459
1511
|
if (params instanceof Function) {
|
|
@@ -1503,7 +1555,7 @@ Database.prototype.__proto__ = Object.create(Events.EventEmitter.prototype, {
|
|
|
1503
1555
|
});
|
|
1504
1556
|
|
|
1505
1557
|
Database.prototype.escape = function(value) {
|
|
1506
|
-
return exports.escape(value);
|
|
1558
|
+
return exports.escape(value, this.connection.accept.protocolVersion);
|
|
1507
1559
|
};
|
|
1508
1560
|
|
|
1509
1561
|
Database.prototype.detach = function(callback, force) {
|
|
@@ -1572,6 +1624,7 @@ Database.prototype.newStatement = function (query, callback) {
|
|
|
1572
1624
|
Database.prototype.execute = function(query, params, callback, custom) {
|
|
1573
1625
|
|
|
1574
1626
|
if (params instanceof Function) {
|
|
1627
|
+
custom = callback;
|
|
1575
1628
|
callback = params;
|
|
1576
1629
|
params = undefined;
|
|
1577
1630
|
}
|
|
@@ -1606,19 +1659,25 @@ Database.prototype.execute = function(query, params, callback, custom) {
|
|
|
1606
1659
|
|
|
1607
1660
|
Database.prototype.sequentially = function(query, params, on, callback, asArray) {
|
|
1608
1661
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1662
|
+
if (params instanceof Function) {
|
|
1663
|
+
asArray = callback;
|
|
1664
|
+
callback = on;
|
|
1665
|
+
on = params;
|
|
1666
|
+
params = undefined;
|
|
1667
|
+
}
|
|
1615
1668
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1669
|
+
if (on === undefined){
|
|
1670
|
+
throw new Error('Expected "on" delegate.');
|
|
1671
|
+
}
|
|
1618
1672
|
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1673
|
+
if (callback instanceof Boolean) {
|
|
1674
|
+
asArray = callback;
|
|
1675
|
+
callback = undefined;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
var self = this;
|
|
1679
|
+
self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: on });
|
|
1680
|
+
return self;
|
|
1622
1681
|
};
|
|
1623
1682
|
|
|
1624
1683
|
Database.prototype.query = function(query, params, callback) {
|
|
@@ -1793,7 +1852,7 @@ ServiceManager.prototype._infosmapping = {
|
|
|
1793
1852
|
"63"/*isc_info_svc_to_eof*/ : "",
|
|
1794
1853
|
"64"/*isc_info_svc_timeout*/ : "",
|
|
1795
1854
|
"65"/*isc_info_svc_get_licensed_users*/ : "",
|
|
1796
|
-
"66"/*isc_info_svc_limbo_trans*/ : "",
|
|
1855
|
+
"66"/*isc_info_svc_limbo_trans*/ : "limbotrans",
|
|
1797
1856
|
"67"/*isc_info_svc_running*/ : "",
|
|
1798
1857
|
"68"/*isc_info_svc_get_users*/ : "fbusers",
|
|
1799
1858
|
"78"/*isc_info_svc_stdin*/ : ""
|
|
@@ -2175,11 +2234,11 @@ ServiceManager.prototype._fixpropertie = function (options, callback) {
|
|
|
2175
2234
|
var online = options.bringonline || false;
|
|
2176
2235
|
var shutdown = options.shutdown != null ? options.shutdown : null; // 0 Forced, 1 deny transaction, 2 deny attachment
|
|
2177
2236
|
var shutdowndelay = options.shutdowndelay || 0;
|
|
2178
|
-
var shutdownmode = options.shutdownmode
|
|
2237
|
+
var shutdownmode = options.shutdownmode; // 0 normal 1 multi 2 single 3 full
|
|
2179
2238
|
var shadow = options.activateshadow || false;
|
|
2180
|
-
var forcewrite = options.forcewrite
|
|
2181
|
-
var reservespace = options.reservespace
|
|
2182
|
-
var accessmode = options.accessmode
|
|
2239
|
+
var forcewrite = options.forcewrite;
|
|
2240
|
+
var reservespace = options.reservespace;
|
|
2241
|
+
var accessmode = options.accessmode; // 0 readonly 1 readwrite
|
|
2183
2242
|
|
|
2184
2243
|
if (dbpath == null || dbpath.length === 0) {
|
|
2185
2244
|
doError(new Error('No database specified'), callback);
|
|
@@ -2213,9 +2272,9 @@ ServiceManager.prototype._fixpropertie = function (options, callback) {
|
|
|
2213
2272
|
}
|
|
2214
2273
|
}
|
|
2215
2274
|
if (forcewrite) blr.addBytes([isc_spb_prp_write_mode, isc_spb_prp_wm_sync]);
|
|
2216
|
-
if (forcewrite
|
|
2217
|
-
if (accessmode) blr.addBytes([isc_spb_prp_access_mode, isc_spb_prp_am_readwrite]);
|
|
2218
|
-
if (accessmode
|
|
2275
|
+
if (forcewrite === false) blr.addBytes([isc_spb_prp_write_mode, isc_spb_prp_wm_async]);
|
|
2276
|
+
if (accessmode === 1) blr.addBytes([isc_spb_prp_access_mode, isc_spb_prp_am_readwrite]);
|
|
2277
|
+
if (accessmode === 0) blr.addBytes([isc_spb_prp_access_mode, isc_spb_prp_am_readonly]);
|
|
2219
2278
|
if (reservespace) blr.addBytes([isc_spb_prp_reserve_space, isc_spb_prp_res]);
|
|
2220
2279
|
if (reservespace != null && !reservespace) blr.addBytes([isc_spb_prp_reserve_space, isc_spb_prp_res_use_full]);
|
|
2221
2280
|
var opts = 0;
|
|
@@ -2265,6 +2324,11 @@ const SHUTDOWNEX_MODE = {
|
|
|
2265
2324
|
2: isc_spb_prp_sm_single,
|
|
2266
2325
|
3: isc_spb_prp_sm_full
|
|
2267
2326
|
};
|
|
2327
|
+
const ShutdownMode = { NORMAL: 0, MULTI: 1, SINGLE: 2, FULL: 3 };
|
|
2328
|
+
const ShutdownKind = { FORCED: 0, DENY_TRANSACTION: 1, DENY_ATTACHMENT: 2 };
|
|
2329
|
+
exports.ShutdownMode = ShutdownMode;
|
|
2330
|
+
exports.ShutdownKind = ShutdownKind;
|
|
2331
|
+
|
|
2268
2332
|
ServiceManager.prototype.Shutdown = function (db, kind, delay, mode, callback) {
|
|
2269
2333
|
// mode parameter is for server version >= 2.0
|
|
2270
2334
|
if (mode instanceof Function) {
|
|
@@ -2355,7 +2419,7 @@ ServiceManager.prototype.commit = function(db, transactid, callback) {
|
|
|
2355
2419
|
doError(new Error(err), callback);
|
|
2356
2420
|
return;
|
|
2357
2421
|
}
|
|
2358
|
-
self._createOutputStream(
|
|
2422
|
+
self._createOutputStream(null, null, callback);
|
|
2359
2423
|
});
|
|
2360
2424
|
}
|
|
2361
2425
|
|
|
@@ -2376,7 +2440,7 @@ ServiceManager.prototype.rollback = function (db, transactid, callback) {
|
|
|
2376
2440
|
doError(new Error(err), callback);
|
|
2377
2441
|
return;
|
|
2378
2442
|
}
|
|
2379
|
-
self._createOutputStream(
|
|
2443
|
+
self._createOutputStream(null, null, callback);
|
|
2380
2444
|
});
|
|
2381
2445
|
}
|
|
2382
2446
|
|
|
@@ -2397,7 +2461,7 @@ ServiceManager.prototype.recover = function (db, transactid, callback) {
|
|
|
2397
2461
|
doError(new Error(err), callback);
|
|
2398
2462
|
return;
|
|
2399
2463
|
}
|
|
2400
|
-
self._createOutputStream(
|
|
2464
|
+
self._createOutputStream(null, null, callback);
|
|
2401
2465
|
});
|
|
2402
2466
|
}
|
|
2403
2467
|
|
|
@@ -2576,12 +2640,11 @@ ServiceManager.prototype.getFbserverInfos = function (infos, options, callback)
|
|
|
2576
2640
|
};
|
|
2577
2641
|
// if infos is empty all options are asked to the service
|
|
2578
2642
|
|
|
2579
|
-
var tops = [];
|
|
2643
|
+
var tops = [], empty = isEmpty(infos);
|
|
2580
2644
|
for (popts in opts)
|
|
2581
|
-
if (infos[popts]
|
|
2645
|
+
if (empty || infos[popts])
|
|
2582
2646
|
tops.push(opts[popts]);
|
|
2583
2647
|
|
|
2584
|
-
|
|
2585
2648
|
var self = this;
|
|
2586
2649
|
this.connection.svcquery(tops, buffersize, timeout, function (err, data) {
|
|
2587
2650
|
if (err || !data.buffer) {
|
|
@@ -2592,6 +2655,11 @@ ServiceManager.prototype.getFbserverInfos = function (infos, options, callback)
|
|
|
2592
2655
|
});
|
|
2593
2656
|
}
|
|
2594
2657
|
|
|
2658
|
+
function isEmpty(obj){
|
|
2659
|
+
for(var p in obj) return false;
|
|
2660
|
+
return true;
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2595
2663
|
ServiceManager.prototype.startTrace = function (options, callback) {
|
|
2596
2664
|
var self = this;
|
|
2597
2665
|
var blr = this.connection._blr;
|
|
@@ -2689,7 +2757,6 @@ ServiceManager.prototype.stopTrace = function (options, callback) {
|
|
|
2689
2757
|
ServiceManager.prototype.getTraceList = function (options, callback) {
|
|
2690
2758
|
var self = this;
|
|
2691
2759
|
var blr = this.connection._blr;
|
|
2692
|
-
var optread = options.optread || 'byline';
|
|
2693
2760
|
blr.pos = 0;
|
|
2694
2761
|
blr.addByte(isc_action_svc_trace_list);
|
|
2695
2762
|
this.connection.svcstart(blr, function (err, data) {
|
|
@@ -2767,7 +2834,7 @@ ServiceManager.prototype.readlimbo = function (options, callback) {
|
|
|
2767
2834
|
}
|
|
2768
2835
|
|
|
2769
2836
|
// Pooling
|
|
2770
|
-
exports.pool = function(max, options
|
|
2837
|
+
exports.pool = function(max, options) {
|
|
2771
2838
|
return new Pool(max, Object.assign({}, options, { isPool: true }));
|
|
2772
2839
|
};
|
|
2773
2840
|
|
|
@@ -2838,17 +2905,40 @@ Pool.prototype.check = function() {
|
|
|
2838
2905
|
return self;
|
|
2839
2906
|
};
|
|
2840
2907
|
|
|
2841
|
-
Pool.prototype.destroy = function() {
|
|
2908
|
+
Pool.prototype.destroy = function(callback) {
|
|
2842
2909
|
var self = this;
|
|
2910
|
+
|
|
2911
|
+
var connectionCount = this.internaldb.length;
|
|
2912
|
+
|
|
2913
|
+
if (connectionCount === 0 && callback) {
|
|
2914
|
+
callback();
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
function detachCallback(err) {
|
|
2918
|
+
if (err) {
|
|
2919
|
+
if (callback) {
|
|
2920
|
+
callback(err);
|
|
2921
|
+
}
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
connectionCount--;
|
|
2926
|
+
if (connectionCount === 0 && callback) {
|
|
2927
|
+
callback();
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2843
2931
|
this.internaldb.forEach(function(db) {
|
|
2844
|
-
if (db.connection._pooled === false)
|
|
2932
|
+
if (db.connection._pooled === false) {
|
|
2933
|
+
detachCallback();
|
|
2845
2934
|
return;
|
|
2935
|
+
}
|
|
2846
2936
|
// check if the db is not free into the pool otherwise user should manual detach it
|
|
2847
2937
|
var _db_in_pool = self.pooldb.indexOf(db);
|
|
2848
2938
|
if (_db_in_pool !== -1) {
|
|
2849
2939
|
self.pooldb.splice(_db_in_pool, 1);
|
|
2850
2940
|
db.connection._pooled = false;
|
|
2851
|
-
db.detach();
|
|
2941
|
+
db.detach(detachCallback);
|
|
2852
2942
|
}
|
|
2853
2943
|
});
|
|
2854
2944
|
};
|
|
@@ -2871,6 +2961,7 @@ var Connection = exports.Connection = function (host, port, callback, options, d
|
|
|
2871
2961
|
this._detachAuto;
|
|
2872
2962
|
this._socket = net.createConnection(port, host);
|
|
2873
2963
|
this._pending = [];
|
|
2964
|
+
this._isOpened = false;
|
|
2874
2965
|
this._isClosed = false;
|
|
2875
2966
|
this._isDetach = false;
|
|
2876
2967
|
this._isUsed = false;
|
|
@@ -2878,6 +2969,8 @@ var Connection = exports.Connection = function (host, port, callback, options, d
|
|
|
2878
2969
|
this.options = options;
|
|
2879
2970
|
this._bind_events(host, port, callback);
|
|
2880
2971
|
this.error;
|
|
2972
|
+
this._retry_connection_id;
|
|
2973
|
+
this._retry_connection_interval = options.retryConnectionInterval || 1000;
|
|
2881
2974
|
this._max_cached_query = options.maxCachedQuery || -1;
|
|
2882
2975
|
this._cache_query = options.cacheQuery?{}:null;
|
|
2883
2976
|
this._messageFile = options.messageFile || path.join(__dirname, 'firebird.msg');
|
|
@@ -2903,10 +2996,11 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2903
2996
|
|
|
2904
2997
|
self._socket.on('close', function() {
|
|
2905
2998
|
|
|
2906
|
-
self.
|
|
2907
|
-
|
|
2908
|
-
if (self._isDetach)
|
|
2999
|
+
if (!self._isOpened || self._isDetach) {
|
|
2909
3000
|
return;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
self._isOpened = false;
|
|
2910
3004
|
|
|
2911
3005
|
if (!self.db) {
|
|
2912
3006
|
if (callback)
|
|
@@ -2914,10 +3008,9 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2914
3008
|
return;
|
|
2915
3009
|
}
|
|
2916
3010
|
|
|
2917
|
-
|
|
3011
|
+
self._retry_connection_id = setTimeout(function() {
|
|
3012
|
+
self._socket.removeAllListeners();
|
|
2918
3013
|
self._socket = null;
|
|
2919
|
-
self._msg = null;
|
|
2920
|
-
self._blr = null;
|
|
2921
3014
|
|
|
2922
3015
|
var ctx = new Connection(host, port, function(err) {
|
|
2923
3016
|
ctx.connect(self.options, function(err) {
|
|
@@ -2941,8 +3034,10 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2941
3034
|
}, self.db);
|
|
2942
3035
|
});
|
|
2943
3036
|
|
|
3037
|
+
Object.assign(self, ctx);
|
|
3038
|
+
|
|
2944
3039
|
}, self.options, self.db);
|
|
2945
|
-
});
|
|
3040
|
+
}, self._retry_connection_interval);
|
|
2946
3041
|
|
|
2947
3042
|
});
|
|
2948
3043
|
|
|
@@ -3165,14 +3260,7 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3165
3260
|
|
|
3166
3261
|
data.fcolumn = 0;
|
|
3167
3262
|
statement.connection.db.emit('row', data.frow, statement.nbrowsfetched, custom.asObject);
|
|
3168
|
-
|
|
3169
|
-
if (!custom.asStream) {
|
|
3170
|
-
data.frows.push(data.frow);
|
|
3171
|
-
}
|
|
3172
|
-
|
|
3173
|
-
if (custom.on) {
|
|
3174
|
-
custom.on(data.frow, statement.nbrowsfetched);
|
|
3175
|
-
}
|
|
3263
|
+
data.frows.push(data.frow);
|
|
3176
3264
|
data.frow = custom.asObject ? {} : new Array(output.length);
|
|
3177
3265
|
|
|
3178
3266
|
try {
|
|
@@ -3215,22 +3303,77 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3215
3303
|
protocolArchitecture: data.readInt(),
|
|
3216
3304
|
protocolMinimumType: data.readInt(),
|
|
3217
3305
|
pluginName: '',
|
|
3218
|
-
authData: ''
|
|
3306
|
+
authData: '',
|
|
3307
|
+
sessionKey: ''
|
|
3219
3308
|
};
|
|
3220
3309
|
|
|
3221
3310
|
accept.protocolMinimumType = accept.protocolMinimumType & 0xFF;
|
|
3311
|
+
//accept.compress = (accept.acceptType & pflag_compress) !== 0; // TODO Handle zlib compression
|
|
3222
3312
|
if (accept.protocolVersion < 0) {
|
|
3223
3313
|
accept.protocolVersion = (accept.protocolVersion & FB_PROTOCOL_MASK) | FB_PROTOCOL_FLAG;
|
|
3224
3314
|
}
|
|
3225
3315
|
|
|
3226
3316
|
if (r === op_cond_accept || r === op_accept_data) {
|
|
3227
|
-
var d = data.
|
|
3317
|
+
var d = new BlrReader(data.readArray());
|
|
3228
3318
|
accept.pluginName = data.readString(DEFAULT_ENCODING);
|
|
3229
3319
|
var is_authenticated = data.readInt();
|
|
3230
3320
|
var keys = data.readString(DEFAULT_ENCODING); // keys
|
|
3231
3321
|
|
|
3232
3322
|
if (is_authenticated === 0) {
|
|
3233
|
-
|
|
3323
|
+
if (cnx.options.pluginName && cnx.options.pluginName !== accept.pluginName) {
|
|
3324
|
+
doError(new Error('Server don\'t accept plugin : ' + cnx.options.pluginName + ', but support : ' + accept.pluginName), callback);
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
if (AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
3328
|
+
var crypto = {
|
|
3329
|
+
Srp: 'sha1',
|
|
3330
|
+
Srp256: 'sha256'
|
|
3331
|
+
};
|
|
3332
|
+
accept.srpAlgo = crypto[accept.pluginName];
|
|
3333
|
+
|
|
3334
|
+
// TODO : Fallback Srp256 to Srp ?
|
|
3335
|
+
/*if (!d.buffer) {
|
|
3336
|
+
cnx.sendOpContAuth(
|
|
3337
|
+
cnx.clientKeys.public.toString(16),
|
|
3338
|
+
DEFAULT_ENCODING,
|
|
3339
|
+
accept.pluginName
|
|
3340
|
+
);
|
|
3341
|
+
|
|
3342
|
+
return cb(new Error('login'));
|
|
3343
|
+
}*/
|
|
3344
|
+
|
|
3345
|
+
// Check buffer contains salt
|
|
3346
|
+
var saltLen = d.buffer.readUInt16LE(0);
|
|
3347
|
+
if (saltLen > 32 * 2) {
|
|
3348
|
+
console.log('salt to long'); // TODO : Throw error
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
// Check buffer contains key
|
|
3352
|
+
var keyLen = d.buffer.readUInt16LE(saltLen + 2);
|
|
3353
|
+
var keyStart = saltLen + 4;
|
|
3354
|
+
if (d.buffer.length - keyStart !== keyLen) {
|
|
3355
|
+
console.log('key error'); // TODO : Throw error
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3358
|
+
// Server keys
|
|
3359
|
+
cnx.serverKeys = {
|
|
3360
|
+
salt: d.buffer.slice(2, saltLen + 2).toString('utf8'),
|
|
3361
|
+
public: BigInt(d.buffer.slice(keyStart, d.buffer.length).toString('utf8'), 16)
|
|
3362
|
+
};
|
|
3363
|
+
|
|
3364
|
+
var proof = srp.clientProof(
|
|
3365
|
+
cnx.options.user.toUpperCase(),
|
|
3366
|
+
cnx.options.password,
|
|
3367
|
+
cnx.serverKeys.salt,
|
|
3368
|
+
cnx.clientKeys.public,
|
|
3369
|
+
cnx.serverKeys.public,
|
|
3370
|
+
cnx.clientKeys.private,
|
|
3371
|
+
accept.srpAlgo
|
|
3372
|
+
);
|
|
3373
|
+
|
|
3374
|
+
accept.authData = proof.authData.toString(16);
|
|
3375
|
+
accept.sessionKey = proof.clientSessionKey;
|
|
3376
|
+
} else if (accept.pluginName === AUTH_PLUGIN_LEGACY) {
|
|
3234
3377
|
accept.authData = crypt.crypt(cnx.options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3235
3378
|
} else {
|
|
3236
3379
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
@@ -3240,7 +3383,35 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3240
3383
|
accept.sessionKey = '';
|
|
3241
3384
|
}
|
|
3242
3385
|
}
|
|
3386
|
+
|
|
3243
3387
|
return cb(undefined, accept);
|
|
3388
|
+
case op_cont_auth:
|
|
3389
|
+
var d = new BlrReader(data.readArray());
|
|
3390
|
+
var pluginName = data.readString(DEFAULT_ENCODING);
|
|
3391
|
+
data.readString(DEFAULT_ENCODING); // plist
|
|
3392
|
+
data.readString(DEFAULT_ENCODING); // pkey
|
|
3393
|
+
|
|
3394
|
+
if (!cnx.options.pluginName) {
|
|
3395
|
+
if (cnx.accept.pluginName === pluginName) {
|
|
3396
|
+
// Erreur plugin not able to connect
|
|
3397
|
+
return cb(new Error("Unable to connect with plugin " + cnx.accept.pluginName));
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
if (pluginName === AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
3401
|
+
cnx.accept.pluginName = pluginName;
|
|
3402
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3403
|
+
|
|
3404
|
+
cnx.sendOpContAuth(
|
|
3405
|
+
cnx.accept.authData,
|
|
3406
|
+
DEFAULT_ENCODING,
|
|
3407
|
+
pluginName
|
|
3408
|
+
);
|
|
3409
|
+
|
|
3410
|
+
return {error: new Error('login')};
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
return data.accept;
|
|
3244
3415
|
default:
|
|
3245
3416
|
return cb(new Error('Unexpected:' + r));
|
|
3246
3417
|
}
|
|
@@ -3326,6 +3497,20 @@ function parseOpResponse(data, response, cb) {
|
|
|
3326
3497
|
}
|
|
3327
3498
|
}
|
|
3328
3499
|
|
|
3500
|
+
Connection.prototype.sendOpContAuth = function(authData, authDataEnc, pluginName) {
|
|
3501
|
+
var msg = this._msg;
|
|
3502
|
+
msg.pos = 0;
|
|
3503
|
+
|
|
3504
|
+
msg.addInt(op_cont_auth);
|
|
3505
|
+
msg.addString(authData, authDataEnc);
|
|
3506
|
+
msg.addString(pluginName, DEFAULT_ENCODING)
|
|
3507
|
+
msg.addString(AUTH_PLUGIN_LIST.join(','), DEFAULT_ENCODING);
|
|
3508
|
+
// msg.addInt(0); // p_list
|
|
3509
|
+
msg.addInt(0); // keys
|
|
3510
|
+
|
|
3511
|
+
this._socket.write(msg.getData());
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3329
3514
|
Connection.prototype._queueEvent = function(callback){
|
|
3330
3515
|
var self = this;
|
|
3331
3516
|
|
|
@@ -3340,7 +3525,7 @@ Connection.prototype._queueEvent = function(callback){
|
|
|
3340
3525
|
};
|
|
3341
3526
|
|
|
3342
3527
|
Connection.prototype.connect = function (options, callback) {
|
|
3343
|
-
var pluginName = AUTH_PLUGIN_LEGACY;
|
|
3528
|
+
var pluginName = options.manager ? AUTH_PLUGIN_LEGACY : options.pluginName || AUTH_PLUGIN_LIST[0]; // TODO Srp for service
|
|
3344
3529
|
var msg = this._msg;
|
|
3345
3530
|
var blr = this._blr;
|
|
3346
3531
|
|
|
@@ -3353,13 +3538,19 @@ Connection.prototype.connect = function (options, callback) {
|
|
|
3353
3538
|
blr.addString(CNCT_plugin_name, pluginName, DEFAULT_ENCODING);
|
|
3354
3539
|
blr.addString(CNCT_plugin_list, AUTH_PLUGIN_LIST.join(','), DEFAULT_ENCODING);
|
|
3355
3540
|
|
|
3356
|
-
|
|
3357
|
-
|
|
3541
|
+
var specificData = '';
|
|
3542
|
+
if (AUTH_PLUGIN_SRP_LIST.indexOf(pluginName) > -1) {
|
|
3543
|
+
this.clientKeys = srp.clientSeed();
|
|
3544
|
+
specificData = this.clientKeys.public.toString(16);
|
|
3545
|
+
blr.addMultiblockPart(CNCT_specific_data, specificData, DEFAULT_ENCODING);
|
|
3546
|
+
} else if (pluginName === AUTH_PLUGIN_LEGACY) {
|
|
3547
|
+
specificData = crypt.crypt(options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3358
3548
|
blr.addMultiblockPart(CNCT_specific_data, specificData, DEFAULT_ENCODING);
|
|
3359
3549
|
} else {
|
|
3360
|
-
|
|
3550
|
+
doError(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
3551
|
+
return;
|
|
3361
3552
|
}
|
|
3362
|
-
blr.addBytes([CNCT_client_crypt, 4,
|
|
3553
|
+
blr.addBytes([CNCT_client_crypt, 4, WIRE_CRYPT_DISABLE, 0, 0, 0]); // WireCrypt = Disabled
|
|
3363
3554
|
blr.addString(CNCT_user, os.userInfo().username || 'Unknown', DEFAULT_ENCODING);
|
|
3364
3555
|
blr.addString(CNCT_host, os.hostname(), DEFAULT_ENCODING);
|
|
3365
3556
|
blr.addBytes([CNCT_user_verification, 0]);
|
|
@@ -3416,19 +3607,25 @@ Connection.prototype.attach = function (options, callback, db) {
|
|
|
3416
3607
|
blr.addByte(isc_dpb_version1);
|
|
3417
3608
|
blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING);
|
|
3418
3609
|
blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING);
|
|
3419
|
-
if (this.accept.
|
|
3420
|
-
if (this.accept.protocolVersion
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3610
|
+
if (options.password && !this.accept.authData) {
|
|
3611
|
+
if (this.accept.protocolVersion < PROTOCOL_VERSION13) {
|
|
3612
|
+
if (this.accept.protocolVersion === PROTOCOL_VERSION10) {
|
|
3613
|
+
blr.addString(isc_dpb_password, password, DEFAULT_ENCODING);
|
|
3614
|
+
} else {
|
|
3615
|
+
blr.addString(isc_dpb_password_enc, crypt.crypt(password, LEGACY_AUTH_SALT).substring(2), DEFAULT_ENCODING);
|
|
3616
|
+
}
|
|
3424
3617
|
}
|
|
3425
3618
|
}
|
|
3619
|
+
|
|
3426
3620
|
if (role)
|
|
3427
3621
|
blr.addString(isc_dpb_sql_role_name, role, DEFAULT_ENCODING);
|
|
3428
3622
|
|
|
3429
3623
|
blr.addBytes([isc_dpb_process_id, 4]);
|
|
3430
3624
|
blr.addInt32(process.pid);
|
|
3431
|
-
|
|
3625
|
+
|
|
3626
|
+
let processName = process.title || "";
|
|
3627
|
+
blr.addString(isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, DEFAULT_ENCODING);
|
|
3628
|
+
|
|
3432
3629
|
if (this.accept.authData) {
|
|
3433
3630
|
blr.addString(isc_dpb_specific_auth_data, this.accept.authData, DEFAULT_ENCODING);
|
|
3434
3631
|
}
|
|
@@ -3479,6 +3676,7 @@ Connection.prototype.detach = function (callback) {
|
|
|
3479
3676
|
msg.addInt(0); // Database Object ID
|
|
3480
3677
|
|
|
3481
3678
|
self._queueEvent(function(err, ret) {
|
|
3679
|
+
clearTimeout(self._retry_connection_id);
|
|
3482
3680
|
delete(self.dbhandle);
|
|
3483
3681
|
if (callback)
|
|
3484
3682
|
callback(err, ret);
|
|
@@ -3515,7 +3713,10 @@ Connection.prototype.createDatabase = function (options, callback) {
|
|
|
3515
3713
|
|
|
3516
3714
|
blr.addBytes([isc_dpb_process_id, 4]);
|
|
3517
3715
|
blr.addInt32(process.pid);
|
|
3518
|
-
|
|
3716
|
+
|
|
3717
|
+
let processName = process.title || "";
|
|
3718
|
+
blr.addString(isc_dpb_process_name, processName.length > 255 ? processName.substring(processName.length - 255, processName.length) : processName, DEFAULT_ENCODING);
|
|
3719
|
+
|
|
3519
3720
|
if (this.accept.authData) {
|
|
3520
3721
|
blr.addString(isc_dpb_specific_auth_data, this.accept.authData, DEFAULT_ENCODING);
|
|
3521
3722
|
}
|
|
@@ -3598,11 +3799,6 @@ Connection.prototype.startTransaction = function(isolation, callback) {
|
|
|
3598
3799
|
blr.pos = 0;
|
|
3599
3800
|
msg.pos = 0;
|
|
3600
3801
|
|
|
3601
|
-
if (isolation instanceof Function) {
|
|
3602
|
-
callback = isolation;
|
|
3603
|
-
isolation = null;
|
|
3604
|
-
}
|
|
3605
|
-
|
|
3606
3802
|
blr.addBytes(isolation || ISOLATION_REPEATABLE_READ);
|
|
3607
3803
|
msg.addInt(op_transaction);
|
|
3608
3804
|
msg.addInt(this.dbhandle);
|
|
@@ -4313,43 +4509,40 @@ Connection.prototype.fetch = function(statement, transaction, count, callback) {
|
|
|
4313
4509
|
msg.addInt(0); // message number
|
|
4314
4510
|
msg.addInt(count || DEFAULT_FETCHSIZE); // fetch count
|
|
4315
4511
|
|
|
4316
|
-
if (!transaction) {
|
|
4317
|
-
callback.statement = statement;
|
|
4318
|
-
this._queueEvent(callback);
|
|
4319
|
-
return;
|
|
4320
|
-
}
|
|
4321
|
-
|
|
4322
4512
|
callback.statement = statement;
|
|
4323
4513
|
this._queueEvent(callback);
|
|
4324
4514
|
};
|
|
4325
4515
|
|
|
4326
|
-
Connection.prototype.fetchAll = function(statement, transaction, callback) {
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4516
|
+
Connection.prototype.fetchAll = function (statement, transaction, callback) {
|
|
4517
|
+
var self = this, data = [];
|
|
4518
|
+
var loop = function (err, ret) {
|
|
4519
|
+
if (err) {
|
|
4520
|
+
return callback(err);
|
|
4521
|
+
} else if (ret && ret.data && ret.data.length) {
|
|
4522
|
+
for (var i = 0; i < ret.data.length; i++) {
|
|
4523
|
+
var pos = data.push(ret.data[i]);
|
|
4524
|
+
if (statement.custom && statement.custom.asStream && statement.custom.on) {
|
|
4525
|
+
statement.custom.on(ret.data[i], pos - 1);
|
|
4526
|
+
}
|
|
4527
|
+
if (i === ret.data.length - 1) {
|
|
4528
|
+
if (ret.fetched) {
|
|
4529
|
+
return callback(undefined, data);
|
|
4530
|
+
} else {
|
|
4531
|
+
self.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop);
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
} else if (ret.fetched) {
|
|
4536
|
+
callback(undefined, data);
|
|
4537
|
+
} else {
|
|
4538
|
+
self.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop);
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4349
4541
|
|
|
4350
|
-
|
|
4542
|
+
this.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop);
|
|
4351
4543
|
};
|
|
4352
4544
|
|
|
4545
|
+
|
|
4353
4546
|
Connection.prototype.openBlob = function(blob, transaction, callback) {
|
|
4354
4547
|
var msg = this._msg;
|
|
4355
4548
|
msg.pos = 0;
|