@socket-mesh/server 17.3.7 → 18.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/action.d.ts +34 -34
- package/action.js +4 -8
- package/auth-engine.d.ts +5 -5
- package/inbound-packet.d.ts +11 -11
- package/index.d.ts +11 -11
- package/index.js +4 -4
- package/middleware-stream.d.ts +2 -2
- package/outbound-packet.d.ts +8 -8
- package/package.json +56 -58
- package/request.d.ts +4 -4
- package/server-options.d.ts +2 -2
- package/server.d.ts +52 -52
- package/server.js +88 -126
- package/serversocket-procedure.d.ts +6 -6
- package/serversocket.d.ts +20 -21
- package/serversocket.js +659 -723
package/serversocket.js
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
1
|
import cloneDeep from 'clone-deep';
|
|
18
2
|
import { AuthState } from "@socket-mesh/auth";
|
|
19
3
|
import { WritableConsumableStream } from "@socket-mesh/writable-consumable-stream";
|
|
@@ -21,14 +5,14 @@ import { AsyncStreamEmitter } from "@socket-mesh/async-stream-emitter";
|
|
|
21
5
|
import { StreamDemux, StreamDemuxWrapper } from "@socket-mesh/stream-demux";
|
|
22
6
|
import { Request, RequestWithResponse, createErrorResponse } from "@socket-mesh/request";
|
|
23
7
|
import { dehydrateError, hydrateError, socketProtocolIgnoreStatuses, socketProtocolErrorStatuses, InvalidArgumentsError, SocketProtocolError, TimeoutError, BadConnectionError, InvalidActionError, AuthError, AuthTokenExpiredError, AuthTokenInvalidError, AuthTokenNotBeforeError, AuthTokenError, BrokerError } from "@socket-mesh/errors";
|
|
24
|
-
import { SocketState } from "./socket-state";
|
|
25
|
-
import { MiddlewareType } from "./middleware-type";
|
|
26
|
-
import { ActionAuthenticate, ActionHandshakeSC, ActionInvoke, ActionMessage, ActionPublishIn, ActionPublishOut, ActionSubscribe, ActionTransmit } from "./action";
|
|
27
|
-
import { MiddlewareStream } from './middleware-stream';
|
|
28
|
-
import { isAuthenticatePacket, isHandshakePacket, isPublishPacket, isRemoveAuthTokenPacket, isSubscribePacket, isUnsubscribePacket } from './inbound-packet';
|
|
29
|
-
import { isPublishOutPacket } from './outbound-packet';
|
|
30
|
-
import { AuthenticateRequest, HandshakeRequest, UnsubscribeRequest } from './request';
|
|
31
|
-
import { ServerSocketProcedure } from './serversocket-procedure';
|
|
8
|
+
import { SocketState } from "./socket-state.js";
|
|
9
|
+
import { MiddlewareType } from "./middleware-type.js";
|
|
10
|
+
import { ActionAuthenticate, ActionHandshakeSC, ActionInvoke, ActionMessage, ActionPublishIn, ActionPublishOut, ActionSubscribe, ActionTransmit } from "./action.js";
|
|
11
|
+
import { MiddlewareStream } from './middleware-stream.js';
|
|
12
|
+
import { isAuthenticatePacket, isHandshakePacket, isPublishPacket, isRemoveAuthTokenPacket, isSubscribePacket, isUnsubscribePacket } from './inbound-packet.js';
|
|
13
|
+
import { isPublishOutPacket } from './outbound-packet.js';
|
|
14
|
+
import { AuthenticateRequest, HandshakeRequest, UnsubscribeRequest } from './request.js';
|
|
15
|
+
import { ServerSocketProcedure } from './serversocket-procedure.js';
|
|
32
16
|
const HANDSHAKE_REJECTION_STATUS_CODE = 4008;
|
|
33
17
|
export class ServerSocket extends AsyncStreamEmitter {
|
|
34
18
|
constructor(id, server, socket, protocolVersion) {
|
|
@@ -117,7 +101,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
117
101
|
this._handleInboundMessageStream(pongMessage);
|
|
118
102
|
this._handleOutboundPacketStream();
|
|
119
103
|
// Receive incoming raw messages
|
|
120
|
-
this.socket.on('message', (messageBuffer, isBinary) =>
|
|
104
|
+
this.socket.on('message', async (messageBuffer, isBinary) => {
|
|
121
105
|
let message = isBinary ? messageBuffer : messageBuffer.toString();
|
|
122
106
|
this.inboundReceivedMessageCount++;
|
|
123
107
|
let isPong = message === pongMessage;
|
|
@@ -127,7 +111,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
127
111
|
if (this.server.hasMiddleware(MiddlewareType.MIDDLEWARE_INBOUND_RAW)) {
|
|
128
112
|
const action = new ActionMessage(this, message);
|
|
129
113
|
try {
|
|
130
|
-
const { data } =
|
|
114
|
+
const { data } = await this.server._processMiddlewareAction(this.middlewareInboundRawStream, action, this);
|
|
131
115
|
message = data;
|
|
132
116
|
}
|
|
133
117
|
catch (error) {
|
|
@@ -137,7 +121,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
137
121
|
}
|
|
138
122
|
this.inboundMessageStream.write(message);
|
|
139
123
|
this.emit('message', { message });
|
|
140
|
-
})
|
|
124
|
+
});
|
|
141
125
|
}
|
|
142
126
|
getBackpressure() {
|
|
143
127
|
return Math.max(this.getInboundBackpressure(), this.getOutboundBackpressure(), this.getListenerBackpressure(), this.receiver.getBackpressure(), this.procedure.getBackpressure());
|
|
@@ -159,453 +143,429 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
159
143
|
}
|
|
160
144
|
}, this.batchOnHandshakeDuration);
|
|
161
145
|
}
|
|
162
|
-
_handleInboundMessageStream(pongMessage) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
this.inboundProcessedMessageCount++;
|
|
172
|
-
let isPong = message === pongMessage;
|
|
173
|
-
if (isPong) {
|
|
174
|
-
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
175
|
-
this._destroy(4009);
|
|
176
|
-
this.socket.close(4009);
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
let token = this.getAuthToken();
|
|
180
|
-
if (this.isAuthTokenExpired(token)) {
|
|
181
|
-
this.deauthenticate();
|
|
182
|
-
}
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
let packet;
|
|
186
|
-
try {
|
|
187
|
-
packet = this.decode(message);
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
if (error.name === 'Error') {
|
|
191
|
-
error.name = 'InvalidMessageError';
|
|
192
|
-
}
|
|
193
|
-
this.emitError(error);
|
|
194
|
-
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
195
|
-
this._destroy(4009);
|
|
196
|
-
this.socket.close(4009);
|
|
197
|
-
}
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (Array.isArray(packet)) {
|
|
201
|
-
let len = packet.length;
|
|
202
|
-
for (let i = 0; i < len; i++) {
|
|
203
|
-
yield this._processInboundPacket(packet[i], message);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
yield this._processInboundPacket(packet, message);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
finally {
|
|
211
|
-
_d = true;
|
|
212
|
-
}
|
|
146
|
+
async _handleInboundMessageStream(pongMessage) {
|
|
147
|
+
for await (let message of this.inboundMessageStream) {
|
|
148
|
+
this.inboundProcessedMessageCount++;
|
|
149
|
+
let isPong = message === pongMessage;
|
|
150
|
+
if (isPong) {
|
|
151
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
152
|
+
this._destroy(4009);
|
|
153
|
+
this.socket.close(4009);
|
|
154
|
+
continue;
|
|
213
155
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
156
|
+
let token = this.getAuthToken();
|
|
157
|
+
if (this.isAuthTokenExpired(token)) {
|
|
158
|
+
this.deauthenticate();
|
|
219
159
|
}
|
|
220
|
-
|
|
160
|
+
continue;
|
|
221
161
|
}
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
_handleHandshakeTimeout() {
|
|
225
|
-
this.disconnect(4005);
|
|
226
|
-
}
|
|
227
|
-
_processHandshakeRequest(request) {
|
|
228
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
229
|
-
let data = request.data || { authToken: '' };
|
|
230
|
-
let signedAuthToken = data.authToken;
|
|
231
|
-
clearTimeout(this._handshakeTimeoutRef);
|
|
232
|
-
const authInfo = yield this._validateAuthToken(signedAuthToken);
|
|
233
|
-
const action = new ActionHandshakeSC(this, request, authInfo);
|
|
162
|
+
let packet;
|
|
234
163
|
try {
|
|
235
|
-
|
|
164
|
+
packet = this.decode(message);
|
|
236
165
|
}
|
|
237
166
|
catch (error) {
|
|
238
|
-
if (error.
|
|
239
|
-
error.
|
|
167
|
+
if (error.name === 'Error') {
|
|
168
|
+
error.name = 'InvalidMessageError';
|
|
240
169
|
}
|
|
241
|
-
|
|
242
|
-
this.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const oldAuthState = this.authState;
|
|
246
|
-
let authError = undefined;
|
|
247
|
-
try {
|
|
248
|
-
yield this._processAuthentication(authInfo);
|
|
249
|
-
if (this.state === SocketState.CLOSED) {
|
|
250
|
-
return;
|
|
170
|
+
this.emitError(error);
|
|
171
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
172
|
+
this._destroy(4009);
|
|
173
|
+
this.socket.close(4009);
|
|
251
174
|
}
|
|
175
|
+
continue;
|
|
252
176
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
authError = dehydrateError(error);
|
|
258
|
-
if (error.isBadToken) {
|
|
259
|
-
this.deauthenticate();
|
|
260
|
-
}
|
|
177
|
+
if (Array.isArray(packet)) {
|
|
178
|
+
let len = packet.length;
|
|
179
|
+
for (let i = 0; i < len; i++) {
|
|
180
|
+
await this._processInboundPacket(packet[i], message);
|
|
261
181
|
}
|
|
262
182
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
pingTimeout: this.server.pingTimeout,
|
|
266
|
-
isAuthenticated: !!this.authToken,
|
|
267
|
-
authError: authError
|
|
268
|
-
};
|
|
269
|
-
const serverSocketStatus = {
|
|
270
|
-
id: this.id,
|
|
271
|
-
pingTimeout: this.server.pingTimeout,
|
|
272
|
-
isAuthenticated: !!this.authToken,
|
|
273
|
-
authError: authError
|
|
274
|
-
};
|
|
275
|
-
if (this.server.pendingClients[this.id]) {
|
|
276
|
-
delete this.server.pendingClients[this.id];
|
|
277
|
-
this.server.pendingClientsCount--;
|
|
278
|
-
}
|
|
279
|
-
this.server.clients[this.id] = this;
|
|
280
|
-
this.server.clientsCount++;
|
|
281
|
-
this.state = SocketState.OPEN;
|
|
282
|
-
if (clientSocketStatus.isAuthenticated) {
|
|
283
|
-
// Needs to be executed after the connection event to allow
|
|
284
|
-
// consumers to be setup from inside the connection loop.
|
|
285
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
286
|
-
yield this.listen('connect').once();
|
|
287
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
288
|
-
}))();
|
|
289
|
-
}
|
|
290
|
-
// Treat authentication failure as a 'soft' error
|
|
291
|
-
request.end(clientSocketStatus);
|
|
292
|
-
if (this.batchOnHandshake) {
|
|
293
|
-
this._startBatchOnHandshake();
|
|
183
|
+
else {
|
|
184
|
+
await this._processInboundPacket(packet, message);
|
|
294
185
|
}
|
|
295
|
-
|
|
296
|
-
this.server.emit('connection', Object.assign({ socket: this }, serverSocketStatus));
|
|
297
|
-
this.middlewareHandshakeStream.close();
|
|
298
|
-
});
|
|
186
|
+
}
|
|
299
187
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
188
|
+
_handleHandshakeTimeout() {
|
|
189
|
+
this.disconnect(4005);
|
|
190
|
+
}
|
|
191
|
+
async _processHandshakeRequest(request) {
|
|
192
|
+
let data = request.data || { authToken: '' };
|
|
193
|
+
let signedAuthToken = data.authToken;
|
|
194
|
+
clearTimeout(this._handshakeTimeoutRef);
|
|
195
|
+
const authInfo = await this._validateAuthToken(signedAuthToken);
|
|
196
|
+
const action = new ActionHandshakeSC(this, request, authInfo);
|
|
197
|
+
try {
|
|
198
|
+
await this.server._processMiddlewareAction(this.middlewareHandshakeStream, action);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
if (error.statusCode == null) {
|
|
202
|
+
error.statusCode = HANDSHAKE_REJECTION_STATUS_CODE;
|
|
307
203
|
}
|
|
308
|
-
|
|
309
|
-
|
|
204
|
+
request.error(error);
|
|
205
|
+
this.disconnect(error.statusCode);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const oldAuthState = this.authState;
|
|
209
|
+
let authError = undefined;
|
|
210
|
+
try {
|
|
211
|
+
await this._processAuthentication(authInfo);
|
|
212
|
+
if (this.state === SocketState.CLOSED) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (signedAuthToken != null) {
|
|
218
|
+
// Because the token is optional as part of the handshake, we don't count
|
|
219
|
+
// it as an error if the token wasn't provided.
|
|
220
|
+
authError = dehydrateError(error);
|
|
221
|
+
if (error.isBadToken) {
|
|
310
222
|
this.deauthenticate();
|
|
311
|
-
request.error(error);
|
|
312
|
-
return;
|
|
313
223
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const clientSocketStatus = {
|
|
227
|
+
id: this.id,
|
|
228
|
+
pingTimeout: this.server.pingTimeout,
|
|
229
|
+
isAuthenticated: !!this.authToken,
|
|
230
|
+
authError: authError
|
|
231
|
+
};
|
|
232
|
+
const serverSocketStatus = {
|
|
233
|
+
id: this.id,
|
|
234
|
+
pingTimeout: this.server.pingTimeout,
|
|
235
|
+
isAuthenticated: !!this.authToken,
|
|
236
|
+
authError: authError
|
|
237
|
+
};
|
|
238
|
+
if (this.server.pendingClients[this.id]) {
|
|
239
|
+
delete this.server.pendingClients[this.id];
|
|
240
|
+
this.server.pendingClientsCount--;
|
|
241
|
+
}
|
|
242
|
+
this.server.clients[this.id] = this;
|
|
243
|
+
this.server.clientsCount++;
|
|
244
|
+
this.state = SocketState.OPEN;
|
|
245
|
+
if (clientSocketStatus.isAuthenticated) {
|
|
246
|
+
// Needs to be executed after the connection event to allow
|
|
247
|
+
// consumers to be setup from inside the connection loop.
|
|
248
|
+
(async () => {
|
|
249
|
+
await this.listen('connect').once();
|
|
250
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
251
|
+
})();
|
|
252
|
+
}
|
|
253
|
+
// Treat authentication failure as a 'soft' error
|
|
254
|
+
request.end(clientSocketStatus);
|
|
255
|
+
if (this.batchOnHandshake) {
|
|
256
|
+
this._startBatchOnHandshake();
|
|
257
|
+
}
|
|
258
|
+
this.emit('connect', serverSocketStatus);
|
|
259
|
+
this.server.emit('connection', { socket: this, ...serverSocketStatus });
|
|
260
|
+
this.middlewareHandshakeStream.close();
|
|
261
|
+
}
|
|
262
|
+
async _processAuthenticateRequest(request) {
|
|
263
|
+
let signedAuthToken = request.data;
|
|
264
|
+
let oldAuthState = this.authState;
|
|
265
|
+
let authInfo = await this._validateAuthToken(signedAuthToken);
|
|
266
|
+
try {
|
|
267
|
+
await this._processAuthentication(authInfo);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
if (error instanceof AuthTokenError) {
|
|
271
|
+
this.deauthenticate();
|
|
272
|
+
request.error(error);
|
|
318
273
|
return;
|
|
319
274
|
}
|
|
320
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
321
275
|
request.end({
|
|
322
276
|
isAuthenticated: !!this.authToken,
|
|
323
|
-
authError: null
|
|
277
|
+
authError: signedAuthToken == null ? null : dehydrateError(error)
|
|
324
278
|
});
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
282
|
+
request.end({
|
|
283
|
+
isAuthenticated: !!this.authToken,
|
|
284
|
+
authError: null
|
|
325
285
|
});
|
|
326
286
|
}
|
|
327
|
-
_subscribeSocket(channelName, subscriptionOptions) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
channel: channelName,
|
|
355
|
-
subscriptionOptions
|
|
356
|
-
});
|
|
357
|
-
this.server.emit('subscription', {
|
|
358
|
-
socket: this,
|
|
359
|
-
channel: channelName,
|
|
360
|
-
subscriptionOptions
|
|
361
|
-
});
|
|
287
|
+
async _subscribeSocket(channelName, subscriptionOptions) {
|
|
288
|
+
if (this.server.socketChannelLimit && this.channelSubscriptionsCount >= this.server.socketChannelLimit) {
|
|
289
|
+
throw new InvalidActionError(`Socket ${this.id} tried to exceed the channel subscription limit of ${this.server.socketChannelLimit}`);
|
|
290
|
+
}
|
|
291
|
+
if (this.channelSubscriptionsCount == null) {
|
|
292
|
+
this.channelSubscriptionsCount = 0;
|
|
293
|
+
}
|
|
294
|
+
if (this.channelSubscriptions[channelName] == null) {
|
|
295
|
+
this.channelSubscriptions[channelName] = true;
|
|
296
|
+
this.channelSubscriptionsCount++;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
this.server.brokerEngine.subscribeSocket(this, channelName);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
delete this.channelSubscriptions[channelName];
|
|
303
|
+
this.channelSubscriptionsCount--;
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
this.emit('subscribe', {
|
|
307
|
+
channel: channelName,
|
|
308
|
+
subscriptionOptions
|
|
309
|
+
});
|
|
310
|
+
this.server.emit('subscription', {
|
|
311
|
+
socket: this,
|
|
312
|
+
channel: channelName,
|
|
313
|
+
subscriptionOptions
|
|
362
314
|
});
|
|
363
315
|
}
|
|
364
|
-
_processSubscribeRequest(request) {
|
|
365
|
-
|
|
316
|
+
async _processSubscribeRequest(request) {
|
|
317
|
+
if (this.state === SocketState.OPEN) {
|
|
366
318
|
let subscriptionOptions = Object.assign({}, request.data);
|
|
367
319
|
let channelName = subscriptionOptions.channel;
|
|
368
320
|
delete subscriptionOptions.channel;
|
|
369
|
-
if (this.state === SocketState.OPEN) {
|
|
370
|
-
try {
|
|
371
|
-
yield this._subscribeSocket(channelName, subscriptionOptions);
|
|
372
|
-
}
|
|
373
|
-
catch (err) {
|
|
374
|
-
let error = new BrokerError(`Failed to subscribe socket to the ${channelName} channel - ${err}`);
|
|
375
|
-
this.emitError(error);
|
|
376
|
-
request.error(error);
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
request.end();
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
// This is an invalid state; it means the client tried to subscribe before
|
|
383
|
-
// having completed the handshake.
|
|
384
|
-
let error = new InvalidActionError('Cannot subscribe socket to a channel before it has completed the handshake');
|
|
385
|
-
this.emitError(error);
|
|
386
|
-
request.error(error);
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
_unsubscribeFromAllChannels() {
|
|
390
|
-
const channels = Object.keys(this.channelSubscriptions);
|
|
391
|
-
return Promise.all(channels.map((channel) => this._unsubscribe(channel)));
|
|
392
|
-
}
|
|
393
|
-
_unsubscribe(channel) {
|
|
394
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
395
|
-
if (typeof channel !== 'string') {
|
|
396
|
-
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from an invalid channel name`);
|
|
397
|
-
}
|
|
398
|
-
if (!this.channelSubscriptions[channel]) {
|
|
399
|
-
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from a channel which it is not subscribed to`);
|
|
400
|
-
}
|
|
401
321
|
try {
|
|
402
|
-
|
|
403
|
-
delete this.channelSubscriptions[channel];
|
|
404
|
-
if (this.channelSubscriptionsCount != null) {
|
|
405
|
-
this.channelSubscriptionsCount--;
|
|
406
|
-
}
|
|
407
|
-
this.emit('unsubscribe', { channel });
|
|
408
|
-
this.server.emit('unsubscription', { socket: this, channel });
|
|
322
|
+
await this._subscribeSocket(channelName, subscriptionOptions);
|
|
409
323
|
}
|
|
410
324
|
catch (err) {
|
|
411
|
-
|
|
412
|
-
this.emitError(error);
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
_processUnsubscribePacket(packet) {
|
|
417
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
418
|
-
let channel = packet.data;
|
|
419
|
-
try {
|
|
420
|
-
yield this._unsubscribe(channel);
|
|
421
|
-
}
|
|
422
|
-
catch (err) {
|
|
423
|
-
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
424
|
-
this.emitError(error);
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
_processUnsubscribeRequest(request) {
|
|
429
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
430
|
-
const channel = request.data;
|
|
431
|
-
try {
|
|
432
|
-
yield this._unsubscribe(channel);
|
|
433
|
-
}
|
|
434
|
-
catch (err) {
|
|
435
|
-
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
325
|
+
let error = new BrokerError(`Failed to subscribe socket to the ${channelName} channel - ${err}`);
|
|
436
326
|
this.emitError(error);
|
|
437
327
|
request.error(error);
|
|
438
328
|
return;
|
|
439
329
|
}
|
|
440
330
|
request.end();
|
|
441
|
-
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
// This is an invalid state; it means the client tried to subscribe before
|
|
334
|
+
// having completed the handshake.
|
|
335
|
+
let error = new InvalidActionError('Cannot subscribe socket to a channel before it has completed the handshake');
|
|
336
|
+
this.emitError(error);
|
|
337
|
+
request.error(error);
|
|
442
338
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
339
|
+
async _unsubscribeFromAllChannels() {
|
|
340
|
+
const channels = Object.keys(this.channelSubscriptions);
|
|
341
|
+
await Promise.all(channels.map((channel) => this._unsubscribe(channel)));
|
|
342
|
+
}
|
|
343
|
+
async _unsubscribe(channel) {
|
|
344
|
+
if (typeof channel !== 'string') {
|
|
345
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from an invalid channel name`);
|
|
346
|
+
}
|
|
347
|
+
if (!this.channelSubscriptions[channel]) {
|
|
348
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from a channel which it is not subscribed to`);
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
await this.server.brokerEngine.unsubscribeSocket(this, channel);
|
|
352
|
+
delete this.channelSubscriptions[channel];
|
|
353
|
+
if (this.channelSubscriptionsCount != null) {
|
|
354
|
+
this.channelSubscriptionsCount--;
|
|
456
355
|
}
|
|
457
|
-
|
|
356
|
+
this.emit('unsubscribe', { channel });
|
|
357
|
+
this.server.emit('unsubscription', { socket: this, channel });
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
const error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
361
|
+
this.emitError(error);
|
|
362
|
+
}
|
|
458
363
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
364
|
+
async _processUnsubscribePacket(packet) {
|
|
365
|
+
let channel = packet.data;
|
|
366
|
+
try {
|
|
367
|
+
await this._unsubscribe(channel);
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
371
|
+
this.emitError(error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async _processUnsubscribeRequest(request) {
|
|
375
|
+
const channel = request.data;
|
|
376
|
+
try {
|
|
377
|
+
await this._unsubscribe(channel);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
381
|
+
this.emitError(error);
|
|
382
|
+
request.error(error);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
request.end();
|
|
386
|
+
}
|
|
387
|
+
async _processInboundPublishPacket(packet) {
|
|
388
|
+
try {
|
|
389
|
+
await this.server.exchange.invokePublish(packet.data.channel, packet.data.data);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
this.emitError(error);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async _processInboundPublishRequest(request) {
|
|
396
|
+
try {
|
|
397
|
+
await this.server.exchange.invokePublish(request.data.channel, request.data.data);
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
this.emitError(error);
|
|
401
|
+
request.error(error);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
request.end();
|
|
405
|
+
}
|
|
406
|
+
async _processInboundPacket(packet, message) {
|
|
407
|
+
if (packet && typeof packet.event === 'string') {
|
|
408
|
+
let isRPC = ('cid' in packet) && typeof packet.cid === 'number';
|
|
409
|
+
if (isHandshakePacket(packet)) {
|
|
410
|
+
if (!isRPC) {
|
|
411
|
+
let error = new InvalidActionError('Handshake request was malformatted');
|
|
412
|
+
this.emitError(error);
|
|
413
|
+
this._destroy(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
414
|
+
this.socket.close(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const request = new HandshakeRequest(this, packet.cid, packet.event, packet.data);
|
|
418
|
+
await this._processHandshakeRequest(request);
|
|
419
|
+
this._procedureDemux.write(request.procedure, request);
|
|
466
420
|
return;
|
|
467
421
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
catch (error) {
|
|
472
|
-
this.emitError(error);
|
|
473
|
-
request.error(error);
|
|
422
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
423
|
+
this._destroy(4009);
|
|
424
|
+
this.socket.close(4009);
|
|
474
425
|
return;
|
|
475
426
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
let isRPC = ('cid' in packet);
|
|
483
|
-
if (isHandshakePacket(packet)) {
|
|
484
|
-
const request = new HandshakeRequest(this, packet.cid, packet.event, packet.data);
|
|
485
|
-
yield this._processHandshakeRequest(request);
|
|
486
|
-
this._procedureDemux.write(request.procedure, request);
|
|
427
|
+
if (isAuthenticatePacket(packet)) {
|
|
428
|
+
if (!isRPC) {
|
|
429
|
+
let error = new InvalidActionError('Authenticate request was malformatted');
|
|
430
|
+
this.emitError(error);
|
|
431
|
+
this._destroy(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
432
|
+
this.socket.close(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
487
433
|
return;
|
|
488
434
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
435
|
+
// Let AGServer handle these events.
|
|
436
|
+
const request = new AuthenticateRequest(this, packet.cid, packet.event, packet.data);
|
|
437
|
+
await this._processAuthenticateRequest(request);
|
|
438
|
+
this._procedureDemux.write(request.procedure, request);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (isRemoveAuthTokenPacket(packet)) {
|
|
442
|
+
this.deauthenticateSelf();
|
|
443
|
+
this._receiverDemux.write(packet.event, packet.data);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (isUnsubscribePacket(packet)) {
|
|
447
|
+
if (typeof packet.data !== 'string') {
|
|
448
|
+
const error = new InvalidActionError('Unsubscribe channel name was malformatted');
|
|
449
|
+
this.emitError(error);
|
|
450
|
+
if (isRPC) {
|
|
451
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
452
|
+
request.error(error);
|
|
453
|
+
}
|
|
492
454
|
return;
|
|
493
455
|
}
|
|
494
|
-
if (
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
yield this._processAuthenticateRequest(request);
|
|
456
|
+
if (isRPC) {
|
|
457
|
+
const request = new UnsubscribeRequest(this, packet.cid, packet.event, packet.data);
|
|
458
|
+
await this._processUnsubscribeRequest(request);
|
|
498
459
|
this._procedureDemux.write(request.procedure, request);
|
|
499
460
|
return;
|
|
500
461
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
462
|
+
await this._processUnsubscribePacket(packet);
|
|
463
|
+
this._receiverDemux.write(packet.event, packet.data);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
let action;
|
|
467
|
+
if (isPublishPacket(packet)) {
|
|
468
|
+
if (!this.server.allowClientPublish) {
|
|
469
|
+
let error = new InvalidActionError('Client publish feature is disabled');
|
|
470
|
+
this.emitError(error);
|
|
507
471
|
if (isRPC) {
|
|
508
|
-
const request = new
|
|
509
|
-
|
|
510
|
-
this._procedureDemux.write(request.procedure, request);
|
|
511
|
-
return;
|
|
472
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
473
|
+
request.error(error);
|
|
512
474
|
}
|
|
513
|
-
yield this._processUnsubscribePacket(packet);
|
|
514
|
-
this._receiverDemux.write(packet.event, packet.data);
|
|
515
475
|
return;
|
|
516
476
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
this.
|
|
522
|
-
|
|
523
|
-
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
524
|
-
request.error(error);
|
|
525
|
-
}
|
|
526
|
-
return;
|
|
477
|
+
if (!packet.data || typeof packet.data.channel !== 'string') {
|
|
478
|
+
const error = new InvalidActionError('Publish channel name was malformatted');
|
|
479
|
+
this.emitError(error);
|
|
480
|
+
if (isRPC) {
|
|
481
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
482
|
+
request.error(error);
|
|
527
483
|
}
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
else if (isSubscribePacket(packet)) {
|
|
531
|
-
action = new ActionSubscribe(this, packet.data);
|
|
532
|
-
}
|
|
533
|
-
else if (isRPC) {
|
|
534
|
-
action = new ActionInvoke(this, packet.event, packet.data);
|
|
535
|
-
}
|
|
536
|
-
else {
|
|
537
|
-
action = new ActionTransmit(this, packet.event, packet.data);
|
|
538
|
-
}
|
|
539
|
-
const tokenExpiredError = this._processAuthTokenExpiry();
|
|
540
|
-
if (tokenExpiredError) {
|
|
541
|
-
action.authTokenExpiredError = tokenExpiredError;
|
|
484
|
+
return;
|
|
542
485
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
this
|
|
551
|
-
|
|
552
|
-
}
|
|
553
|
-
let request;
|
|
554
|
-
if (isSubscribePacket(packet) || isPublishPacket(packet)) {
|
|
555
|
-
request = new Request(this, packet.cid, packet.event, packet.data);
|
|
556
|
-
if (!request.data) {
|
|
557
|
-
request.data = {};
|
|
558
|
-
}
|
|
559
|
-
request.data.data = newData;
|
|
560
|
-
if (isSubscribePacket(packet)) {
|
|
561
|
-
yield this._processSubscribeRequest(request);
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
yield this._processInboundPublishRequest(request);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
request = new RequestWithResponse(this, packet.cid, packet.event, newData);
|
|
486
|
+
action = new ActionPublishIn(this, packet.data);
|
|
487
|
+
}
|
|
488
|
+
else if (isSubscribePacket(packet)) {
|
|
489
|
+
if (!packet.data || typeof packet.data.channel !== 'string') {
|
|
490
|
+
const error = new InvalidActionError('Subscribe channel name was malformatted');
|
|
491
|
+
this.emitError(error);
|
|
492
|
+
if (isRPC) {
|
|
493
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
494
|
+
request.error(error);
|
|
569
495
|
}
|
|
570
|
-
this._procedureDemux.write(request.procedure, request);
|
|
571
496
|
return;
|
|
572
497
|
}
|
|
498
|
+
action = new ActionSubscribe(this, packet.data);
|
|
499
|
+
}
|
|
500
|
+
else if (isRPC) {
|
|
501
|
+
action = new ActionInvoke(this, packet.event, packet.data);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
action = new ActionTransmit(this, packet.event, packet.data);
|
|
505
|
+
}
|
|
506
|
+
const tokenExpiredError = this._processAuthTokenExpiry();
|
|
507
|
+
if (tokenExpiredError) {
|
|
508
|
+
action.authTokenExpiredError = tokenExpiredError;
|
|
509
|
+
}
|
|
510
|
+
let newData;
|
|
511
|
+
if (isRPC) {
|
|
573
512
|
try {
|
|
574
|
-
let { data } =
|
|
513
|
+
let { data } = await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
575
514
|
newData = data;
|
|
576
515
|
}
|
|
577
516
|
catch (error) {
|
|
517
|
+
this.sendObject(createErrorResponse(packet.cid, error));
|
|
578
518
|
return;
|
|
579
519
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
520
|
+
let request;
|
|
521
|
+
if (isSubscribePacket(packet) || isPublishPacket(packet)) {
|
|
522
|
+
request = new Request(this, packet.cid, packet.event, packet.data);
|
|
523
|
+
request.data.data = newData;
|
|
524
|
+
if (isSubscribePacket(packet)) {
|
|
525
|
+
await this._processSubscribeRequest(request);
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
await this._processInboundPublishRequest(request);
|
|
583
529
|
}
|
|
584
|
-
packet.data.data = newData;
|
|
585
|
-
yield this._processInboundPublishPacket(packet);
|
|
586
530
|
}
|
|
587
|
-
|
|
531
|
+
else {
|
|
532
|
+
request = new RequestWithResponse(this, packet.cid, packet.event, newData);
|
|
533
|
+
}
|
|
534
|
+
this._procedureDemux.write(request.procedure, request);
|
|
588
535
|
return;
|
|
589
536
|
}
|
|
590
|
-
|
|
591
|
-
this.
|
|
592
|
-
|
|
593
|
-
return;
|
|
537
|
+
try {
|
|
538
|
+
let { data } = await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
539
|
+
newData = data;
|
|
594
540
|
}
|
|
595
|
-
|
|
596
|
-
// If incoming message is a response to a previously sent message
|
|
597
|
-
const ret = this._callbackMap[packet.rid];
|
|
598
|
-
if (ret) {
|
|
599
|
-
clearTimeout(ret.timeout);
|
|
600
|
-
delete this._callbackMap[packet.rid];
|
|
601
|
-
const rehydratedError = hydrateError(packet.error);
|
|
602
|
-
ret.callback(rehydratedError, packet.data);
|
|
603
|
-
}
|
|
541
|
+
catch (error) {
|
|
604
542
|
return;
|
|
605
543
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
544
|
+
if (isPublishPacket(packet)) {
|
|
545
|
+
packet.data.data = newData;
|
|
546
|
+
await this._processInboundPublishPacket(packet);
|
|
547
|
+
}
|
|
548
|
+
this._receiverDemux.write(packet.event, newData);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
552
|
+
this._destroy(4009);
|
|
553
|
+
this.socket.close(4009);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (packet && 'rid' in packet && typeof packet.rid === 'number') {
|
|
557
|
+
// If incoming message is a response to a previously sent message
|
|
558
|
+
const ret = this._callbackMap[packet.rid];
|
|
559
|
+
if (ret) {
|
|
560
|
+
clearTimeout(ret.timeout);
|
|
561
|
+
delete this._callbackMap[packet.rid];
|
|
562
|
+
const rehydratedError = hydrateError(packet.error);
|
|
563
|
+
ret.callback(rehydratedError, packet.data);
|
|
564
|
+
}
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
// The last remaining case is to treat the message as raw
|
|
568
|
+
this.emit('raw', { message });
|
|
609
569
|
}
|
|
610
570
|
_resetPongTimeout() {
|
|
611
571
|
if (this.server.pingTimeoutDisabled) {
|
|
@@ -636,7 +596,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
636
596
|
delete this._callbackMap[i];
|
|
637
597
|
clearTimeout(eventObject.timeout);
|
|
638
598
|
delete eventObject.timeout;
|
|
639
|
-
const errorMessage = `Event
|
|
599
|
+
const errorMessage = `Event ${eventObject.event} was aborted due to a bad connection`;
|
|
640
600
|
const badConnectionError = new BadConnectionError(errorMessage, failureType);
|
|
641
601
|
const callback = eventObject.callback;
|
|
642
602
|
delete eventObject.callback;
|
|
@@ -689,71 +649,69 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
689
649
|
this.procedure.kill();
|
|
690
650
|
this.killListeners();
|
|
691
651
|
}
|
|
692
|
-
_destroy(code, reason) {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
652
|
+
async _destroy(code, reason) {
|
|
653
|
+
clearInterval(this._pingIntervalTicker);
|
|
654
|
+
clearTimeout(this._pingTimeoutTicker);
|
|
655
|
+
this._cancelBatching();
|
|
656
|
+
if (this.state === SocketState.CLOSED) {
|
|
657
|
+
this._abortAllPendingEventsDueToBadConnection('connectAbort');
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
if (!reason) {
|
|
661
|
+
reason = socketProtocolErrorStatuses[code];
|
|
662
|
+
}
|
|
663
|
+
const prevState = this.state;
|
|
664
|
+
this.state = SocketState.CLOSED;
|
|
665
|
+
if (prevState === SocketState.CONNECTING) {
|
|
698
666
|
this._abortAllPendingEventsDueToBadConnection('connectAbort');
|
|
667
|
+
this.emit('connectAbort', { code, reason });
|
|
668
|
+
this.server.emit('connectionAbort', { socket: this, code, reason });
|
|
699
669
|
}
|
|
700
670
|
else {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
671
|
+
this._abortAllPendingEventsDueToBadConnection('disconnect');
|
|
672
|
+
this.emit('disconnect', { code, reason });
|
|
673
|
+
this.server.emit('disconnection', { socket: this, code, reason });
|
|
674
|
+
}
|
|
675
|
+
this.emit('close', { code, reason });
|
|
676
|
+
this.server.emit('closure', { socket: this, code, reason });
|
|
677
|
+
clearTimeout(this._handshakeTimeoutRef);
|
|
678
|
+
let isClientFullyConnected = !!this.server.clients[this.id];
|
|
679
|
+
if (isClientFullyConnected) {
|
|
680
|
+
delete this.server.clients[this.id];
|
|
681
|
+
this.server.clientsCount--;
|
|
682
|
+
}
|
|
683
|
+
let isClientPending = !!this.server.pendingClients[this.id];
|
|
684
|
+
if (isClientPending) {
|
|
685
|
+
delete this.server.pendingClients[this.id];
|
|
686
|
+
this.server.pendingClientsCount--;
|
|
687
|
+
}
|
|
688
|
+
if (!socketProtocolIgnoreStatuses[code]) {
|
|
689
|
+
let closeMessage;
|
|
690
|
+
if (typeof reason === 'string') {
|
|
691
|
+
closeMessage = `Socket connection closed with status code ${code} and reason: ${reason}`;
|
|
710
692
|
}
|
|
711
693
|
else {
|
|
712
|
-
|
|
713
|
-
this.emit('disconnect', { code, reason });
|
|
714
|
-
this.server.emit('disconnection', { socket: this, code, reason });
|
|
715
|
-
}
|
|
716
|
-
this.emit('close', { code, reason });
|
|
717
|
-
this.server.emit('closure', { socket: this, code, reason });
|
|
718
|
-
clearTimeout(this._handshakeTimeoutRef);
|
|
719
|
-
let isClientFullyConnected = !!this.server.clients[this.id];
|
|
720
|
-
if (isClientFullyConnected) {
|
|
721
|
-
delete this.server.clients[this.id];
|
|
722
|
-
this.server.clientsCount--;
|
|
723
|
-
}
|
|
724
|
-
let isClientPending = !!this.server.pendingClients[this.id];
|
|
725
|
-
if (isClientPending) {
|
|
726
|
-
delete this.server.pendingClients[this.id];
|
|
727
|
-
this.server.pendingClientsCount--;
|
|
728
|
-
}
|
|
729
|
-
if (!socketProtocolIgnoreStatuses[code]) {
|
|
730
|
-
let closeMessage;
|
|
731
|
-
if (reason) {
|
|
732
|
-
closeMessage = `Socket connection closed with status code ${code} and reason: ${reason}`;
|
|
733
|
-
}
|
|
734
|
-
else {
|
|
735
|
-
closeMessage = `Socket connection closed with status code ${code}`;
|
|
736
|
-
}
|
|
737
|
-
let err = new SocketProtocolError(socketProtocolErrorStatuses[code] || closeMessage, code);
|
|
738
|
-
this.emitError(err);
|
|
739
|
-
}
|
|
740
|
-
yield this._unsubscribeFromAllChannels();
|
|
741
|
-
let cleanupMode = this.server.options.socketStreamCleanupMode;
|
|
742
|
-
if (cleanupMode === 'kill') {
|
|
743
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
744
|
-
yield this.listen('end').once();
|
|
745
|
-
this.killAllStreams();
|
|
746
|
-
}))();
|
|
694
|
+
closeMessage = `Socket connection closed with status code ${code}`;
|
|
747
695
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
yield this.listen('end').once();
|
|
751
|
-
this.closeAllStreams();
|
|
752
|
-
}))();
|
|
753
|
-
}
|
|
754
|
-
this.emit('end');
|
|
696
|
+
let err = new SocketProtocolError(socketProtocolErrorStatuses[code] || closeMessage, code);
|
|
697
|
+
this.emitError(err);
|
|
755
698
|
}
|
|
756
|
-
|
|
699
|
+
await this._unsubscribeFromAllChannels();
|
|
700
|
+
let cleanupMode = this.server.options.socketStreamCleanupMode;
|
|
701
|
+
if (cleanupMode === 'kill') {
|
|
702
|
+
(async () => {
|
|
703
|
+
await this.listen('end').once();
|
|
704
|
+
this.killAllStreams();
|
|
705
|
+
})();
|
|
706
|
+
}
|
|
707
|
+
else if (cleanupMode === 'close') {
|
|
708
|
+
(async () => {
|
|
709
|
+
await this.listen('end').once();
|
|
710
|
+
this.closeAllStreams();
|
|
711
|
+
})();
|
|
712
|
+
}
|
|
713
|
+
this.emit('end');
|
|
714
|
+
}
|
|
757
715
|
}
|
|
758
716
|
disconnect(code, reason) {
|
|
759
717
|
code = code || 1000;
|
|
@@ -863,47 +821,27 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
863
821
|
this.send(str);
|
|
864
822
|
}
|
|
865
823
|
}
|
|
866
|
-
_handleOutboundPacketStream() {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
_d = false;
|
|
824
|
+
async _handleOutboundPacketStream() {
|
|
825
|
+
for await (let packet of this.outboundPacketStream) {
|
|
826
|
+
if ('resolve' in packet) {
|
|
827
|
+
// Invoke has no middleware, so there is no need to await here.
|
|
828
|
+
(async () => {
|
|
829
|
+
let result;
|
|
873
830
|
try {
|
|
874
|
-
|
|
875
|
-
if ('resolve' in packet) {
|
|
876
|
-
// Invoke has no middleware, so there is no need to await here.
|
|
877
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
878
|
-
let result;
|
|
879
|
-
try {
|
|
880
|
-
result = yield this._invoke(packet);
|
|
881
|
-
}
|
|
882
|
-
catch (error) {
|
|
883
|
-
packet.reject(error);
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
packet.resolve(result);
|
|
887
|
-
}))();
|
|
888
|
-
this.outboundSentMessageCount++;
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
yield this._processTransmit(packet);
|
|
892
|
-
this.outboundSentMessageCount++;
|
|
831
|
+
result = await this._invoke(packet);
|
|
893
832
|
}
|
|
894
|
-
|
|
895
|
-
|
|
833
|
+
catch (error) {
|
|
834
|
+
packet.reject(error);
|
|
835
|
+
return;
|
|
896
836
|
}
|
|
897
|
-
|
|
837
|
+
packet.resolve(result);
|
|
838
|
+
})();
|
|
839
|
+
this.outboundSentMessageCount++;
|
|
840
|
+
continue;
|
|
898
841
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
903
|
-
}
|
|
904
|
-
finally { if (e_2) throw e_2.error; }
|
|
905
|
-
}
|
|
906
|
-
});
|
|
842
|
+
await this._processTransmit(packet);
|
|
843
|
+
this.outboundSentMessageCount++;
|
|
844
|
+
}
|
|
907
845
|
}
|
|
908
846
|
_transmit(event, data, options) {
|
|
909
847
|
if (this.cloneData) {
|
|
@@ -918,31 +856,29 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
918
856
|
}
|
|
919
857
|
transmit(event, data, options) {
|
|
920
858
|
if (this.state !== SocketState.OPEN) {
|
|
921
|
-
let error = new BadConnectionError(`Socket transmit
|
|
859
|
+
let error = new BadConnectionError(`Socket transmit ${event} event was aborted due to a bad connection`, 'connectAbort');
|
|
922
860
|
this.emitError(error);
|
|
923
861
|
return;
|
|
924
862
|
}
|
|
925
863
|
this._transmit(event, data, options);
|
|
926
864
|
}
|
|
927
|
-
invoke(event, data, options) {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
reject
|
|
945
|
-
});
|
|
865
|
+
async invoke(event, data, options) {
|
|
866
|
+
if (this.state !== SocketState.OPEN) {
|
|
867
|
+
const error = new BadConnectionError(`Socket invoke ${event} event was aborted due to a bad connection`, 'connectAbort');
|
|
868
|
+
this.emitError(error);
|
|
869
|
+
throw error;
|
|
870
|
+
}
|
|
871
|
+
if (this.cloneData) {
|
|
872
|
+
data = cloneDeep(data);
|
|
873
|
+
}
|
|
874
|
+
this.outboundPreparedMessageCount++;
|
|
875
|
+
return new Promise((resolve, reject) => {
|
|
876
|
+
this.outboundPacketStream.write({
|
|
877
|
+
event,
|
|
878
|
+
data,
|
|
879
|
+
options,
|
|
880
|
+
resolve,
|
|
881
|
+
reject
|
|
946
882
|
});
|
|
947
883
|
});
|
|
948
884
|
}
|
|
@@ -952,86 +888,82 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
952
888
|
listen(eventName) {
|
|
953
889
|
return super.listen(eventName);
|
|
954
890
|
}
|
|
955
|
-
_processTransmit(packet) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
891
|
+
async _processTransmit(packet) {
|
|
892
|
+
let newData;
|
|
893
|
+
let useCache = packet.options ? packet.options.useCache : false;
|
|
894
|
+
if (isPublishOutPacket(packet)) {
|
|
895
|
+
const action = new ActionPublishOut(this);
|
|
896
|
+
if (packet.data !== undefined) {
|
|
897
|
+
action.channel = packet.data.channel;
|
|
898
|
+
action.data = packet.data.data;
|
|
899
|
+
}
|
|
900
|
+
useCache = !this.server.hasMiddleware(this.middlewareOutboundStream.type);
|
|
901
|
+
try {
|
|
902
|
+
const { data, options } = await this.server._processMiddlewareAction(this.middlewareOutboundStream, action, this);
|
|
903
|
+
newData = data;
|
|
904
|
+
useCache = options == null ? useCache : options.useCache;
|
|
905
|
+
}
|
|
906
|
+
catch (error) {
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
newData = packet.data;
|
|
912
|
+
}
|
|
913
|
+
if (packet.options && useCache && packet.options.stringifiedData != null && !this.isBufferingBatch) {
|
|
914
|
+
// Optimized
|
|
915
|
+
this.send(packet.options.stringifiedData);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
const eventObject = {
|
|
919
|
+
event: packet.event
|
|
920
|
+
};
|
|
959
921
|
if (isPublishOutPacket(packet)) {
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
action.channel = packet.data.channel;
|
|
963
|
-
action.data = packet.data.data;
|
|
964
|
-
}
|
|
965
|
-
useCache = !this.server.hasMiddleware(this.middlewareOutboundStream.type);
|
|
966
|
-
try {
|
|
967
|
-
const { data, options } = yield this.server._processMiddlewareAction(this.middlewareOutboundStream, action, this);
|
|
968
|
-
newData = data;
|
|
969
|
-
useCache = options == null ? useCache : options.useCache;
|
|
970
|
-
}
|
|
971
|
-
catch (error) {
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
922
|
+
eventObject.data = packet.data || {};
|
|
923
|
+
eventObject.data.data = newData;
|
|
974
924
|
}
|
|
975
925
|
else {
|
|
976
|
-
|
|
926
|
+
eventObject.data = newData;
|
|
977
927
|
}
|
|
978
|
-
|
|
928
|
+
this.sendObject(eventObject);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
async _invoke({ event, data, options }) {
|
|
932
|
+
options = options || {};
|
|
933
|
+
return new Promise((resolve, reject) => {
|
|
934
|
+
const eventObject = {
|
|
935
|
+
event,
|
|
936
|
+
cid: this._nextCallId()
|
|
937
|
+
};
|
|
938
|
+
if (data !== undefined) {
|
|
939
|
+
eventObject.data = data;
|
|
940
|
+
}
|
|
941
|
+
const ackTimeout = options.ackTimeout == null ? this.server.ackTimeout : options.ackTimeout;
|
|
942
|
+
const timeout = setTimeout(() => {
|
|
943
|
+
let error = new TimeoutError(`Event response for ${event} event timed out`);
|
|
944
|
+
delete this._callbackMap[eventObject.cid];
|
|
945
|
+
reject(error);
|
|
946
|
+
}, ackTimeout);
|
|
947
|
+
this._callbackMap[eventObject.cid] = {
|
|
948
|
+
event,
|
|
949
|
+
callback: (err, result) => {
|
|
950
|
+
if (err) {
|
|
951
|
+
reject(err);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
resolve(result);
|
|
955
|
+
},
|
|
956
|
+
timeout
|
|
957
|
+
};
|
|
958
|
+
if (options.useCache && options.stringifiedData != null && !this.isBufferingBatch) {
|
|
979
959
|
// Optimized
|
|
980
|
-
this.send(
|
|
960
|
+
this.send(options.stringifiedData);
|
|
981
961
|
}
|
|
982
962
|
else {
|
|
983
|
-
const eventObject = {
|
|
984
|
-
event: packet.event
|
|
985
|
-
};
|
|
986
|
-
if (isPublishOutPacket(packet)) {
|
|
987
|
-
eventObject.data = packet.data || {};
|
|
988
|
-
eventObject.data.data = newData;
|
|
989
|
-
}
|
|
990
|
-
else {
|
|
991
|
-
eventObject.data = newData;
|
|
992
|
-
}
|
|
993
963
|
this.sendObject(eventObject);
|
|
994
964
|
}
|
|
995
965
|
});
|
|
996
966
|
}
|
|
997
|
-
_invoke({ event, data, options }) {
|
|
998
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
999
|
-
options = options || {};
|
|
1000
|
-
return new Promise((resolve, reject) => {
|
|
1001
|
-
const eventObject = {
|
|
1002
|
-
event,
|
|
1003
|
-
cid: this._nextCallId()
|
|
1004
|
-
};
|
|
1005
|
-
if (data !== undefined) {
|
|
1006
|
-
eventObject.data = data;
|
|
1007
|
-
}
|
|
1008
|
-
const ackTimeout = options.ackTimeout == null ? this.server.ackTimeout : options.ackTimeout;
|
|
1009
|
-
const timeout = setTimeout(() => {
|
|
1010
|
-
let error = new TimeoutError(`Event response for "${event}" timed out`);
|
|
1011
|
-
delete this._callbackMap[eventObject.cid];
|
|
1012
|
-
reject(error);
|
|
1013
|
-
}, ackTimeout);
|
|
1014
|
-
this._callbackMap[eventObject.cid] = {
|
|
1015
|
-
event,
|
|
1016
|
-
callback: (err, result) => {
|
|
1017
|
-
if (err) {
|
|
1018
|
-
reject(err);
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
resolve(result);
|
|
1022
|
-
},
|
|
1023
|
-
timeout
|
|
1024
|
-
};
|
|
1025
|
-
if (options.useCache && options.stringifiedData != null && !this.isBufferingBatch) {
|
|
1026
|
-
// Optimized
|
|
1027
|
-
this.send(options.stringifiedData);
|
|
1028
|
-
}
|
|
1029
|
-
else {
|
|
1030
|
-
this.sendObject(eventObject);
|
|
1031
|
-
}
|
|
1032
|
-
});
|
|
1033
|
-
});
|
|
1034
|
-
}
|
|
1035
967
|
triggerAuthenticationEvents(oldAuthState) {
|
|
1036
968
|
if (oldAuthState !== AuthState.AUTHENTICATED) {
|
|
1037
969
|
let stateChangeData = {
|
|
@@ -1040,7 +972,10 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1040
972
|
authToken: this.authToken
|
|
1041
973
|
};
|
|
1042
974
|
this.emit('authStateChange', stateChangeData);
|
|
1043
|
-
this.server.emit('authenticationStateChange',
|
|
975
|
+
this.server.emit('authenticationStateChange', {
|
|
976
|
+
socket: this,
|
|
977
|
+
...stateChangeData
|
|
978
|
+
});
|
|
1044
979
|
}
|
|
1045
980
|
this.emit('authenticate', { authToken: this.authToken });
|
|
1046
981
|
this.server.emit('authentication', {
|
|
@@ -1048,87 +983,91 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1048
983
|
authToken: this.authToken
|
|
1049
984
|
});
|
|
1050
985
|
}
|
|
1051
|
-
setAuthToken(data, options) {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
986
|
+
async setAuthToken(data, options) {
|
|
987
|
+
if (this.state === SocketState.CONNECTING) {
|
|
988
|
+
const err = new InvalidActionError('Cannot call setAuthToken before completing the handshake');
|
|
989
|
+
this.emitError(err);
|
|
990
|
+
throw err;
|
|
991
|
+
}
|
|
992
|
+
const authToken = cloneDeep(data);
|
|
993
|
+
const oldAuthState = this.authState;
|
|
994
|
+
this.authState = AuthState.AUTHENTICATED;
|
|
995
|
+
if (options == null) {
|
|
996
|
+
options = {};
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
options = { ...options };
|
|
1000
|
+
if (options.algorithm != null) {
|
|
1001
|
+
delete options.algorithm;
|
|
1002
|
+
let err = new InvalidArgumentsError('Cannot change auth token algorithm at runtime - It must be specified as a config option on launch');
|
|
1055
1003
|
this.emitError(err);
|
|
1056
|
-
throw err;
|
|
1057
1004
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1005
|
+
}
|
|
1006
|
+
options.mutatePayload = true;
|
|
1007
|
+
const rejectOnFailedDelivery = options.rejectOnFailedDelivery;
|
|
1008
|
+
delete options.rejectOnFailedDelivery;
|
|
1009
|
+
const defaultSignatureOptions = this.server.defaultSignatureOptions;
|
|
1010
|
+
// We cannot have the exp claim on the token and the expiresIn option
|
|
1011
|
+
// set at the same time or else auth.signToken will throw an error.
|
|
1012
|
+
let expiresIn;
|
|
1013
|
+
if (options.expiresIn == null) {
|
|
1014
|
+
expiresIn = defaultSignatureOptions.expiresIn;
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
expiresIn = options.expiresIn;
|
|
1018
|
+
}
|
|
1019
|
+
if (authToken) {
|
|
1020
|
+
if (authToken.exp == null) {
|
|
1021
|
+
options.expiresIn = expiresIn;
|
|
1063
1022
|
}
|
|
1064
1023
|
else {
|
|
1065
|
-
options
|
|
1066
|
-
if (options.algorithm != null) {
|
|
1067
|
-
delete options.algorithm;
|
|
1068
|
-
let err = new InvalidArgumentsError('Cannot change auth token algorithm at runtime - It must be specified as a config option on launch');
|
|
1069
|
-
this.emitError(err);
|
|
1070
|
-
}
|
|
1024
|
+
delete options.expiresIn;
|
|
1071
1025
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1026
|
+
}
|
|
1027
|
+
else {
|
|
1028
|
+
options.expiresIn = expiresIn;
|
|
1029
|
+
}
|
|
1030
|
+
// Always use the default algorithm since it cannot be changed at runtime.
|
|
1031
|
+
if (defaultSignatureOptions.algorithm != null) {
|
|
1032
|
+
options.algorithm = defaultSignatureOptions.algorithm;
|
|
1033
|
+
}
|
|
1034
|
+
this.authToken = authToken;
|
|
1035
|
+
let signedAuthToken;
|
|
1036
|
+
try {
|
|
1037
|
+
signedAuthToken = await this.server.auth.signToken(authToken, this.server.signatureKey, options);
|
|
1038
|
+
}
|
|
1039
|
+
catch (error) {
|
|
1040
|
+
this.emitError(error);
|
|
1041
|
+
this._destroy(4002, error.toString());
|
|
1042
|
+
this.socket.close(4002);
|
|
1043
|
+
throw error;
|
|
1044
|
+
}
|
|
1045
|
+
if (this.authToken === authToken) {
|
|
1046
|
+
this.signedAuthToken = signedAuthToken;
|
|
1047
|
+
this.emit('authTokenSigned', { signedAuthToken });
|
|
1048
|
+
}
|
|
1049
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
1050
|
+
const tokenData = {
|
|
1051
|
+
token: signedAuthToken
|
|
1052
|
+
};
|
|
1053
|
+
if (rejectOnFailedDelivery) {
|
|
1054
|
+
try {
|
|
1055
|
+
await this.invoke('#setAuthToken', tokenData);
|
|
1084
1056
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1057
|
+
catch (err) {
|
|
1058
|
+
let error;
|
|
1059
|
+
if (err && typeof err.message === 'string') {
|
|
1060
|
+
error = new AuthError(`Failed to deliver auth token to client - ${err.message}`);
|
|
1088
1061
|
}
|
|
1089
1062
|
else {
|
|
1090
|
-
|
|
1063
|
+
error = new AuthError('Failed to confirm delivery of auth token to client due to malformatted error response');
|
|
1091
1064
|
}
|
|
1092
|
-
}
|
|
1093
|
-
else {
|
|
1094
|
-
options.expiresIn = expiresIn;
|
|
1095
|
-
}
|
|
1096
|
-
// Always use the default algorithm since it cannot be changed at runtime.
|
|
1097
|
-
if (defaultSignatureOptions.algorithm != null) {
|
|
1098
|
-
options.algorithm = defaultSignatureOptions.algorithm;
|
|
1099
|
-
}
|
|
1100
|
-
this.authToken = authToken;
|
|
1101
|
-
let signedAuthToken;
|
|
1102
|
-
try {
|
|
1103
|
-
signedAuthToken = yield this.server.auth.signToken(authToken, this.server.signatureKey, options);
|
|
1104
|
-
}
|
|
1105
|
-
catch (error) {
|
|
1106
1065
|
this.emitError(error);
|
|
1107
|
-
this._destroy(4002, error.toString());
|
|
1108
|
-
this.socket.close(4002);
|
|
1109
1066
|
throw error;
|
|
1110
1067
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
}
|
|
1115
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
1116
|
-
const tokenData = {
|
|
1117
|
-
token: signedAuthToken
|
|
1118
|
-
};
|
|
1119
|
-
if (rejectOnFailedDelivery) {
|
|
1120
|
-
try {
|
|
1121
|
-
yield this.invoke('#setAuthToken', tokenData);
|
|
1122
|
-
}
|
|
1123
|
-
catch (err) {
|
|
1124
|
-
const error = new AuthError(`Failed to deliver auth token to client - ${err}`);
|
|
1125
|
-
this.emitError(error);
|
|
1126
|
-
throw error;
|
|
1127
|
-
}
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
this.transmit('#setAuthToken', tokenData);
|
|
1131
|
-
});
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
this.transmit('#setAuthToken', tokenData);
|
|
1132
1071
|
}
|
|
1133
1072
|
getAuthToken() {
|
|
1134
1073
|
return this.authToken;
|
|
@@ -1145,7 +1084,10 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1145
1084
|
newAuthState: this.authState
|
|
1146
1085
|
};
|
|
1147
1086
|
this.emit('authStateChange', stateChangeData);
|
|
1148
|
-
this.server.emit('authenticationStateChange',
|
|
1087
|
+
this.server.emit('authenticationStateChange', {
|
|
1088
|
+
socket: this,
|
|
1089
|
+
...stateChangeData
|
|
1090
|
+
});
|
|
1149
1091
|
}
|
|
1150
1092
|
this.emit('deauthenticate', { oldAuthToken });
|
|
1151
1093
|
this.server.emit('deauthentication', {
|
|
@@ -1153,23 +1095,21 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1153
1095
|
oldAuthToken
|
|
1154
1096
|
});
|
|
1155
1097
|
}
|
|
1156
|
-
deauthenticate(options) {
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
throw error;
|
|
1167
|
-
}
|
|
1098
|
+
async deauthenticate(options) {
|
|
1099
|
+
this.deauthenticateSelf();
|
|
1100
|
+
if (options && options.rejectOnFailedDelivery) {
|
|
1101
|
+
try {
|
|
1102
|
+
await this.invoke('#removeAuthToken');
|
|
1103
|
+
}
|
|
1104
|
+
catch (error) {
|
|
1105
|
+
this.emitError(error);
|
|
1106
|
+
if (options && options.rejectOnFailedDelivery) {
|
|
1107
|
+
throw error;
|
|
1168
1108
|
}
|
|
1169
|
-
return;
|
|
1170
1109
|
}
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
this._transmit('#removeAuthToken');
|
|
1173
1113
|
}
|
|
1174
1114
|
kickOut(channel, message) {
|
|
1175
1115
|
const channels = channel ? [channel] : Object.keys(this.channelSubscriptions);
|
|
@@ -1193,7 +1133,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1193
1133
|
return null;
|
|
1194
1134
|
}
|
|
1195
1135
|
isAuthTokenExpired(token) {
|
|
1196
|
-
if (
|
|
1136
|
+
if (token?.exp != null) {
|
|
1197
1137
|
const currentTime = Date.now();
|
|
1198
1138
|
const expiryMilliseconds = token.exp * 1000;
|
|
1199
1139
|
return currentTime > expiryMilliseconds;
|
|
@@ -1224,61 +1164,57 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1224
1164
|
signedAuthToken
|
|
1225
1165
|
});
|
|
1226
1166
|
}
|
|
1227
|
-
_validateAuthToken(signedAuthToken) {
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
const authTokenError = this._processTokenError(error);
|
|
1236
|
-
return {
|
|
1237
|
-
signedAuthToken,
|
|
1238
|
-
authTokenError,
|
|
1239
|
-
authToken: null,
|
|
1240
|
-
authState: AuthState.UNAUTHENTICATED
|
|
1241
|
-
};
|
|
1242
|
-
}
|
|
1167
|
+
async _validateAuthToken(signedAuthToken) {
|
|
1168
|
+
const verificationOptions = Object.assign({ socket: this }, this.server.defaultVerificationOptions);
|
|
1169
|
+
let authToken;
|
|
1170
|
+
try {
|
|
1171
|
+
authToken = await this.server.auth.verifyToken(signedAuthToken, this.server.verificationKey, verificationOptions);
|
|
1172
|
+
}
|
|
1173
|
+
catch (error) {
|
|
1174
|
+
const authTokenError = this._processTokenError(error);
|
|
1243
1175
|
return {
|
|
1244
1176
|
signedAuthToken,
|
|
1245
|
-
authTokenError
|
|
1246
|
-
authToken,
|
|
1247
|
-
authState: AuthState.
|
|
1177
|
+
authTokenError,
|
|
1178
|
+
authToken: null,
|
|
1179
|
+
authState: AuthState.UNAUTHENTICATED
|
|
1248
1180
|
};
|
|
1249
|
-
}
|
|
1181
|
+
}
|
|
1182
|
+
return {
|
|
1183
|
+
signedAuthToken,
|
|
1184
|
+
authTokenError: null,
|
|
1185
|
+
authToken,
|
|
1186
|
+
authState: AuthState.AUTHENTICATED
|
|
1187
|
+
};
|
|
1250
1188
|
}
|
|
1251
|
-
_processAuthentication({ signedAuthToken, authTokenError, authToken }) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
this._emitBadAuthTokenError(authTokenError, signedAuthToken);
|
|
1263
|
-
}
|
|
1189
|
+
async _processAuthentication({ signedAuthToken, authTokenError, authToken }) {
|
|
1190
|
+
if (authTokenError) {
|
|
1191
|
+
this.signedAuthToken = null;
|
|
1192
|
+
this.authToken = null;
|
|
1193
|
+
this.authState = AuthState.UNAUTHENTICATED;
|
|
1194
|
+
// If the error is related to the JWT being badly formatted, then we will
|
|
1195
|
+
// treat the error as a socket error.
|
|
1196
|
+
if (signedAuthToken != null) {
|
|
1197
|
+
this.emitError(authTokenError);
|
|
1198
|
+
if (authTokenError instanceof AuthTokenError) {
|
|
1199
|
+
this._emitBadAuthTokenError(authTokenError, signedAuthToken);
|
|
1264
1200
|
}
|
|
1265
|
-
throw authTokenError;
|
|
1266
|
-
}
|
|
1267
|
-
this.signedAuthToken = signedAuthToken;
|
|
1268
|
-
this.authToken = authToken;
|
|
1269
|
-
this.authState = AuthState.AUTHENTICATED;
|
|
1270
|
-
const action = new ActionAuthenticate(this, authToken, signedAuthToken);
|
|
1271
|
-
try {
|
|
1272
|
-
yield this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
1273
1201
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1202
|
+
throw authTokenError;
|
|
1203
|
+
}
|
|
1204
|
+
this.signedAuthToken = signedAuthToken;
|
|
1205
|
+
this.authToken = authToken;
|
|
1206
|
+
this.authState = AuthState.AUTHENTICATED;
|
|
1207
|
+
const action = new ActionAuthenticate(this, authToken, signedAuthToken);
|
|
1208
|
+
try {
|
|
1209
|
+
await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
1210
|
+
}
|
|
1211
|
+
catch (error) {
|
|
1212
|
+
this.authToken = null;
|
|
1213
|
+
this.authState = AuthState.UNAUTHENTICATED;
|
|
1214
|
+
if (error instanceof AuthTokenError) {
|
|
1215
|
+
this._emitBadAuthTokenError(error, signedAuthToken);
|
|
1281
1216
|
}
|
|
1282
|
-
|
|
1217
|
+
throw error;
|
|
1218
|
+
}
|
|
1283
1219
|
}
|
|
1284
1220
|
}
|