@hapi/nes 14.0.0 → 14.0.2
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/LICENSE.md +0 -0
- package/README.md +0 -0
- package/lib/client.d.ts +5 -2
- package/lib/client.js +0 -0
- package/lib/index.js +0 -0
- package/lib/listener.js +70 -17
- package/lib/socket.js +9 -4
- package/package.json +16 -17
package/LICENSE.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/lib/client.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { ClientRequestArgs } from "http";
|
|
2
|
+
import type { ClientOptions } from "ws";
|
|
3
|
+
|
|
1
4
|
// Same as exported type in @hapi/hapi v20
|
|
2
5
|
type HTTP_METHODS = 'ACL' | 'BIND' | 'CHECKOUT' | 'CONNECT' | 'COPY' | 'DELETE' | 'GET' | 'HEAD' | 'LINK' | 'LOCK' |
|
|
3
6
|
'M-SEARCH' | 'MERGE' | 'MKACTIVITY' | 'MKCALENDAR' | 'MKCOL' | 'MOVE' | 'NOTIFY' | 'OPTIONS' | 'PATCH' | 'POST' |
|
|
@@ -173,7 +176,7 @@ export class Client {
|
|
|
173
176
|
constructor(
|
|
174
177
|
url: `ws://${string}` | `wss://${string}`,
|
|
175
178
|
options?: {
|
|
176
|
-
ws?:
|
|
179
|
+
ws?: ClientOptions | ClientRequestArgs;
|
|
177
180
|
timeout?: number | boolean;
|
|
178
181
|
});
|
|
179
182
|
|
|
@@ -369,4 +372,4 @@ export class Client {
|
|
|
369
372
|
* `client.connect()`
|
|
370
373
|
*/
|
|
371
374
|
reauthenticate(auth: ClientConnectOptions['auth']): Promise<unknown>;
|
|
372
|
-
}
|
|
375
|
+
}
|
package/lib/client.js
CHANGED
|
File without changes
|
package/lib/index.js
CHANGED
|
File without changes
|
package/lib/listener.js
CHANGED
|
@@ -441,26 +441,37 @@ internals.Sockets.prototype.add = function (socket) {
|
|
|
441
441
|
};
|
|
442
442
|
|
|
443
443
|
|
|
444
|
-
internals.Sockets.prototype.auth = function (socket) {
|
|
444
|
+
internals.Sockets.prototype.auth = function (socket, previous, credentials) {
|
|
445
|
+
|
|
446
|
+
// Called before the socket credentials are replaced
|
|
447
|
+
|
|
448
|
+
if (!this._listener._settings.auth.index ||
|
|
449
|
+
!this._items[socket.id]) { // Closed while authenticating
|
|
445
450
|
|
|
446
|
-
if (!this._listener._settings.auth.index) {
|
|
447
451
|
return;
|
|
448
452
|
}
|
|
449
453
|
|
|
450
|
-
|
|
451
|
-
|
|
454
|
+
const user = credentials.user;
|
|
455
|
+
if (user === previous) {
|
|
456
|
+
return; // Same user as before, index unchanged
|
|
452
457
|
}
|
|
453
458
|
|
|
454
|
-
|
|
455
|
-
|
|
459
|
+
if (user &&
|
|
460
|
+
this._listener._settings.auth.maxConnectionsPerUser &&
|
|
456
461
|
this._byUser[user] &&
|
|
457
462
|
this._byUser[user].length >= this._listener._settings.auth.maxConnectionsPerUser) {
|
|
458
463
|
|
|
459
464
|
throw Boom.serverUnavailable('Too many connections for the authenticated user');
|
|
460
465
|
}
|
|
461
466
|
|
|
462
|
-
|
|
463
|
-
|
|
467
|
+
if (previous) {
|
|
468
|
+
this._deindex(socket, previous);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (user) {
|
|
472
|
+
this._byUser[user] = this._byUser[user] ?? [];
|
|
473
|
+
this._byUser[user].push(socket);
|
|
474
|
+
}
|
|
464
475
|
};
|
|
465
476
|
|
|
466
477
|
|
|
@@ -471,12 +482,17 @@ internals.Sockets.prototype.remove = function (socket) {
|
|
|
471
482
|
if (socket.auth.credentials &&
|
|
472
483
|
socket.auth.credentials.user) {
|
|
473
484
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
485
|
+
this._deindex(socket, socket.auth.credentials.user);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
internals.Sockets.prototype._deindex = function (socket, user) {
|
|
491
|
+
|
|
492
|
+
if (this._byUser[user]) {
|
|
493
|
+
this._byUser[user] = this._byUser[user].filter((item) => item !== socket);
|
|
494
|
+
if (!this._byUser[user].length) {
|
|
495
|
+
delete this._byUser[user];
|
|
480
496
|
}
|
|
481
497
|
}
|
|
482
498
|
};
|
|
@@ -582,15 +598,52 @@ internals.Subscribers.prototype._remove = async function (socket, path, params)
|
|
|
582
598
|
};
|
|
583
599
|
|
|
584
600
|
|
|
601
|
+
internals.Subscribers.prototype.reauth = function (socket, previous) {
|
|
602
|
+
|
|
603
|
+
// Called after the socket credentials are replaced
|
|
604
|
+
|
|
605
|
+
if (!this._settings.auth ||
|
|
606
|
+
!this._settings.auth.index) {
|
|
607
|
+
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const user = socket.auth.credentials.user;
|
|
612
|
+
if (user === previous) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const item = this._items[socket.id];
|
|
617
|
+
if (!item) {
|
|
618
|
+
return; // Removed while the socket was closing
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (previous) {
|
|
622
|
+
this._deindex(item, previous);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (user) {
|
|
626
|
+
this._byUser[user] = this._byUser[user] ?? [];
|
|
627
|
+
this._byUser[user].push(item);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
|
|
585
632
|
internals.Subscribers.prototype._cleanup = function (socket, item) {
|
|
586
633
|
|
|
587
634
|
delete this._items[socket.id];
|
|
588
635
|
|
|
589
636
|
if (socket.auth.credentials &&
|
|
590
|
-
socket.auth.credentials.user
|
|
591
|
-
|
|
637
|
+
socket.auth.credentials.user) {
|
|
638
|
+
|
|
639
|
+
this._deindex(item, socket.auth.credentials.user);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
internals.Subscribers.prototype._deindex = function (item, user) {
|
|
592
645
|
|
|
593
|
-
|
|
646
|
+
if (this._byUser[user]) {
|
|
594
647
|
this._byUser[user] = this._byUser[user].filter((record) => record !== item);
|
|
595
648
|
if (!this._byUser[user].length) {
|
|
596
649
|
delete this._byUser[user];
|
package/lib/socket.js
CHANGED
|
@@ -237,7 +237,7 @@ internals.Socket.prototype._onMessage = async function (message) {
|
|
|
237
237
|
try {
|
|
238
238
|
var request = JSON.parse(message);
|
|
239
239
|
}
|
|
240
|
-
catch
|
|
240
|
+
catch {
|
|
241
241
|
return this._error(Boom.badRequest('Cannot parse message'));
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -563,7 +563,7 @@ internals.Socket.prototype._authenticate = async function (request) {
|
|
|
563
563
|
const auth = await Iron.unseal(request.auth, config.password, config.iron ?? Iron.defaults);
|
|
564
564
|
this._setCredentials(auth);
|
|
565
565
|
}
|
|
566
|
-
catch
|
|
566
|
+
catch {
|
|
567
567
|
throw Boom.unauthorized('Invalid token');
|
|
568
568
|
}
|
|
569
569
|
}
|
|
@@ -585,7 +585,7 @@ internals.Socket.prototype._authByCookie = async function () {
|
|
|
585
585
|
try {
|
|
586
586
|
var { states } = await this.server.states.parse(cookies);
|
|
587
587
|
}
|
|
588
|
-
catch
|
|
588
|
+
catch {
|
|
589
589
|
throw Boom.unauthorized('Invalid nes authentication cookie');
|
|
590
590
|
}
|
|
591
591
|
|
|
@@ -598,6 +598,9 @@ internals.Socket.prototype._authByCookie = async function () {
|
|
|
598
598
|
|
|
599
599
|
internals.Socket.prototype._setCredentials = function (auth) {
|
|
600
600
|
|
|
601
|
+
const previous = this.auth.credentials ? this.auth.credentials.user : undefined;
|
|
602
|
+
this._listener._sockets.auth(this, previous, auth.credentials); // Throws before any state changes when the user limit is reached
|
|
603
|
+
|
|
601
604
|
this.auth.isAuthenticated = true;
|
|
602
605
|
this.auth.credentials = auth.credentials;
|
|
603
606
|
this.auth.artifacts = auth.artifacts;
|
|
@@ -605,7 +608,9 @@ internals.Socket.prototype._setCredentials = function (auth) {
|
|
|
605
608
|
|
|
606
609
|
this.auth._verified = Date.now();
|
|
607
610
|
|
|
608
|
-
|
|
611
|
+
for (const subscribers of new Set(Object.values(this._subscriptions))) { // Paths on the same route share one subscribers object
|
|
612
|
+
subscribers.reauth(this, previous);
|
|
613
|
+
}
|
|
609
614
|
};
|
|
610
615
|
|
|
611
616
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hapi/nes",
|
|
3
3
|
"description": "WebSocket adapter plugin for hapi routes",
|
|
4
|
-
"version": "14.0.
|
|
5
|
-
"repository":
|
|
4
|
+
"version": "14.0.2",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git://github.com/hapijs/nes"
|
|
8
|
+
},
|
|
6
9
|
"main": "lib/index.js",
|
|
7
10
|
"types": "lib/index.d.ts",
|
|
8
11
|
"engines": {
|
|
@@ -16,34 +19,30 @@
|
|
|
16
19
|
"plugin",
|
|
17
20
|
"websocket"
|
|
18
21
|
],
|
|
19
|
-
"eslintConfig": {
|
|
20
|
-
"extends": [
|
|
21
|
-
"plugin:@hapi/module"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
22
|
"dependencies": {
|
|
25
23
|
"@hapi/boom": "^10.0.1",
|
|
26
|
-
"@hapi/bounce": "^3.0.
|
|
24
|
+
"@hapi/bounce": "^3.0.2",
|
|
27
25
|
"@hapi/call": "^9.0.1",
|
|
28
26
|
"@hapi/cryptiles": "^6.0.1",
|
|
29
|
-
"@hapi/hoek": "^11.0.
|
|
27
|
+
"@hapi/hoek": "^11.0.7",
|
|
30
28
|
"@hapi/iron": "^7.0.1",
|
|
31
29
|
"@hapi/teamwork": "^6.0.0",
|
|
32
30
|
"@hapi/validate": "^2.0.1",
|
|
33
|
-
"ws": "^8.
|
|
31
|
+
"@types/ws": "^8.5.13",
|
|
32
|
+
"ws": "^8.18.0"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"@hapi/code": "^9.0.3",
|
|
37
|
-
"@hapi/eslint-plugin": "
|
|
38
|
-
"@hapi/hapi": "^21.3.
|
|
39
|
-
"@hapi/lab": "^
|
|
40
|
-
"@types/node": "^20.
|
|
36
|
+
"@hapi/eslint-plugin": "^7.0.0",
|
|
37
|
+
"@hapi/hapi": "^21.3.12",
|
|
38
|
+
"@hapi/lab": "^26.0.0",
|
|
39
|
+
"@types/node": "^20.17.12",
|
|
41
40
|
"joi": "^17.13.3",
|
|
42
41
|
"typescript": "^5.4.5"
|
|
43
42
|
},
|
|
43
|
+
"license": "BSD-3-Clause",
|
|
44
44
|
"scripts": {
|
|
45
45
|
"test": "lab -a @hapi/code -t 100 -L -m 10000 -Y",
|
|
46
46
|
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -m 10000"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
}
|
|
47
|
+
}
|
|
48
|
+
}
|