Adding back authentication to uws websocket
This commit is contained in:
parent
e9b538e43c
commit
5de2f61231
@ -39,6 +39,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
res.onAborted(() => {
|
res.onAborted(() => {
|
||||||
console.warn('Login request was aborted');
|
console.warn('Login request was aborted');
|
||||||
})
|
})
|
||||||
|
const host = req.getHeader('host');
|
||||||
const param = await res.json();
|
const param = await res.json();
|
||||||
|
|
||||||
//todo: what to do if the organizationMemberToken is already used?
|
//todo: what to do if the organizationMemberToken is already used?
|
||||||
@ -63,7 +64,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
newUrl = this.getNewUrlOnAdminAuth(data)
|
newUrl = this.getNewUrlOnAdminAuth(data)
|
||||||
} else {
|
} else {
|
||||||
userUuid = uuid();
|
userUuid = uuid();
|
||||||
mapUrlStart = req.getHeader('host').replace('api.', 'maps.') + URL_ROOM_STARTED;
|
mapUrlStart = host.replace('api.', 'maps.') + URL_ROOM_STARTED;
|
||||||
newUrl = null;
|
newUrl = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e.message)
|
console.log("An error happened", e)
|
||||||
res.writeStatus(e.status || "500 Internal Server Error").end('An error happened');
|
res.writeStatus(e.status || "500 Internal Server Error").end('An error happened');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ import {
|
|||||||
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
import {App, TemplatedApp, WebSocket} from "uWebSockets.js"
|
import {App, HttpRequest, TemplatedApp, WebSocket} from "uWebSockets.js"
|
||||||
|
import {parse} from "query-string";
|
||||||
|
|
||||||
enum SocketIoEvent {
|
enum SocketIoEvent {
|
||||||
CONNECTION = "connection",
|
CONNECTION = "connection",
|
||||||
@ -135,67 +136,122 @@ export class IoSocketController {
|
|||||||
return null;
|
return null;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
private authenticate(ws: WebSocket) {
|
private async authenticate(req: HttpRequest): Promise<{ token: string, userUuid: string }> {
|
||||||
//console.log(socket.handshake.query.token);
|
//console.log(socket.handshake.query.token);
|
||||||
|
|
||||||
/*if (!socket.handshake.query || !socket.handshake.query.token) {
|
const query = parse(req.getQuery());
|
||||||
|
|
||||||
|
if (!query.token) {
|
||||||
console.error('An authentication error happened, a user tried to connect without a token.');
|
console.error('An authentication error happened, a user tried to connect without a token.');
|
||||||
return next(new Error('Authentication error'));
|
throw new Error('An authentication error happened, a user tried to connect without a token.');
|
||||||
}
|
}
|
||||||
if(socket.handshake.query.token === 'test'){
|
|
||||||
|
const token = query.token;
|
||||||
|
if (typeof(token) !== "string") {
|
||||||
|
throw new Error('Token is expected to be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(token === 'test'){
|
||||||
if (ALLOW_ARTILLERY) {
|
if (ALLOW_ARTILLERY) {
|
||||||
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
return {
|
||||||
(socket as ExSocketInterface).userId = this.nextUserId;
|
token,
|
||||||
(socket as ExSocketInterface).userUuid = uuid();
|
userUuid: uuid()
|
||||||
this.nextUserId++;
|
}
|
||||||
(socket as ExSocketInterface).isArtillery = true;
|
|
||||||
console.log((socket as ExSocketInterface).userId);
|
|
||||||
next();
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
console.warn("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
throw new Error("In order to perform a load-testing test on this environment, you must set the ALLOW_ARTILLERY environment variable to 'true'");
|
||||||
next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(socket as ExSocketInterface).isArtillery = false;
|
|
||||||
if(this.searchClientByToken(socket.handshake.query.token)){
|
/*if(this.searchClientByToken(socket.handshake.query.token)){
|
||||||
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
|
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
|
||||||
return next(new Error('Authentication error'));
|
return next(new Error('Authentication error'));
|
||||||
}
|
}*/
|
||||||
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
|
|
||||||
|
const promise = new Promise<{ token: string, userUuid: string }>((resolve, reject) => {
|
||||||
|
Jwt.verify(token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
|
||||||
const tokenInterface = tokenDecoded as TokenInterface;
|
const tokenInterface = tokenDecoded as TokenInterface;
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
console.error('An authentication error happened, invalid JsonWebToken.', err);
|
||||||
return next(new Error('Authentication error'));
|
reject(new Error('An authentication error happened, invalid JsonWebToken. '+err.message));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isValidToken(tokenInterface)) {
|
if (!this.isValidToken(tokenInterface)) {
|
||||||
return next(new Error('Authentication error, invalid token structure'));
|
reject(new Error('Authentication error, invalid token structure.'));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(socket as ExSocketInterface).token = socket.handshake.query.token;
|
resolve({
|
||||||
(socket as ExSocketInterface).userId = this.nextUserId;
|
token,
|
||||||
(socket as ExSocketInterface).userUuid = tokenInterface.userUuid;
|
userUuid: tokenInterface.userUuid
|
||||||
this.nextUserId++;
|
});
|
||||||
next();
|
});
|
||||||
});*/
|
});
|
||||||
const socket = ws as ExSocketInterface;
|
|
||||||
socket.userId = this.nextUserId;
|
return promise;
|
||||||
this.nextUserId++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ioConnection() {
|
ioConnection() {
|
||||||
this.app.ws('/*', {
|
this.app.ws('/*', {
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
//compression: uWS.SHARED_COMPRESSOR,
|
//compression: uWS.SHARED_COMPRESSOR,
|
||||||
maxPayloadLength: 16 * 1024 * 1024,
|
maxPayloadLength: 16 * 1024 * 1024,
|
||||||
//idleTimeout: 10,
|
//idleTimeout: 10,
|
||||||
|
upgrade: (res, req, context) => {
|
||||||
|
console.log('An Http connection wants to become WebSocket, URL: ' + req.getUrl() + '!');
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
/* Keep track of abortions */
|
||||||
|
const upgradeAborted = {aborted: false};
|
||||||
|
|
||||||
|
res.onAborted(() => {
|
||||||
|
/* We can simply signal that we were aborted */
|
||||||
|
upgradeAborted.aborted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await this.authenticate(req);
|
||||||
|
|
||||||
|
if (upgradeAborted.aborted) {
|
||||||
|
console.log("Ouch! Client disconnected before we could upgrade it!");
|
||||||
|
/* You must not upgrade now */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This immediately calls open handler, you must not use res after this call */
|
||||||
|
res.upgrade({
|
||||||
|
// Data passed here is accessible on the "websocket" socket object.
|
||||||
|
url: req.getUrl(),
|
||||||
|
token: result.token,
|
||||||
|
userUuid: result.userUuid
|
||||||
|
},
|
||||||
|
/* Spell these correctly */
|
||||||
|
req.getHeader('sec-websocket-key'),
|
||||||
|
req.getHeader('sec-websocket-protocol'),
|
||||||
|
req.getHeader('sec-websocket-extensions'),
|
||||||
|
context);
|
||||||
|
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
console.warn(e.message);
|
||||||
|
res.writeStatus("401 Unauthorized").end(e.message);
|
||||||
|
} else {
|
||||||
|
console.warn(e);
|
||||||
|
res.writeStatus("500 Internal Server Error").end('An error occurred');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
},
|
||||||
/* Handlers */
|
/* Handlers */
|
||||||
open: (ws) => {
|
open: (ws) => {
|
||||||
this.authenticate(ws);
|
|
||||||
// TODO: close if authenticate is ko
|
|
||||||
|
|
||||||
const client : ExSocketInterface = ws as ExSocketInterface;
|
const client : ExSocketInterface = ws as ExSocketInterface;
|
||||||
|
client.userId = this.nextUserId;
|
||||||
|
this.nextUserId++;
|
||||||
|
client.userUuid = ws.userUuid;
|
||||||
|
client.token = ws.token;
|
||||||
client.batchedMessages = new BatchMessage();
|
client.batchedMessages = new BatchMessage();
|
||||||
client.batchTimeout = null;
|
client.batchTimeout = null;
|
||||||
client.emitInBatch = (payload: SubMessage): void => {
|
client.emitInBatch = (payload: SubMessage): void => {
|
||||||
|
@ -13,7 +13,6 @@ export interface ExSocketInterface extends WebSocket, Identificable {
|
|||||||
characterLayers: string[];
|
characterLayers: string[];
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
viewport: ViewportInterface;
|
viewport: ViewportInterface;
|
||||||
isArtillery: boolean; // Whether this socket is opened by Artillery for load testing (hack)
|
|
||||||
/**
|
/**
|
||||||
* Pushes an event that will be sent in the next batch of events
|
* Pushes an event that will be sent in the next batch of events
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user