Merge pull request #339 from thecodingmachine/jitsijwt
Adding JWT authentication to Jitsi
This commit is contained in:
commit
84566f08f3
14 changed files with 201 additions and 48 deletions
|
@ -1,3 +1,7 @@
|
||||||
DEBUG_MODE=false
|
DEBUG_MODE=false
|
||||||
JITSI_URL=meet.jit.si
|
JITSI_URL=meet.jit.si
|
||||||
|
# If your Jitsi environment has authentication set up, you MUST set JITSI_PRIVATE_MODE to "true" and you MUST pass a SECRET_JITSI_KEY to generate the JWT secret
|
||||||
|
JITSI_PRIVATE_MODE=false
|
||||||
|
JITSI_ISS=
|
||||||
|
SECRET_JITSI_KEY=
|
||||||
ADMIN_API_TOKEN=123
|
ADMIN_API_TOKEN=123
|
||||||
|
|
3
.github/workflows/build-and-deploy.yml
vendored
3
.github/workflows/build-and-deploy.yml
vendored
|
@ -121,6 +121,9 @@ jobs:
|
||||||
env:
|
env:
|
||||||
KUBE_CONFIG_FILE: ${{ secrets.KUBE_CONFIG_FILE }}
|
KUBE_CONFIG_FILE: ${{ secrets.KUBE_CONFIG_FILE }}
|
||||||
ADMIN_API_TOKEN: ${{ secrets.ADMIN_API_TOKEN }}
|
ADMIN_API_TOKEN: ${{ secrets.ADMIN_API_TOKEN }}
|
||||||
|
JITSI_ISS: ${{ secrets.JITSI_ISS }}
|
||||||
|
JITSI_URL: ${{ secrets.JITSI_URL }}
|
||||||
|
SECRET_JITSI_KEY: ${{ secrets.SECRET_JITSI_KEY }}
|
||||||
with:
|
with:
|
||||||
namespace: workadventure-${{ env.GITHUB_REF_SLUG }}
|
namespace: workadventure-${{ env.GITHUB_REF_SLUG }}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {
|
||||||
WebRtcSignalToServerMessage,
|
WebRtcSignalToServerMessage,
|
||||||
PlayGlobalMessage,
|
PlayGlobalMessage,
|
||||||
ReportPlayerMessage,
|
ReportPlayerMessage,
|
||||||
|
QueryJitsiJwtMessage,
|
||||||
|
SendJitsiJwtMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
import {UserMovesMessage} from "../Messages/generated/messages_pb";
|
||||||
import {TemplatedApp} from "uWebSockets.js"
|
import {TemplatedApp} from "uWebSockets.js"
|
||||||
|
@ -20,6 +22,7 @@ import {jwtTokenManager} from "../Services/JWTTokenManager";
|
||||||
import {adminApi} from "../Services/AdminApi";
|
import {adminApi} from "../Services/AdminApi";
|
||||||
import {socketManager} from "../Services/SocketManager";
|
import {socketManager} from "../Services/SocketManager";
|
||||||
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
import {emitInBatch, resetPing} from "../Services/IoSocketHelpers";
|
||||||
|
import Jwt from "jsonwebtoken";
|
||||||
|
|
||||||
export class IoSocketController {
|
export class IoSocketController {
|
||||||
private nextUserId: number = 1;
|
private nextUserId: number = 1;
|
||||||
|
@ -191,6 +194,8 @@ export class IoSocketController {
|
||||||
socketManager.emitPlayGlobalMessage(client, message.getPlayglobalmessage() as PlayGlobalMessage);
|
socketManager.emitPlayGlobalMessage(client, message.getPlayglobalmessage() as PlayGlobalMessage);
|
||||||
} else if (message.hasReportplayermessage()){
|
} else if (message.hasReportplayermessage()){
|
||||||
socketManager.handleReportMessage(client, message.getReportplayermessage() as ReportPlayerMessage);
|
socketManager.handleReportMessage(client, message.getReportplayermessage() as ReportPlayerMessage);
|
||||||
|
} else if (message.hasQueryjitsijwtmessage()){
|
||||||
|
socketManager.handleQueryJitsiJwtMessage(client, message.getQueryjitsijwtmessage() as QueryJitsiJwtMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok is false if backpressure was built up, wait for drain */
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
|
|
|
@ -6,6 +6,9 @@ const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLER
|
||||||
const ADMIN_API_URL = process.env.ADMIN_API_URL || 'http://admin';
|
const ADMIN_API_URL = process.env.ADMIN_API_URL || 'http://admin';
|
||||||
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || 'myapitoken';
|
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || 'myapitoken';
|
||||||
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
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 || '';
|
||||||
|
const SECRET_JITSI_KEY = process.env.SECRET_JITSI_KEY || '';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SECRET_KEY,
|
SECRET_KEY,
|
||||||
|
@ -16,4 +19,7 @@ export {
|
||||||
GROUP_RADIUS,
|
GROUP_RADIUS,
|
||||||
ALLOW_ARTILLERY,
|
ALLOW_ARTILLERY,
|
||||||
CPU_OVERHEAT_THRESHOLD,
|
CPU_OVERHEAT_THRESHOLD,
|
||||||
|
JITSI_URL,
|
||||||
|
JITSI_ISS,
|
||||||
|
SECRET_JITSI_KEY
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
UserMovesMessage,
|
UserMovesMessage,
|
||||||
ViewportMessage, WebRtcDisconnectMessage,
|
ViewportMessage, WebRtcDisconnectMessage,
|
||||||
WebRtcSignalToClientMessage,
|
WebRtcSignalToClientMessage,
|
||||||
WebRtcSignalToServerMessage, WebRtcStartMessage
|
WebRtcSignalToServerMessage, WebRtcStartMessage, QueryJitsiJwtMessage, SendJitsiJwtMessage
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import {PointInterface} from "../Model/Websocket/PointInterface";
|
import {PointInterface} from "../Model/Websocket/PointInterface";
|
||||||
import {User} from "../Model/User";
|
import {User} from "../Model/User";
|
||||||
|
@ -27,13 +27,15 @@ import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
import {Group} from "../Model/Group";
|
import {Group} from "../Model/Group";
|
||||||
import {cpuTracker} from "./CpuTracker";
|
import {cpuTracker} from "./CpuTracker";
|
||||||
import {isSetPlayerDetailsMessage} from "../Model/Websocket/SetPlayerDetailsMessage";
|
import {isSetPlayerDetailsMessage} from "../Model/Websocket/SetPlayerDetailsMessage";
|
||||||
import {GROUP_RADIUS, MINIMUM_DISTANCE} from "../Enum/EnvironmentVariable";
|
import {GROUP_RADIUS, JITSI_ISS, MINIMUM_DISTANCE, SECRET_JITSI_KEY} from "../Enum/EnvironmentVariable";
|
||||||
import {Movable} from "../Model/Movable";
|
import {Movable} from "../Model/Movable";
|
||||||
import {PositionInterface} from "../Model/PositionInterface";
|
import {PositionInterface} from "../Model/PositionInterface";
|
||||||
import {adminApi} from "./AdminApi";
|
import {adminApi} from "./AdminApi";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
import {Gauge} from "prom-client";
|
import {Gauge} from "prom-client";
|
||||||
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
import {emitError, emitInBatch} from "./IoSocketHelpers";
|
||||||
|
import Jwt from "jsonwebtoken";
|
||||||
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
class SocketManager {
|
class SocketManager {
|
||||||
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
private Worlds: Map<string, GameRoom> = new Map<string, GameRoom>();
|
||||||
|
@ -593,6 +595,43 @@ class SocketManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public handleQueryJitsiJwtMessage(client: ExSocketInterface, queryJitsiJwtMessage: QueryJitsiJwtMessage) {
|
||||||
|
const room = queryJitsiJwtMessage.getJitsiroom();
|
||||||
|
const tag = queryJitsiJwtMessage.getTag(); // FIXME: this is not secure. We should load the JSON for the current room and check rights associated to room instead.
|
||||||
|
|
||||||
|
if (SECRET_JITSI_KEY === '') {
|
||||||
|
throw new Error('You must set the SECRET_JITSI_KEY key to the secret to generate JWT tokens for Jitsi.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's see if the current client has
|
||||||
|
const isAdmin = client.tags.includes(tag);
|
||||||
|
|
||||||
|
const jwt = Jwt.sign({
|
||||||
|
"aud": "jitsi",
|
||||||
|
"iss": JITSI_ISS,
|
||||||
|
"sub": JITSI_URL,
|
||||||
|
"room": room,
|
||||||
|
"moderator": isAdmin
|
||||||
|
}, SECRET_JITSI_KEY, {
|
||||||
|
expiresIn: '1d',
|
||||||
|
algorithm: "HS256",
|
||||||
|
header:
|
||||||
|
{
|
||||||
|
"alg": "HS256",
|
||||||
|
"typ": "JWT"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendJitsiJwtMessage = new SendJitsiJwtMessage();
|
||||||
|
sendJitsiJwtMessage.setJitsiroom(room);
|
||||||
|
sendJitsiJwtMessage.setJwt(jwt);
|
||||||
|
|
||||||
|
const serverToClientMessage = new ServerToClientMessage();
|
||||||
|
serverToClientMessage.setSendjitsijwtmessage(sendJitsiJwtMessage);
|
||||||
|
|
||||||
|
client.send(serverToClientMessage.serializeBinary().buffer, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const socketManager = new SocketManager();
|
export const socketManager = new SocketManager();
|
|
@ -16,7 +16,10 @@
|
||||||
"env": {
|
"env": {
|
||||||
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
"SECRET_KEY": "tempSecretKeyNeedsToChange",
|
||||||
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
"ADMIN_API_TOKEN": env.ADMIN_API_TOKEN,
|
||||||
"ADMIN_API_URL": "https://admin."+url
|
"ADMIN_API_URL": "https://admin."+url,
|
||||||
|
"JITSI_ISS": env.JITSI_ISS,
|
||||||
|
"JITSI_URL": env.JITSI_URL,
|
||||||
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"front": {
|
"front": {
|
||||||
|
@ -28,10 +31,12 @@
|
||||||
"ports": [80],
|
"ports": [80],
|
||||||
"env": {
|
"env": {
|
||||||
"API_URL": "api."+url,
|
"API_URL": "api."+url,
|
||||||
"JITSI_URL": "meet.jit.si",
|
"JITSI_URL": env.JITSI_URL,
|
||||||
|
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
|
||||||
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
|
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
|
||||||
"TURN_USER": "workadventure",
|
"TURN_USER": "workadventure",
|
||||||
"TURN_PASSWORD": "WorkAdventure123"
|
"TURN_PASSWORD": "WorkAdventure123",
|
||||||
|
"JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"maps": {
|
"maps": {
|
||||||
|
|
|
@ -23,6 +23,7 @@ services:
|
||||||
environment:
|
environment:
|
||||||
DEBUG_MODE: "$DEBUG_MODE"
|
DEBUG_MODE: "$DEBUG_MODE"
|
||||||
JITSI_URL: $JITSI_URL
|
JITSI_URL: $JITSI_URL
|
||||||
|
JITSI_PRIVATE_MODE: "$JITSI_PRIVATE_MODE"
|
||||||
HOST: "0.0.0.0"
|
HOST: "0.0.0.0"
|
||||||
NODE_ENV: development
|
NODE_ENV: development
|
||||||
API_URL: api.workadventure.localhost
|
API_URL: api.workadventure.localhost
|
||||||
|
@ -72,8 +73,11 @@ services:
|
||||||
environment:
|
environment:
|
||||||
STARTUP_COMMAND_1: yarn install
|
STARTUP_COMMAND_1: yarn install
|
||||||
SECRET_KEY: yourSecretKey
|
SECRET_KEY: yourSecretKey
|
||||||
|
SECRET_JITSI_KEY: "$SECRET_JITSI_KEY"
|
||||||
ALLOW_ARTILLERY: "true"
|
ALLOW_ARTILLERY: "true"
|
||||||
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
ADMIN_API_TOKEN: "$ADMIN_API_TOKEN"
|
||||||
|
JITSI_URL: $JITSI_URL
|
||||||
|
JITSI_ISS: $JITSI_ISS
|
||||||
volumes:
|
volumes:
|
||||||
- ./back:/usr/src/app
|
- ./back:/usr/src/app
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -27,6 +27,7 @@ export enum EventMessage{
|
||||||
STOP_GLOBAL_MESSAGE = "stop-global-message",
|
STOP_GLOBAL_MESSAGE = "stop-global-message",
|
||||||
|
|
||||||
TELEPORT = "teleport",
|
TELEPORT = "teleport",
|
||||||
|
START_JITSI_ROOM = "start-jitsi-room",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PointInterface {
|
export interface PointInterface {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
WebRtcSignalToServerMessage,
|
WebRtcSignalToServerMessage,
|
||||||
WebRtcStartMessage,
|
WebRtcStartMessage,
|
||||||
ReportPlayerMessage,
|
ReportPlayerMessage,
|
||||||
TeleportMessageMessage
|
TeleportMessageMessage, QueryJitsiJwtMessage, SendJitsiJwtMessage
|
||||||
} from "../Messages/generated/messages_pb"
|
} from "../Messages/generated/messages_pb"
|
||||||
|
|
||||||
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
import {UserSimplePeerInterface} from "../WebRtc/SimplePeer";
|
||||||
|
@ -150,6 +150,8 @@ export class RoomConnection implements RoomConnection {
|
||||||
this.dispatch(EventMessage.STOP_GLOBAL_MESSAGE, message.getStopglobalmessage());
|
this.dispatch(EventMessage.STOP_GLOBAL_MESSAGE, message.getStopglobalmessage());
|
||||||
} else if (message.hasTeleportmessagemessage()) {
|
} else if (message.hasTeleportmessagemessage()) {
|
||||||
this.dispatch(EventMessage.TELEPORT, message.getTeleportmessagemessage());
|
this.dispatch(EventMessage.TELEPORT, message.getTeleportmessagemessage());
|
||||||
|
} else if (message.hasSendjitsijwtmessage()) {
|
||||||
|
this.dispatch(EventMessage.START_JITSI_ROOM, message.getSendjitsijwtmessage());
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown message received');
|
throw new Error('Unknown message received');
|
||||||
}
|
}
|
||||||
|
@ -501,6 +503,25 @@ export class RoomConnection implements RoomConnection {
|
||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public emitQueryJitsiJwtMessage(jitsiRoom: string, tag: string|undefined ): void {
|
||||||
|
const queryJitsiJwtMessage = new QueryJitsiJwtMessage();
|
||||||
|
queryJitsiJwtMessage.setJitsiroom(jitsiRoom);
|
||||||
|
if (tag !== undefined) {
|
||||||
|
queryJitsiJwtMessage.setTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setQueryjitsijwtmessage(queryJitsiJwtMessage);
|
||||||
|
|
||||||
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStartJitsiRoom(callback: (jwt: string, room: string) => void): void {
|
||||||
|
this.onMessage(EventMessage.START_JITSI_ROOM, (message: SendJitsiJwtMessage) => {
|
||||||
|
callback(message.getJwt(), message.getJitsiroom());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public hasTag(tag: string): boolean {
|
public hasTag(tag: string): boolean {
|
||||||
return this.tags.includes(tag);
|
return this.tags.includes(tag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca";
|
||||||
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
|
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
|
||||||
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
|
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
|
||||||
const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined : process.env.JITSI_URL;
|
const JITSI_URL : string|undefined = (process.env.JITSI_URL === '') ? undefined : process.env.JITSI_URL;
|
||||||
|
const JITSI_PRIVATE_MODE : boolean = process.env.JITSI_PRIVATE_MODE == "true";
|
||||||
const RESOLUTION = 3;
|
const RESOLUTION = 3;
|
||||||
const ZOOM_LEVEL = 1/*3/4*/;
|
const ZOOM_LEVEL = 1/*3/4*/;
|
||||||
const POSITION_DELAY = 200; // Wait 200ms between sending position events
|
const POSITION_DELAY = 200; // Wait 200ms between sending position events
|
||||||
|
@ -19,5 +20,6 @@ export {
|
||||||
TURN_SERVER,
|
TURN_SERVER,
|
||||||
TURN_USER,
|
TURN_USER,
|
||||||
TURN_PASSWORD,
|
TURN_PASSWORD,
|
||||||
JITSI_URL
|
JITSI_URL,
|
||||||
|
JITSI_PRIVATE_MODE
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {ITiledMap} from "../Map/ITiledMap";
|
import {ITiledMap} from "../Map/ITiledMap";
|
||||||
|
|
||||||
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined) => void;
|
export type PropertyChangeCallback = (newValue: string | number | boolean | undefined, oldValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a ITiledMap interface to provide additional capabilities.
|
* A wrapper around a ITiledMap interface to provide additional capabilities.
|
||||||
|
@ -35,14 +35,14 @@ export class GameMap {
|
||||||
for (const [newPropName, newPropValue] of newProps.entries()) {
|
for (const [newPropName, newPropValue] of newProps.entries()) {
|
||||||
const oldPropValue = oldProps.get(newPropName);
|
const oldPropValue = oldProps.get(newPropName);
|
||||||
if (oldPropValue !== newPropValue) {
|
if (oldPropValue !== newPropValue) {
|
||||||
this.trigger(newPropName, oldPropValue, newPropValue);
|
this.trigger(newPropName, oldPropValue, newPropValue, newProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [oldPropName, oldPropValue] of oldProps.entries()) {
|
for (const [oldPropName, oldPropValue] of oldProps.entries()) {
|
||||||
if (!newProps.has(oldPropName)) {
|
if (!newProps.has(oldPropName)) {
|
||||||
// We found a property that disappeared
|
// We found a property that disappeared
|
||||||
this.trigger(oldPropName, oldPropValue, undefined);
|
this.trigger(oldPropName, oldPropValue, undefined, newProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +74,11 @@ export class GameMap {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
private trigger(propName: string, oldValue: string | number | boolean | undefined, newValue: string | number | boolean | undefined) {
|
private trigger(propName: string, oldValue: string | number | boolean | undefined, newValue: string | number | boolean | undefined, allProps: Map<string, string | boolean | number>) {
|
||||||
const callbacksArray = this.callbacks.get(propName);
|
const callbacksArray = this.callbacks.get(propName);
|
||||||
if (callbacksArray !== undefined) {
|
if (callbacksArray !== undefined) {
|
||||||
for (const callback of callbacksArray) {
|
for (const callback of callbacksArray) {
|
||||||
callback(newValue, oldValue);
|
callback(newValue, oldValue, allProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,14 @@ import {
|
||||||
RoomJoinedMessageInterface
|
RoomJoinedMessageInterface
|
||||||
} from "../../Connexion/ConnexionModels";
|
} from "../../Connexion/ConnexionModels";
|
||||||
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
import {CurrentGamerInterface, hasMovedEventName, Player} from "../Player/Player";
|
||||||
import {DEBUG_MODE, JITSI_URL, POSITION_DELAY, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
import {
|
||||||
|
DEBUG_MODE,
|
||||||
|
JITSI_PRIVATE_MODE,
|
||||||
|
JITSI_URL,
|
||||||
|
POSITION_DELAY,
|
||||||
|
RESOLUTION,
|
||||||
|
ZOOM_LEVEL
|
||||||
|
} from "../../Enum/EnvironmentVariable";
|
||||||
import {
|
import {
|
||||||
ITiledMap,
|
ITiledMap,
|
||||||
ITiledMapLayer,
|
ITiledMapLayer,
|
||||||
|
@ -137,6 +144,8 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
private outlinedItem: ActionableItem|null = null;
|
private outlinedItem: ActionableItem|null = null;
|
||||||
private userInputManager!: UserInputManager;
|
private userInputManager!: UserInputManager;
|
||||||
|
|
||||||
|
private jitsiApi: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
static createFromUrl(room: Room, mapUrlFile: string, gameSceneKey: string|null = null): GameScene {
|
static createFromUrl(room: Room, mapUrlFile: string, gameSceneKey: string|null = null): GameScene {
|
||||||
// We use the map URL as a key
|
// We use the map URL as a key
|
||||||
if (gameSceneKey === null) {
|
if (gameSceneKey === null) {
|
||||||
|
@ -460,34 +469,18 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
CoWebsiteManager.loadCoWebsite(newValue as string);
|
CoWebsiteManager.loadCoWebsite(newValue as string);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let jitsiApi: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
|
||||||
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue) => {
|
|
||||||
if (newValue === undefined) {
|
if (newValue === undefined) {
|
||||||
this.connection.setSilent(false);
|
this.stopJitsi();
|
||||||
jitsiApi?.dispose();
|
|
||||||
CoWebsiteManager.closeCoWebsite();
|
|
||||||
mediaManager.showGameOverlay();
|
|
||||||
} else {
|
} else {
|
||||||
CoWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
console.log("JITSI_PRIVATE_MODE", JITSI_PRIVATE_MODE);
|
||||||
const domain = JITSI_URL;
|
if (JITSI_PRIVATE_MODE) {
|
||||||
const options = {
|
const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined;
|
||||||
roomName: this.instance + "-" + newValue,
|
|
||||||
width: "100%",
|
this.connection.emitQueryJitsiJwtMessage(this.instance + "-" + newValue, adminTag);
|
||||||
height: "100%",
|
} else {
|
||||||
parentNode: cowebsiteDiv,
|
this.startJitsi(newValue as string);
|
||||||
configOverwrite: {
|
|
||||||
prejoinPageEnabled: false
|
|
||||||
},
|
|
||||||
interfaceConfigOverwrite: {
|
|
||||||
SHOW_CHROME_EXTENSION_BANNER: false,
|
|
||||||
MOBILE_APP_PROMO: false
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
jitsiApi = new (window as any).JitsiMeetExternalAPI(domain, options); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
||||||
jitsiApi.executeCommand('displayName', gameManager.getPlayerName());
|
|
||||||
}));
|
|
||||||
this.connection.setSilent(true);
|
|
||||||
mediaManager.hideGameOverlay();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -597,6 +590,13 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
item.fire(message.event, message.state, message.parameters);
|
item.fire(message.event, message.state, message.parameters);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered when we receive the JWT token to connect to Jitsi
|
||||||
|
*/
|
||||||
|
connection.onStartJitsiRoom((jwt, room) => {
|
||||||
|
this.startJitsi(room, jwt);
|
||||||
|
});
|
||||||
|
|
||||||
// When connection is performed, let's connect SimplePeer
|
// When connection is performed, let's connect SimplePeer
|
||||||
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
|
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic);
|
||||||
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
|
||||||
|
@ -1191,4 +1191,55 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||||
public onCenterChange(): void {
|
public onCenterChange(): void {
|
||||||
this.updateCameraOffset();
|
this.updateCameraOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public startJitsi(roomName: string, jwt?: string): void {
|
||||||
|
CoWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
||||||
|
const domain = JITSI_URL;
|
||||||
|
const options = {
|
||||||
|
roomName: roomName,
|
||||||
|
jwt: jwt,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
parentNode: cowebsiteDiv,
|
||||||
|
configOverwrite: {
|
||||||
|
prejoinPageEnabled: false
|
||||||
|
},
|
||||||
|
interfaceConfigOverwrite: {
|
||||||
|
SHOW_CHROME_EXTENSION_BANNER: false,
|
||||||
|
MOBILE_APP_PROMO: false,
|
||||||
|
|
||||||
|
HIDE_INVITE_MORE_HEADER: true,
|
||||||
|
|
||||||
|
// Note: hiding brand does not seem to work, we probably need to put this on the server side.
|
||||||
|
SHOW_BRAND_WATERMARK: false,
|
||||||
|
SHOW_JITSI_WATERMARK: false,
|
||||||
|
SHOW_POWERED_BY: false,
|
||||||
|
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
||||||
|
SHOW_WATERMARK_FOR_GUESTS: false,
|
||||||
|
|
||||||
|
TOOLBAR_BUTTONS: [
|
||||||
|
'microphone', 'camera', 'closedcaptions', 'desktop', /*'embedmeeting',*/ 'fullscreen',
|
||||||
|
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
||||||
|
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
||||||
|
'videoquality', 'filmstrip', /*'invite',*/ 'feedback', 'stats', 'shortcuts',
|
||||||
|
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', /*'security'*/
|
||||||
|
],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!options.jwt) {
|
||||||
|
delete options.jwt;
|
||||||
|
}
|
||||||
|
this.jitsiApi = new (window as any).JitsiMeetExternalAPI(domain, options); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||||
|
this.jitsiApi.executeCommand('displayName', gameManager.getPlayerName());
|
||||||
|
}));
|
||||||
|
this.connection.setSilent(true);
|
||||||
|
mediaManager.hideGameOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public stopJitsi(): void {
|
||||||
|
this.connection.setSilent(false);
|
||||||
|
this.jitsiApi?.dispose();
|
||||||
|
CoWebsiteManager.closeCoWebsite();
|
||||||
|
mediaManager.showGameOverlay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ module.exports = {
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
Phaser: 'phaser'
|
Phaser: 'phaser'
|
||||||
}),
|
}),
|
||||||
new webpack.EnvironmentPlugin(['API_URL', 'DEBUG_MODE', 'TURN_SERVER', 'TURN_USER', 'TURN_PASSWORD', 'JITSI_URL'])
|
new webpack.EnvironmentPlugin(['API_URL', 'DEBUG_MODE', 'TURN_SERVER', 'TURN_USER', 'TURN_PASSWORD', 'JITSI_URL', 'JITSI_PRIVATE_MODE'])
|
||||||
],
|
],
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,6 +53,11 @@ message ReportPlayerMessage {
|
||||||
string reportComment = 2;
|
string reportComment = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message QueryJitsiJwtMessage {
|
||||||
|
string jitsiRoom = 1;
|
||||||
|
string tag = 2; // FIXME: rather than reading the tag from the query, we should read it from the current map!
|
||||||
|
}
|
||||||
|
|
||||||
message ClientToServerMessage {
|
message ClientToServerMessage {
|
||||||
oneof message {
|
oneof message {
|
||||||
UserMovesMessage userMovesMessage = 2;
|
UserMovesMessage userMovesMessage = 2;
|
||||||
|
@ -65,6 +70,7 @@ message ClientToServerMessage {
|
||||||
PlayGlobalMessage playGlobalMessage = 9;
|
PlayGlobalMessage playGlobalMessage = 9;
|
||||||
StopGlobalMessage stopGlobalMessage = 10;
|
StopGlobalMessage stopGlobalMessage = 10;
|
||||||
ReportPlayerMessage reportPlayerMessage = 11;
|
ReportPlayerMessage reportPlayerMessage = 11;
|
||||||
|
QueryJitsiJwtMessage queryJitsiJwtMessage = 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +173,11 @@ message TeleportMessageMessage{
|
||||||
string map = 1;
|
string map = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SendJitsiJwtMessage {
|
||||||
|
string jitsiRoom = 1;
|
||||||
|
string jwt = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ServerToClientMessage {
|
message ServerToClientMessage {
|
||||||
oneof message {
|
oneof message {
|
||||||
BatchMessage batchMessage = 1;
|
BatchMessage batchMessage = 1;
|
||||||
|
@ -179,5 +190,6 @@ message ServerToClientMessage {
|
||||||
PlayGlobalMessage playGlobalMessage = 8;
|
PlayGlobalMessage playGlobalMessage = 8;
|
||||||
StopGlobalMessage stopGlobalMessage = 9;
|
StopGlobalMessage stopGlobalMessage = 9;
|
||||||
TeleportMessageMessage teleportMessageMessage = 10;
|
TeleportMessageMessage teleportMessageMessage = 10;
|
||||||
|
SendJitsiJwtMessage sendJitsiJwtMessage = 11;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue