node-firebird 2.3.4 → 2.4.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.
Files changed (109) hide show
  1. package/README.md +544 -6
  2. package/lib/callback.d.ts +20 -0
  3. package/lib/callback.js +6 -16
  4. package/lib/firebird.msg.json +1370 -1370
  5. package/lib/gdscodes.d.ts +1519 -1520
  6. package/lib/gdscodes.js +5 -5
  7. package/lib/ieee754-decimal.d.ts +38 -0
  8. package/lib/ieee754-decimal.js +71 -118
  9. package/lib/index.d.ts +37 -338
  10. package/lib/index.js +97 -86
  11. package/lib/messages.d.ts +6 -0
  12. package/lib/messages.js +135 -162
  13. package/lib/pool.d.ts +23 -0
  14. package/lib/pool.js +34 -47
  15. package/lib/srp.d.ts +51 -0
  16. package/lib/srp.js +62 -72
  17. package/lib/types.d.ts +375 -0
  18. package/lib/types.js +22 -0
  19. package/lib/unix-crypt.d.ts +1 -0
  20. package/lib/unix-crypt.js +126 -152
  21. package/lib/utils.d.ts +16 -0
  22. package/lib/utils.js +24 -48
  23. package/lib/wire/connection.d.ts +100 -0
  24. package/lib/wire/connection.js +1029 -1009
  25. package/lib/wire/const.d.ts +567 -0
  26. package/lib/wire/const.js +620 -599
  27. package/lib/wire/database.d.ts +57 -0
  28. package/lib/wire/database.js +111 -108
  29. package/lib/wire/eventConnection.d.ts +16 -0
  30. package/lib/wire/eventConnection.js +29 -31
  31. package/lib/wire/fbEventManager.d.ts +45 -0
  32. package/lib/wire/fbEventManager.js +38 -57
  33. package/lib/wire/serialize.d.ts +97 -0
  34. package/lib/wire/serialize.js +42 -141
  35. package/lib/wire/service.d.ts +66 -0
  36. package/lib/wire/service.js +374 -401
  37. package/lib/wire/socket.d.ts +59 -0
  38. package/lib/wire/socket.js +79 -40
  39. package/lib/wire/statement.d.ts +25 -0
  40. package/lib/wire/statement.js +13 -9
  41. package/lib/wire/transaction.d.ts +21 -0
  42. package/lib/wire/transaction.js +33 -61
  43. package/lib/wire/xsqlvar.d.ts +175 -0
  44. package/lib/wire/xsqlvar.js +169 -269
  45. package/package.json +12 -4
  46. package/src/callback.ts +55 -0
  47. package/{poc/node_modules/node-firebird/lib/gdscodes.js → src/gdscodes.ts} +3 -3
  48. package/{poc/node_modules/node-firebird/lib/ieee754-decimal.js → src/ieee754-decimal.ts} +7 -14
  49. package/src/index.ts +157 -0
  50. package/{poc/node_modules/node-firebird/lib/messages.js → src/messages.ts} +163 -162
  51. package/src/pool.ts +209 -0
  52. package/{poc/node_modules/node-firebird/lib/srp.js → src/srp.ts} +74 -33
  53. package/src/types.ts +419 -0
  54. package/{poc/node_modules/node-firebird/lib/unix-crypt.js → src/unix-crypt.ts} +6 -12
  55. package/{poc/node_modules/node-firebird/lib/utils.js → src/utils.ts} +11 -20
  56. package/{poc/node_modules/node-firebird/lib/wire/connection.js → src/wire/connection.ts} +611 -129
  57. package/{poc/node_modules/node-firebird/lib/wire/const.js → src/wire/const.ts} +96 -9
  58. package/{poc/node_modules/node-firebird/lib/wire/database.js → src/wire/database.ts} +110 -44
  59. package/{poc/node_modules/node-firebird/lib/wire/eventConnection.js → src/wire/eventConnection.ts} +29 -14
  60. package/{poc/node_modules/node-firebird/lib/wire/fbEventManager.js → src/wire/fbEventManager.ts} +39 -30
  61. package/{poc/node_modules/node-firebird/lib/wire/serialize.js → src/wire/serialize.ts} +78 -59
  62. package/{poc/node_modules/node-firebird/lib/wire/service.js → src/wire/service.ts} +90 -88
  63. package/src/wire/socket.ts +262 -0
  64. package/src/wire/statement.ts +71 -0
  65. package/{poc/node_modules/node-firebird/lib/wire/transaction.js → src/wire/transaction.ts} +25 -19
  66. package/{poc/node_modules/node-firebird/lib/wire/xsqlvar.js → src/wire/xsqlvar.ts} +244 -143
  67. package/.eslintrc.json +0 -12
  68. package/.github/workflows/codeql.yml +0 -76
  69. package/.github/workflows/node.js.yml +0 -95
  70. package/BIGINT_MIGRATION.md +0 -374
  71. package/CI_DEBUGGING_GUIDE.md +0 -148
  72. package/ENCRYPTION_CALLBACK.md +0 -152
  73. package/FIREBIRD_LOG_FEATURE.md +0 -145
  74. package/MINIMAL_CHANGES_SUMMARY.md +0 -136
  75. package/PR_SUMMARY.md +0 -96
  76. package/ROADMAP.md +0 -223
  77. package/SRP_PROTOCOL.md +0 -482
  78. package/poc/README.md +0 -160
  79. package/poc/helpers.js +0 -59
  80. package/poc/node_modules/.package-lock.json +0 -14
  81. package/poc/node_modules/node-firebird/.eslintrc.json +0 -12
  82. package/poc/node_modules/node-firebird/.github/workflows/codeql.yml +0 -76
  83. package/poc/node_modules/node-firebird/.github/workflows/node.js.yml +0 -95
  84. package/poc/node_modules/node-firebird/BIGINT_MIGRATION.md +0 -374
  85. package/poc/node_modules/node-firebird/CI_DEBUGGING_GUIDE.md +0 -148
  86. package/poc/node_modules/node-firebird/ENCRYPTION_CALLBACK.md +0 -152
  87. package/poc/node_modules/node-firebird/FIREBIRD_LOG_FEATURE.md +0 -145
  88. package/poc/node_modules/node-firebird/LICENSE +0 -373
  89. package/poc/node_modules/node-firebird/MINIMAL_CHANGES_SUMMARY.md +0 -136
  90. package/poc/node_modules/node-firebird/PR_SUMMARY.md +0 -96
  91. package/poc/node_modules/node-firebird/README.md +0 -794
  92. package/poc/node_modules/node-firebird/ROADMAP.md +0 -223
  93. package/poc/node_modules/node-firebird/SRP_PROTOCOL.md +0 -482
  94. package/poc/node_modules/node-firebird/lib/callback.js +0 -38
  95. package/poc/node_modules/node-firebird/lib/gdscodes.d.ts +0 -1524
  96. package/poc/node_modules/node-firebird/lib/index.d.ts +0 -316
  97. package/poc/node_modules/node-firebird/lib/index.js +0 -128
  98. package/poc/node_modules/node-firebird/lib/pool.js +0 -108
  99. package/poc/node_modules/node-firebird/lib/wire/socket.js +0 -175
  100. package/poc/node_modules/node-firebird/lib/wire/statement.js +0 -48
  101. package/poc/node_modules/node-firebird/package.json +0 -38
  102. package/poc/node_modules/node-firebird/vitest.config.js +0 -24
  103. package/poc/package-lock.json +0 -21
  104. package/poc/package.json +0 -12
  105. package/poc/reproduce-fixed.js +0 -150
  106. package/poc/reproduce.js +0 -133
  107. package/vitest.config.js +0 -27
  108. /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg +0 -0
  109. /package/{poc/node_modules/node-firebird/lib → src}/firebird.msg.json +0 -0
package/src/pool.ts ADDED
@@ -0,0 +1,209 @@
1
+ /***************************************
2
+ *
3
+ * Simple Pooling
4
+ *
5
+ ***************************************/
6
+
7
+ import type { Callback } from './callback';
8
+
9
+ type AttachFn = (options: any, callback: Callback) => void;
10
+
11
+ class Pool {
12
+ attach: AttachFn;
13
+ internaldb: any[];
14
+ pooldb: any[];
15
+ dbinuse: number;
16
+ _creating: number;
17
+ max: number;
18
+ pending: Callback[];
19
+ options: any;
20
+ _destroyed: boolean;
21
+
22
+ constructor(attach: AttachFn, max: number, options: any) {
23
+ this.attach = attach;
24
+ this.internaldb = []; // connections created by the pool (for destroy)
25
+ this.pooldb = []; // connections available in the pool (idle)
26
+ this.dbinuse = 0; // connections currently handed out to callers
27
+ this._creating = 0; // connections currently being created (attach in flight)
28
+ this.max = max || 4;
29
+ this.pending = []; // callbacks waiting for a free slot
30
+ this.options = options;
31
+ this._destroyed = false; // true after destroy() — prevents further use
32
+ }
33
+
34
+ get(callback: Callback): this {
35
+ // [Fix 2] Reject immediately if the pool has already been destroyed.
36
+ if (this._destroyed) {
37
+ callback(new Error('Pool has been destroyed'), null);
38
+ return this;
39
+ }
40
+ var self = this;
41
+ self.pending.push(callback);
42
+ self.check();
43
+ return self;
44
+ }
45
+
46
+ check(): this {
47
+ var self = this;
48
+
49
+ // [Fix 2] Do not serve requests on a destroyed pool.
50
+ if (self._destroyed) return self;
51
+
52
+ if ((self.dbinuse + self._creating) >= self.max)
53
+ return self;
54
+
55
+ var cb = self.pending.shift();
56
+ if (!cb)
57
+ return self;
58
+ if (self.pooldb.length) {
59
+ var db = self.pooldb.shift();
60
+ // Discard connections that have been closed or destroyed while idle
61
+ if (db.connection && (db.connection._isClosed || db.connection._isDetach || !db.connection._socket || db.connection._socket.destroyed)) {
62
+ var idx = self.internaldb.indexOf(db);
63
+ if (idx !== -1) self.internaldb.splice(idx, 1);
64
+ self.pending.unshift(cb);
65
+ setImmediate(function () { self.check(); });
66
+ return self;
67
+ }
68
+ // Idle connection available — hand it out immediately.
69
+ self.dbinuse++;
70
+ cb(null, db);
71
+ } else {
72
+ // No idle connection — create a new one via attach().
73
+ self._creating++;
74
+
75
+ var timedOut = false;
76
+ var timer: NodeJS.Timeout | null = null;
77
+
78
+ // [Fix 1] Optional per-attach timeout.
79
+ // If attach() does not call back within connectTimeout ms (e.g. because
80
+ // the server accepted TCP but stalled on the Firebird wire protocol), we
81
+ // free the slot and notify the caller. Any connection that arrives late
82
+ // is discarded in the attach() callback below.
83
+ if (self.options.connectTimeout > 0) {
84
+ timer = setTimeout(function () {
85
+ timedOut = true;
86
+ self._creating--;
87
+ cb(new Error(
88
+ 'Connection timeout after ' + self.options.connectTimeout + 'ms'
89
+ ), null);
90
+ // Free the slot so the next pending request can be served.
91
+ setImmediate(function () { self.check(); });
92
+ }, self.options.connectTimeout);
93
+ }
94
+
95
+ this.attach(self.options, function (err, db) {
96
+
97
+ // [Fix 1] Timeout already fired — discard this late connection.
98
+ // Without this guard the socket would stay open until the OS-level
99
+ // TCP timeout (potentially minutes), leaking a file descriptor.
100
+ if (timedOut) {
101
+ if (db) {
102
+ try {
103
+ // _pooled = false forces a real op_detach / socket close
104
+ // instead of a silent pool-return emit.
105
+ if (db.connection) db.connection._pooled = false;
106
+ db.detach();
107
+ } catch (e) { /* ignore cleanup errors */ }
108
+ }
109
+ return;
110
+ }
111
+
112
+ if (timer) clearTimeout(timer);
113
+ self._creating--;
114
+
115
+ // [Fix 3] Pool was destroyed while attach() was in flight.
116
+ if (self._destroyed) {
117
+ if (db) {
118
+ try {
119
+ if (db.connection) db.connection._pooled = false;
120
+ db.detach();
121
+ } catch (e) { /* ignore cleanup errors */ }
122
+ }
123
+ cb(new Error('Pool has been destroyed'), null);
124
+ return;
125
+ }
126
+
127
+ if (!err) {
128
+ self.dbinuse++;
129
+ self.internaldb.push(db);
130
+ db.on('detach', function () {
131
+ // also in pool (could be a twice call to detach)
132
+ if (self.pooldb.indexOf(db) !== -1 || self.internaldb.indexOf(db) === -1)
133
+ return;
134
+ // if not usable don't put it back in the pool
135
+ if (db.connection._isClosed || db.connection._isDetach || db.connection._pooled === false)
136
+ self.internaldb.splice(self.internaldb.indexOf(db), 1);
137
+ else
138
+ self.pooldb.push(db);
139
+
140
+ self.dbinuse--;
141
+ self.check();
142
+ });
143
+ }
144
+
145
+ cb(err, db);
146
+ });
147
+ }
148
+ setImmediate(function() {
149
+ self.check();
150
+ });
151
+
152
+ return self;
153
+ }
154
+
155
+ destroy(callback?: (err?: any) => void): void {
156
+ var self = this;
157
+ self._destroyed = true;
158
+
159
+ // [Fix 4] Drain pending callbacks so callers are not left hanging.
160
+ // This is critical when destroy() is called as a recovery measure after
161
+ // a timeout: without draining, every concurrent pool.get() that had not
162
+ // yet received a slot would hang until the process exits.
163
+ var draining = self.pending.splice(0);
164
+ draining.forEach(function (cb) {
165
+ try { cb(new Error('Pool is being destroyed'), null); } catch (e) { /* ignore */ }
166
+ });
167
+
168
+ var connectionCount = this.internaldb.length;
169
+
170
+ if (connectionCount === 0 && callback) {
171
+ callback();
172
+ }
173
+
174
+ function detachCallback(err?: any) {
175
+ if (err) {
176
+ if (callback) {
177
+ callback(err);
178
+ }
179
+ return;
180
+ }
181
+
182
+ connectionCount--;
183
+ if (connectionCount === 0 && callback) {
184
+ callback();
185
+ }
186
+ }
187
+
188
+ this.internaldb.forEach(function(db) {
189
+ if (db.connection._pooled === false) {
190
+ detachCallback();
191
+ return;
192
+ }
193
+ // check if the db is not free into the pool otherwise user should manual detach it
194
+ var _db_in_pool = self.pooldb.indexOf(db);
195
+ if (_db_in_pool !== -1) {
196
+ self.pooldb.splice(_db_in_pool, 1);
197
+ db.connection._pooled = false;
198
+ db.detach(detachCallback);
199
+ } else {
200
+ // [Fix 5] Connection is currently in use (dbinuse > 0).
201
+ // The caller is responsible for releasing it via detach().
202
+ // Count it down here so the destroy() callback is not blocked forever.
203
+ detachCallback();
204
+ }
205
+ });
206
+ }
207
+ }
208
+
209
+ export = Pool;
@@ -1,4 +1,14 @@
1
- var crypto = require('crypto');
1
+ import crypto from 'crypto';
2
+
3
+ export interface KeyPair {
4
+ public: bigint;
5
+ private: bigint;
6
+ }
7
+
8
+ export interface ClientProof {
9
+ clientSessionKey: bigint;
10
+ authData: bigint;
11
+ }
2
12
 
3
13
  const SRP_KEY_SIZE = 128,
4
14
  SRP_KEY_MAX = BigInt('340282366920938463463374607431768211456'), // 1 << SRP_KEY_SIZE
@@ -18,13 +28,25 @@ const PRIME = {
18
28
  k: BigInt('1277432915985975349439481660349303019122249719989')
19
29
  };
20
30
 
31
+ const kCache: Record<string, bigint> = {};
32
+ function getK(hashAlgo: string): bigint {
33
+ if (!kCache[hashAlgo]) {
34
+ kCache[hashAlgo] = BigInt('0x' + getHash(hashAlgo, pad(PRIME.N), pad(PRIME.g)));
35
+ }
36
+ return kCache[hashAlgo];
37
+ }
38
+
21
39
  /**
22
40
  * Generate a client key pair.
23
41
  *
24
42
  * @param a BigInt Client private key.
25
43
  * @returns {{private: BigInt, public: BigInt}}
26
44
  */
27
- exports.clientSeed = function(a = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
45
+ export function clientSeed(a: bigint = toBigInt(crypto.randomBytes(SRP_KEY_SIZE)) % PRIME.N): KeyPair {
46
+ // a must be in [0, N): clientSession() reduces the exponent (a + ux) mod N
47
+ // to match the Firebird engine, but A = g^a is computed from the raw a.
48
+ // When random a >= N (~10% of 1024-bit values), the proof diverges from
49
+ // the server's session key, causing sporadic auth failures.
28
50
  var A = modPow(PRIME.g, a, PRIME.N);
29
51
 
30
52
  dump('a', a);
@@ -45,21 +67,29 @@ exports.clientSeed = function(a = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
45
67
  * @param b BigInt Server private key.
46
68
  * @returns {{private: BigInt, public: BigInt}}
47
69
  */
48
- exports.serverSeed = function(user, password, salt, b = toBigInt(crypto.randomBytes(SRP_KEY_SIZE))) {
49
- var v = getVerifier(user, password, salt);
50
- var gb = modPow(PRIME.g, b, PRIME.N);
51
- var kv = (PRIME.k * v) % PRIME.N;
70
+ export function serverSeed(user: string, password: string, salt: Buffer, b?: bigint | string, hashAlgo: string = 'sha1'): KeyPair {
71
+ if (typeof b === 'string') {
72
+ hashAlgo = b;
73
+ b = undefined;
74
+ }
75
+ const bKey: bigint = (b === undefined || b === null)
76
+ ? toBigInt(crypto.randomBytes(SRP_KEY_SIZE))
77
+ : b as bigint;
78
+ var v = getVerifier(user, password, salt, 'sha1');
79
+ var gb = modPow(PRIME.g, bKey, PRIME.N);
80
+ var k = getK('sha1');
81
+ var kv = (k * v) % PRIME.N;
52
82
  var B = (kv + gb) % PRIME.N;
53
83
 
54
84
  dump('v', v);
55
- dump('b', b);
56
- dump('gb', b);
85
+ dump('b', bKey);
86
+ dump('gb', bKey);
57
87
  dump('kv', v);
58
88
  dump('B', B);
59
89
 
60
90
  return {
61
91
  public: B,
62
- private: b
92
+ private: bKey
63
93
  };
64
94
  }
65
95
 
@@ -74,9 +104,9 @@ exports.serverSeed = function(user, password, salt, b = toBigInt(crypto.randomBy
74
104
  * @param b BigInt Server private key.
75
105
  * @returns {BigInt}
76
106
  */
77
- exports.serverSession = function(user, password, salt, A, B, b) {
78
- var u = getScramble(A, B);
79
- var v = getVerifier(user, password, salt);
107
+ export function serverSession(user: string, password: string, salt: Buffer, A: bigint, B: bigint, b: bigint, hashAlgo: string = 'sha1'): bigint {
108
+ var u = getScramble(A, B, 'sha1');
109
+ var v = getVerifier(user, password, salt, 'sha1');
80
110
  var vu = modPow(v, u, PRIME.N);
81
111
  var Avu = (A * vu) % PRIME.N;
82
112
  var sessionSecret = modPow(Avu, b, PRIME.N);
@@ -91,8 +121,8 @@ exports.serverSession = function(user, password, salt, A, B, b) {
91
121
  /**
92
122
  * M = H(H(N) xor H(g), H(I), s, A, B, K)
93
123
  */
94
- exports.clientProof = function(user, password, salt, A, B, a, hashAlgo) {
95
- var K = clientSession(user, password, salt, A, B, a);
124
+ export function clientProof(user: string, password: string, salt: Buffer, A: bigint, B: bigint, a: bigint, hashAlgo: string = 'sha1'): ClientProof {
125
+ var K = clientSession(user, password, salt, A, B, a, 'sha1');
96
126
  var n1, n2;
97
127
 
98
128
  n1 = toBigInt(getHash('sha1', toBuffer(PRIME.N)));
@@ -118,14 +148,20 @@ exports.clientProof = function(user, password, salt, A, B, a, hashAlgo) {
118
148
  /**
119
149
  * Pad hex string.
120
150
  */
121
- function hexPad(hex) {
151
+ export function hexPad(hex: string): string {
122
152
  if (hex.length % 2 !== 0) {
123
153
  hex = '0' + hex;
124
154
  }
125
155
 
126
156
  return hex;
127
157
  }
128
- exports.hexPad = hexPad;
158
+
159
+ /**
160
+ * The SRP prime modulus N (1024-bit, same value used by Firebird).
161
+ * Exported so tests and tooling can assert key-size invariants without
162
+ * duplicating the constant.
163
+ */
164
+ export const PRIME_N: bigint = PRIME.N;
129
165
 
130
166
  /**
131
167
  * Pad key with SRP_KEY_SIZE.
@@ -133,11 +169,15 @@ exports.hexPad = hexPad;
133
169
  * @param n BigInt Key to pad.
134
170
  * @returns Buffer
135
171
  */
136
- function pad(n) {
172
+ function pad(n: bigint): Buffer {
137
173
  var buff = Buffer.from(hexPad(n.toString(16)), 'hex');
138
174
 
139
175
  if (buff.length > SRP_KEY_SIZE) {
140
176
  buff = buff.slice(buff.length - SRP_KEY_SIZE, buff.length);
177
+ } else if (buff.length < SRP_KEY_SIZE) {
178
+ var padded = Buffer.alloc(SRP_KEY_SIZE);
179
+ buff.copy(padded, SRP_KEY_SIZE - buff.length);
180
+ buff = padded;
141
181
  }
142
182
 
143
183
  return buff;
@@ -150,8 +190,8 @@ function pad(n) {
150
190
  * @param B BigInt Server public key.
151
191
  * @returns {BigInt}
152
192
  */
153
- function getScramble(A, B) {
154
- return BigInt('0x' + getHash('sha1', pad(A), pad(B)));
193
+ function getScramble(A: bigint, B: bigint, hashAlgo: string = 'sha1'): bigint {
194
+ return BigInt('0x' + getHash(hashAlgo, pad(A), pad(B)));
155
195
  }
156
196
 
157
197
  /**
@@ -169,11 +209,12 @@ function getScramble(A, B) {
169
209
  * @param B BigInt Server public key.
170
210
  * @param a BigInt Client private key.
171
211
  */
172
- function clientSession(user, password, salt, A, B, a) {
173
- var u = getScramble(A, B);
174
- var x = getUserHash(user, salt, password);
212
+ function clientSession(user: string, password: string, salt: Buffer, A: bigint, B: bigint, a: bigint, hashAlgo: string = 'sha1'): bigint {
213
+ var u = getScramble(A, B, 'sha1');
214
+ var x = getUserHash(user, salt, password, 'sha1');
175
215
  var gx = modPow(PRIME.g, x, PRIME.N);
176
- var kgx = (PRIME.k * gx) % PRIME.N;
216
+ var k = getK('sha1');
217
+ var kgx = (k * gx) % PRIME.N;
177
218
  var diff = (B - kgx) % PRIME.N;
178
219
 
179
220
  if (diff < 0n) {
@@ -210,9 +251,9 @@ function clientSession(user, password, salt, A, B, a) {
210
251
  * @param password string Connection password.
211
252
  * @returns {BigInt}
212
253
  */
213
- function getUserHash(user, salt, password) {
214
- var hash1 = getHash('sha1', user.toUpperCase(), ':', password);
215
- var hash2 = getHash('sha1', salt, toBuffer(hash1));
254
+ function getUserHash(user: string, salt: Buffer, password: string, hashAlgo: string = 'sha1'): bigint {
255
+ var hash1 = getHash(hashAlgo, user.toUpperCase(), ':', password);
256
+ var hash2 = getHash(hashAlgo, salt, toBuffer(hash1));
216
257
 
217
258
  return toBigInt(hash2);
218
259
  }
@@ -225,8 +266,8 @@ function getUserHash(user, salt, password) {
225
266
  * @param salt BigInt Connection salt.
226
267
  * @returns {BigInt}
227
268
  */
228
- function getVerifier(user, password, salt) {
229
- return modPow(PRIME.g, getUserHash(user, salt, password), PRIME.N);
269
+ function getVerifier(user: string, password: string, salt: Buffer, hashAlgo: string = 'sha1'): bigint {
270
+ return modPow(PRIME.g, getUserHash(user, salt, password, hashAlgo), PRIME.N);
230
271
  }
231
272
 
232
273
  /**
@@ -236,7 +277,7 @@ function getVerifier(user, password, salt) {
236
277
  * @param data any[] Data to hash.
237
278
  * @returns {string}
238
279
  */
239
- function getHash(algo, ...data) {
280
+ function getHash(algo: string, ...data: (string | Buffer)[]): string {
240
281
  var hash = crypto.createHash(algo);
241
282
 
242
283
  for (var d of data) {
@@ -252,7 +293,7 @@ function getHash(algo, ...data) {
252
293
  * @param bigInt
253
294
  * @returns {*}
254
295
  */
255
- function toBuffer(bigInt) {
296
+ function toBuffer(bigInt: bigint | string): Buffer {
256
297
  return Buffer.from(typeof bigInt === 'bigint' ? hexPad(bigInt.toString(16)) : bigInt, 'hex');
257
298
  }
258
299
 
@@ -262,7 +303,7 @@ function toBuffer(bigInt) {
262
303
  * @param hex
263
304
  * @returns {BigInt}
264
305
  */
265
- function toBigInt(hex) {
306
+ function toBigInt(hex: Buffer | string): bigint {
266
307
  return BigInt('0x' + (Buffer.isBuffer(hex) ? hex.toString('hex') : hex));
267
308
  }
268
309
 
@@ -272,7 +313,7 @@ function toBigInt(hex) {
272
313
  * @param key
273
314
  * @param value
274
315
  */
275
- function dump(key, value) {
316
+ function dump(key: string, value: any): void {
276
317
  if (DEBUG) {
277
318
  if (typeof value === 'bigint') {
278
319
  value = value.toString(16);
@@ -285,7 +326,7 @@ function dump(key, value) {
285
326
  /**
286
327
  * Calculates (base ^ exp) % mod using native BigInt.
287
328
  */
288
- function modPow(base, exp, mod) {
329
+ function modPow(base: bigint, exp: bigint, mod: bigint): bigint {
289
330
  let result = 1n;
290
331
  base = base % mod;
291
332
  while (exp > 0n) {