Merge branch 'develop' of github.com:thecodingmachine/workadventure into uws

# Conflicts:
#	back/src/Controller/AdminController.ts
#	back/src/Controller/AuthenticateController.ts
#	back/src/Controller/IoSocketController.ts
#	back/src/Controller/MapController.ts
#	benchmark/index.ts
#	front/src/Connexion/RoomConnection.ts
This commit is contained in:
David Négrier 2020-09-29 17:12:28 +02:00
commit 9f3577286d
24 changed files with 342 additions and 337 deletions

View file

@ -3,7 +3,6 @@ import {IoSocketController} from "./Controller/IoSocketController"; //TODO fix i
import {AuthenticateController} from "./Controller/AuthenticateController"; //TODO fix import by "_Controller/..."
import {MapController} from "./Controller/MapController";
import {PrometheusController} from "./Controller/PrometheusController";
import {AdminController} from "./Controller/AdminController";
import {DebugController} from "./Controller/DebugController";
import {App as uwsApp} from "./Server/sifrr.server";
@ -13,7 +12,6 @@ class App {
public authenticateController: AuthenticateController;
public mapController: MapController;
public prometheusController: PrometheusController;
private adminController: AdminController;
private debugController: DebugController;
constructor() {
@ -39,7 +37,6 @@ class App {
this.authenticateController = new AuthenticateController(this.app);
this.mapController = new MapController(this.app);
this.prometheusController = new PrometheusController(this.app, this.ioSocketController);
this.adminController = new AdminController(this.app);
this.debugController = new DebugController(this.app, this.ioSocketController);
}

View file

@ -1,40 +0,0 @@
import {OK} from "http-status-codes";
import {ADMIN_API_TOKEN, ADMIN_API_URL} from "../Enum/EnvironmentVariable";
import Axios from "axios";
import {HttpRequest, HttpResponse} from "uWebSockets.js";
import {parse} from "query-string";
import {App} from "../Server/sifrr.server";
export class AdminController {
constructor(private App : App) {
this.getLoginUrlByToken();
}
getLoginUrlByToken(){
this.App.get("/register/:token", (res: HttpResponse, req: HttpRequest) => {
(async () => {
if (!ADMIN_API_URL) {
return res.writeStatus("500 Internal Server Error").end('No admin backoffice set!');
}
const query = parse(req.getQuery());
const token:string = query.token as string;
let response = null
try {
response = await Axios.get(ADMIN_API_URL+'/api/login-url/'+token, { headers: {"Authorization" : `${ADMIN_API_TOKEN}`} })
} catch (e) {
console.log(e.message)
return res.status(e.status || 500).send('An error happened');
}
const organizationSlug = response.data.organizationSlug;
const worldSlug = response.data.worldSlug;
const roomSlug = response.data.roomSlug;
res.writeStatus("200 OK").end(JSON.stringify({organizationSlug, worldSlug, roomSlug}));
})();
});
}
}

View file

@ -1,11 +1,21 @@
import Jwt from "jsonwebtoken";
import {SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
import {OK} from "http-status-codes";
import {ADMIN_API_TOKEN, ADMIN_API_URL, SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
import { uuid } from 'uuidv4';
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {BaseController} from "./BaseController";
import Axios from "axios";
export interface TokenInterface {
name: string,
userUuid: string
}
interface AdminApiData {
organizationSlug: string
worldSlug: string
roomSlug: string
mapUrlStart: string
userUuid: string
}
@ -16,21 +26,6 @@ export class AuthenticateController extends BaseController {
this.login();
}
onAbortedOrFinishedResponse(res: HttpResponse/*, readStream: any*/) {
console.log("ERROR! onAbortedOrFinishedResponse called!");
/*if (res.id == -1) {
console.log("ERROR! onAbortedOrFinishedResponse called twice for the same res!");
} else {
console.log('Stream was closed, openStreams: ' + --openStreams);
console.timeEnd(res.id);
readStream.destroy();
}*/
/* Mark this response already accounted for */
//res.id = -1;
}
//permit to login on application. Return token to connect on Websocket IO.
login(){
this.App.options("/login", (res: HttpResponse, req: HttpRequest) => {
@ -47,14 +42,55 @@ export class AuthenticateController extends BaseController {
console.warn('Login request was aborted');
})
const param = await res.json();
const userUuid = uuid();
const token = Jwt.sign({name: param.name, userUuid: userUuid} as TokenInterface, SECRET_KEY, {expiresIn: '24h'});
res.writeStatus("200 OK").end(JSON.stringify({
token: token,
mapUrlStart: URL_ROOM_STARTED,
userId: userUuid,
}));
//todo: what to do if the organizationMemberToken is already used?
const organizationMemberToken:string|null = param.organizationMemberToken;
try {
let userUuid;
let mapUrlStart;
let newUrl = null;
if (organizationMemberToken) {
if (!ADMIN_API_URL) {
return res.status(401).send('No admin backoffice set!');
}
//todo: this call can fail if the corresponding world is not activated or if the token is invalid. Handle that case.
const data = await Axios.get(ADMIN_API_URL+'/api/login-url/'+organizationMemberToken,
{ headers: {"Authorization" : `${ADMIN_API_TOKEN}`} }
).then((res): AdminApiData => res.data);
userUuid = data.userUuid;
mapUrlStart = data.mapUrlStart;
newUrl = this.getNewUrlOnAdminAuth(data)
} else {
userUuid = uuid();
mapUrlStart = req.getHeader('host').replace('api.', 'maps.') + URL_ROOM_STARTED;
newUrl = null;
}
const authToken = Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '24h'});
res.writeStatus("200 OK").end(JSON.stringify({
authToken,
userUuid,
mapUrlStart,
newUrl,
}));
} catch (e) {
console.log(e.message)
res.writeStatus(e.status || "500 Internal Server Error").end('An error happened');
}
})();
});
}
private getNewUrlOnAdminAuth(data:AdminApiData): string {
const organizationSlug = data.organizationSlug;
const worldSlug = data.worldSlug;
const roomSlug = data.roomSlug;
return '/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug;
}
}

View file

@ -116,9 +116,6 @@ export class IoSocketController {
if (typeof((token as TokenInterface).userUuid) !== 'string') {
return false;
}
if (typeof((token as TokenInterface).name) !== 'string') {
return false;
}
return true;
}
@ -142,45 +139,46 @@ export class IoSocketController {
//console.log(socket.handshake.query.token);
/*if (!socket.handshake.query || !socket.handshake.query.token) {
console.error('An authentication error happened, a user tried to connect without a token.');
return next(new Error('Authentication error'));
}
if(socket.handshake.query.token === 'test'){
if (ALLOW_ARTILLERY) {
(socket as ExSocketInterface).token = socket.handshake.query.token;
(socket as ExSocketInterface).userId = this.nextUserId;
(socket as ExSocketInterface).userUuid = uuid();
this.nextUserId++;
(socket as ExSocketInterface).isArtillery = true;
console.log((socket as ExSocketInterface).userId);
next();
return;
} else {
console.warn("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)){
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
return next(new Error('Authentication error'));
}
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
if (err) {
console.error('An authentication error happened, invalid JsonWebToken.', err);
console.error('An authentication error happened, a user tried to connect without a token.');
return next(new Error('Authentication error'));
}
if (!this.isValidToken(tokenDecoded)) {
return next(new Error('Authentication error, invalid token structure'));
if(socket.handshake.query.token === 'test'){
if (ALLOW_ARTILLERY) {
(socket as ExSocketInterface).token = socket.handshake.query.token;
(socket as ExSocketInterface).userId = this.nextUserId;
(socket as ExSocketInterface).userUuid = uuid();
this.nextUserId++;
(socket as ExSocketInterface).isArtillery = true;
console.log((socket as ExSocketInterface).userId);
next();
return;
} else {
console.warn("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)){
console.error('An authentication error happened, a user tried to connect while its token is already connected.');
return next(new Error('Authentication error'));
}
Jwt.verify(socket.handshake.query.token, SECRET_KEY, (err: JsonWebTokenError, tokenDecoded: object) => {
const tokenInterface = tokenDecoded as TokenInterface;
if (err) {
console.error('An authentication error happened, invalid JsonWebToken.', err);
return next(new Error('Authentication error'));
}
(socket as ExSocketInterface).token = socket.handshake.query.token;
(socket as ExSocketInterface).userId = this.nextUserId;
(socket as ExSocketInterface).userUuid = tokenDecoded.userUuid;
this.nextUserId++;
next();
});*/
if (!this.isValidToken(tokenInterface)) {
return next(new Error('Authentication error, invalid token structure'));
}
(socket as ExSocketInterface).token = socket.handshake.query.token;
(socket as ExSocketInterface).userId = this.nextUserId;
(socket as ExSocketInterface).userUuid = tokenInterface.userUuid;
this.nextUserId++;
next();
});*/
const socket = ws as ExSocketInterface;
socket.userId = this.nextUserId;
this.nextUserId++;

View file

@ -3,6 +3,7 @@ import {URL_ROOM_STARTED} from "../Enum/EnvironmentVariable";
import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {BaseController} from "./BaseController";
//todo: delete this
export class MapController extends BaseController{
constructor(private App : TemplatedApp) {

View file

@ -1,6 +1,5 @@
import {PointInterface} from "./PointInterface";
import {Identificable} from "./Identificable";
import {TokenInterface} from "../../Controller/AuthenticateController";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {BatchMessage, SubMessage} from "../../Messages/generated/messages_pb";
import {WebSocket} from "uWebSockets.js"