From f87422187f1ca06011373027a461dfeba3ec2477 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Thu, 14 Oct 2021 17:22:43 +0200 Subject: [PATCH 01/32] HotFix user data connection Create local store for user connected in SSO Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 19 +++++--- .../src/Controller/AuthenticateController.ts | 44 +++++++++++++++++-- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index b346f450..b85e045e 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -98,7 +98,7 @@ class ConnectionManager { localUserStore.setCode(code); this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); try { - await this.checkAuthUserConnexion(); + await this.checkAuthUserConnexion(this._currentRoom.key); analyticsClient.loggedWithSso(); } catch (err) { console.error(err); @@ -169,7 +169,7 @@ class ConnectionManager { await this.anonymousLogin(); } else { try { - await this.checkAuthUserConnexion(); + await this.checkAuthUserConnexion(this._currentRoom.key); } catch (err) { console.error(err); } @@ -275,7 +275,7 @@ class ConnectionManager { return this.connexionType; } - async checkAuthUserConnexion() { + async checkAuthUserConnexion(playUri: string) { //set connected store for menu at false userIsConnected.set(false); @@ -289,10 +289,17 @@ class ConnectionManager { } const nonce = localUserStore.getNonce(); const token = localUserStore.getAuthToken(); - const { authToken } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce, token } }).then( - (res) => res.data - ); + const { authToken, userUuid, tags, textures, emails } = await Axios.get(`${PUSHER_URL}/login-callback`, { + params: { code, nonce, token, playUri }, + }).then((res) => res.data); localUserStore.setAuthToken(authToken); + const localUser: LocalUser = { + uuid: userUuid, + textures: textures, + email: emails, + }; + this.localUser = new LocalUser(userUuid, textures, emails); + localUserStore.saveUser(this.localUser); this.authToken = authToken; //user connected, set connected store for menu at true diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 972cc102..3d01d30c 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -1,7 +1,7 @@ import { v4 } from "uuid"; import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js"; import { BaseController } from "./BaseController"; -import { adminApi } from "../Services/AdminApi"; +import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { parse } from "query-string"; import { openIDClient } from "../Services/OpenIDClient"; @@ -55,7 +55,8 @@ export class AuthenticateController extends BaseController { res.onAborted(() => { console.warn("/message request was aborted"); }); - const { code, nonce, token } = parse(req.getQuery()); + const IPAddress = req.getHeader("x-forwarded-for"); + const { code, nonce, token, playUri } = parse(req.getQuery()); try { //verify connected by token if (token != undefined) { @@ -65,9 +66,17 @@ export class AuthenticateController extends BaseController { throw Error("Token cannot to be check on Hydra"); } await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken); + + //Get user data from Admin Back Office + //This is very important to create User Local in LocalStorage in WorkAdventure + const data = await this.getUserByUserIdentifier( + authTokenData.identifier, + playUri as string, + IPAddress + ); res.writeStatus("200"); this.addCorsHeaders(res); - return res.end(JSON.stringify({ authToken: token })); + return res.end(JSON.stringify({ ...data, authToken: token })); } catch (err) { console.info("User was not connected", err); } @@ -80,9 +89,14 @@ export class AuthenticateController extends BaseController { throw new Error("No email in the response"); } const authToken = jwtTokenManager.createAuthToken(email, userInfo.access_token); + + //Get user data from Admin Back Office + //This is very important to create User Local in LocalStorage in WorkAdventure + const data = await this.getUserByUserIdentifier(email, playUri as string, IPAddress); + res.writeStatus("200"); this.addCorsHeaders(res); - return res.end(JSON.stringify({ authToken })); + return res.end(JSON.stringify({ ...data, authToken })); } catch (e) { console.error("openIDCallback => ERROR", e); return this.errorToResponse(e, res); @@ -223,4 +237,26 @@ export class AuthenticateController extends BaseController { } }); } + + /** + * + * @param email + * @param playUri + * @param IPAddress + * @return FetchMemberDataByUuidResponse|object + * @private + */ + private async getUserByUserIdentifier( + email: string, + playUri: string, + IPAddress: string + ): Promise { + let data: FetchMemberDataByUuidResponse | object = {}; + try { + data = await adminApi.fetchMemberDataByUuid(email, playUri, IPAddress); + } catch (err) { + console.error("openIDCallback => fetchMemberDataByUuid", err); + } + return data; + } } From b7692dd3550ad1ec1b5f3726795cadbd2ba5ca4e Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Thu, 14 Oct 2021 17:25:36 +0200 Subject: [PATCH 02/32] Fix local user useless Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index b85e045e..06c20a5c 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -293,11 +293,6 @@ class ConnectionManager { params: { code, nonce, token, playUri }, }).then((res) => res.data); localUserStore.setAuthToken(authToken); - const localUser: LocalUser = { - uuid: userUuid, - textures: textures, - email: emails, - }; this.localUser = new LocalUser(userUuid, textures, emails); localUserStore.saveUser(this.localUser); this.authToken = authToken; From 497a7c3467aed14577ce1762f9197614095b410e Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Thu, 14 Oct 2021 17:33:53 +0200 Subject: [PATCH 03/32] Fix typo emails => email Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 06c20a5c..1995759e 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -289,11 +289,11 @@ class ConnectionManager { } const nonce = localUserStore.getNonce(); const token = localUserStore.getAuthToken(); - const { authToken, userUuid, tags, textures, emails } = await Axios.get(`${PUSHER_URL}/login-callback`, { + const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce, token, playUri }, }).then((res) => res.data); localUserStore.setAuthToken(authToken); - this.localUser = new LocalUser(userUuid, textures, emails); + this.localUser = new LocalUser(userUuid, textures, email); localUserStore.saveUser(this.localUser); this.authToken = authToken; From 6832fe49901ce28b3413000337a142cc9dae445c Mon Sep 17 00:00:00 2001 From: Lurkars Date: Thu, 21 Oct 2021 16:28:57 +0200 Subject: [PATCH 04/32] use OIDC without admin api, option to disable anonymous login --- .env.template | 1 + docker-compose.single-domain.yaml | 1 + docker-compose.yaml | 1 + front/src/Connexion/ConnectionManager.ts | 34 ++++++++++++++----- .../src/Controller/AuthenticateController.ts | 26 ++++++++------ pusher/src/Controller/IoSocketController.ts | 7 +++- pusher/src/Controller/MapController.ts | 9 +++-- pusher/src/Enum/EnvironmentVariable.ts | 1 + .../src/Services/AdminApi/MapDetailsData.ts | 1 + 9 files changed, 59 insertions(+), 22 deletions(-) diff --git a/.env.template b/.env.template index 715ebeec..f511b398 100644 --- a/.env.template +++ b/.env.template @@ -22,6 +22,7 @@ MAX_USERNAME_LENGTH=8 OPID_CLIENT_ID= OPID_CLIENT_SECRET= OPID_CLIENT_ISSUER= +DISABLE_ANONYMOUS= # If you want to have a contact page in your menu, you MUST set CONTACT_URL to the URL of the page that you want CONTACT_URL= \ No newline at end of file diff --git a/docker-compose.single-domain.yaml b/docker-compose.single-domain.yaml index 4e85d702..2e2cab7d 100644 --- a/docker-compose.single-domain.yaml +++ b/docker-compose.single-domain.yaml @@ -70,6 +70,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER + DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: - ./pusher:/usr/src/app labels: diff --git a/docker-compose.yaml b/docker-compose.yaml index 4b3904dd..65dcc61f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -70,6 +70,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER + DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: - ./pusher:/usr/src/app labels: diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index b346f450..c91e4590 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -42,11 +42,22 @@ class ConnectionManager { localUserStore.setAuthToken(null); //TODO fix me to redirect this URL by pusher - if (!this._currentRoom || !this._currentRoom.iframeAuthentication) { + if (!this._currentRoom) { loginSceneVisibleIframeStore.set(false); return null; } - const redirectUrl = new URL(`${this._currentRoom.iframeAuthentication}`); + + // also allow OIDC login without admin API by using pusher + let redirectUrl: URL; + if (this._currentRoom.iframeAuthentication) { + redirectUrl = new URL(`${this._currentRoom.iframeAuthentication}`); + } else { + // need origin if PUSHER_URL is relative (in Single-Domain-Deployment) + redirectUrl = new URL( + `${PUSHER_URL}/login-screen`, + !PUSHER_URL.startsWith("http:") || !PUSHER_URL.startsWith("https:") ? window.location.origin : undefined + ); + } redirectUrl.searchParams.append("state", state); redirectUrl.searchParams.append("nonce", nonce); redirectUrl.searchParams.append("playUri", this._currentRoom.key); @@ -204,13 +215,18 @@ class ConnectionManager { } public async anonymousLogin(isBenchmark: boolean = false): Promise { - const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); - this.localUser = new LocalUser(data.userUuid, []); - this.authToken = data.authToken; - if (!isBenchmark) { - // In benchmark, we don't have a local storage. - localUserStore.saveUser(this.localUser); - localUserStore.setAuthToken(this.authToken); + try { + const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); + this.localUser = new LocalUser(data.userUuid, []); + this.authToken = data.authToken; + if (!isBenchmark) { + // In benchmark, we don't have a local storage. + localUserStore.saveUser(this.localUser); + localUserStore.setAuthToken(this.authToken); + } + } catch (error) { + // anonymous login failed (through 403 DISABLE_ANONYMOUS) + this.loadOpenIDScreen(); } } diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 972cc102..2dafe065 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -5,6 +5,7 @@ import { adminApi } from "../Services/AdminApi"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { parse } from "query-string"; import { openIDClient } from "../Services/OpenIDClient"; +import { DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; export interface TokenInterface { userUuid: string; @@ -175,16 +176,21 @@ export class AuthenticateController extends BaseController { console.warn("Login request was aborted"); }); - const userUuid = v4(); - const authToken = jwtTokenManager.createAuthToken(userUuid); - res.writeStatus("200 OK"); - this.addCorsHeaders(res); - res.end( - JSON.stringify({ - authToken, - userUuid, - }) - ); + if (DISABLE_ANONYMOUS) { + res.writeStatus("403 FORBIDDEN"); + res.end(); + } else { + const userUuid = v4(); + const authToken = jwtTokenManager.createAuthToken(userUuid); + res.writeStatus("200 OK"); + this.addCorsHeaders(res); + res.end( + JSON.stringify({ + authToken, + userUuid, + }) + ); + } }); } diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 0466100c..500f4142 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -26,7 +26,7 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi"; import { SocketManager, socketManager } from "../Services/SocketManager"; import { emitInBatch } from "../Services/IoSocketHelpers"; -import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; import { Zone } from "_Model/Zone"; import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface"; import { v4 } from "uuid"; @@ -175,6 +175,11 @@ export class IoSocketController { const tokenData = token && typeof token === "string" ? jwtTokenManager.verifyJWTToken(token) : null; + + if (DISABLE_ANONYMOUS && !tokenData) { + throw new Error("Expecting token"); + } + const userIdentifier = tokenData ? tokenData.identifier : ""; let memberTags: string[] = []; diff --git a/pusher/src/Controller/MapController.ts b/pusher/src/Controller/MapController.ts index f775b50c..437bac6a 100644 --- a/pusher/src/Controller/MapController.ts +++ b/pusher/src/Controller/MapController.ts @@ -2,9 +2,9 @@ import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js"; import { BaseController } from "./BaseController"; import { parse } from "query-string"; import { adminApi } from "../Services/AdminApi"; -import { ADMIN_API_URL } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_URL, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable"; import { GameRoomPolicyTypes } from "../Model/PusherRoom"; -import { MapDetailsData } from "../Services/AdminApi/MapDetailsData"; +import { isMapDetailsData, MapDetailsData } from "../Services/AdminApi/MapDetailsData"; import { socketManager } from "../Services/SocketManager"; import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager"; import { v4 } from "uuid"; @@ -64,6 +64,7 @@ export class MapController extends BaseController { tags: [], textures: [], contactPage: undefined, + authenticationMandatory: DISABLE_ANONYMOUS, } as MapDetailsData) ); @@ -87,6 +88,10 @@ export class MapController extends BaseController { } const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId); + if (isMapDetailsData(mapDetails) && DISABLE_ANONYMOUS) { + (mapDetails as MapDetailsData).authenticationMandatory = true; + } + res.writeStatus("200 OK"); this.addCorsHeaders(res); res.end(JSON.stringify(mapDetails)); diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index ab1ce110..be81871d 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -15,6 +15,7 @@ export const FRONT_URL = process.env.FRONT_URL || "http://localhost"; export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; +export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS ? process.env.DISABLE_ANONYMOUS == "true" : false; export { SECRET_KEY, diff --git a/pusher/src/Services/AdminApi/MapDetailsData.ts b/pusher/src/Services/AdminApi/MapDetailsData.ts index 278b81bb..7a1f57ff 100644 --- a/pusher/src/Services/AdminApi/MapDetailsData.ts +++ b/pusher/src/Services/AdminApi/MapDetailsData.ts @@ -16,6 +16,7 @@ export const isMapDetailsData = new tg.IsInterface() tags: tg.isArray(tg.isString), textures: tg.isArray(isCharacterTexture), contactPage: tg.isUnion(tg.isString, tg.isUndefined), + authenticationMandatory: tg.isUnion(tg.isBoolean, tg.isUndefined), }) .get(); From 78e0d1bead402348f36a3341ceea68b3f8e462e3 Mon Sep 17 00:00:00 2001 From: Lurkars Date: Thu, 21 Oct 2021 16:53:24 +0200 Subject: [PATCH 05/32] fix linter, cleanup --- front/src/Connexion/ConnectionManager.ts | 19 +++++++------------ pusher/src/Controller/MapController.ts | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index c91e4590..aae8440a 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -215,18 +215,13 @@ class ConnectionManager { } public async anonymousLogin(isBenchmark: boolean = false): Promise { - try { - const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); - this.localUser = new LocalUser(data.userUuid, []); - this.authToken = data.authToken; - if (!isBenchmark) { - // In benchmark, we don't have a local storage. - localUserStore.saveUser(this.localUser); - localUserStore.setAuthToken(this.authToken); - } - } catch (error) { - // anonymous login failed (through 403 DISABLE_ANONYMOUS) - this.loadOpenIDScreen(); + const data = await Axios.post(`${PUSHER_URL}/anonymLogin`).then((res) => res.data); + this.localUser = new LocalUser(data.userUuid, []); + this.authToken = data.authToken; + if (!isBenchmark) { + // In benchmark, we don't have a local storage. + localUserStore.saveUser(this.localUser); + localUserStore.setAuthToken(this.authToken); } } diff --git a/pusher/src/Controller/MapController.ts b/pusher/src/Controller/MapController.ts index 437bac6a..18748d9e 100644 --- a/pusher/src/Controller/MapController.ts +++ b/pusher/src/Controller/MapController.ts @@ -89,7 +89,7 @@ export class MapController extends BaseController { const mapDetails = await adminApi.fetchMapDetails(query.playUri as string, userId); if (isMapDetailsData(mapDetails) && DISABLE_ANONYMOUS) { - (mapDetails as MapDetailsData).authenticationMandatory = true; + mapDetails.authenticationMandatory = true; } res.writeStatus("200 OK"); From d809682c08c71f9860b883c70de66275fe8ec6f3 Mon Sep 17 00:00:00 2001 From: Kharhamel Date: Tue, 26 Oct 2021 14:58:34 +0200 Subject: [PATCH 06/32] HOTFIX: now uses a specific secret token for the admin sockets --- deeployer.libsonnet | 1 + pusher/src/Controller/IoSocketController.ts | 5 ++--- pusher/src/Enum/EnvironmentVariable.ts | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/deeployer.libsonnet b/deeployer.libsonnet index d3320bc0..c4b34e38 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -62,6 +62,7 @@ } + (if adminUrl != null then { "ADMIN_API_URL": adminUrl, "ADMIN_API_TOKEN": env.ADMIN_API_TOKEN, + "ADMIN_SOCKETS_TOKEN": env.ADMIN_SOCKETS_TOKEN, } else {}) }, "front": { diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 0466100c..c2aded67 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -26,10 +26,9 @@ import { jwtTokenManager, tokenInvalidException } from "../Services/JWTTokenMana import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi"; import { SocketManager, socketManager } from "../Services/SocketManager"; import { emitInBatch } from "../Services/IoSocketHelpers"; -import { ADMIN_API_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable"; +import { ADMIN_SOCKETS_TOKEN, ADMIN_API_URL, SOCKET_IDLE_TIMER } from "../Enum/EnvironmentVariable"; import { Zone } from "_Model/Zone"; import { ExAdminSocketInterface } from "_Model/Websocket/ExAdminSocketInterface"; -import { v4 } from "uuid"; import { CharacterTexture } from "../Services/AdminApi/CharacterTexture"; export class IoSocketController { @@ -48,7 +47,7 @@ export class IoSocketController { const websocketProtocol = req.getHeader("sec-websocket-protocol"); const websocketExtensions = req.getHeader("sec-websocket-extensions"); const token = query.token; - if (token !== ADMIN_API_TOKEN) { + if (token !== ADMIN_SOCKETS_TOKEN) { console.log("Admin access refused for token: " + token); res.writeStatus("401 Unauthorized").end("Incorrect token"); return; diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index ab1ce110..ad369a17 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -4,6 +4,7 @@ const API_URL = process.env.API_URL || ""; const ADMIN_API_URL = process.env.ADMIN_API_URL || ""; const ADMIN_URL = process.env.ADMIN_URL || ""; const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || "myapitoken"; +export const ADMIN_SOCKETS_TOKEN = process.env.ADMIN_SOCKETS_TOKEN || "myapitoken"; const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80; const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : process.env.JITSI_URL; const JITSI_ISS = process.env.JITSI_ISS || ""; From f8ae189cee2e0f1d8133fcde39b220da5d1e045e Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Wed, 27 Oct 2021 14:29:39 +0200 Subject: [PATCH 07/32] HotFix handler message in chat store Signed-off-by: Gregoire Parant --- front/src/Api/IframeListener.ts | 2 +- front/src/Stores/ChatStore.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 5a9aca85..668b2e94 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -284,7 +284,7 @@ class IframeListener { registerScript(scriptUrl: string): Promise { return new Promise((resolve, reject) => { - console.log("Loading map related script at ", scriptUrl); + console.info("Loading map related script at ", scriptUrl); if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") { // Using external iframe mode ( diff --git a/front/src/Stores/ChatStore.ts b/front/src/Stores/ChatStore.ts index feb1f3ec..0cda645d 100644 --- a/front/src/Stores/ChatStore.ts +++ b/front/src/Stores/ChatStore.ts @@ -1,6 +1,7 @@ import { writable } from "svelte/store"; import { playersStore } from "./PlayersStore"; import type { PlayerInterface } from "../Phaser/Game/PlayerInterface"; +import { iframeListener } from "../Api/IframeListener"; export const chatVisibilityStore = writable(false); export const chatInputFocusStore = writable(false); @@ -66,6 +67,9 @@ function createChatMessagesStore() { }); }, addPersonnalMessage(text: string) { + //post message iframe listener + iframeListener.sendUserInputChat(text); + newChatMessageStore.set(text); update((list) => { const lastMessage = list[list.length - 1]; From 6c0d8942e54081adf5e25dcfa2858a1611b12da3 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Wed, 27 Oct 2021 16:48:33 +0200 Subject: [PATCH 08/32] HotFix set last room for first connexion Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 1995759e..70d29f08 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -164,6 +164,9 @@ class ConnectionManager { //before set token of user we must load room and all information. For example the mandatory authentication could be require on current room this._currentRoom = await Room.createRoom(new URL(roomPath)); + //defined last room url this room path + localUserStore.setLastRoomUrl(this._currentRoom.key); + //todo: add here some kind of warning if authToken has expired. if (!this.authToken && !this._currentRoom.authenticationMandatory) { await this.anonymousLogin(); From 6c78717d9790775fb05575ee3dfc02f56b4c484b Mon Sep 17 00:00:00 2001 From: Kharhamel Date: Thu, 28 Oct 2021 14:53:07 +0200 Subject: [PATCH 09/32] FIX: the admin sockets now uses a short live to check room authorization --- pusher/src/Controller/IoSocketController.ts | 16 +++++++++------- pusher/src/Services/JWTTokenManager.ts | 9 ++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index c2aded67..7cfd9bd7 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -47,15 +47,19 @@ export class IoSocketController { const websocketProtocol = req.getHeader("sec-websocket-protocol"); const websocketExtensions = req.getHeader("sec-websocket-extensions"); const token = query.token; - if (token !== ADMIN_SOCKETS_TOKEN) { - console.log("Admin access refused for token: " + token); + let authorizedRoomIds: string[]; + try { + const data = jwtTokenManager.verifyAdminSocketToken(token as string); + authorizedRoomIds = data.authorizedRoomIds; + } catch (e) { + console.error("Admin access refused for token: " + token); res.writeStatus("401 Unauthorized").end("Incorrect token"); return; } const roomId = query.roomId; - if (typeof roomId !== "string") { - console.error("Received"); - res.writeStatus("400 Bad Request").end("Missing room id"); + if (typeof roomId !== "string" || !authorizedRoomIds.includes(roomId)) { + console.error("Invalid room id"); + res.writeStatus("403 Bad Request").end("Invalid room id"); return; } @@ -69,8 +73,6 @@ export class IoSocketController { }, message: (ws, arrayBuffer, isBinary): void => { try { - const roomId = ws.roomId as string; - //TODO refactor message type and data const message: { event: string; message: { type: string; message: unknown; userUuid: string } } = JSON.parse(new TextDecoder("utf-8").decode(new Uint8Array(arrayBuffer))); diff --git a/pusher/src/Services/JWTTokenManager.ts b/pusher/src/Services/JWTTokenManager.ts index 24393084..fe418475 100644 --- a/pusher/src/Services/JWTTokenManager.ts +++ b/pusher/src/Services/JWTTokenManager.ts @@ -1,4 +1,4 @@ -import { ADMIN_API_URL, ALLOW_ARTILLERY, SECRET_KEY } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_URL, ADMIN_SOCKETS_TOKEN, ALLOW_ARTILLERY, SECRET_KEY } from "../Enum/EnvironmentVariable"; import { uuid } from "uuidv4"; import Jwt, { verify } from "jsonwebtoken"; import { TokenInterface } from "../Controller/AuthenticateController"; @@ -8,9 +8,16 @@ export interface AuthTokenData { identifier: string; //will be a email if logged in or an uuid if anonymous hydraAccessToken?: string; } +export interface AdminSocketTokenData { + authorizedRoomIds: string[]; //the list of rooms the client is authorized to read from. +} export const tokenInvalidException = "tokenInvalid"; class JWTTokenManager { + public verifyAdminSocketToken(token: string): AdminSocketTokenData { + return Jwt.verify(token, ADMIN_SOCKETS_TOKEN) as AdminSocketTokenData; + } + public createAuthToken(identifier: string, hydraAccessToken?: string) { return Jwt.sign({ identifier, hydraAccessToken }, SECRET_KEY, { expiresIn: "30d" }); } From f20c39f6a4605130eca4a49750845d09e770a22e Mon Sep 17 00:00:00 2001 From: Benedicte Quimbert Date: Wed, 3 Nov 2021 16:51:33 +0100 Subject: [PATCH 10/32] wip --- maps/tests/TriggerMessageApi/script.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/maps/tests/TriggerMessageApi/script.js b/maps/tests/TriggerMessageApi/script.js index 9ab02ec2..a09b7653 100644 --- a/maps/tests/TriggerMessageApi/script.js +++ b/maps/tests/TriggerMessageApi/script.js @@ -1,16 +1,19 @@ WA.onInit().then(() => { - let message; + let message; + console.log('the right place!') - WA.room.onEnterZone("carpet", () => { - message = WA.ui.displayActionMessage({ - message: "This is a test message. Press space to display a chat message. Walk out to hide the message.", - callback: () => { - WA.chat.sendChatMessage("Hello world!", "The bot"); - } - }); + WA.room.onEnterLayer("carpet").subscribe(() => { + message = WA.ui.displayActionMessage({ + message: + "This is a bis test message. Press space to display a chat message. Walk out to hide the message.", + callback: () => { + WA.chat.sendChatMessage("Hello world!", "The bot"); + }, }); + }); - WA.room.onLeaveZone("carpet", () => { - message && message.remove(); - }); + + WA.room.onLeaveLayer("carpet").subscribe(() => { + message && message.remove(); + }); }); From 854d8775d5ab12ff839e3ba3a6bc72ab63aa82b3 Mon Sep 17 00:00:00 2001 From: Benedicte Quimbert Date: Wed, 3 Nov 2021 19:24:24 +0100 Subject: [PATCH 11/32] Edit documentation exemples --- docs/maps/api-controls.md | 4 ++-- docs/maps/api-ui.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/maps/api-controls.md b/docs/maps/api-controls.md index dcb0f17b..c2b47262 100644 --- a/docs/maps/api-controls.md +++ b/docs/maps/api-controls.md @@ -15,7 +15,7 @@ When controls are disabled, the user cannot move anymore using keyboard input. T Example: ```javascript -WA.room.onEnterZone('myZone', () => { +WA.room.onEnterLayer('myZone').subscribe(() => { WA.controls.disablePlayerControls(); WA.ui.openPopup("popupRectangle", 'This is an imporant message!', [{ label: "Got it!", @@ -25,5 +25,5 @@ WA.room.onEnterZone('myZone', () => { popup.close(); } }]); -}); +}) ``` diff --git a/docs/maps/api-ui.md b/docs/maps/api-ui.md index dc701500..8583c061 100644 --- a/docs/maps/api-ui.md +++ b/docs/maps/api-ui.md @@ -49,7 +49,7 @@ Example: let helloWorldPopup; // Open the popup when we enter a given zone -helloWorldPopup = WA.room.onEnterZone('myZone', () => { +helloWorldPopup = WA.room.onEnterLayer("myZone").subscribe(() => { WA.ui.openPopup("popupRectangle", 'Hello world!', [{ label: "Close", className: "primary", @@ -57,13 +57,13 @@ helloWorldPopup = WA.room.onEnterZone('myZone', () => { // Close the popup when the "Close" button is pressed. popup.close(); } - }); -}]); + }]); +}); // Close the popup when we leave the zone. -WA.room.onLeaveZone('myZone', () => { +WA.room.onLeaveLayer("myZone").subscribe(() => { helloWorldPopup.close(); -}); +}) ``` ### Add custom menu From 7da975749c025807bfde287c364d34ee73efc428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dicte=20Q?= <37311765+HimeShaman@users.noreply.github.com> Date: Mon, 8 Nov 2021 10:51:08 +0100 Subject: [PATCH 12/32] Update maps/tests/TriggerMessageApi/script.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David NĂ©grier --- maps/tests/TriggerMessageApi/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maps/tests/TriggerMessageApi/script.js b/maps/tests/TriggerMessageApi/script.js index a09b7653..143f418b 100644 --- a/maps/tests/TriggerMessageApi/script.js +++ b/maps/tests/TriggerMessageApi/script.js @@ -5,7 +5,7 @@ WA.onInit().then(() => { WA.room.onEnterLayer("carpet").subscribe(() => { message = WA.ui.displayActionMessage({ message: - "This is a bis test message. Press space to display a chat message. Walk out to hide the message.", + "This is a test message. Press space to display a chat message. Walk out to hide the message.", callback: () => { WA.chat.sendChatMessage("Hello world!", "The bot"); }, From b9bf27983f839ccdb49753451d05776e8e6c3bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dicte=20Q?= <37311765+HimeShaman@users.noreply.github.com> Date: Mon, 8 Nov 2021 10:51:18 +0100 Subject: [PATCH 13/32] Update maps/tests/TriggerMessageApi/script.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David NĂ©grier --- maps/tests/TriggerMessageApi/script.js | 1 - 1 file changed, 1 deletion(-) diff --git a/maps/tests/TriggerMessageApi/script.js b/maps/tests/TriggerMessageApi/script.js index 143f418b..4041d98b 100644 --- a/maps/tests/TriggerMessageApi/script.js +++ b/maps/tests/TriggerMessageApi/script.js @@ -1,6 +1,5 @@ WA.onInit().then(() => { let message; - console.log('the right place!') WA.room.onEnterLayer("carpet").subscribe(() => { message = WA.ui.displayActionMessage({ From 4c028bfcb3f64748b310645eadadb6163b7b00e8 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 8 Nov 2021 19:27:01 +0100 Subject: [PATCH 14/32] OpenId from Admin connect - Create admin environment for redirect uri of openID - Add log out redirect when user click on log out button Signed-off-by: Gregoire Parant --- pusher/src/Enum/EnvironmentVariable.ts | 1 + pusher/src/Services/AdminApi.ts | 4 ++++ pusher/src/Services/OpenIDClient.ts | 33 +++++++++++++------------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index ab1ce110..22c4db4f 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -15,6 +15,7 @@ export const FRONT_URL = process.env.FRONT_URL || "http://localhost"; export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; +export const OPID_CLIENT_REDIREC_URL = process.env.OPID_CLIENT_REDIREC_URL || FRONT_URL + "/jwt"; export { SECRET_KEY, diff --git a/pusher/src/Services/AdminApi.ts b/pusher/src/Services/AdminApi.ts index e53d00ae..d002ff8b 100644 --- a/pusher/src/Services/AdminApi.ts +++ b/pusher/src/Services/AdminApi.ts @@ -150,6 +150,10 @@ class AdminApi { return ADMIN_URL + `/profile?token=${accessToken}`; } + + async logoutOauth(token: string) { + await Axios.get(ADMIN_API_URL + `/oauth/logout?token=${token}`); + } } export const adminApi = new AdminApi(); diff --git a/pusher/src/Services/OpenIDClient.ts b/pusher/src/Services/OpenIDClient.ts index c9137ad5..1a475224 100644 --- a/pusher/src/Services/OpenIDClient.ts +++ b/pusher/src/Services/OpenIDClient.ts @@ -1,7 +1,10 @@ import { Issuer, Client, IntrospectionResponse } from "openid-client"; -import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, FRONT_URL } from "../Enum/EnvironmentVariable"; - -const opidRedirectUri = FRONT_URL + "/jwt"; +import { + OPID_CLIENT_ID, + OPID_CLIENT_SECRET, + OPID_CLIENT_ISSUER, + OPID_CLIENT_REDIREC_URL, +} from "../Enum/EnvironmentVariable"; class OpenIDClient { private issuerPromise: Promise | null = null; @@ -12,7 +15,7 @@ class OpenIDClient { return new issuer.Client({ client_id: OPID_CLIENT_ID, client_secret: OPID_CLIENT_SECRET, - redirect_uris: [opidRedirectUri], + redirect_uris: [OPID_CLIENT_REDIREC_URL], response_types: ["code"], }); }); @@ -20,30 +23,26 @@ class OpenIDClient { return this.issuerPromise; } - public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) { + public authorizationUrl(playUri?: string, redirect?: string) { return this.initClient().then((client) => { return client.authorizationUrl({ scope: "openid email", prompt: "login", - state: state, - nonce: nonce, playUri: playUri, redirect: redirect, }); }); } - public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> { + public getUserInfo(accessToken: string): Promise<{ email: string; sub: string; access_token: string }> { return this.initClient().then((client) => { - return client.callback(opidRedirectUri, { code }, { nonce }).then((tokenSet) => { - return client.userinfo(tokenSet).then((res) => { - return { - ...res, - email: res.email as string, - sub: res.sub, - access_token: tokenSet.access_token as string, - }; - }); + return client.userinfo(accessToken).then((res) => { + return { + ...res, + email: res.email as string, + sub: res.sub, + access_token: accessToken as string, + }; }); }); } From 89baafba2fb69f8252d49958f1a9c455a5251047 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Tue, 9 Nov 2021 00:08:01 +0100 Subject: [PATCH 15/32] Rollback openid connect to use code and nonce Signed-off-by: Gregoire Parant --- front/src/Connexion/LocalUserStore.ts | 4 ++++ pusher/src/Services/OpenIDClient.ts | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index 6c20aadb..a113291d 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -165,6 +165,10 @@ class LocalUserStore { verifyState(value: string): boolean { const oldValue = localStorage.getItem(state); + if (!oldValue) { + localStorage.setItem(state, value); + return true; + } return oldValue === value; } getState(): string | null { diff --git a/pusher/src/Services/OpenIDClient.ts b/pusher/src/Services/OpenIDClient.ts index 1a475224..bc0dd6c9 100644 --- a/pusher/src/Services/OpenIDClient.ts +++ b/pusher/src/Services/OpenIDClient.ts @@ -23,26 +23,30 @@ class OpenIDClient { return this.issuerPromise; } - public authorizationUrl(playUri?: string, redirect?: string) { + public authorizationUrl(state: string, nonce: string, playUri?: string, redirect?: string) { return this.initClient().then((client) => { return client.authorizationUrl({ scope: "openid email", prompt: "login", + state: state, + nonce: nonce, playUri: playUri, redirect: redirect, }); }); } - public getUserInfo(accessToken: string): Promise<{ email: string; sub: string; access_token: string }> { + public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> { return this.initClient().then((client) => { - return client.userinfo(accessToken).then((res) => { - return { - ...res, - email: res.email as string, - sub: res.sub, - access_token: accessToken as string, - }; + return client.callback(OPID_CLIENT_REDIREC_URL, { code }, { nonce }).then((tokenSet) => { + return client.userinfo(tokenSet).then((res) => { + return { + ...res, + email: res.email as string, + sub: res.sub, + access_token: tokenSet.access_token as string, + }; + }); }); }); } From 7406b620939af5d508144722437ef1965cc26bd4 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Tue, 9 Nov 2021 00:38:32 +0100 Subject: [PATCH 16/32] Add jwt token if is defined un URL Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index b346f450..032a60f1 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -87,6 +87,8 @@ class ConnectionManager { urlManager.pushRoomIdToUrl(this._currentRoom); } else if (connexionType === GameConnexionTypes.jwt) { const urlParams = new URLSearchParams(window.location.search); + + //TODO if jwt is defined, state and nonce can to be deleted const code = urlParams.get("code"); const state = urlParams.get("state"); if (!state || !localUserStore.verifyState(state)) { @@ -96,6 +98,12 @@ class ConnectionManager { throw "No Auth code provided"; } localUserStore.setCode(code); + + const jwt = urlParams.get("jwt"); + if (jwt) { + this.authToken = jwt; + localUserStore.setAuthToken(jwt); + } this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); try { await this.checkAuthUserConnexion(); From 1db22d82af53cbfe241319a956e64435443cef54 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Wed, 10 Nov 2021 18:26:50 +0100 Subject: [PATCH 17/32] Set state in local storage when openid provider redirect on jwt with token value Signed-off-by: Gregoire Parant --- front/src/Connexion/ConnectionManager.ts | 16 ++++++++++------ front/src/Connexion/LocalUserStore.ts | 3 +++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 032a60f1..cb600d6d 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -91,6 +91,16 @@ class ConnectionManager { //TODO if jwt is defined, state and nonce can to be deleted const code = urlParams.get("code"); const state = urlParams.get("state"); + const jwt = urlParams.get("jwt"); + + if (jwt) { + this.authToken = jwt; + localUserStore.setAuthToken(jwt); + //if we use jwt we can update new state from openid provider + if (state) { + localUserStore.setState(state); + } + } if (!state || !localUserStore.verifyState(state)) { throw "Could not validate state!"; } @@ -98,12 +108,6 @@ class ConnectionManager { throw "No Auth code provided"; } localUserStore.setCode(code); - - const jwt = urlParams.get("jwt"); - if (jwt) { - this.authToken = jwt; - localUserStore.setAuthToken(jwt); - } this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); try { await this.checkAuthUserConnexion(); diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index a113291d..7607fb2d 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -171,6 +171,9 @@ class LocalUserStore { } return oldValue === value; } + setState(value: string) { + localStorage.setItem(state, value); + } getState(): string | null { return localStorage.getItem(state); } From d3f120f2bb0b38db31e05e5050b6ade628e1d091 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Fri, 12 Nov 2021 12:13:44 +0100 Subject: [PATCH 18/32] Update to have token when user is connected - Update menu design Signed-off-by: Gregoire Parant --- .../src/Components/Menu/ContactSubMenu.svelte | 52 +++++++++++- .../Components/Menu/CreateMapSubMenu.svelte | 51 ----------- front/src/Components/Menu/GuestSubMenu.svelte | 75 ++++++++++++++++ front/src/Components/Menu/Menu.svelte | 14 +-- .../src/Components/Menu/ProfileSubMenu.svelte | 85 ++++++++++++------- front/src/Connexion/ConnectionManager.ts | 56 ++++++------ front/src/Stores/MenuStore.ts | 10 +-- 7 files changed, 220 insertions(+), 123 deletions(-) delete mode 100644 front/src/Components/Menu/CreateMapSubMenu.svelte create mode 100644 front/src/Components/Menu/GuestSubMenu.svelte diff --git a/front/src/Components/Menu/ContactSubMenu.svelte b/front/src/Components/Menu/ContactSubMenu.svelte index 61ecc56e..3cf1f5fb 100644 --- a/front/src/Components/Menu/ContactSubMenu.svelte +++ b/front/src/Components/Menu/ContactSubMenu.svelte @@ -1,10 +1,60 @@ - +
+
+
+

Getting started

+

+ WorkAdventure allows you to create an online space to communicate spontaneously with others. + And it all starts with creating your own space. Choose from a large selection of prefabricated maps by our team. +

+ +
+ +
+

Create your map

+

You can also create your own custom map by following the step of the documentation.

+ +
+ + +
+
diff --git a/front/src/Components/Menu/GuestSubMenu.svelte b/front/src/Components/Menu/GuestSubMenu.svelte new file mode 100644 index 00000000..13a7981a --- /dev/null +++ b/front/src/Components/Menu/GuestSubMenu.svelte @@ -0,0 +1,75 @@ + + +
+
+ +
+

Share the link of the room !

+ + +
+
+
+ + \ No newline at end of file diff --git a/front/src/Components/Menu/Menu.svelte b/front/src/Components/Menu/Menu.svelte index 4eecb370..83715304 100644 --- a/front/src/Components/Menu/Menu.svelte +++ b/front/src/Components/Menu/Menu.svelte @@ -2,11 +2,11 @@ import {fly} from "svelte/transition"; import SettingsSubMenu from "./SettingsSubMenu.svelte"; import ProfileSubMenu from "./ProfileSubMenu.svelte"; - import CreateMapSubMenu from "./CreateMapSubMenu.svelte"; import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte"; import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte"; import ContactSubMenu from "./ContactSubMenu.svelte"; import CustomSubMenu from "./CustomSubMenu.svelte" + import GuestSubMenu from "./GuestSubMenu.svelte"; import { checkSubMenuToShow, customMenuIframe, @@ -19,21 +19,21 @@ import type {Unsubscriber} from "svelte/store"; import {sendMenuClickedEvent} from "../../Api/iframe/Ui/MenuItem"; - let activeSubMenu: string = SubMenusInterface.settings; - let activeComponent: typeof SettingsSubMenu | typeof CustomSubMenu = SettingsSubMenu; + let activeSubMenu: string = SubMenusInterface.profile; + let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu; let props: { url: string, allowApi: boolean }; let unsubscriberSubMenuStore: Unsubscriber; onMount(() => { unsubscriberSubMenuStore = subMenusStore.subscribe(() => { if(!get(subMenusStore).includes(activeSubMenu)) { - switchMenu(SubMenusInterface.settings); + switchMenu(SubMenusInterface.profile); } }) checkSubMenuToShow(); - switchMenu(SubMenusInterface.settings); + switchMenu(SubMenusInterface.profile); }) onDestroy(() => { @@ -52,8 +52,8 @@ case SubMenusInterface.profile: activeComponent = ProfileSubMenu; break; - case SubMenusInterface.createMap: - activeComponent = CreateMapSubMenu; + case SubMenusInterface.invite: + activeComponent = GuestSubMenu; break; case SubMenusInterface.aboutRoom: activeComponent = AboutRoomSubMenu; diff --git a/front/src/Components/Menu/ProfileSubMenu.svelte b/front/src/Components/Menu/ProfileSubMenu.svelte index 83ec329c..e543096e 100644 --- a/front/src/Components/Menu/ProfileSubMenu.svelte +++ b/front/src/Components/Menu/ProfileSubMenu.svelte @@ -55,54 +55,73 @@
- {#if $userIsConnected} + + +
+ {#if $userIsConnected} +
+ {#if PROFILE_URL != undefined} + + {/if} +
+
+ +
+ {:else} +
+ Sign in +
+ {/if} +
+ + +
+
+ +
+
+ Profile validated by domain: ${domain} +
+
+ Your email: ${email} +
+
+ + ` + ); + } +} diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index 43bfc7bf..52382266 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -16,6 +16,7 @@ export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; export const OPID_CLIENT_REDIREC_URL = process.env.OPID_CLIENT_REDIREC_URL || FRONT_URL + "/jwt"; +export const OPID_PROFILE_SCREEN_PROVIDER = process.env.OPID_PROFILE_SCREEN_PROVIDER || ADMIN_URL + "/profile"; export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS || false; export { diff --git a/pusher/src/Services/AdminApi.ts b/pusher/src/Services/AdminApi.ts index d002ff8b..6e1848eb 100644 --- a/pusher/src/Services/AdminApi.ts +++ b/pusher/src/Services/AdminApi.ts @@ -1,4 +1,4 @@ -import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL } from "../Enum/EnvironmentVariable"; +import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL, OPID_PROFILE_SCREEN_PROVIDER } from "../Enum/EnvironmentVariable"; import Axios from "axios"; import { GameRoomPolicyTypes } from "_Model/PusherRoom"; import { CharacterTexture } from "./AdminApi/CharacterTexture"; @@ -142,13 +142,15 @@ class AdminApi { }); } - /*TODO add constant to use profile companny*/ + /** + * + * @param accessToken + */ getProfileUrl(accessToken: string): string { - if (!ADMIN_URL) { + if (!OPID_PROFILE_SCREEN_PROVIDER) { throw new Error("No admin backoffice set!"); } - - return ADMIN_URL + `/profile?token=${accessToken}`; + return `${OPID_PROFILE_SCREEN_PROVIDER}?accessToken=${accessToken}`; } async logoutOauth(token: string) { From 16c08d86f29e144bf995b72b136d48fc5f41c5ba Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 12:30:25 +0100 Subject: [PATCH 27/32] Update hydraAccessToken to accessToken --- pusher/src/Controller/AuthenticateController.ts | 15 ++++++++------- pusher/src/Services/JWTTokenManager.ts | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 2dafe065..7b1f50bd 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -62,10 +62,11 @@ export class AuthenticateController extends BaseController { if (token != undefined) { try { const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); - if (authTokenData.hydraAccessToken == undefined) { + if (authTokenData.accessToken == undefined) { throw Error("Token cannot to be check on Hydra"); } - await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken); + const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken); + console.log("resCheckTokenAuth", resCheckTokenAuth); res.writeStatus("200"); this.addCorsHeaders(res); return res.end(JSON.stringify({ authToken: token })); @@ -100,10 +101,10 @@ export class AuthenticateController extends BaseController { try { const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); - if (authTokenData.hydraAccessToken == undefined) { + if (authTokenData.accessToken == undefined) { throw Error("Token cannot to be logout on Hydra"); } - await openIDClient.logoutUser(authTokenData.hydraAccessToken); + await openIDClient.logoutUser(authTokenData.accessToken); } catch (error) { console.error("openIDCallback => logout-callback", error); } finally { @@ -208,14 +209,14 @@ export class AuthenticateController extends BaseController { if (token != undefined) { try { const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false); - if (authTokenData.hydraAccessToken == undefined) { + if (authTokenData.accessToken == undefined) { throw Error("Token cannot to be check on Hydra"); } - await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken); + await openIDClient.checkTokenAuth(authTokenData.accessToken); //get login profile res.writeStatus("302"); - res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.hydraAccessToken)); + res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.accessToken)); this.addCorsHeaders(res); // eslint-disable-next-line no-unsafe-finally return res.end(); diff --git a/pusher/src/Services/JWTTokenManager.ts b/pusher/src/Services/JWTTokenManager.ts index 24393084..2f482dbf 100644 --- a/pusher/src/Services/JWTTokenManager.ts +++ b/pusher/src/Services/JWTTokenManager.ts @@ -6,13 +6,13 @@ import { adminApi, AdminBannedData } from "../Services/AdminApi"; export interface AuthTokenData { identifier: string; //will be a email if logged in or an uuid if anonymous - hydraAccessToken?: string; + accessToken?: string; } export const tokenInvalidException = "tokenInvalid"; class JWTTokenManager { - public createAuthToken(identifier: string, hydraAccessToken?: string) { - return Jwt.sign({ identifier, hydraAccessToken }, SECRET_KEY, { expiresIn: "30d" }); + public createAuthToken(identifier: string, accessToken?: string) { + return Jwt.sign({ identifier, accessToken }, SECRET_KEY, { expiresIn: "30d" }); } public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData { From 61b8d584af01432deca9b4d014c5b97f3e086e2e Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 14:34:23 +0100 Subject: [PATCH 28/32] delete useless userIdentify --- pusher/src/Controller/AuthenticateController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 7b1f50bd..0cef24bb 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -203,7 +203,7 @@ export class AuthenticateController extends BaseController { res.onAborted(() => { console.warn("/message request was aborted"); }); - const { userIdentify, token } = parse(req.getQuery()); + const { token } = parse(req.getQuery()); try { //verify connected by token if (token != undefined) { From bbc2ac255002133b00607b0cb8d6e73bc0c6dfc9 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 15:25:49 +0100 Subject: [PATCH 29/32] Update Connection manager to clean url history of navigator --- front/src/Connexion/ConnectionManager.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 1f844bf2..793831bf 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -212,6 +212,8 @@ class ConnectionManager { analyticsClient.identifyUser(this.localUser.uuid, this.localUser.email); } + //clean history with new URL + window.history.pushState({}, document.title, window.location.pathname); this.serviceWorker = new _ServiceWorker(); return Promise.resolve(this._currentRoom); } From 210a789aa460c63d759dc3d85e3eb5a49def0346 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 15:58:08 +0100 Subject: [PATCH 30/32] Fix feedback @moufmouf --- .env.template | 2 +- docker-compose.single-domain.yaml | 2 +- docker-compose.yaml | 2 +- front/src/Connexion/ConnectionManager.ts | 3 + .../src/Controller/AuthenticateController.ts | 1 - .../src/Controller/OpenIdProfileController.ts | 64 +++++++++---------- pusher/src/Enum/EnvironmentVariable.ts | 2 +- pusher/src/Services/OpenIDClient.ts | 6 +- 8 files changed, 42 insertions(+), 40 deletions(-) diff --git a/.env.template b/.env.template index 5328fe08..0bd7bf6d 100644 --- a/.env.template +++ b/.env.template @@ -22,7 +22,7 @@ MAX_USERNAME_LENGTH=8 OPID_CLIENT_ID= OPID_CLIENT_SECRET= OPID_CLIENT_ISSUER= -OPID_CLIENT_REDIREC_URL= +OPID_CLIENT_REDIRECT_URL= OPID_LOGIN_SCREEN_PROVIDER=http://pusher.workadventure.localhost/login-screen OPID_PROFILE_SCREEN_PROVIDER= DISABLE_ANONYMOUS= diff --git a/docker-compose.single-domain.yaml b/docker-compose.single-domain.yaml index e241c108..cd38a0f9 100644 --- a/docker-compose.single-domain.yaml +++ b/docker-compose.single-domain.yaml @@ -71,7 +71,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER - OPID_CLIENT_REDIREC_URL: $OPID_CLIENT_REDIREC_URL + OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: diff --git a/docker-compose.yaml b/docker-compose.yaml index 03395f22..0e22fa91 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -73,7 +73,7 @@ services: OPID_CLIENT_ID: $OPID_CLIENT_ID OPID_CLIENT_SECRET: $OPID_CLIENT_SECRET OPID_CLIENT_ISSUER: $OPID_CLIENT_ISSUER - OPID_CLIENT_REDIREC_URL: $OPID_CLIENT_REDIREC_URL + OPID_CLIENT_REDIRECT_URL: $OPID_CLIENT_REDIRECT_URL OPID_PROFILE_SCREEN_PROVIDER: $OPID_PROFILE_SCREEN_PROVIDER DISABLE_ANONYMOUS: $DISABLE_ANONYMOUS volumes: diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 793831bf..9316e37f 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -183,8 +183,11 @@ class ConnectionManager { } else { try { await this.checkAuthUserConnexion(); + analyticsClient.loggedWithSso(); } catch (err) { console.error(err); + this.loadOpenIDScreen(); + return Promise.reject(new Error("You will be redirect on login page")); } } this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 0cef24bb..70e333a8 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -66,7 +66,6 @@ export class AuthenticateController extends BaseController { throw Error("Token cannot to be check on Hydra"); } const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken); - console.log("resCheckTokenAuth", resCheckTokenAuth); res.writeStatus("200"); this.addCorsHeaders(res); return res.end(JSON.stringify({ authToken: token })); diff --git a/pusher/src/Controller/OpenIdProfileController.ts b/pusher/src/Controller/OpenIdProfileController.ts index 372b603b..f33e7a22 100644 --- a/pusher/src/Controller/OpenIdProfileController.ts +++ b/pusher/src/Controller/OpenIdProfileController.ts @@ -44,37 +44,37 @@ export class OpenIdProfileController extends BaseController { } buildHtml(domain: string, email: string, pictureUrl?: string) { - return ( - "" + - ` -
- -
- -
-
- -
-
- Profile validated by domain: ${domain} -
-
- Your email: ${email} -
-
- - ` - ); + return ` + + + + + + +
+
+ +
+
+ Profile validated by domain: ${domain} +
+
+ Your email: ${email} +
+
+ + + `; } } diff --git a/pusher/src/Enum/EnvironmentVariable.ts b/pusher/src/Enum/EnvironmentVariable.ts index 52382266..23d2c23f 100644 --- a/pusher/src/Enum/EnvironmentVariable.ts +++ b/pusher/src/Enum/EnvironmentVariable.ts @@ -15,7 +15,7 @@ export const FRONT_URL = process.env.FRONT_URL || "http://localhost"; export const OPID_CLIENT_ID = process.env.OPID_CLIENT_ID || ""; export const OPID_CLIENT_SECRET = process.env.OPID_CLIENT_SECRET || ""; export const OPID_CLIENT_ISSUER = process.env.OPID_CLIENT_ISSUER || ""; -export const OPID_CLIENT_REDIREC_URL = process.env.OPID_CLIENT_REDIREC_URL || FRONT_URL + "/jwt"; +export const OPID_CLIENT_REDIRECT_URL = process.env.OPID_CLIENT_REDIRECT_URL || FRONT_URL + "/jwt"; export const OPID_PROFILE_SCREEN_PROVIDER = process.env.OPID_PROFILE_SCREEN_PROVIDER || ADMIN_URL + "/profile"; export const DISABLE_ANONYMOUS = process.env.DISABLE_ANONYMOUS || false; diff --git a/pusher/src/Services/OpenIDClient.ts b/pusher/src/Services/OpenIDClient.ts index bc0dd6c9..13bf6f76 100644 --- a/pusher/src/Services/OpenIDClient.ts +++ b/pusher/src/Services/OpenIDClient.ts @@ -3,7 +3,7 @@ import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, - OPID_CLIENT_REDIREC_URL, + OPID_CLIENT_REDIRECT_URL, } from "../Enum/EnvironmentVariable"; class OpenIDClient { @@ -15,7 +15,7 @@ class OpenIDClient { return new issuer.Client({ client_id: OPID_CLIENT_ID, client_secret: OPID_CLIENT_SECRET, - redirect_uris: [OPID_CLIENT_REDIREC_URL], + redirect_uris: [OPID_CLIENT_REDIRECT_URL], response_types: ["code"], }); }); @@ -38,7 +38,7 @@ class OpenIDClient { public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> { return this.initClient().then((client) => { - return client.callback(OPID_CLIENT_REDIREC_URL, { code }, { nonce }).then((tokenSet) => { + return client.callback(OPID_CLIENT_REDIRECT_URL, { code }, { nonce }).then((tokenSet) => { return client.userinfo(tokenSet).then((res) => { return { ...res, From 20164417fb2be7149bd0885138828ceb1267d606 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 16:34:23 +0100 Subject: [PATCH 31/32] Change data by resCheckTokenAuth --- pusher/src/Controller/AuthenticateController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pusher/src/Controller/AuthenticateController.ts b/pusher/src/Controller/AuthenticateController.ts index 21b636f9..f505923c 100644 --- a/pusher/src/Controller/AuthenticateController.ts +++ b/pusher/src/Controller/AuthenticateController.ts @@ -69,7 +69,7 @@ export class AuthenticateController extends BaseController { const resCheckTokenAuth = await openIDClient.checkTokenAuth(authTokenData.accessToken); res.writeStatus("200"); this.addCorsHeaders(res); - return res.end(JSON.stringify({ ...data, authToken: token })); + return res.end(JSON.stringify({ ...resCheckTokenAuth, authToken: token })); } catch (err) { console.info("User was not connected", err); } From d3964ae25b86ee03af1a212a8412eda89365b86a Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Mon, 15 Nov 2021 16:36:10 +0100 Subject: [PATCH 32/32] HotFix conflict merging --- front/src/Connexion/ConnectionManager.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 87f23843..00e721ae 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -111,7 +111,7 @@ class ConnectionManager { this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); try { - await this.checkAuthUserConnexion(this._currentRoom.key); + await this.checkAuthUserConnexion(); analyticsClient.loggedWithSso(); } catch (err) { console.error(err); @@ -296,7 +296,7 @@ class ConnectionManager { return this.connexionType; } - async checkAuthUserConnexion(playUri: string) { + async checkAuthUserConnexion() { //set connected store for menu at false userIsConnected.set(false); @@ -313,9 +313,9 @@ class ConnectionManager { throw "No Auth code provided"; } } - const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce, token } }).then( - (res) => res.data - ); + const { authToken, userUuid, textures, email } = await Axios.get(`${PUSHER_URL}/login-callback`, { + params: { code, nonce, token }, + }).then((res) => res.data); localUserStore.setAuthToken(authToken); this.localUser = new LocalUser(userUuid, textures, email); localUserStore.saveUser(this.localUser);