Merge branch 'develop' of github.com:thecodingmachine/workadventure into player-report

# Conflicts:
#	back/src/Controller/AuthenticateController.ts
This commit is contained in:
David Négrier 2020-10-15 18:01:44 +02:00
commit c75f1edc40
22 changed files with 325 additions and 220 deletions

View file

@ -3,6 +3,7 @@ import {HttpRequest, HttpResponse, TemplatedApp} from "uWebSockets.js";
import {BaseController} from "./BaseController";
import {adminApi} from "../Services/AdminApi";
import {jwtTokenManager} from "../Services/JWTTokenManager";
import {parse} from "query-string";
export interface TokenInterface {
userUuid: string
@ -13,11 +14,12 @@ export class AuthenticateController extends BaseController {
constructor(private App : TemplatedApp) {
super();
this.register();
this.verify();
this.anonymLogin();
}
//Try to login with an admin token
register(){
private register(){
this.App.options("/register", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
@ -26,8 +28,6 @@ export class AuthenticateController extends BaseController {
this.App.post("/register", (res: HttpResponse, req: HttpRequest) => {
(async () => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('Login request was aborted');
})
@ -47,7 +47,9 @@ export class AuthenticateController extends BaseController {
const mapUrlStart = data.mapUrlStart;
const authToken = jwtTokenManager.createJWTToken(userUuid);
res.writeStatus("200 OK").end(JSON.stringify({
res.writeStatus("200 OK");
this.addCorsHeaders(res);
res.end(JSON.stringify({
authToken,
userUuid,
organizationSlug,
@ -58,7 +60,9 @@ export class AuthenticateController extends BaseController {
} catch (e) {
console.error("An error happened", e)
res.writeStatus(e.status || "500 Internal Server Error").end('An error happened');
res.writeStatus(e.status || "500 Internal Server Error");
this.addCorsHeaders(res);
res.end('An error happened');
}
@ -67,8 +71,44 @@ export class AuthenticateController extends BaseController {
}
private verify(){
this.App.options("/verify", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.end();
});
this.App.get("/verify", (res: HttpResponse, req: HttpRequest) => {
(async () => {
const query = parse(req.getQuery());
res.onAborted(() => {
console.warn('verify request was aborted');
})
try {
await jwtTokenManager.getUserUuidFromToken(query.token as string);
} catch (e) {
res.writeStatus("400 Bad Request");
this.addCorsHeaders(res);
res.end(JSON.stringify({
"success": false,
"message": "Invalid JWT token"
}));
return;
}
res.writeStatus("200 OK");
this.addCorsHeaders(res);
res.end(JSON.stringify({
"success": true
}));
})();
});
}
//permit to login on application. Return token to connect on Websocket IO.
anonymLogin(){
private anonymLogin(){
this.App.options("/anonymLogin", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
@ -76,7 +116,6 @@ export class AuthenticateController extends BaseController {
});
this.App.post("/anonymLogin", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('Login request was aborted');
@ -84,7 +123,9 @@ export class AuthenticateController extends BaseController {
const userUuid = v4();
const authToken = jwtTokenManager.createJWTToken(userUuid);
res.writeStatus("200 OK").end(JSON.stringify({
res.writeStatus("200 OK");
this.addCorsHeaders(res);
res.end(JSON.stringify({
authToken,
userUuid,
}));

View file

@ -44,8 +44,6 @@ export class FileController extends BaseController {
this.App.post("/upload-audio-message", (res: HttpResponse, req: HttpRequest) => {
(async () => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('upload-audio-message request was aborted');
})
@ -80,14 +78,18 @@ export class FileController extends BaseController {
}
});
res.writeStatus("200 OK").end(JSON.stringify({
res.writeStatus("200 OK");
this.addCorsHeaders(res);
res.end(JSON.stringify({
id: audioMessageId,
path: `/download-audio-message/${audioMessageId}`
}));
} catch (e) {
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");
this.addCorsHeaders(res);
res.end('An error happened');
}
})();
});
@ -101,7 +103,6 @@ export class FileController extends BaseController {
});
this.App.get("/download-audio-message/:id", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('upload-audio-message request was aborted');
@ -111,7 +112,9 @@ export class FileController extends BaseController {
const file = this.uploadedFileBuffers.get(id);
if (file === undefined) {
res.writeStatus("404 Not found").end("Cannot find file");
res.writeStatus("404 Not found");
this.addCorsHeaders(res);
res.end("Cannot find file");
return;
}

View file

@ -62,6 +62,26 @@ function emitInBatch(socket: ExSocketInterface, payload: SubMessage): void {
socket.batchTimeout = null;
}, 100);
}
// If we send a message, we don't need to keep the connection alive
resetPing(socket);
}
/**
* Schedule a ping to keep the connection open.
* If a ping is already set, the timeout of the ping is reset.
*/
function resetPing(ws: ExSocketInterface): void {
if (ws.pingTimeout) {
clearTimeout(ws.pingTimeout);
}
ws.pingTimeout = setTimeout(() => {
if (ws.disconnecting) {
return;
}
ws.ping();
resetPing(ws);
}, 29000);
}
export class IoSocketController {
@ -234,6 +254,8 @@ export class IoSocketController {
// Let's join the room
this.handleJoinRoom(client, client.position, client.viewport);
resetPing(client);
},
message: (ws, arrayBuffer, isBinary): void => {
const client = ws as ExSocketInterface;

View file

@ -24,7 +24,6 @@ export class MapController extends BaseController{
});
this.App.get("/map", (res: HttpResponse, req: HttpRequest) => {
this.addCorsHeaders(res);
res.onAborted(() => {
console.warn('/map request was aborted');
@ -34,25 +33,35 @@ export class MapController extends BaseController{
if (typeof query.organizationSlug !== 'string') {
console.error('Expected organizationSlug parameter');
res.writeStatus("400 Bad request").end("Expected organizationSlug parameter");
res.writeStatus("400 Bad request");
this.addCorsHeaders(res);
res.end("Expected organizationSlug parameter");
}
if (typeof query.worldSlug !== 'string') {
console.error('Expected worldSlug parameter');
res.writeStatus("400 Bad request").end("Expected worldSlug parameter");
res.writeStatus("400 Bad request");
this.addCorsHeaders(res);
res.end("Expected worldSlug parameter");
}
if (typeof query.roomSlug !== 'string' && query.roomSlug !== undefined) {
console.error('Expected only one roomSlug parameter');
res.writeStatus("400 Bad request").end("Expected only one roomSlug parameter");
res.writeStatus("400 Bad request");
this.addCorsHeaders(res);
res.end("Expected only one roomSlug parameter");
}
(async () => {
try {
const mapDetails = await adminApi.fetchMapDetails(query.organizationSlug as string, query.worldSlug as string, query.roomSlug as string|undefined);
res.writeStatus("200 OK").end(JSON.stringify(mapDetails));
res.writeStatus("200 OK");
this.addCorsHeaders(res);
res.end(JSON.stringify(mapDetails));
} catch (e) {
console.error(e);
res.writeStatus("500 Internal Server Error").end("An error occurred");
res.writeStatus("500 Internal Server Error")
this.addCorsHeaders(res);
res.end("An error occurred");
}
})();

View file

@ -19,6 +19,7 @@ export interface ExSocketInterface extends WebSocket, Identificable {
emitInBatch: (payload: SubMessage) => void;
batchedMessages: BatchMessage;
batchTimeout: NodeJS.Timeout|null;
pingTimeout: NodeJS.Timeout|null;
disconnecting: boolean,
tags: string[]
}

View file

@ -6,7 +6,7 @@ import {TokenInterface} from "../Controller/AuthenticateController";
class JWTTokenManager {
public createJWTToken(userUuid: string) {
return Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '24h'});
return Jwt.sign({userUuid: userUuid}, SECRET_KEY, {expiresIn: '200d'}); //todo: add a mechanic to refresh or recreate token
}
public async getUserUuidFromToken(token: unknown): Promise<string> {