node-firebird 0.9.9 → 1.1.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 +87 -3
- package/lib/index.d.ts +55 -7
- package/lib/index.js +369 -103
- package/lib/serialize.js +3 -2
- package/lib/srp.js +281 -0
- package/package.json +2 -1
- package/.github/workflows/npmpublish.yml +0 -47
- package/git +0 -0
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;
|
|
@@ -1284,7 +1302,9 @@ SQLParamBool.prototype.calcBlr = function(blr) {
|
|
|
1284
1302
|
***************************************/
|
|
1285
1303
|
|
|
1286
1304
|
function isError(obj) {
|
|
1287
|
-
return (
|
|
1305
|
+
return Boolean(
|
|
1306
|
+
obj != null && typeof obj === "object" && !Array.isArray(obj) && obj.status
|
|
1307
|
+
);
|
|
1288
1308
|
}
|
|
1289
1309
|
|
|
1290
1310
|
function doCallback(obj, callback) {
|
|
@@ -2885,17 +2905,40 @@ Pool.prototype.check = function() {
|
|
|
2885
2905
|
return self;
|
|
2886
2906
|
};
|
|
2887
2907
|
|
|
2888
|
-
Pool.prototype.destroy = function() {
|
|
2908
|
+
Pool.prototype.destroy = function(callback) {
|
|
2889
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
|
+
|
|
2890
2931
|
this.internaldb.forEach(function(db) {
|
|
2891
|
-
if (db.connection._pooled === false)
|
|
2932
|
+
if (db.connection._pooled === false) {
|
|
2933
|
+
detachCallback();
|
|
2892
2934
|
return;
|
|
2935
|
+
}
|
|
2893
2936
|
// check if the db is not free into the pool otherwise user should manual detach it
|
|
2894
2937
|
var _db_in_pool = self.pooldb.indexOf(db);
|
|
2895
2938
|
if (_db_in_pool !== -1) {
|
|
2896
2939
|
self.pooldb.splice(_db_in_pool, 1);
|
|
2897
2940
|
db.connection._pooled = false;
|
|
2898
|
-
db.detach();
|
|
2941
|
+
db.detach(detachCallback);
|
|
2899
2942
|
}
|
|
2900
2943
|
});
|
|
2901
2944
|
};
|
|
@@ -2918,6 +2961,7 @@ var Connection = exports.Connection = function (host, port, callback, options, d
|
|
|
2918
2961
|
this._detachAuto;
|
|
2919
2962
|
this._socket = net.createConnection(port, host);
|
|
2920
2963
|
this._pending = [];
|
|
2964
|
+
this._isOpened = false;
|
|
2921
2965
|
this._isClosed = false;
|
|
2922
2966
|
this._isDetach = false;
|
|
2923
2967
|
this._isUsed = false;
|
|
@@ -2925,6 +2969,8 @@ var Connection = exports.Connection = function (host, port, callback, options, d
|
|
|
2925
2969
|
this.options = options;
|
|
2926
2970
|
this._bind_events(host, port, callback);
|
|
2927
2971
|
this.error;
|
|
2972
|
+
this._retry_connection_id;
|
|
2973
|
+
this._retry_connection_interval = options.retryConnectionInterval || 1000;
|
|
2928
2974
|
this._max_cached_query = options.maxCachedQuery || -1;
|
|
2929
2975
|
this._cache_query = options.cacheQuery?{}:null;
|
|
2930
2976
|
this._messageFile = options.messageFile || path.join(__dirname, 'firebird.msg');
|
|
@@ -2950,10 +2996,11 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2950
2996
|
|
|
2951
2997
|
self._socket.on('close', function() {
|
|
2952
2998
|
|
|
2953
|
-
self.
|
|
2954
|
-
|
|
2955
|
-
if (self._isDetach)
|
|
2999
|
+
if (!self._isOpened || self._isDetach) {
|
|
2956
3000
|
return;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
self._isOpened = false;
|
|
2957
3004
|
|
|
2958
3005
|
if (!self.db) {
|
|
2959
3006
|
if (callback)
|
|
@@ -2961,10 +3008,9 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2961
3008
|
return;
|
|
2962
3009
|
}
|
|
2963
3010
|
|
|
2964
|
-
|
|
3011
|
+
self._retry_connection_id = setTimeout(function() {
|
|
3012
|
+
self._socket.removeAllListeners();
|
|
2965
3013
|
self._socket = null;
|
|
2966
|
-
self._msg = null;
|
|
2967
|
-
self._blr = null;
|
|
2968
3014
|
|
|
2969
3015
|
var ctx = new Connection(host, port, function(err) {
|
|
2970
3016
|
ctx.connect(self.options, function(err) {
|
|
@@ -2988,8 +3034,10 @@ exports.Connection.prototype._bind_events = function(host, port, callback) {
|
|
|
2988
3034
|
}, self.db);
|
|
2989
3035
|
});
|
|
2990
3036
|
|
|
3037
|
+
Object.assign(self, ctx);
|
|
3038
|
+
|
|
2991
3039
|
}, self.options, self.db);
|
|
2992
|
-
});
|
|
3040
|
+
}, self._retry_connection_interval);
|
|
2993
3041
|
|
|
2994
3042
|
});
|
|
2995
3043
|
|
|
@@ -3152,6 +3200,8 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3152
3200
|
}
|
|
3153
3201
|
}
|
|
3154
3202
|
|
|
3203
|
+
const arrBlob = [];
|
|
3204
|
+
|
|
3155
3205
|
while (data.fcount && (data.fstatus !== 100)) {
|
|
3156
3206
|
var lowerV13 = statement.connection.accept.protocolVersion < PROTOCOL_VERSION13;
|
|
3157
3207
|
|
|
@@ -3161,10 +3211,16 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3161
3211
|
|
|
3162
3212
|
try {
|
|
3163
3213
|
_xdrpos = data.pos;
|
|
3164
|
-
|
|
3214
|
+
const key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
3215
|
+
const row = data.frows.length;
|
|
3165
3216
|
let value = item.decode(data, lowerV13);
|
|
3166
|
-
if (item.type === SQL_BLOB) {
|
|
3167
|
-
|
|
3217
|
+
if (item.type === SQL_BLOB && value !== null) {
|
|
3218
|
+
if (item.subType === isc_blob_text && cnx.options.blobAsText) {
|
|
3219
|
+
value = fetch_blob_async_transaction(statement, value, key, row);
|
|
3220
|
+
arrBlob.push(value);
|
|
3221
|
+
} else {
|
|
3222
|
+
value = fetch_blob_async(statement, value, key, row);
|
|
3223
|
+
}
|
|
3168
3224
|
}
|
|
3169
3225
|
data.frow[key] = value;
|
|
3170
3226
|
} catch (e) {
|
|
@@ -3197,8 +3253,13 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3197
3253
|
_xdrpos = data.pos;
|
|
3198
3254
|
var key = custom.asObject ? data.fcols[data.fcolumn] : data.fcolumn;
|
|
3199
3255
|
var value = item.decode(data, lowerV13);
|
|
3200
|
-
if (item.type === SQL_BLOB) {
|
|
3201
|
-
|
|
3256
|
+
if (item.type === SQL_BLOB && value !== null) {
|
|
3257
|
+
if (item.subType === isc_blob_text && cnx.options.blobAsText) {
|
|
3258
|
+
value = fetch_blob_async_transaction(statement, value, key, data);
|
|
3259
|
+
arrBlob.push(value);
|
|
3260
|
+
} else {
|
|
3261
|
+
value = fetch_blob_async(statement, value, key);
|
|
3262
|
+
}
|
|
3202
3263
|
}
|
|
3203
3264
|
data.frow[key] = value;
|
|
3204
3265
|
} catch (e) {
|
|
@@ -3211,6 +3272,9 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3211
3272
|
}
|
|
3212
3273
|
|
|
3213
3274
|
data.fcolumn = 0;
|
|
3275
|
+
// ToDo: emit "row" with blob subtype string decoded
|
|
3276
|
+
// use: data.frow['fieldBlob'](transaction?).then(({ value }) => console.log(value))
|
|
3277
|
+
// arg "transaction" is optional
|
|
3214
3278
|
statement.connection.db.emit('row', data.frow, statement.nbrowsfetched, custom.asObject);
|
|
3215
3279
|
data.frows.push(data.frow);
|
|
3216
3280
|
data.frow = custom.asObject ? {} : new Array(output.length);
|
|
@@ -3245,8 +3309,9 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3245
3309
|
statement.nbrowsfetched++;
|
|
3246
3310
|
}
|
|
3247
3311
|
|
|
3248
|
-
|
|
3249
|
-
|
|
3312
|
+
// ToDo: emit "result" with blob subtype string decoded
|
|
3313
|
+
statement.connection.db.emit('result', data.frows, arrBlob);
|
|
3314
|
+
return cb(null, {data: data.frows, fetched: Boolean(!isOpFetch || data.fstatus === 100), arrBlob});
|
|
3250
3315
|
case op_accept:
|
|
3251
3316
|
case op_cond_accept:
|
|
3252
3317
|
case op_accept_data:
|
|
@@ -3255,22 +3320,77 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3255
3320
|
protocolArchitecture: data.readInt(),
|
|
3256
3321
|
protocolMinimumType: data.readInt(),
|
|
3257
3322
|
pluginName: '',
|
|
3258
|
-
authData: ''
|
|
3323
|
+
authData: '',
|
|
3324
|
+
sessionKey: ''
|
|
3259
3325
|
};
|
|
3260
3326
|
|
|
3261
3327
|
accept.protocolMinimumType = accept.protocolMinimumType & 0xFF;
|
|
3328
|
+
//accept.compress = (accept.acceptType & pflag_compress) !== 0; // TODO Handle zlib compression
|
|
3262
3329
|
if (accept.protocolVersion < 0) {
|
|
3263
3330
|
accept.protocolVersion = (accept.protocolVersion & FB_PROTOCOL_MASK) | FB_PROTOCOL_FLAG;
|
|
3264
3331
|
}
|
|
3265
3332
|
|
|
3266
3333
|
if (r === op_cond_accept || r === op_accept_data) {
|
|
3267
|
-
var d = data.
|
|
3334
|
+
var d = new BlrReader(data.readArray());
|
|
3268
3335
|
accept.pluginName = data.readString(DEFAULT_ENCODING);
|
|
3269
3336
|
var is_authenticated = data.readInt();
|
|
3270
3337
|
var keys = data.readString(DEFAULT_ENCODING); // keys
|
|
3271
3338
|
|
|
3272
3339
|
if (is_authenticated === 0) {
|
|
3273
|
-
|
|
3340
|
+
if (cnx.options.pluginName && cnx.options.pluginName !== accept.pluginName) {
|
|
3341
|
+
doError(new Error('Server don\'t accept plugin : ' + cnx.options.pluginName + ', but support : ' + accept.pluginName), callback);
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
if (AUTH_PLUGIN_SRP_LIST.indexOf(accept.pluginName) !== -1) {
|
|
3345
|
+
var crypto = {
|
|
3346
|
+
Srp: 'sha1',
|
|
3347
|
+
Srp256: 'sha256'
|
|
3348
|
+
};
|
|
3349
|
+
accept.srpAlgo = crypto[accept.pluginName];
|
|
3350
|
+
|
|
3351
|
+
// TODO : Fallback Srp256 to Srp ?
|
|
3352
|
+
/*if (!d.buffer) {
|
|
3353
|
+
cnx.sendOpContAuth(
|
|
3354
|
+
cnx.clientKeys.public.toString(16),
|
|
3355
|
+
DEFAULT_ENCODING,
|
|
3356
|
+
accept.pluginName
|
|
3357
|
+
);
|
|
3358
|
+
|
|
3359
|
+
return cb(new Error('login'));
|
|
3360
|
+
}*/
|
|
3361
|
+
|
|
3362
|
+
// Check buffer contains salt
|
|
3363
|
+
var saltLen = d.buffer.readUInt16LE(0);
|
|
3364
|
+
if (saltLen > 32 * 2) {
|
|
3365
|
+
console.log('salt to long'); // TODO : Throw error
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
// Check buffer contains key
|
|
3369
|
+
var keyLen = d.buffer.readUInt16LE(saltLen + 2);
|
|
3370
|
+
var keyStart = saltLen + 4;
|
|
3371
|
+
if (d.buffer.length - keyStart !== keyLen) {
|
|
3372
|
+
console.log('key error'); // TODO : Throw error
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
// Server keys
|
|
3376
|
+
cnx.serverKeys = {
|
|
3377
|
+
salt: d.buffer.slice(2, saltLen + 2).toString('utf8'),
|
|
3378
|
+
public: BigInt(d.buffer.slice(keyStart, d.buffer.length).toString('utf8'), 16)
|
|
3379
|
+
};
|
|
3380
|
+
|
|
3381
|
+
var proof = srp.clientProof(
|
|
3382
|
+
cnx.options.user.toUpperCase(),
|
|
3383
|
+
cnx.options.password,
|
|
3384
|
+
cnx.serverKeys.salt,
|
|
3385
|
+
cnx.clientKeys.public,
|
|
3386
|
+
cnx.serverKeys.public,
|
|
3387
|
+
cnx.clientKeys.private,
|
|
3388
|
+
accept.srpAlgo
|
|
3389
|
+
);
|
|
3390
|
+
|
|
3391
|
+
accept.authData = proof.authData.toString(16);
|
|
3392
|
+
accept.sessionKey = proof.clientSessionKey;
|
|
3393
|
+
} else if (accept.pluginName === AUTH_PLUGIN_LEGACY) {
|
|
3274
3394
|
accept.authData = crypt.crypt(cnx.options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3275
3395
|
} else {
|
|
3276
3396
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
@@ -3280,7 +3400,35 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3280
3400
|
accept.sessionKey = '';
|
|
3281
3401
|
}
|
|
3282
3402
|
}
|
|
3403
|
+
|
|
3283
3404
|
return cb(undefined, accept);
|
|
3405
|
+
case op_cont_auth:
|
|
3406
|
+
var d = new BlrReader(data.readArray());
|
|
3407
|
+
var pluginName = data.readString(DEFAULT_ENCODING);
|
|
3408
|
+
data.readString(DEFAULT_ENCODING); // plist
|
|
3409
|
+
data.readString(DEFAULT_ENCODING); // pkey
|
|
3410
|
+
|
|
3411
|
+
if (!cnx.options.pluginName) {
|
|
3412
|
+
if (cnx.accept.pluginName === pluginName) {
|
|
3413
|
+
// Erreur plugin not able to connect
|
|
3414
|
+
return cb(new Error("Unable to connect with plugin " + cnx.accept.pluginName));
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3417
|
+
if (pluginName === AUTH_PLUGIN_LEGACY) { // Fallback to LegacyAuth
|
|
3418
|
+
cnx.accept.pluginName = pluginName;
|
|
3419
|
+
cnx.accept.authData = crypt.crypt(cnx.options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3420
|
+
|
|
3421
|
+
cnx.sendOpContAuth(
|
|
3422
|
+
cnx.accept.authData,
|
|
3423
|
+
DEFAULT_ENCODING,
|
|
3424
|
+
pluginName
|
|
3425
|
+
);
|
|
3426
|
+
|
|
3427
|
+
return {error: new Error('login')};
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
return data.accept;
|
|
3284
3432
|
default:
|
|
3285
3433
|
return cb(new Error('Unexpected:' + r));
|
|
3286
3434
|
}
|
|
@@ -3366,6 +3514,20 @@ function parseOpResponse(data, response, cb) {
|
|
|
3366
3514
|
}
|
|
3367
3515
|
}
|
|
3368
3516
|
|
|
3517
|
+
Connection.prototype.sendOpContAuth = function(authData, authDataEnc, pluginName) {
|
|
3518
|
+
var msg = this._msg;
|
|
3519
|
+
msg.pos = 0;
|
|
3520
|
+
|
|
3521
|
+
msg.addInt(op_cont_auth);
|
|
3522
|
+
msg.addString(authData, authDataEnc);
|
|
3523
|
+
msg.addString(pluginName, DEFAULT_ENCODING)
|
|
3524
|
+
msg.addString(AUTH_PLUGIN_LIST.join(','), DEFAULT_ENCODING);
|
|
3525
|
+
// msg.addInt(0); // p_list
|
|
3526
|
+
msg.addInt(0); // keys
|
|
3527
|
+
|
|
3528
|
+
this._socket.write(msg.getData());
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3369
3531
|
Connection.prototype._queueEvent = function(callback){
|
|
3370
3532
|
var self = this;
|
|
3371
3533
|
|
|
@@ -3380,7 +3542,7 @@ Connection.prototype._queueEvent = function(callback){
|
|
|
3380
3542
|
};
|
|
3381
3543
|
|
|
3382
3544
|
Connection.prototype.connect = function (options, callback) {
|
|
3383
|
-
var pluginName = AUTH_PLUGIN_LEGACY;
|
|
3545
|
+
var pluginName = options.manager ? AUTH_PLUGIN_LEGACY : options.pluginName || AUTH_PLUGIN_LIST[0]; // TODO Srp for service
|
|
3384
3546
|
var msg = this._msg;
|
|
3385
3547
|
var blr = this._blr;
|
|
3386
3548
|
|
|
@@ -3393,13 +3555,19 @@ Connection.prototype.connect = function (options, callback) {
|
|
|
3393
3555
|
blr.addString(CNCT_plugin_name, pluginName, DEFAULT_ENCODING);
|
|
3394
3556
|
blr.addString(CNCT_plugin_list, AUTH_PLUGIN_LIST.join(','), DEFAULT_ENCODING);
|
|
3395
3557
|
|
|
3396
|
-
|
|
3397
|
-
|
|
3558
|
+
var specificData = '';
|
|
3559
|
+
if (AUTH_PLUGIN_SRP_LIST.indexOf(pluginName) > -1) {
|
|
3560
|
+
this.clientKeys = srp.clientSeed();
|
|
3561
|
+
specificData = this.clientKeys.public.toString(16);
|
|
3562
|
+
blr.addMultiblockPart(CNCT_specific_data, specificData, DEFAULT_ENCODING);
|
|
3563
|
+
} else if (pluginName === AUTH_PLUGIN_LEGACY) {
|
|
3564
|
+
specificData = crypt.crypt(options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3398
3565
|
blr.addMultiblockPart(CNCT_specific_data, specificData, DEFAULT_ENCODING);
|
|
3399
3566
|
} else {
|
|
3400
|
-
|
|
3567
|
+
doError(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
3568
|
+
return;
|
|
3401
3569
|
}
|
|
3402
|
-
blr.addBytes([CNCT_client_crypt, 4,
|
|
3570
|
+
blr.addBytes([CNCT_client_crypt, 4, WIRE_CRYPT_DISABLE, 0, 0, 0]); // WireCrypt = Disabled
|
|
3403
3571
|
blr.addString(CNCT_user, os.userInfo().username || 'Unknown', DEFAULT_ENCODING);
|
|
3404
3572
|
blr.addString(CNCT_host, os.hostname(), DEFAULT_ENCODING);
|
|
3405
3573
|
blr.addBytes([CNCT_user_verification, 0]);
|
|
@@ -3454,15 +3622,18 @@ Connection.prototype.attach = function (options, callback, db) {
|
|
|
3454
3622
|
blr.pos = 0;
|
|
3455
3623
|
|
|
3456
3624
|
blr.addByte(isc_dpb_version1);
|
|
3457
|
-
blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING);
|
|
3625
|
+
blr.addString(isc_dpb_lc_ctype, options.encoding || 'UTF8', DEFAULT_ENCODING);
|
|
3458
3626
|
blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING);
|
|
3459
|
-
if (this.accept.
|
|
3460
|
-
if (this.accept.protocolVersion
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3627
|
+
if (options.password && !this.accept.authData) {
|
|
3628
|
+
if (this.accept.protocolVersion < PROTOCOL_VERSION13) {
|
|
3629
|
+
if (this.accept.protocolVersion === PROTOCOL_VERSION10) {
|
|
3630
|
+
blr.addString(isc_dpb_password, password, DEFAULT_ENCODING);
|
|
3631
|
+
} else {
|
|
3632
|
+
blr.addString(isc_dpb_password_enc, crypt.crypt(password, LEGACY_AUTH_SALT).substring(2), DEFAULT_ENCODING);
|
|
3633
|
+
}
|
|
3464
3634
|
}
|
|
3465
3635
|
}
|
|
3636
|
+
|
|
3466
3637
|
if (role)
|
|
3467
3638
|
blr.addString(isc_dpb_sql_role_name, role, DEFAULT_ENCODING);
|
|
3468
3639
|
|
|
@@ -3522,6 +3693,7 @@ Connection.prototype.detach = function (callback) {
|
|
|
3522
3693
|
msg.addInt(0); // Database Object ID
|
|
3523
3694
|
|
|
3524
3695
|
self._queueEvent(function(err, ret) {
|
|
3696
|
+
clearTimeout(self._retry_connection_id);
|
|
3525
3697
|
delete(self.dbhandle);
|
|
3526
3698
|
if (callback)
|
|
3527
3699
|
callback(err, ret);
|
|
@@ -4258,63 +4430,129 @@ Connection.prototype.sendExecute = function (op, statement, transaction, callbac
|
|
|
4258
4430
|
this._queueEvent(callback);
|
|
4259
4431
|
}
|
|
4260
4432
|
|
|
4261
|
-
function
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4433
|
+
function fetch_blob_async_transaction(statement, id, name, row) {
|
|
4434
|
+
const infoValue = {
|
|
4435
|
+
row,
|
|
4436
|
+
column: name,
|
|
4437
|
+
value: ''
|
|
4438
|
+
};
|
|
4265
4439
|
|
|
4266
|
-
return
|
|
4267
|
-
|
|
4268
|
-
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, function(err, transaction) {
|
|
4440
|
+
return (transactionArg) => {
|
|
4441
|
+
const singleTransaction = transactionArg === undefined;
|
|
4269
4442
|
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4443
|
+
let promiseTransaction;
|
|
4444
|
+
if (singleTransaction) {
|
|
4445
|
+
promiseTransaction = new Promise((resolve, reject) => {
|
|
4446
|
+
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
4447
|
+
if (err) {
|
|
4448
|
+
return reject(err);
|
|
4449
|
+
}
|
|
4450
|
+
resolve(transaction);
|
|
4451
|
+
});
|
|
4452
|
+
});
|
|
4453
|
+
} else {
|
|
4454
|
+
promiseTransaction = Promise.resolve(transactionArg);
|
|
4455
|
+
}
|
|
4274
4456
|
|
|
4275
|
-
|
|
4276
|
-
|
|
4457
|
+
return promiseTransaction.then((transaction) => {
|
|
4458
|
+
return new Promise((resolve, reject) => {
|
|
4459
|
+
statement.connection._pending.push('openBlob');
|
|
4460
|
+
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
4461
|
+
|
|
4462
|
+
if (err) {
|
|
4463
|
+
reject(err);
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
const read = () => {
|
|
4468
|
+
statement.connection.getSegment(blob, (err, ret) => {
|
|
4469
|
+
|
|
4470
|
+
if (err) {
|
|
4471
|
+
if (singleTransaction) {
|
|
4472
|
+
transaction.rollback(() => reject(err));
|
|
4473
|
+
} else {
|
|
4474
|
+
reject(err);
|
|
4475
|
+
}
|
|
4476
|
+
return;
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4479
|
+
if (ret.buffer) {
|
|
4480
|
+
const blr = new BlrReader(ret.buffer);
|
|
4481
|
+
const data = blr.readSegment();
|
|
4482
|
+
infoValue.value += data.toString(DEFAULT_ENCODING);
|
|
4483
|
+
}
|
|
4484
|
+
|
|
4485
|
+
if (ret.handle !== 2) {
|
|
4486
|
+
read();
|
|
4487
|
+
return;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
statement.connection.closeBlob(blob);
|
|
4491
|
+
if (singleTransaction) {
|
|
4492
|
+
transaction.commit((err) => {
|
|
4493
|
+
if (err) {
|
|
4494
|
+
reject(err);
|
|
4495
|
+
} else {
|
|
4496
|
+
resolve(infoValue);
|
|
4497
|
+
}
|
|
4498
|
+
});
|
|
4499
|
+
} else {
|
|
4500
|
+
resolve(infoValue);
|
|
4501
|
+
}
|
|
4502
|
+
});
|
|
4503
|
+
};
|
|
4504
|
+
|
|
4505
|
+
read();
|
|
4506
|
+
});
|
|
4507
|
+
});
|
|
4508
|
+
});
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4277
4511
|
|
|
4278
|
-
|
|
4512
|
+
function fetch_blob_async(statement, id, name, row) {
|
|
4513
|
+
const cbTransaction = (transaction, close, callback) => {
|
|
4514
|
+
statement.connection._pending.push('openBlob');
|
|
4515
|
+
statement.connection.openBlob(id, transaction, (err, blob) => {
|
|
4516
|
+
let e = new Events.EventEmitter();
|
|
4279
4517
|
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4518
|
+
e.pipe = (stream) => {
|
|
4519
|
+
e.on('data', (chunk) => {
|
|
4520
|
+
stream.write(chunk);
|
|
4521
|
+
});
|
|
4522
|
+
e.on('end', () => {
|
|
4523
|
+
stream.end();
|
|
4524
|
+
});
|
|
4525
|
+
};
|
|
4288
4526
|
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
}
|
|
4527
|
+
if (err) {
|
|
4528
|
+
return callback(err, name, e, row);
|
|
4529
|
+
}
|
|
4293
4530
|
|
|
4294
|
-
|
|
4295
|
-
|
|
4531
|
+
const read = () => {
|
|
4532
|
+
statement.connection.getSegment(blob, (err, ret) => {
|
|
4296
4533
|
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4534
|
+
if (err) {
|
|
4535
|
+
transaction.rollback(() => {
|
|
4536
|
+
e.emit('error', err);
|
|
4537
|
+
});
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4303
4540
|
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4541
|
+
if (ret.buffer) {
|
|
4542
|
+
const blr = new BlrReader(ret.buffer);
|
|
4543
|
+
const data = blr.readSegment();
|
|
4307
4544
|
|
|
4308
|
-
|
|
4309
|
-
|
|
4545
|
+
e.emit('data', data);
|
|
4546
|
+
}
|
|
4310
4547
|
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4548
|
+
if (ret.handle !== 2) {
|
|
4549
|
+
read();
|
|
4550
|
+
return;
|
|
4551
|
+
}
|
|
4315
4552
|
|
|
4316
|
-
|
|
4317
|
-
|
|
4553
|
+
statement.connection.closeBlob(blob);
|
|
4554
|
+
if (close) {
|
|
4555
|
+
transaction.commit((err) => {
|
|
4318
4556
|
if (err) {
|
|
4319
4557
|
e.emit('error', err);
|
|
4320
4558
|
} else {
|
|
@@ -4322,15 +4560,33 @@ function fetch_blob_async(statement, id, name) {
|
|
|
4322
4560
|
}
|
|
4323
4561
|
e = null;
|
|
4324
4562
|
});
|
|
4563
|
+
} else {
|
|
4564
|
+
e.emit('end');
|
|
4565
|
+
e = null;
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
};
|
|
4325
4569
|
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
read();
|
|
4570
|
+
callback(err, name, e, row);
|
|
4571
|
+
read();
|
|
4572
|
+
});
|
|
4573
|
+
};
|
|
4331
4574
|
|
|
4575
|
+
return (transaction, callback) => {
|
|
4576
|
+
// callback(error, nameField, eventEmitter, row)
|
|
4577
|
+
const singleTransaction = callback === undefined;
|
|
4578
|
+
if (singleTransaction) {
|
|
4579
|
+
callback = transaction;
|
|
4580
|
+
statement.connection.startTransaction(ISOLATION_READ_UNCOMMITTED, (err, transaction) => {
|
|
4581
|
+
if (err) {
|
|
4582
|
+
callback(err);
|
|
4583
|
+
return;
|
|
4584
|
+
}
|
|
4585
|
+
cbTransaction(transaction, singleTransaction, callback);
|
|
4332
4586
|
});
|
|
4333
|
-
}
|
|
4587
|
+
} else {
|
|
4588
|
+
cbTransaction(transaction, singleTransaction, callback);
|
|
4589
|
+
}
|
|
4334
4590
|
};
|
|
4335
4591
|
}
|
|
4336
4592
|
|
|
@@ -4359,24 +4615,34 @@ Connection.prototype.fetch = function(statement, transaction, count, callback) {
|
|
|
4359
4615
|
};
|
|
4360
4616
|
|
|
4361
4617
|
Connection.prototype.fetchAll = function (statement, transaction, callback) {
|
|
4362
|
-
|
|
4363
|
-
|
|
4618
|
+
const self = this, data = [];
|
|
4619
|
+
const loop = (err, ret) => {
|
|
4364
4620
|
if (err) {
|
|
4365
4621
|
return callback(err);
|
|
4366
4622
|
} else if (ret && ret.data && ret.data.length) {
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4623
|
+
const arrPromise = (ret.arrBlob || []).map(value => value(transaction));
|
|
4624
|
+
|
|
4625
|
+
Promise.all(arrPromise).then((arrBlob) => {
|
|
4626
|
+
for (let i = 0; i < arrBlob.length; i++) {
|
|
4627
|
+
const blob = arrBlob[i];
|
|
4628
|
+
ret.data[blob.row][blob.column] = blob.value;
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
const lastIndex = ret.data.length - 1;
|
|
4632
|
+
for (let i = 0; i < ret.data.length; i++) {
|
|
4633
|
+
const pos = data.push(ret.data[i]);
|
|
4634
|
+
if (statement.custom && statement.custom.asStream && statement.custom.on) {
|
|
4635
|
+
statement.custom.on(ret.data[i], pos - 1);
|
|
4636
|
+
}
|
|
4637
|
+
if (i === lastIndex) {
|
|
4638
|
+
if (ret.fetched) {
|
|
4639
|
+
return callback(undefined, data);
|
|
4640
|
+
} else {
|
|
4641
|
+
self.fetch(statement, transaction, DEFAULT_FETCHSIZE, loop);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
}).catch(callback);
|
|
4380
4646
|
} else if (ret.fetched) {
|
|
4381
4647
|
callback(undefined, data);
|
|
4382
4648
|
} else {
|