Improve profile menu to implement user identity connected URL (#2055)
# Improve profile menu to implement user identity connected URL - Create URL and get user identity - Check if user is connected or show connexion button - Improve profile to check before user data and don't display error webpage in menu
This commit is contained in:
parent
a3fd891530
commit
a13c7e9e2f
@ -9,7 +9,7 @@ class AnalyticsClient {
|
|||||||
constructor() {
|
constructor() {
|
||||||
if (POSTHOG_API_KEY && POSTHOG_URL) {
|
if (POSTHOG_API_KEY && POSTHOG_URL) {
|
||||||
this.posthogPromise = import("posthog-js").then(({ default: posthog }) => {
|
this.posthogPromise = import("posthog-js").then(({ default: posthog }) => {
|
||||||
posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL, disable_cookie: true });
|
posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL });
|
||||||
//the posthog toolbar need a reference in window to be able to work
|
//the posthog toolbar need a reference in window to be able to work
|
||||||
window.posthog = posthog;
|
window.posthog = posthog;
|
||||||
return posthog;
|
return posthog;
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
import { SelectCompanionScene, SelectCompanionSceneName } from "../../Phaser/Login/SelectCompanionScene";
|
import { SelectCompanionScene, SelectCompanionSceneName } from "../../Phaser/Login/SelectCompanionScene";
|
||||||
import { menuIconVisiblilityStore, menuVisiblilityStore, userIsConnected } from "../../Stores/MenuStore";
|
import {
|
||||||
|
menuIconVisiblilityStore,
|
||||||
|
menuVisiblilityStore,
|
||||||
|
userIsConnected,
|
||||||
|
profileAvailable,
|
||||||
|
getProfileUrl,
|
||||||
|
} from "../../Stores/MenuStore";
|
||||||
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
import { selectCompanionSceneVisibleStore } from "../../Stores/SelectCompanionStore";
|
||||||
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
|
||||||
import { loginSceneVisibleStore } from "../../Stores/LoginSceneStore";
|
import { loginSceneVisibleStore } from "../../Stores/LoginSceneStore";
|
||||||
@ -9,7 +15,6 @@
|
|||||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene";
|
import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene";
|
||||||
import { connectionManager } from "../../Connexion/ConnectionManager";
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
import { PROFILE_URL } from "../../Enum/EnvironmentVariable";
|
import { PROFILE_URL } from "../../Enum/EnvironmentVariable";
|
||||||
import { localUserStore } from "../../Connexion/LocalUserStore";
|
|
||||||
import { EnableCameraScene, EnableCameraSceneName } from "../../Phaser/Login/EnableCameraScene";
|
import { EnableCameraScene, EnableCameraSceneName } from "../../Phaser/Login/EnableCameraScene";
|
||||||
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
||||||
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
|
import btnProfileSubMenuCamera from "../images/btn-menu-profile-camera.svg";
|
||||||
@ -47,10 +52,6 @@
|
|||||||
return connectionManager.logout();
|
return connectionManager.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProfileUrl() {
|
|
||||||
return PROFILE_URL + `?token=${localUserStore.getAuthToken()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openEnableCameraScene() {
|
function openEnableCameraScene() {
|
||||||
disableMenuStores();
|
disableMenuStores();
|
||||||
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
||||||
@ -81,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#if $userIsConnected}
|
{#if $userIsConnected && $profileAvailable}
|
||||||
<section>
|
<section>
|
||||||
{#if PROFILE_URL != undefined}
|
{#if PROFILE_URL != undefined}
|
||||||
<iframe title="profile" src={getProfileUrl()} />
|
<iframe title="profile" src={getProfileUrl()} />
|
||||||
|
@ -290,12 +290,12 @@ class ConnectionManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
connection.onConnectError((error: object) => {
|
connection.onConnectError((error: object) => {
|
||||||
console.log("An error occurred while connecting to socket server. Retrying");
|
console.log("onConnectError => An error occurred while connecting to socket server. Retrying");
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.connectionErrorStream.subscribe((event: CloseEvent) => {
|
connection.connectionErrorStream.subscribe((event: CloseEvent) => {
|
||||||
console.log("An error occurred while connecting to socket server. Retrying");
|
console.log("connectionErrorStream => An error occurred while connecting to socket server. Retrying");
|
||||||
reject(
|
reject(
|
||||||
new Error(
|
new Error(
|
||||||
"An error occurred while connecting to socket server. Retrying. Code: " +
|
"An error occurred while connecting to socket server. Retrying. Code: " +
|
||||||
|
@ -23,6 +23,7 @@ export const DISPLAY_TERMS_OF_USE = getEnvConfig("DISPLAY_TERMS_OF_USE") == "tru
|
|||||||
export const NODE_ENV = getEnvConfig("NODE_ENV") || "development";
|
export const NODE_ENV = getEnvConfig("NODE_ENV") || "development";
|
||||||
export const CONTACT_URL = getEnvConfig("CONTACT_URL") || undefined;
|
export const CONTACT_URL = getEnvConfig("CONTACT_URL") || undefined;
|
||||||
export const PROFILE_URL = getEnvConfig("PROFILE_URL") || undefined;
|
export const PROFILE_URL = getEnvConfig("PROFILE_URL") || undefined;
|
||||||
|
export const IDENTITY_URL = getEnvConfig("IDENTITY_URL") || undefined;
|
||||||
export const POSTHOG_API_KEY: string = (getEnvConfig("POSTHOG_API_KEY") as string) || "";
|
export const POSTHOG_API_KEY: string = (getEnvConfig("POSTHOG_API_KEY") as string) || "";
|
||||||
export const POSTHOG_URL = getEnvConfig("POSTHOG_URL") || undefined;
|
export const POSTHOG_URL = getEnvConfig("POSTHOG_URL") || undefined;
|
||||||
export const DISABLE_ANONYMOUS: boolean = getEnvConfig("DISABLE_ANONYMOUS") === "true";
|
export const DISABLE_ANONYMOUS: boolean = getEnvConfig("DISABLE_ANONYMOUS") === "true";
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
import { get, writable } from "svelte/store";
|
import { get, writable } from "svelte/store";
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
import { userIsAdminStore } from "./GameStore";
|
import { userIsAdminStore } from "./GameStore";
|
||||||
import { CONTACT_URL } from "../Enum/EnvironmentVariable";
|
import { CONTACT_URL, IDENTITY_URL, PROFILE_URL } from "../Enum/EnvironmentVariable";
|
||||||
import { analyticsClient } from "../Administration/AnalyticsClient";
|
import { analyticsClient } from "../Administration/AnalyticsClient";
|
||||||
import type { Translation } from "../i18n/i18n-types";
|
import type { Translation } from "../i18n/i18n-types";
|
||||||
|
import axios from "axios";
|
||||||
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export const menuIconVisiblilityStore = writable(false);
|
export const menuIconVisiblilityStore = writable(false);
|
||||||
export const menuVisiblilityStore = writable(false);
|
export const menuVisiblilityStore = writable(false);
|
||||||
menuVisiblilityStore.subscribe((value) => {
|
|
||||||
if (value) analyticsClient.openedMenu();
|
|
||||||
});
|
|
||||||
export const menuInputFocusStore = writable(false);
|
export const menuInputFocusStore = writable(false);
|
||||||
export const userIsConnected = writable(false);
|
export const userIsConnected = writable(false);
|
||||||
|
export const profileAvailable = writable(true);
|
||||||
|
|
||||||
|
menuVisiblilityStore.subscribe((value) => {
|
||||||
|
if (value) analyticsClient.openedMenu();
|
||||||
|
if (userIsConnected && value && IDENTITY_URL != null) {
|
||||||
|
axios.get(getMeUrl()).catch((err) => {
|
||||||
|
console.error("menuVisiblilityStore => err => ", err);
|
||||||
|
profileAvailable.set(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let warningContainerTimeout: Timeout | null = null;
|
let warningContainerTimeout: Timeout | null = null;
|
||||||
function createWarningContainerStore() {
|
function createWarningContainerStore() {
|
||||||
@ -173,3 +183,11 @@ export function handleMenuUnregisterEvent(menuName: string) {
|
|||||||
subMenusStore.removeScriptingMenu(menuName);
|
subMenusStore.removeScriptingMenu(menuName);
|
||||||
customMenuIframe.delete(menuName);
|
customMenuIframe.delete(menuName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProfileUrl() {
|
||||||
|
return PROFILE_URL + `?token=${localUserStore.getAuthToken()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMeUrl() {
|
||||||
|
return IDENTITY_URL + `?token=${localUserStore.getAuthToken()}`;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@ export default defineConfig({
|
|||||||
"ADMIN_URL",
|
"ADMIN_URL",
|
||||||
"CONTACT_URL",
|
"CONTACT_URL",
|
||||||
"PROFILE_URL",
|
"PROFILE_URL",
|
||||||
|
"IDENTITY_URL",
|
||||||
"ICON_URL",
|
"ICON_URL",
|
||||||
"DEBUG_MODE",
|
"DEBUG_MODE",
|
||||||
"STUN_SERVER",
|
"STUN_SERVER",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import { BaseHttpController } from "./BaseHttpController";
|
import { BaseHttpController } from "./BaseHttpController";
|
||||||
import { adminApi } from "../Services/AdminApi";
|
import { adminApi, FetchMemberDataByUuidResponse } from "../Services/AdminApi";
|
||||||
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
||||||
import { parse } from "query-string";
|
import { parse } from "query-string";
|
||||||
import { openIDClient } from "../Services/OpenIDClient";
|
import { openIDClient } from "../Services/OpenIDClient";
|
||||||
@ -19,6 +19,7 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
this.register();
|
this.register();
|
||||||
this.anonymLogin();
|
this.anonymLogin();
|
||||||
this.profileCallback();
|
this.profileCallback();
|
||||||
|
this.me();
|
||||||
}
|
}
|
||||||
|
|
||||||
openIDLogin() {
|
openIDLogin() {
|
||||||
@ -180,7 +181,7 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
if (!code && !nonce) {
|
if (!code && !nonce) {
|
||||||
return res.json({ ...resUserData, authToken: token });
|
return res.json({ ...resUserData, authToken: token });
|
||||||
}
|
}
|
||||||
console.error("Token cannot to be check on OpenId provider");
|
console.error("Token cannot be checked on OpenId provider");
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.send("User cannot to be connected on openid provider");
|
res.send("User cannot to be connected on openid provider");
|
||||||
return;
|
return;
|
||||||
@ -255,7 +256,7 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
try {
|
try {
|
||||||
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
if (authTokenData.accessToken == undefined) {
|
if (authTokenData.accessToken == undefined) {
|
||||||
throw Error("Token cannot to be logout on Hydra");
|
throw Error("Token cannot be logout on Hydra");
|
||||||
}
|
}
|
||||||
await openIDClient.logoutUser(authTokenData.accessToken);
|
await openIDClient.logoutUser(authTokenData.accessToken);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -412,7 +413,7 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
try {
|
try {
|
||||||
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
if (authTokenData.accessToken == undefined) {
|
if (authTokenData.accessToken == undefined) {
|
||||||
throw Error("Token cannot to be check on Hydra");
|
throw Error("Token cannot be checked on OpenID connect provider");
|
||||||
}
|
}
|
||||||
await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
|
|
||||||
@ -432,4 +433,80 @@ export class AuthenticateController extends BaseHttpController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /me:
|
||||||
|
* get:
|
||||||
|
* description: ???
|
||||||
|
* parameters:
|
||||||
|
* - name: "token"
|
||||||
|
* in: "query"
|
||||||
|
* description: "A JWT authentication token ???"
|
||||||
|
* required: true
|
||||||
|
* type: "string"
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Data of user connected
|
||||||
|
*/
|
||||||
|
me() {
|
||||||
|
// @ts-ignore
|
||||||
|
this.app.get("/me", async (req, res): void => {
|
||||||
|
const { token } = parse(req.path_query);
|
||||||
|
try {
|
||||||
|
//verify connected by token
|
||||||
|
if (token != undefined) {
|
||||||
|
try {
|
||||||
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
|
if (authTokenData.accessToken == undefined) {
|
||||||
|
throw Error("Token cannot to be checked on Hydra");
|
||||||
|
}
|
||||||
|
const me = await openIDClient.checkTokenAuth(authTokenData.accessToken);
|
||||||
|
|
||||||
|
//get login profile
|
||||||
|
res.status(200);
|
||||||
|
res.json({ ...me });
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
this.castErrorToResponse(error, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("me => ERROR", error);
|
||||||
|
this.castErrorToResponse(error, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param email
|
||||||
|
* @param playUri
|
||||||
|
* @param IPAddress
|
||||||
|
* @return FetchMemberDataByUuidResponse|object
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private async getUserByUserIdentifier(
|
||||||
|
email: string,
|
||||||
|
playUri: string,
|
||||||
|
IPAddress: string
|
||||||
|
): Promise<FetchMemberDataByUuidResponse | object> {
|
||||||
|
let data: FetchMemberDataByUuidResponse = {
|
||||||
|
email: email,
|
||||||
|
userUuid: email,
|
||||||
|
tags: [],
|
||||||
|
messages: [],
|
||||||
|
visitCardUrl: null,
|
||||||
|
textures: [],
|
||||||
|
userRoomToken: undefined,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
data = await adminApi.fetchMemberDataByUuid(email, playUri, IPAddress, []);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("openIDCallback => fetchMemberDataByUuid", err);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user