node-firebird 0.9.9 → 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 +19 -3
- package/lib/index.d.ts +22 -7
- package/lib/index.js +184 -29
- 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
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ${{ matrix.os }}
|
|
8
|
+
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
os: [ubuntu-16.04, ubuntu-18.04, windows-2019, macos-10.15]
|
|
12
|
+
node-version: [10.x, 12.x, 14.x, 15.x]
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v1
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 10
|
|
18
|
+
|
|
19
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
20
|
+
uses: actions/setup-node@v1
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
|
|
24
|
+
- name: Firebird install (Linux)
|
|
25
|
+
if: matrix.os == 'ubuntu-16.04' || matrix.os == 'ubuntu-18.04'
|
|
26
|
+
run: |
|
|
27
|
+
if [ `lsb_release -rs` = '16.04' ]
|
|
28
|
+
then
|
|
29
|
+
sudo apt-get install libtommath0
|
|
30
|
+
else
|
|
31
|
+
sudo apt-get install libtommath1
|
|
32
|
+
sudo ln -s /usr/lib/x86_64-linux-gnu/libtommath.so.1 /usr/lib/x86_64-linux-gnu/libtommath.so.0
|
|
33
|
+
fi
|
|
34
|
+
wget -nv -O Firebird-3.0.7.33374-0.amd64.tar.gz "https://github.com/FirebirdSQL/firebird/releases/download/R3_0_7/Firebird-3.0.7.33374-0.amd64.tar.gz"
|
|
35
|
+
tar xzvf Firebird-3.0.7.33374-0.amd64.tar.gz
|
|
36
|
+
(cd Firebird-3.0.7.33374-0.amd64; sudo ./install.sh -silent)
|
|
37
|
+
sudo usermod -a -G firebird `whoami`
|
|
38
|
+
|
|
39
|
+
- name: Firebird install (MacOS)
|
|
40
|
+
if: matrix.os == 'macos-10.15'
|
|
41
|
+
run: |
|
|
42
|
+
wget -nv -O Firebird-3.0.7-33374-x86_64.pkg "https://github.com/FirebirdSQL/firebird/releases/download/R3_0_7/Firebird-3.0.7-33374-x86_64.pkg"
|
|
43
|
+
sudo installer -verbose -pkg "Firebird-3.0.7-33374-x86_64.pkg" -target /
|
|
44
|
+
|
|
45
|
+
- name: Firebird install (Windows)
|
|
46
|
+
if: matrix.os == 'windows-2019'
|
|
47
|
+
shell: cmd
|
|
48
|
+
run: |
|
|
49
|
+
set FB_ZIP=Firebird-3.0.7.33374-1_x64.zip
|
|
50
|
+
powershell Invoke-WebRequest "https://github.com/FirebirdSQL/firebird/releases/download/R3_0_7/$env:FB_ZIP" -OutFile "$env:FB_ZIP"
|
|
51
|
+
7z x -oC:\Firebird %FB_ZIP%
|
|
52
|
+
|
|
53
|
+
- name: Build
|
|
54
|
+
shell: bash
|
|
55
|
+
run: |
|
|
56
|
+
npm ci
|
|
57
|
+
|
|
58
|
+
- name: Test (Linux)
|
|
59
|
+
if: matrix.os == 'ubuntu-16.04' || matrix.os == 'ubuntu-18.04'
|
|
60
|
+
run: |
|
|
61
|
+
sg firebird -c "npx nyc npm test"
|
|
62
|
+
|
|
63
|
+
- name: Test (MacOS)
|
|
64
|
+
if: matrix.os == 'macos-10.15'
|
|
65
|
+
run: |
|
|
66
|
+
sudo mkdir `pwd`/tmp-node-fb
|
|
67
|
+
sudo chmod 777 `pwd`/tmp-node-fb
|
|
68
|
+
export ISC_USER=sysdba
|
|
69
|
+
export ISC_PASSWORD=masterkey
|
|
70
|
+
export NODE_FB_TEST_TMP_DIR=`pwd`/tmp-node-fb
|
|
71
|
+
npx nyc npm test
|
|
72
|
+
|
|
73
|
+
- name: Test (Windows)
|
|
74
|
+
if: matrix.os == 'windows-2019'
|
|
75
|
+
shell: cmd
|
|
76
|
+
run: |
|
|
77
|
+
set PATH=C:\Firebird;%PATH%
|
|
78
|
+
call npx nyc npm test
|
package/README.md
CHANGED
|
@@ -66,7 +66,8 @@ options.password = 'masterkey';
|
|
|
66
66
|
options.lowercase_keys = false; // set to true to lowercase keys
|
|
67
67
|
options.role = null; // default
|
|
68
68
|
options.pageSize = 4096; // default when creating database
|
|
69
|
-
|
|
69
|
+
options.pageSize = 4096; // default when creating database
|
|
70
|
+
options.retryConnectionInterval = 1000; // reconnect interval in case of connection drop
|
|
70
71
|
```
|
|
71
72
|
|
|
72
73
|
### Classic
|
|
@@ -183,7 +184,7 @@ Firebird.attach(options, function(err, db) {
|
|
|
183
184
|
});
|
|
184
185
|
```
|
|
185
186
|
|
|
186
|
-
### Reading Blobs (
|
|
187
|
+
### Reading Blobs (Asynchronous)
|
|
187
188
|
|
|
188
189
|
```js
|
|
189
190
|
Firebird.attach(options, function(err, db) {
|
|
@@ -513,7 +514,7 @@ This is why you should use **Firebird 2.5** server at least.
|
|
|
513
514
|
### Firebird 3.0 Support
|
|
514
515
|
|
|
515
516
|
Firebird new wire protocol is not supported yet so
|
|
516
|
-
for Firebird 3.0 you need to add the following in firebird.conf according to Firebird
|
|
517
|
+
for Firebird 3.0 you need to add the following in firebird.conf according to Firebird 3 release notes
|
|
517
518
|
<https://firebirdsql.org/file/documentation/release_notes/html/en/3_0/rnfb30-security-new-authentication.html>
|
|
518
519
|
|
|
519
520
|
```bash
|
|
@@ -522,6 +523,21 @@ WireCrypt = Disabled
|
|
|
522
523
|
UserManager = Legacy_UserManager
|
|
523
524
|
```
|
|
524
525
|
|
|
526
|
+
Firebird 4 wire protocol is not supported yet so
|
|
527
|
+
for Firebird 4.0 you need to add the following in firebird.conf according to Firebird release notes
|
|
528
|
+
<https://firebirdsql.org/file/documentation/release_notes/html/en/4_0/rlsnotes40.html#rnfb40-config-srp256>
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
AuthServer = Srp256, Srp, Legacy_Auth
|
|
532
|
+
WireCrypt = Disabled
|
|
533
|
+
UserManager = Legacy_UserManager
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
Please read also Authorization with Firebird 2.5 client library from Firebird 4 migration guide
|
|
537
|
+
<https://ib-aid.com/download/docs/fb4migrationguide.html#_authorization_with_firebird_2_5_client_library_fbclient_dll>
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
525
541
|
## Contributors
|
|
526
542
|
|
|
527
543
|
- Henri Gourvest, <https://github.com/hgourvest>
|
package/lib/index.d.ts
CHANGED
|
@@ -9,9 +9,23 @@ declare module 'node-firebird' {
|
|
|
9
9
|
type SimpleCallback = (err: any) => void;
|
|
10
10
|
type SequentialCallback = (row: any, index: number) => void;
|
|
11
11
|
|
|
12
|
+
export const AUTH_PLUGIN_LEGACY: string;
|
|
13
|
+
export const AUTH_PLUGIN_SRP: string;
|
|
14
|
+
export const AUTH_PLUGIN_SRP256: string;
|
|
15
|
+
|
|
16
|
+
export const WIRE_CRYPT_ENABLE: number;
|
|
17
|
+
export const WIRE_CRYPT_DISABLE: number;
|
|
18
|
+
|
|
19
|
+
/** A transaction sees changes done by uncommitted transactions. */
|
|
12
20
|
export const ISOLATION_READ_UNCOMMITTED: number[];
|
|
21
|
+
/** A transaction sees only data committed before the statement has been executed. */
|
|
13
22
|
export const ISOLATION_READ_COMMITED: number[];
|
|
23
|
+
/** A transaction sees during its lifetime only data committed before the transaction has been started. */
|
|
14
24
|
export const ISOLATION_REPEATABLE_READ: number[];
|
|
25
|
+
/**
|
|
26
|
+
* This is the strictest isolation level, which enforces transaction serialization.
|
|
27
|
+
* Data accessed in the context of a serializable transaction cannot be accessed by any other transaction.
|
|
28
|
+
*/
|
|
15
29
|
export const ISOLATION_SERIALIZABLE: number[];
|
|
16
30
|
export const ISOLATION_READ_COMMITED_READ_ONLY: number[];
|
|
17
31
|
|
|
@@ -46,6 +60,7 @@ declare module 'node-firebird' {
|
|
|
46
60
|
lowercase_keys?: boolean;
|
|
47
61
|
role?: string;
|
|
48
62
|
pageSize?: number;
|
|
63
|
+
retryConnectionInterval?: number;
|
|
49
64
|
}
|
|
50
65
|
|
|
51
66
|
export interface SvcMgrOptions extends Options {
|
|
@@ -54,12 +69,12 @@ declare module 'node-firebird' {
|
|
|
54
69
|
|
|
55
70
|
export interface ConnectionPool {
|
|
56
71
|
get(callback: DatabaseCallback): void;
|
|
57
|
-
destroy(): void;
|
|
72
|
+
destroy(callback?: SimpleCallback): void;
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
export function attach(options: Options, callback: DatabaseCallback): void;
|
|
61
76
|
export function attach(options: SvcMgrOptions, callback: ServiceManagerCallback): void;
|
|
62
|
-
export function escape(value: any, protocolVersion
|
|
77
|
+
export function escape(value: any, protocolVersion?: number /*PROTOCOL_VERSION13*/): string;
|
|
63
78
|
export function create(options: Options, callback: DatabaseCallback): void;
|
|
64
79
|
export function attachOrCreate(options: Options, callback: DatabaseCallback): void;
|
|
65
80
|
export function pool(max: number, options: Options): ConnectionPool;
|
|
@@ -207,18 +222,18 @@ declare module 'node-firebird' {
|
|
|
207
222
|
backup(options: BackupOptions, callback: ReadableCallback): void;
|
|
208
223
|
nbackup(options: BackupOptions, callback: ReadableCallback): void;
|
|
209
224
|
restore(options: NRestoreOptions, callback: ReadableCallback): void;
|
|
210
|
-
nrestore(options, callback): void;
|
|
225
|
+
nrestore(options: any, callback: Function): void;
|
|
211
226
|
setDialect(db: string, dialect: 1 | 3, callback: ReadableCallback): void;
|
|
212
|
-
setSweepinterval(db: string, interval: number, callback): void; // gfix -h INTERVAL
|
|
213
|
-
setCachebuffer(db: string, nbpages, callback: ReadableCallback): void; // gfix -b NBPAGES
|
|
227
|
+
setSweepinterval(db: string, interval: number, callback: Function): void; // gfix -h INTERVAL
|
|
228
|
+
setCachebuffer(db: string, nbpages: any, callback: ReadableCallback): void; // gfix -b NBPAGES
|
|
214
229
|
BringOnline(db: string, callback: ReadableCallback): void; // gfix -o
|
|
215
230
|
Shutdown(db: string, kind: ShutdownKind, delay: number, mode: ShutdownMode, callback: ReadableCallback): void; // server version >= 2.0
|
|
216
231
|
Shutdown(db: string, kind: ShutdownKind, delay: number, callback: ReadableCallback): void; // server version < 2.0
|
|
217
232
|
setShadow(db: string, val: boolean, callback: ReadableCallback): void;
|
|
218
233
|
setForcewrite(db: string, val: boolean, callback: ReadableCallback): void; // gfix -write
|
|
219
234
|
setReservespace(db: string, val: boolean, callback: ReadableCallback): void; // true: gfix -use reserve, false: gfix -use full
|
|
220
|
-
setReadonlyMode(db: string, callback: ReadableCallback): void; // gfix -mode read_only
|
|
221
|
-
setReadwriteMode(db: string, callback: ReadableCallback): void; // gfix -mode read_write
|
|
235
|
+
setReadonlyMode(db: string, callback: ReadableCallback): void; // gfix -mode read_only
|
|
236
|
+
setReadwriteMode(db: string, callback: ReadableCallback): void; // gfix -mode read_write
|
|
222
237
|
validate(options: ValidateOptions, callback: ReadableCallback): void; // gfix -validate
|
|
223
238
|
commit(db: string, transactid: number, callback: ReadableCallback): void; // gfix -commit
|
|
224
239
|
rollback(db: string, transactid: number, callback: ReadableCallback): void;
|
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
|
|
|
@@ -3255,22 +3303,77 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3255
3303
|
protocolArchitecture: data.readInt(),
|
|
3256
3304
|
protocolMinimumType: data.readInt(),
|
|
3257
3305
|
pluginName: '',
|
|
3258
|
-
authData: ''
|
|
3306
|
+
authData: '',
|
|
3307
|
+
sessionKey: ''
|
|
3259
3308
|
};
|
|
3260
3309
|
|
|
3261
3310
|
accept.protocolMinimumType = accept.protocolMinimumType & 0xFF;
|
|
3311
|
+
//accept.compress = (accept.acceptType & pflag_compress) !== 0; // TODO Handle zlib compression
|
|
3262
3312
|
if (accept.protocolVersion < 0) {
|
|
3263
3313
|
accept.protocolVersion = (accept.protocolVersion & FB_PROTOCOL_MASK) | FB_PROTOCOL_FLAG;
|
|
3264
3314
|
}
|
|
3265
3315
|
|
|
3266
3316
|
if (r === op_cond_accept || r === op_accept_data) {
|
|
3267
|
-
var d = data.
|
|
3317
|
+
var d = new BlrReader(data.readArray());
|
|
3268
3318
|
accept.pluginName = data.readString(DEFAULT_ENCODING);
|
|
3269
3319
|
var is_authenticated = data.readInt();
|
|
3270
3320
|
var keys = data.readString(DEFAULT_ENCODING); // keys
|
|
3271
3321
|
|
|
3272
3322
|
if (is_authenticated === 0) {
|
|
3273
|
-
|
|
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) {
|
|
3274
3377
|
accept.authData = crypt.crypt(cnx.options.password, LEGACY_AUTH_SALT).substring(2);
|
|
3275
3378
|
} else {
|
|
3276
3379
|
return cb(new Error('Unknow auth plugin : ' + accept.pluginName));
|
|
@@ -3280,7 +3383,35 @@ function decodeResponse(data, callback, cnx, lowercase_keys, cb) {
|
|
|
3280
3383
|
accept.sessionKey = '';
|
|
3281
3384
|
}
|
|
3282
3385
|
}
|
|
3386
|
+
|
|
3283
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;
|
|
3284
3415
|
default:
|
|
3285
3416
|
return cb(new Error('Unexpected:' + r));
|
|
3286
3417
|
}
|
|
@@ -3366,6 +3497,20 @@ function parseOpResponse(data, response, cb) {
|
|
|
3366
3497
|
}
|
|
3367
3498
|
}
|
|
3368
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
|
+
|
|
3369
3514
|
Connection.prototype._queueEvent = function(callback){
|
|
3370
3515
|
var self = this;
|
|
3371
3516
|
|
|
@@ -3380,7 +3525,7 @@ Connection.prototype._queueEvent = function(callback){
|
|
|
3380
3525
|
};
|
|
3381
3526
|
|
|
3382
3527
|
Connection.prototype.connect = function (options, callback) {
|
|
3383
|
-
var pluginName = AUTH_PLUGIN_LEGACY;
|
|
3528
|
+
var pluginName = options.manager ? AUTH_PLUGIN_LEGACY : options.pluginName || AUTH_PLUGIN_LIST[0]; // TODO Srp for service
|
|
3384
3529
|
var msg = this._msg;
|
|
3385
3530
|
var blr = this._blr;
|
|
3386
3531
|
|
|
@@ -3393,13 +3538,19 @@ Connection.prototype.connect = function (options, callback) {
|
|
|
3393
3538
|
blr.addString(CNCT_plugin_name, pluginName, DEFAULT_ENCODING);
|
|
3394
3539
|
blr.addString(CNCT_plugin_list, AUTH_PLUGIN_LIST.join(','), DEFAULT_ENCODING);
|
|
3395
3540
|
|
|
3396
|
-
|
|
3397
|
-
|
|
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);
|
|
3398
3548
|
blr.addMultiblockPart(CNCT_specific_data, specificData, DEFAULT_ENCODING);
|
|
3399
3549
|
} else {
|
|
3400
|
-
|
|
3550
|
+
doError(new Error('Invalide auth plugin \'' + pluginName + '\''), callback);
|
|
3551
|
+
return;
|
|
3401
3552
|
}
|
|
3402
|
-
blr.addBytes([CNCT_client_crypt, 4,
|
|
3553
|
+
blr.addBytes([CNCT_client_crypt, 4, WIRE_CRYPT_DISABLE, 0, 0, 0]); // WireCrypt = Disabled
|
|
3403
3554
|
blr.addString(CNCT_user, os.userInfo().username || 'Unknown', DEFAULT_ENCODING);
|
|
3404
3555
|
blr.addString(CNCT_host, os.hostname(), DEFAULT_ENCODING);
|
|
3405
3556
|
blr.addBytes([CNCT_user_verification, 0]);
|
|
@@ -3456,13 +3607,16 @@ Connection.prototype.attach = function (options, callback, db) {
|
|
|
3456
3607
|
blr.addByte(isc_dpb_version1);
|
|
3457
3608
|
blr.addString(isc_dpb_lc_ctype, 'UTF8', DEFAULT_ENCODING);
|
|
3458
3609
|
blr.addString(isc_dpb_user_name, user, DEFAULT_ENCODING);
|
|
3459
|
-
if (this.accept.
|
|
3460
|
-
if (this.accept.protocolVersion
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
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
|
+
}
|
|
3464
3617
|
}
|
|
3465
3618
|
}
|
|
3619
|
+
|
|
3466
3620
|
if (role)
|
|
3467
3621
|
blr.addString(isc_dpb_sql_role_name, role, DEFAULT_ENCODING);
|
|
3468
3622
|
|
|
@@ -3522,6 +3676,7 @@ Connection.prototype.detach = function (callback) {
|
|
|
3522
3676
|
msg.addInt(0); // Database Object ID
|
|
3523
3677
|
|
|
3524
3678
|
self._queueEvent(function(err, ret) {
|
|
3679
|
+
clearTimeout(self._retry_connection_id);
|
|
3525
3680
|
delete(self.dbhandle);
|
|
3526
3681
|
if (callback)
|
|
3527
3682
|
callback(err, ret);
|
package/lib/serialize.js
CHANGED
|
@@ -111,11 +111,11 @@ BlrWriter.prototype.addBuffer = function (b) {
|
|
|
111
111
|
|
|
112
112
|
BlrWriter.prototype.addString2 = function (c, s, encoding) {
|
|
113
113
|
this.addByte(c);
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
var len = Buffer.byteLength(s, encoding);
|
|
116
116
|
if (len > MAX_STRING_SIZE* MAX_STRING_SIZE)
|
|
117
117
|
throw new Error('blr string is too big');
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
this.ensure(len + 2);
|
|
120
120
|
this.buffer.writeUInt16LE(len, this.pos);
|
|
121
121
|
this.pos += 2;
|
|
@@ -135,6 +135,7 @@ BlrWriter.prototype.addMultiblockPart = function (c, s, encoding) {
|
|
|
135
135
|
this.addByte(toWrite + 1);
|
|
136
136
|
this.addByte(step);
|
|
137
137
|
|
|
138
|
+
this.ensure(toWrite);
|
|
138
139
|
buff.copy(this.buffer, this.pos, step * 254, (step * 254) + toWrite);
|
|
139
140
|
|
|
140
141
|
step++;
|
package/lib/srp.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
var BigInt = require('big-integer'),
|
|
2
|
+
crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
const SRP_KEY_SIZE = 128,
|
|
5
|
+
SRP_KEY_MAX = BigInt('340282366920938463463374607431768211456'), // 1 << SRP_KEY_SIZE
|
|
6
|
+
SRP_SALT_SIZE = 32;
|
|
7
|
+
|
|
8
|
+
const DEBUG = false;
|
|
9
|
+
const DEBUG_PRIVATE_KEY = BigInt('84316857F47914F838918D5C12CE3A3E7A9B2D7C9486346809E9EEFCE8DE7CD4259D8BE4FD0BCC2D259553769E078FA61EE2977025E4DA42F7FD97914D8A33723DFAFBC00770B7DA0C2E3778A05790F0C0F33C32A19ED88A12928567749021B3FD45DCD1CE259C45325067E3DDC972F87867349BA82C303CCCAA9B207218007B', 16);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Prime values.
|
|
13
|
+
*
|
|
14
|
+
* @type {{g: (bigInt.BigInteger), k: (bigInt.BigInteger), N: (bigInt.BigInteger)}}
|
|
15
|
+
*/
|
|
16
|
+
const PRIME = {
|
|
17
|
+
N: BigInt('E67D2E994B2F900C3F41F08F5BB2627ED0D49EE1FE767A52EFCD565CD6E768812C3E1E9CE8F0A8BEA6CB13CD29DDEBF7A96D4A93B55D488DF099A15C89DCB0640738EB2CBDD9A8F7BAB561AB1B0DC1C6CDABF303264A08D1BCA932D1F1EE428B619D970F342ABA9A65793B8B2F041AE5364350C16F735F56ECBCA87BD57B29E7', 16),
|
|
18
|
+
g: BigInt(2),
|
|
19
|
+
k: BigInt('1277432915985975349439481660349303019122249719989')
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a client key pair.
|
|
24
|
+
*
|
|
25
|
+
* @param a bigInt.BigInteger Client private key.
|
|
26
|
+
* @returns {{private: bigInt.BigInteger, public: bigInt.BigInteger}}
|
|
27
|
+
*/
|
|
28
|
+
exports.clientSeed = function(a = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
|
|
29
|
+
var A = PRIME.g.modPow(a, PRIME.N);
|
|
30
|
+
|
|
31
|
+
dump('a', a);
|
|
32
|
+
dump('A', A);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
public: A,
|
|
36
|
+
private: a
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate a server key pair.
|
|
42
|
+
*
|
|
43
|
+
* @param user string Connection username.
|
|
44
|
+
* @param password string Connection password.
|
|
45
|
+
* @param salt bigInt.BigInteger Connection salt.
|
|
46
|
+
* @param b bigInt.BigInteger Server private key.
|
|
47
|
+
* @returns {{private: bigInt.BigInteger, public: bigInt.BigInteger}}
|
|
48
|
+
*/
|
|
49
|
+
exports.serverSeed = function(user, password, salt, b = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
|
|
50
|
+
var v = getVerifier(user, password, salt);
|
|
51
|
+
var gb = PRIME.g.modPow(b, PRIME.N);
|
|
52
|
+
var kv = PRIME.k.multiply(v).mod(PRIME.N);
|
|
53
|
+
var B = kv.add(gb).mod(PRIME.N);
|
|
54
|
+
|
|
55
|
+
dump('v', v);
|
|
56
|
+
dump('b', b);
|
|
57
|
+
dump('gb', b);
|
|
58
|
+
dump('kv', v);
|
|
59
|
+
dump('B', B);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
public: B,
|
|
63
|
+
private: b
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Server session secret.
|
|
69
|
+
*
|
|
70
|
+
* @param user string Connection username.
|
|
71
|
+
* @param password string Connection password.
|
|
72
|
+
* @param salt bigInt.BigInteger Connection salt.
|
|
73
|
+
* @param A bigInt.BigInteger Client public key.
|
|
74
|
+
* @param B bigInt.BigInteger Server public key.
|
|
75
|
+
* @param b bigInt.BigInteger Server private key.
|
|
76
|
+
* @returns {bigInt.BigInteger}
|
|
77
|
+
*/
|
|
78
|
+
exports.serverSession = function(user, password, salt, A, B, b) {
|
|
79
|
+
var u = getScramble(A, B);
|
|
80
|
+
var v = getVerifier(user, password, salt);
|
|
81
|
+
var vu = v.modPow(u, PRIME.N);
|
|
82
|
+
var Avu = A.multiply(vu).mod(PRIME.N);
|
|
83
|
+
var sessionSecret = Avu.modPow(b, PRIME.N);
|
|
84
|
+
var K = getHash('sha1', toBuffer(sessionSecret));
|
|
85
|
+
|
|
86
|
+
dump('server sessionSecret', sessionSecret);
|
|
87
|
+
dump('server K', K);
|
|
88
|
+
|
|
89
|
+
return BigInt(K, 16);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* M = H(H(N) xor H(g), H(I), s, A, B, K)
|
|
94
|
+
*/
|
|
95
|
+
exports.clientProof = function(user, password, salt, A, B, a, hashAlgo) {
|
|
96
|
+
var K = clientSession(user, password, salt, A, B, a);
|
|
97
|
+
var n1, n2;
|
|
98
|
+
|
|
99
|
+
n1 = toBigInt(getHash('sha1', toBuffer(PRIME.N)));
|
|
100
|
+
n2 = toBigInt(getHash('sha1', toBuffer(PRIME.g)));
|
|
101
|
+
|
|
102
|
+
dump('n1', n1);
|
|
103
|
+
dump('n2', n2);
|
|
104
|
+
|
|
105
|
+
n1 = n1.modPow(n2, PRIME.N);
|
|
106
|
+
n2 = toBigInt(getHash('sha1', user));
|
|
107
|
+
var M = toBigInt(getHash(hashAlgo, toBuffer(n1), toBuffer(n2), salt, toBuffer(A), toBuffer(B), toBuffer(K)));
|
|
108
|
+
|
|
109
|
+
dump('n1-2', n1);
|
|
110
|
+
dump('n2-2', n2);
|
|
111
|
+
dump('proof:M', M);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
clientSessionKey: K,
|
|
115
|
+
authData: M,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Pad hex string.
|
|
121
|
+
*/
|
|
122
|
+
function hexPad(hex) {
|
|
123
|
+
if (hex.length % 2 !== 0) {
|
|
124
|
+
hex = '0' + hex;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return hex;
|
|
128
|
+
}
|
|
129
|
+
exports.hexPad = hexPad;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Pad key with SRP_KEY_SIZE.
|
|
133
|
+
*
|
|
134
|
+
* @param n BigInt Key to pad.
|
|
135
|
+
* @returns Buffer
|
|
136
|
+
*/
|
|
137
|
+
function pad(n) {
|
|
138
|
+
var buff = Buffer.from(hexPad(n.toString(16)), 'hex');
|
|
139
|
+
|
|
140
|
+
if (buff.length > SRP_KEY_SIZE) {
|
|
141
|
+
buff = buff.slice(buff.length - SRP_KEY_SIZE, buff.length);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return buff;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Scramble keys.
|
|
149
|
+
*
|
|
150
|
+
* @param A bigInt.BigInteger Client public key.
|
|
151
|
+
* @param B bigInt.BigInteger Server public key.
|
|
152
|
+
* @returns {bigInt.BigInteger}
|
|
153
|
+
*/
|
|
154
|
+
function getScramble(A, B) {
|
|
155
|
+
return BigInt(getHash('sha1', pad(A), pad(B)), 16);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Client session secret.
|
|
160
|
+
*
|
|
161
|
+
* Both: u = H(A, B)
|
|
162
|
+
* User: x = H(s, p) (user enters password)
|
|
163
|
+
* User: S = (B - kg^x) ^ (a + ux) (computes session key)
|
|
164
|
+
* User: K = H(S)
|
|
165
|
+
*
|
|
166
|
+
* @param user string Connection username.
|
|
167
|
+
* @param password string Connection password.
|
|
168
|
+
* @param salt bigInt.BigInteger Connection salt.
|
|
169
|
+
* @param A bigInt.BigInteger Client public key.
|
|
170
|
+
* @param B bigInt.BigInteger Server public key.
|
|
171
|
+
* @param a bigInt.BigInteger Client private key.
|
|
172
|
+
*/
|
|
173
|
+
function clientSession(user, password, salt, A, B, a) {
|
|
174
|
+
var u = getScramble(A, B);
|
|
175
|
+
var x = getUserHash(user, salt, password);
|
|
176
|
+
var gx = PRIME.g.modPow(x, PRIME.N);
|
|
177
|
+
var kgx = PRIME.k.multiply(gx).mod(PRIME.N);
|
|
178
|
+
var diff = B.subtract(kgx).mod(PRIME.N);
|
|
179
|
+
|
|
180
|
+
if (diff.lesser(0)) {
|
|
181
|
+
diff = diff.add(PRIME.N);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
var ux = u.multiply(x).mod(PRIME.N);
|
|
185
|
+
var aux = a.add(ux).mod(PRIME.N);
|
|
186
|
+
var sessionSecret = diff.modPow(aux, PRIME.N);
|
|
187
|
+
var K = toBigInt(getHash('sha1', toBuffer(sessionSecret)));
|
|
188
|
+
|
|
189
|
+
dump('B', B);
|
|
190
|
+
dump('u', u);
|
|
191
|
+
dump('x', x);
|
|
192
|
+
dump('gx', gx);
|
|
193
|
+
dump('kgx', kgx);
|
|
194
|
+
dump('diff', diff);
|
|
195
|
+
dump('ux', ux);
|
|
196
|
+
dump('aux', aux);
|
|
197
|
+
dump('sessionSecret', sessionSecret);
|
|
198
|
+
dump('sessionKey(K)', K);
|
|
199
|
+
|
|
200
|
+
return K;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Compute user hash.
|
|
205
|
+
*
|
|
206
|
+
* @param user string Connection username.
|
|
207
|
+
* @param salt bigInt.BigInteger Connection salt.
|
|
208
|
+
* @param password string Connection password.
|
|
209
|
+
* @returns {bigInt.BigInteger}
|
|
210
|
+
*/
|
|
211
|
+
function getUserHash(user, salt, password) {
|
|
212
|
+
var hash1 = getHash('sha1', user.toUpperCase(), ':', password);
|
|
213
|
+
var hash2 = getHash('sha1', salt, toBuffer(hash1));
|
|
214
|
+
|
|
215
|
+
return toBigInt(hash2);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Verifier of user hash.
|
|
220
|
+
*
|
|
221
|
+
* @param user string Connection username.
|
|
222
|
+
* @param password string Connection password.
|
|
223
|
+
* @param salt bigInt.BigInteger Connection salt.
|
|
224
|
+
* @returns {bigInt.BigInteger}
|
|
225
|
+
*/
|
|
226
|
+
function getVerifier(user, password, salt) {
|
|
227
|
+
return PRIME.g.modPow(getUserHash(user, salt, password), PRIME.N);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Hash data and return hex string.
|
|
232
|
+
*
|
|
233
|
+
* @param algo string Algorithm to use.
|
|
234
|
+
* @param data any[] Data to hash.
|
|
235
|
+
* @returns {string}
|
|
236
|
+
*/
|
|
237
|
+
function getHash(algo, ...data) {
|
|
238
|
+
var hash = crypto.createHash(algo);
|
|
239
|
+
|
|
240
|
+
for (var d of data) {
|
|
241
|
+
hash.update(d);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return hash.digest('hex');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Convert BigInt to buffer.
|
|
249
|
+
*
|
|
250
|
+
* @param bigInt
|
|
251
|
+
* @returns {*}
|
|
252
|
+
*/
|
|
253
|
+
function toBuffer(bigInt) {
|
|
254
|
+
return Buffer.from(BigInt.isInstance(bigInt) ? hexPad(bigInt.toString(16)) : bigInt, 'hex');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Convert hex buffer or string to BigInt.
|
|
259
|
+
*
|
|
260
|
+
* @param hex
|
|
261
|
+
* @returns {bigInt.BigInteger}
|
|
262
|
+
*/
|
|
263
|
+
function toBigInt(hex) {
|
|
264
|
+
return BigInt(Buffer.isBuffer(hex) ? hex.toString('hex') : hex, 16);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Dump value in debug mode.
|
|
269
|
+
*
|
|
270
|
+
* @param key
|
|
271
|
+
* @param value
|
|
272
|
+
*/
|
|
273
|
+
function dump(key, value) {
|
|
274
|
+
if (DEBUG) {
|
|
275
|
+
if (BigInt.isInstance(value)) {
|
|
276
|
+
value = value.toString(16);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
console.log(key + '=' + value);
|
|
280
|
+
}
|
|
281
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-firebird",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Pure JavaScript and Asynchronous Firebird client for Node.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"firebird",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"test": "mocha"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"big-integer": "^1.6.48",
|
|
36
37
|
"long": "^4.0.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
|
3
|
-
|
|
4
|
-
name: Node.js Package
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
release:
|
|
8
|
-
types: [created]
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v2
|
|
15
|
-
- uses: actions/setup-node@v1
|
|
16
|
-
with:
|
|
17
|
-
node-version: 12
|
|
18
|
-
- run: npm ci
|
|
19
|
-
- run: npm test
|
|
20
|
-
|
|
21
|
-
publish-npm:
|
|
22
|
-
needs: build
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v2
|
|
26
|
-
- uses: actions/setup-node@v1
|
|
27
|
-
with:
|
|
28
|
-
node-version: 12
|
|
29
|
-
registry-url: https://registry.npmjs.org/
|
|
30
|
-
- run: npm ci
|
|
31
|
-
- run: npm publish
|
|
32
|
-
env:
|
|
33
|
-
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
|
34
|
-
|
|
35
|
-
publish-gpr:
|
|
36
|
-
needs: build
|
|
37
|
-
runs-on: ubuntu-latest
|
|
38
|
-
steps:
|
|
39
|
-
- uses: actions/checkout@v2
|
|
40
|
-
- uses: actions/setup-node@v1
|
|
41
|
-
with:
|
|
42
|
-
node-version: 12
|
|
43
|
-
registry-url: https://npm.pkg.github.com/
|
|
44
|
-
- run: npm ci
|
|
45
|
-
- run: npm publish
|
|
46
|
-
env:
|
|
47
|
-
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
package/git
DELETED
|
File without changes
|