d1e8243c47
* Zod EVERYWHERE * Add no-unused-vars rule to eslint in front * Add no-unused-vars rule to eslint in pusher * Add no-unused-vars rule to eslint in back * Remove unused PlayerTexture guards * Fix data providing on room connection Co-authored-by: Alexis Faizeau <a.faizeau@workadventu.re>
180 lines
8.0 KiB
TypeScript
180 lines
8.0 KiB
TypeScript
import { adminApi } from "../Services/AdminApi";
|
|
import { ADMIN_API_URL, DISABLE_ANONYMOUS } from "../Enum/EnvironmentVariable";
|
|
import { GameRoomPolicyTypes } from "../Model/PusherRoom";
|
|
import { isMapDetailsData, MapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
|
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
|
import { InvalidTokenError } from "./InvalidTokenError";
|
|
import { parse } from "query-string";
|
|
import { BaseHttpController } from "./BaseHttpController";
|
|
|
|
export class MapController extends BaseHttpController {
|
|
// Returns a map mapping map name to file name of the map
|
|
routes() {
|
|
/**
|
|
* @openapi
|
|
* /map:
|
|
* get:
|
|
* description: Returns a map mapping map name to file name of the map
|
|
* produces:
|
|
* - "application/json"
|
|
* parameters:
|
|
* - name: "playUri"
|
|
* in: "query"
|
|
* description: "The full URL of WorkAdventure to load this map"
|
|
* required: true
|
|
* type: "string"
|
|
* - name: "authToken"
|
|
* in: "query"
|
|
* description: "The authentication token"
|
|
* required: true
|
|
* type: "string"
|
|
* responses:
|
|
* 200:
|
|
* description: The details of the map
|
|
* content:
|
|
* application/json:
|
|
* schema:
|
|
* type: object
|
|
* required:
|
|
* - mapUrl
|
|
* - policy_type
|
|
* - tags
|
|
* - textures
|
|
* - authenticationMandatory
|
|
* - roomSlug
|
|
* - contactPage
|
|
* - group
|
|
* properties:
|
|
* mapUrl:
|
|
* type: string
|
|
* description: The full URL to the JSON map file
|
|
* example: https://myuser.github.io/myrepo/map.json
|
|
* policy_type:
|
|
* type: integer
|
|
* description: ANONYMOUS_POLICY = 1, MEMBERS_ONLY_POLICY = 2, USE_TAGS_POLICY= 3
|
|
* example: 1
|
|
* tags:
|
|
* type: array
|
|
* description: The list of tags required to enter this room
|
|
* items:
|
|
* type: string
|
|
* example: speaker
|
|
* authenticationMandatory:
|
|
* type: boolean|null
|
|
* description: Whether the authentication is mandatory or not for this map.
|
|
* example: true
|
|
* roomSlug:
|
|
* type: string
|
|
* description: The slug of the room
|
|
* deprecated: true
|
|
* example: foo
|
|
* contactPage:
|
|
* type: string|null
|
|
* description: The URL to the contact page
|
|
* example: https://mycompany.com/contact-us
|
|
* group:
|
|
* type: string|null
|
|
* description: The group this room is part of (maps the notion of "world" in WorkAdventure SAAS)
|
|
* example: myorg/myworld
|
|
* iframeAuthentication:
|
|
* type: string|null
|
|
* description: The URL of the authentication Iframe
|
|
* example: https://mycompany.com/authc
|
|
* expireOn:
|
|
* type: string|undefined
|
|
* description: The date (in ISO 8601 format) at which the room will expire
|
|
* example: 2022-11-05T08:15:30-05:00
|
|
* canReport:
|
|
* type: boolean|undefined
|
|
* description: Whether the "report" feature is enabled or not on this room
|
|
* example: true
|
|
* loadingLogo:
|
|
* type: string
|
|
* description: The URL of the image to be used on the loading page
|
|
* example: https://example.com/logo.png
|
|
* loginSceneLogo:
|
|
* type: string
|
|
* description: The URL of the image to be used on the LoginScene
|
|
* example: https://example.com/logo_login.png
|
|
*
|
|
*/
|
|
this.app.get("/map", (req, res) => {
|
|
const query = parse(req.path_query);
|
|
if (typeof query.playUri !== "string") {
|
|
console.error("Expected playUri parameter in /map endpoint");
|
|
res.status(400);
|
|
res.send("Expected playUri parameter");
|
|
return;
|
|
}
|
|
|
|
// If no admin URL is set, let's react on '/_/[instance]/[map url]' URLs
|
|
if (!ADMIN_API_URL) {
|
|
const roomUrl = new URL(query.playUri);
|
|
|
|
const match = /\/_\/[^/]+\/(.+)/.exec(roomUrl.pathname);
|
|
if (!match) {
|
|
res.status(404);
|
|
res.json({});
|
|
return;
|
|
}
|
|
|
|
const mapUrl = roomUrl.protocol + "//" + match[1];
|
|
|
|
res.json({
|
|
mapUrl,
|
|
policy_type: GameRoomPolicyTypes.ANONYMOUS_POLICY,
|
|
roomSlug: null, // Deprecated
|
|
group: null,
|
|
tags: [],
|
|
contactPage: null,
|
|
authenticationMandatory: DISABLE_ANONYMOUS,
|
|
} as MapDetailsData);
|
|
|
|
return;
|
|
}
|
|
|
|
(async () => {
|
|
try {
|
|
let userId: string | undefined = undefined;
|
|
if (query.authToken != undefined) {
|
|
let authTokenData: AuthTokenData;
|
|
try {
|
|
authTokenData = jwtTokenManager.verifyJWTToken(query.authToken as string);
|
|
userId = authTokenData.identifier;
|
|
} catch (e) {
|
|
try {
|
|
// Decode token, in this case we don't need to create new token.
|
|
authTokenData = jwtTokenManager.verifyJWTToken(query.authToken as string, true);
|
|
userId = authTokenData.identifier;
|
|
console.info("JWT expire, but decoded", userId);
|
|
} catch (e) {
|
|
if (e instanceof InvalidTokenError) {
|
|
// The token was not good, redirect user on login page
|
|
res.status(401);
|
|
res.send("Token decrypted error");
|
|
return;
|
|
} else {
|
|
this.castErrorToResponse(e, res);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const mapDetails = isMapDetailsData.safeParse(
|
|
await adminApi.fetchMapDetails(query.playUri as string, userId)
|
|
);
|
|
|
|
if (mapDetails.success && DISABLE_ANONYMOUS) {
|
|
mapDetails.data.authenticationMandatory = true;
|
|
}
|
|
|
|
res.json(mapDetails);
|
|
return;
|
|
} catch (e) {
|
|
this.castErrorToResponse(e, res);
|
|
}
|
|
})();
|
|
});
|
|
}
|
|
}
|