Added frontend code for authentication

This commit is contained in:
Pax1601
2023-05-09 15:41:04 +02:00
parent 865be6283c
commit 57b74bd1b1
12 changed files with 286 additions and 153 deletions

View File

@@ -90,7 +90,7 @@ export class FeatureSwitches {
}),
new FeatureSwitch({
"defaultEnabled": false,
"defaultEnabled": true,
"label": "Show splash screen",
"masterSwitch": true,
"name": "splashScreen"
@@ -116,36 +116,24 @@ export class FeatureSwitches {
#testSwitches() {
for ( const featureSwitch of this.#featureSwitches ) {
if ( featureSwitch.isEnabled() ) {
if ( typeof featureSwitch.onEnabled === "function" ) {
featureSwitch.onEnabled();
}
} else {
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => {
if ( featureSwitch.removeArtifactsIfDisabled === false ) {
el.remove();
} else {
el.classList.add( "hide" );
}
});
}
document.body.classList.toggle( "feature-" + featureSwitch.name, featureSwitch.isEnabled() );
}
}
savePreferences() {
let preferences:any = {};

View File

@@ -9,7 +9,7 @@ import { AIC } from "./aic/aic";
import { ATC } from "./atc/atc";
import { FeatureSwitches } from "./featureswitches";
import { LogPanel } from "./panels/logpanel";
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
import { getAirbases, getBullseye, getConfig, getFreezed, getMission, getUnits, setAddress, setCredentials, setFreezed, startUpdate, toggleDemoEnabled } from "./server/server";
import { UnitDataTable } from "./units/unitdatatable";
import { keyEventWasInInput } from "./other/utils";
import { Popup } from "./popups/popup";
@@ -31,11 +31,8 @@ var logPanel: LogPanel;
var infoPopup: Popup;
var connected: boolean = false;
var paused: boolean = false;
var activeCoalition: string = "blue";
var sessionHash: string | null = null;
var unitDataTable: UnitDataTable;
var featureSwitches;
@@ -49,15 +46,18 @@ function setup() {
missionHandler = new MissionHandler();
/* Panels */
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
unitControlPanel = new UnitControlPanel("unit-control-panel");
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
unitControlPanel = new UnitControlPanel("unit-control-panel");
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
//logPanel = new LogPanel("log-panel");
/* Popups */
infoPopup = new Popup("info-popup");
/* Controls */
new Dropdown("app-icon", () => { });
/* Unit data table */
unitDataTable = new UnitDataTable("unit-data-table");
@@ -65,7 +65,6 @@ function setup() {
let aicFeatureSwitch = featureSwitches.getSwitch("aic");
if (aicFeatureSwitch?.isEnabled()) {
aic = new AIC();
// TODO: add back buttons
}
/* ATC */
@@ -75,82 +74,23 @@ function setup() {
atc.startUpdates();
}
new Dropdown( "app-icon", () => {} );
/* Setup event handlers */
setupEvents();
getConfig(readConfig)
/* Load the config file */
getConfig(readConfig);
}
function readConfig(config: any)
{
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined)
{
function readConfig(config: any) {
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined) {
const address = config["server"]["address"];
const port = config["server"]["port"];
if (typeof address === 'string' && typeof port == 'number')
setAddress(address == "*"? window.location.hostname: address, <number>port);
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
/* Start periodically requesting updates */
startPeriodicUpdate();
setAddress(address == "*" ? window.location.hostname : address, <number>port);
}
else {
throw new Error('Could not read configuration file!');
}
}
function startPeriodicUpdate() {
requestUpdate();
requestRefresh();
}
function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
getUnits((data: UnitsData) => {
if (!getPaused()){
getUnitsManager()?.update(data);
checkSessionHash(data.sessionHash);
}
}, false);
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
getConnectionStatusPanel()?.update(getConnected());
}
function requestRefresh() {
/* Main refresh rate = 5000ms. */
getUnits((data: UnitsData) => {
if (!getPaused()){
getUnitsManager()?.update(data);
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {
getMissionData()?.update(data)
});
// Update the list of existing units
getUnitDataTable()?.update();
checkSessionHash(data.sessionHash);
}
}, true);
window.setTimeout(() => requestRefresh(), 5000);
}
function checkSessionHash(newSessionHash: string) {
if (sessionHash != null) {
if (newSessionHash != sessionHash)
location.reload();
}
else
sessionHash = newSessionHash;
}
function setupEvents() {
@@ -164,7 +104,7 @@ function setupEvents() {
}
const triggerElement = target.closest("[data-on-click]");
if (triggerElement instanceof HTMLElement) {
const eventName: string = triggerElement.dataset.onClick || "";
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
@@ -181,7 +121,7 @@ function setupEvents() {
/* Keyup events */
document.addEventListener("keyup", ev => {
if ( keyEventWasInInput( ev ) ) {
if (keyEventWasInInput(ev)) {
return;
}
switch (ev.code) {
@@ -195,13 +135,13 @@ function setupEvents() {
unitDataTable.toggle();
break
case "Space":
setPaused(!getPaused());
setFreezed(!getFreezed());
break;
case "KeyW":
case "KeyA":
case "KeyS":
case "KeyD":
case "ArrowLeft":
case "ArrowLeft":
case "ArrowRight":
case "ArrowUp":
case "ArrowDown":
@@ -212,7 +152,7 @@ function setupEvents() {
/* Keydown events */
document.addEventListener("keydown", ev => {
if ( keyEventWasInInput( ev ) ) {
if (keyEventWasInInput(ev)) {
return;
}
switch (ev.code) {
@@ -220,7 +160,7 @@ function setupEvents() {
case "KeyA":
case "KeyS":
case "KeyD":
case "ArrowLeft":
case "ArrowLeft":
case "ArrowRight":
case "ArrowUp":
case "ArrowDown":
@@ -229,15 +169,31 @@ function setupEvents() {
}
});
document.addEventListener( "closeDialog", (ev: CustomEventInit) => {
ev.detail._element.closest( ".ol-dialog" ).classList.add( "hide" );
document.addEventListener("closeDialog", (ev: CustomEventInit) => {
ev.detail._element.closest(".ol-dialog").classList.add("hide");
});
document.addEventListener( "toggleElements", (ev: CustomEventInit) => {
document.querySelectorAll( ev.detail.selector ).forEach( el => {
el.classList.toggle( "hide" );
document.addEventListener("toggleElements", (ev: CustomEventInit) => {
document.querySelectorAll(ev.detail.selector).forEach(el => {
el.classList.toggle("hide");
})
});
document.addEventListener("tryConnection", () => {
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form");
const username = (<HTMLInputElement> (form?.querySelector("#username"))).value;
const password = (<HTMLInputElement> (form?.querySelector("#password"))).value;
setCredentials(username, btoa("admin" + ":" + password));
/* Start periodically requesting updates */
startUpdate();
setConnectionStatus("connecting");
})
document.addEventListener("reloadPage", () => {
location.reload();
})
}
export function getMap() {
@@ -285,23 +241,10 @@ export function getActiveCoalition() {
return activeCoalition;
}
export function setConnected(newConnected: boolean) {
if (connected != newConnected)
newConnected? getInfoPopup().setText("Connected to DCS Olympus server"): getInfoPopup().setText("Disconnected from DCS Olympus server");
connected = newConnected;
}
export function getConnected() {
return connected;
}
export function setPaused(newPaused: boolean) {
paused = newPaused;
paused? getInfoPopup().setText("Paused"): getInfoPopup().setText("Unpaused");
}
export function getPaused() {
return paused;
export function setConnectionStatus(status: string) {
const el = document.querySelector("#connection-status") as HTMLElement;
if (el)
el.dataset["status"] = status;
}
export function getInfoPopup() {

View File

@@ -316,7 +316,7 @@ export class Map extends L.Map {
}
this.setView(bounds.getCenter(), 8);
this.setMaxBounds(bounds);
//this.setMaxBounds(bounds);
if (this.#miniMap)
this.#miniMap.remove();

View File

@@ -1,7 +1,10 @@
import * as L from 'leaflet'
import { setConnected } from '..';
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getUnitDataTable, getUnitsManager, setConnectionStatus } from '..';
import { SpawnOptions } from '../controls/mapcontextmenu';
var connected: boolean = false;
var freezed: boolean = false;
var REST_ADDRESS = "http://localhost:30000/olympus";
var DEMO_ADDRESS = window.location.href + "demo";
const UNITS_URI = "units";
@@ -10,29 +13,46 @@ const AIRBASES_URI = "airbases";
const BULLSEYE_URI = "bullseyes";
const MISSION_URI = "mission";
var username = "";
var credentials = "";
var sessionHash: string | null = null;
var lastUpdateTime = 0;
var demoEnabled = false;
export function toggleDemoEnabled()
{
export function toggleDemoEnabled() {
demoEnabled = !demoEnabled;
}
export function GET(callback: CallableFunction, uri: string, options?: string){
export function setCredentials(newUsername: string, newCredentials: string) {
username = newUsername;
credentials = newCredentials;
}
export function GET(callback: CallableFunction, uri: string, options?: string) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}${options? options: ''}`, true);
if (credentials)
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
{
callback(data);
lastUpdateTime = parseInt(data.time);
if (isNaN(lastUpdateTime))
lastUpdateTime = 0;
setConnected(true);
if (xmlHttp.status == 200) {
var data = JSON.parse(xmlHttp.responseText);
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
{
callback(data);
lastUpdateTime = parseInt(data.time);
if (isNaN(lastUpdateTime))
lastUpdateTime = 0;
setConnected(true);
}
} else if (xmlHttp.status == 401) {
console.error("Incorrect username/password");
setConnectionStatus("failed");
} else {
setConnected(false);
}
};
xmlHttp.onerror = function () {
xmlHttp.onerror = function (res) {
console.error("An error occurred during the XMLHttpRequest");
setConnected(false);
};
@@ -40,13 +60,15 @@ export function GET(callback: CallableFunction, uri: string, options?: string){
}
export function POST(request: object, callback: CallableFunction){
var xhr = new XMLHttpRequest();
xhr.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = () => {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
xmlHttp.setRequestHeader("Content-Type", "application/json");
if (credentials)
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
xmlHttp.onreadystatechange = () => {
callback();
};
xhr.send(JSON.stringify(request));
xmlHttp.send(JSON.stringify(request));
}
export function getConfig(callback: CallableFunction) {
@@ -208,4 +230,81 @@ export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolea
var data = { "setAdvancedOptions": command };
POST(data, () => { });
}
export function startUpdate() {
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => { getMissionData()?.update(data) });
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
requestUpdate();
requestRefresh();
}
export function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
getUnits((data: UnitsData) => {
if (!getFreezed()) {
getUnitsManager()?.update(data);
checkSessionHash(data.sessionHash);
}
}, false);
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
getConnectionStatusPanel()?.update(getConnected());
}
export function requestRefresh() {
/* Main refresh rate = 5000ms. */
getUnits((data: UnitsData) => {
if (!getFreezed()) {
getUnitsManager()?.update(data);
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {
getMissionData()?.update(data)
});
// Update the list of existing units
getUnitDataTable()?.update();
checkSessionHash(data.sessionHash);
}
}, true);
window.setTimeout(() => requestRefresh(), 5000);
}
export function checkSessionHash(newSessionHash: string) {
if (sessionHash != null) {
if (newSessionHash != sessionHash)
location.reload();
}
else
sessionHash = newSessionHash;
}
export function setConnected(newConnected: boolean) {
if (connected != newConnected)
newConnected ? getInfoPopup().setText("Connected to DCS Olympus server") : getInfoPopup().setText("Disconnected from DCS Olympus server");
connected = newConnected;
if (connected) {
document.querySelector("#splash-screen")?.classList.add("hide");
document.querySelector("#gray-out")?.classList.add("hide");
}
}
export function getConnected() {
return connected;
}
export function setFreezed(newFreezed: boolean) {
freezed = newFreezed;
freezed ? getInfoPopup().setText("Freezed") : getInfoPopup().setText("Unfreezed");
}
export function getFreezed() {
return freezed;
}