diff options
| author | stonedDiscord <Tukz@gmx.de> | 2023-11-22 19:27:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-22 19:27:10 +0100 |
| commit | 26e3cd4bfe08a78e65935cf494c24193f59c8a7e (patch) | |
| tree | d5bc00fd748bceedb8693003916beed1f242ee3e /webAO | |
| parent | 6480caf604d06778109cb58e5983d883725838a9 (diff) | |
| parent | f848f34b9979740e85b9648eb42ecafd20dd3926 (diff) | |
Merge pull request #201 from Troid-Tech/connect-to-wss
Fix https and add wss support
Diffstat (limited to 'webAO')
| -rw-r--r-- | webAO/client.ts | 29 | ||||
| -rw-r--r-- | webAO/client/aoHost.ts | 9 | ||||
| -rw-r--r-- | webAO/master.ts | 156 | ||||
| -rw-r--r-- | webAO/utils/queryParser.ts | 7 |
4 files changed, 95 insertions, 106 deletions
diff --git a/webAO/client.ts b/webAO/client.ts index 3170ec8..c49a104 100644 --- a/webAO/client.ts +++ b/webAO/client.ts @@ -17,7 +17,7 @@ import { loadResources } from './client/loadResources' import { AO_HOST } from './client/aoHost' import { fetchBackgroundList, fetchEvidenceList, fetchCharacterList } from './client/fetchLists' -const { ip: serverIP, mode, theme, serverName } = queryParser(); +const { ip: serverIP, connect, mode, theme, serverName } = queryParser(); document.title = serverName; @@ -70,12 +70,27 @@ fpPromise .then((result) => { hdid = result.visitorId; - if (!serverIP) { - alert("No server IP specified!"); - return; + let connectionString = connect; + + if (!connectionString) { + if (serverIP) { + // if connectionString is not set, try IP + // and just guess ws, though it could be wss + connectionString = `ws://${serverIP}`; + } else { + alert("No connection string specified!"); + return; + } + } + + if (window.location.protocol === "https:" && connectionString.startsWith("ws://")) { + // If protocol is https: and connectionString is ws:// + // We have a problem, since it's impossible to connect to ws:// from https:// + // Connection will fail, but at least warn the user + alert('Attempted to connect using insecure websockets on https page. Please try removing s from https:// in the URL bar.') } - client = new Client(serverIP); + client = new Client(connectionString); client.connect() isLowMemory(); loadResources(); @@ -117,7 +132,7 @@ class Client extends EventEmitter { connect: () => void; loadResources: () => void isLowMemory: () => void - constructor(address: string) { + constructor(connectionString: string) { super(); this.connect = () => { @@ -126,7 +141,7 @@ class Client extends EventEmitter { this.on("message", this.onMessage.bind(this)); this.on("error", this.onError.bind(this)); if (mode !== "replay") { - this.serv = new WebSocket(`ws://${address}`); + this.serv = new WebSocket(connectionString); // Assign the websocket events this.serv.addEventListener("open", this.emit.bind(this, "open")); this.serv.addEventListener("close", this.emit.bind(this, "close")); diff --git a/webAO/client/aoHost.ts b/webAO/client/aoHost.ts index 6cad62a..33e010d 100644 --- a/webAO/client/aoHost.ts +++ b/webAO/client/aoHost.ts @@ -3,5 +3,14 @@ import queryParser from '../utils/queryParser' const { asset } = queryParser(); export let AO_HOST = asset; export const setAOhost = (val: string) => { + const currentProtocol = window.location.protocol; + const assetProtocol = val.split(':')[0] + ':'; + + if (currentProtocol === 'https:' && assetProtocol === 'http:') { + // In this specific case, we need to request assets over HTTPS + console.log('Upgrading asset link to https'); + val = val.replace('http:', 'https:'); + } + AO_HOST = val; } diff --git a/webAO/master.ts b/webAO/master.ts index 336fc5f..295d326 100644 --- a/webAO/master.ts +++ b/webAO/master.ts @@ -1,5 +1,3 @@ -import FingerprintJS from '@fingerprintjs/fingerprintjs'; - import { safeTags } from './encoding'; declare global { @@ -28,10 +26,6 @@ const protocol = window.location.protocol; const serverlist_cache_key = 'masterlist'; -let hdid: string; - -let selectedServer: number = -1; - const servers: AOServer[] = []; servers[-2] = { name: 'Singleplayer', @@ -52,96 +46,29 @@ servers[-1] = { players: 0, }; -const fpPromise = FingerprintJS.load(); -fpPromise - .then((fp) => fp.get()) - .then(async (result) => { - hdid = result.visitorId; - - check_https(); - - getServerlist().then((serverlist) => { - processServerlist(serverlist); - }); - processClientVersion(clientVersion); +function main() { + getServerlist().then((serverlist) => { + processServerlist(serverlist); + }); - getMasterVersion().then((masterVersion) => { - processMasterVersion(masterVersion); - }); + processClientVersion(clientVersion); - // i don't need the ms to play alone - setTimeout(() => checkOnline(-1, '127.0.0.1:50001'), 0); + getMasterVersion().then((masterVersion) => { + processMasterVersion(masterVersion); }); - -export function check_https() { - if (protocol === 'https:') { - document.getElementById('https_error').style.display = ''; - setTimeout(() => window.location.replace("http://web.aceattorneyonline.com/"), 5000); - } } -export function setServ(ID: number) { - selectedServer = ID; +main(); - if (document.getElementById(`server${ID}`).className === '') { checkOnline(ID, `${servers[ID].ip}:${servers[ID].ws_port}`); } - - document.getElementById('serverdescription_content').innerHTML = `<b>${servers[ID].online}</b><br>${safeTags(servers[ID].description)}`; +export function setServ(ID: number) { + const server = servers[ID]; + const onlineStr = server.online; + const serverDesc = safeTags(server.description); + document.getElementById('serverdescription_content').innerHTML = `<b>${onlineStr}</b><br>${serverDesc}`; } window.setServ = setServ; -function checkOnline(serverID: number, coIP: string) { - let serverConnection: WebSocket; - if (serverID !== -2) { - try { - serverConnection = new WebSocket(`ws://${coIP}`); - } catch (SecurityError) { - document.getElementById(`server${serverID}`).className = 'unavailable'; - return; - } - } - - // define what the callbacks do - function onCOOpen() { - document.getElementById(`server${serverID}`).className = 'available'; - serverConnection.send(`HI#${hdid}#%`); - serverConnection.send('ID#webAO#webAO#%'); - } - - function onCOMessage(e: MessageEvent) { - const comsg = e.data; - const coheader = comsg.split('#', 2)[0]; - const coarguments = comsg.split('#').slice(1); - if (coheader === 'PN') { - servers[serverID].online = `Online: ${Number(coarguments[0])}/${Number(coarguments[1])}`; - serverConnection.close(); - return; - } if (coheader === 'BD') { - servers[serverID].online = 'Banned'; - servers[serverID].description = coarguments[0]; - serverConnection.close(); - return; - } - if (serverID === selectedServer) { - document.getElementById('serverdescription_content').innerHTML = `<b>${servers[serverID].online}</b><br>${safeTags(servers[serverID].description)}`; - } - } - - // assign the callbacks - serverConnection.onopen = function () { - onCOOpen(); - }; - - serverConnection.onmessage = function (evt: MessageEvent) { - onCOMessage(evt); - }; - - serverConnection.onerror = function (_evt: Event) { - document.getElementById(`server${serverID}`).className = 'unavailable'; - console.error(`Error connecting to ${coIP}`); - console.error(_evt); - }; -} // Fetches the serverlist from the masterserver // Returns a properly typed list of servers @@ -209,32 +136,67 @@ function getCachedServerlist(): AOServer[] { return JSON.parse(cached) as AOServer[]; } +// Constructs the client URL robustly, independent of domain and path +function constructClientURL(protocol: string): string { + const clientURL = new URL(window.location.href); + + // Use the given protocol + clientURL.protocol = protocol; + + // Remove the last part of the pathname (e.g., "index.html") + const pathname = clientURL.pathname; + const parts = pathname.split('/'); + parts.pop(); + + // Reconstruct the pathname + clientURL.pathname = parts.join('/'); + + // If clientURL.pathname does not end with a slash, add one + if (clientURL.pathname[clientURL.pathname.length - 1] !== '/') { + clientURL.pathname += '/' + } + + clientURL.pathname += "client.html"; + + return clientURL.href; +} + function processServerlist(serverlist: AOServer[]) { - const host = window.location.host; - const clientURL: string = `${protocol}//${host}/client.html`; - for (let i = 0; i < serverlist.length - 1; i++) { + for (let i = 0; i < serverlist.length; i++) { const server = serverlist[i]; - let port = 0; + let ws_port = 0; + let ws_protocol = ''; + let http_protocol = ''; if (server.ws_port) { - port = server.ws_port; + ws_port = server.ws_port; + ws_protocol = 'ws'; + http_protocol = 'http'; } if (server.wss_port) { - port = server.wss_port; + ws_port = server.wss_port; + ws_protocol = 'wss'; + http_protocol = 'https'; } - if (port === 0) { + + if (ws_port === 0 || ws_protocol === '' || http_protocol === '') { + console.warn(`Server ${server.name} has no websocket port, skipping`) continue; } - const ipport = `${server.ip}:${port}`; + const clientURL = constructClientURL(http_protocol); + const connect = `${ws_protocol}://${server.ip}:${ws_port}`; const serverName = server.name; - server.online = 'Offline'; + const fullClientWatchURL = `${clientURL}?mode=watch&connect=${connect}&serverName=${serverName}`; + const fullClientJoinURL = `${clientURL}?mode=join&connect=${connect}&serverName=${serverName}`; + + server.online = `Players: ${server.players}`; servers.push(server); document.getElementById('masterlist').innerHTML += `<li id="server${i}" onmouseover="setServ(${i})"><p>${safeTags(server.name)} (${server.players})</p>` - + `<a class="button" href="${clientURL}?mode=watch&ip=${ipport}&serverName=${serverName}">Watch</a>` - + `<a class="button" href="${clientURL}?mode=join&ip=${ipport}&serverName=${serverName}">Join</a></li>`; + + `<a class="button" href="${fullClientWatchURL}" target="_blank">Watch</a>` + + `<a class="button" href="${fullClientJoinURL}" target="_blank">Join</a></li>`; } } diff --git a/webAO/utils/queryParser.ts b/webAO/utils/queryParser.ts index f934ac6..1a3cea6 100644 --- a/webAO/utils/queryParser.ts +++ b/webAO/utils/queryParser.ts @@ -2,6 +2,7 @@ interface QueryParams { ip: string; + connect: string; mode: string; asset: string; theme: string; @@ -9,13 +10,15 @@ interface QueryParams { } const queryParser = (): QueryParams => { + const protocol = window.location.protocol; const urlParams = new URLSearchParams(window.location.search); const queryParams = { ip: urlParams.get("ip") || "", + connect: urlParams.get("connect") || "", mode: urlParams.get("mode") || "join", - asset: urlParams.get("asset") || "http://attorneyoffline.de/base/", + asset: urlParams.get("asset") || `${protocol}//attorneyoffline.de/base/`, theme: urlParams.get("theme") || "default", - serverName: urlParams.get("serverName") || "Attorney Online session" + serverName: urlParams.get("serverName") || "Attorney Online session", } return queryParams as QueryParams; }; |
