From 37ca5e22f6a8bb3198fba99f5d8f34e5da589394 Mon Sep 17 00:00:00 2001 From: creeper123123321 <7974274+creeper123123321@users.noreply.github.com> Date: Fri, 6 Aug 2021 22:53:55 -0300 Subject: [PATCH] temp Revert "cleanup, js classes" This reverts commit 8c6c423ec70a15e404c160a9ee30060912aa082d. --- src/main/resources/web/index.html | 9 +- src/main/resources/web/js/account_manager.js | 422 ++++++------------- src/main/resources/web/js/auth_ms.js | 65 +++ src/main/resources/web/js/cors_proxy.js | 8 +- src/main/resources/web/js/minecraft_id.js | 19 + src/main/resources/web/js/notification.js | 21 +- src/main/resources/web/js/page.js | 177 +++----- src/main/resources/web/js/util.js | 14 +- src/main/resources/web/js/websocket.js | 71 ++-- src/main/resources/web/js/worker.js | 50 +-- 10 files changed, 363 insertions(+), 493 deletions(-) create mode 100644 src/main/resources/web/js/auth_ms.js create mode 100644 src/main/resources/web/js/minecraft_id.js diff --git a/src/main/resources/web/index.html b/src/main/resources/web/index.html index 45e2dd0..37d9554 100644 --- a/src/main/resources/web/index.html +++ b/src/main/resources/web/index.html @@ -169,6 +169,13 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*. - + + + + + + + + diff --git a/src/main/resources/web/js/account_manager.js b/src/main/resources/web/js/account_manager.js index 1b8ed39..1e7a524 100644 --- a/src/main/resources/web/js/account_manager.js +++ b/src/main/resources/web/js/account_manager.js @@ -1,226 +1,35 @@ -import {getCorsProxy} from "./cors_proxy.js"; -import {checkFetchSuccess, filterNot, isSuccess} from "./util.js"; -import {addToast, refreshAccountList} from "./page.js"; - -let activeAccounts = []; - -function loadAccounts() { - (JSON.parse(localStorage.getItem("viaaas_mc_accounts")) || []).forEach(it => { - if (it.clientToken) { - addActiveAccount(new MojangAccount(it.id, it.name, it.accessToken, it.clientToken)) - } else if (it.msUser) { - addActiveAccount(new MicrosoftAccount(it.id, it.name, it.accessToken, it.msUser)) - } - }) +// Account storage +function storeMcAccount(accessToken, clientToken, name, id, msUser = null) { + let accounts = JSON.parse(localStorage.getItem("viaaas_mc_accounts")) || []; + let account = {accessToken: accessToken, clientToken: clientToken, name: name, id: id, msUser: msUser}; + accounts.push(account); + localStorage.setItem("viaaas_mc_accounts", JSON.stringify(accounts)); + refreshAccountList(); + return account; } -$(() => loadAccounts()); - -function saveRefreshAccounts() { - localStorage.setItem("viaaas_mc_accounts", JSON.stringify(getActiveAccounts())) - refreshAccountList() +function removeMcAccount(id) { + let accounts = getMcAccounts(); + accounts = accounts.filter(it => it.id != id); + localStorage.setItem("viaaas_mc_accounts", JSON.stringify(accounts)); + refreshAccountList(); } -export function getActiveAccounts() { - return activeAccounts; +function getMcAccounts() { + return JSON.parse(localStorage.getItem("viaaas_mc_accounts")) || []; } -export function getMicrosoftUsers() { - return (myMSALObj.getAllAccounts() || []).map(it => it.username); +function findAccountByMcName(name) { + return getMcAccounts().reverse().find(it => it.name.toLowerCase() == name.toLowerCase()); + +} +function findAccountByMs(username) { + return getMcAccounts().filter(isNotMojang).find(it => it.msUser == username); } -export class McAccount { - id; - name; - accessToken; - loggedOut = false; - - constructor(id, username, accessToken) { - this.id = id; - this.name = username; - this.accessToken = accessToken; - } - - logout() { - activeAccounts = filterNot(activeAccounts, this); - saveRefreshAccounts(); - this.loggedOut = true; - } - - checkActive() { - return fetch(getCorsProxy() + "https://authserver.mojang.com/validate", { - method: "post", - body: JSON.stringify({accessToken: this.accessToken}), - headers: {"content-type": "application/json"} - }).then(data => isSuccess(data.status)); - } - - joinGame(hash) { - return this.acquireActiveToken() - .then(() => fetch(getCorsProxy() + "https://sessionserver.mojang.com/session/minecraft/join", { - method: "post", - body: JSON.stringify({ - accessToken: this.accessToken, - selectedProfile: this.id, - serverId: hash - }), - headers: {"content-type": "application/json"} - })).then(checkFetchSuccess("Failed to join session")); - } - - refresh() { - } - - acquireActiveToken() { - return this.checkActive().then(success => { - if (!success) { - return this.refresh(); - } - return this; - }).catch(e => addToast("Failed to refresh token!", e)); - } -} - -export class MojangAccount extends McAccount { - clientToken; - - constructor(id, username, accessToken, clientToken) { - super(id, username, accessToken); - this.clientToken = clientToken; - } - - logout() { - super.logout(); - fetch(getCorsProxy() + "https://authserver.mojang.com/invalidate", { - method: "post", - body: JSON.stringify({ - accessToken: this.accessToken, - clientToken: this.clientToken - }), - headers: {"content-type": "application/json"} - }).then(checkFetchSuccess("not success logout")); - } - - checkActive() { - return fetch(getCorsProxy() + "https://authserver.mojang.com/validate", { - method: "post", - body: JSON.stringify({ - accessToken: this.accessToken, - clientToken: this.clientToken - }), - headers: {"content-type": "application/json"} - }).then(data => isSuccess(data.status)); - } - - refresh() { - super.refresh(); - - console.log("refreshing " + this.id); - return fetch(getCorsProxy() + "https://authserver.mojang.com/refresh", { - method: "post", - body: JSON.stringify({ - accessToken: this.accessToken, - clientToken: this.clientToken - }), - headers: {"content-type": "application/json"}, - }) - .then(checkFetchSuccess("code")) - .then(r => r.json()) - .then(json => { - console.log("refreshed " + json.selectedProfile.id); - this.accessToken = json.accessToken; - this.clientToken = json.clientToken; - this.name = json.selectedProfile.name; - this.id = json.id; - saveRefreshAccounts(); - }); - } -} - -export class MicrosoftAccount extends McAccount { - msUser; - - constructor(id, username, accessToken, msUser) { - super(id, username, accessToken); - this.msUser = msUser; - } - - logout() { - super.logout(); - - let msAccount = myMSALObj.getAccountByUsername(this.msUser); - if (!msAccount) return; - - const logoutRequest = {account: msAccount}; - myMSALObj.logout(logoutRequest); - } - - refresh() { - super.refresh(); - return getTokenPopup(this.msUser, loginRequest) - .then(response => { - // this supports CORS - return fetch("https://user.auth.xboxlive.com/user/authenticate", { - method: "post", - body: JSON.stringify({ - Properties: { - AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", - RpsTicket: "d=" + response.accessToken - }, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT" - }), - headers: {"content-type": "application/json"} - }).then(checkFetchSuccess("xbox response not success")) - .then(r => r.json()); - }).then(json => { - return fetch("https://xsts.auth.xboxlive.com/xsts/authorize", { - method: "post", - body: JSON.stringify({ - Properties: {SandboxId: "RETAIL", UserTokens: [json.Token]}, - RelyingParty: "rp://api.minecraftservices.com/", TokenType: "JWT" - }), - headers: {"content-type": "application/json"} - }).then(checkFetchSuccess("xsts response not success")) - .then(r => r.json()); - }).then(json => { - return fetch(getCorsProxy() + "https://api.minecraftservices.com/authentication/login_with_xbox", { - method: "post", - body: JSON.stringify({identityToken: "XBL3.0 x=" + json.DisplayClaims.xui[0].uhs + ";" + json.Token}), - headers: {"content-type": "application/json"} - }).then(checkFetchSuccess("mc response not success")) - .then(r => r.json()); - }).then(json => { - return fetch(getCorsProxy() + "https://api.minecraftservices.com/minecraft/profile", { - method: "get", - headers: {"content-type": "application/json", "authorization": "Bearer " + json.access_token} - }).then(profile => { - if (profile.status === 404) return {id: "MHF_Exclamation", name: "[DEMO]", access_token: ""}; - if (!isSuccess(profile.status)) throw "profile response not success"; - return profile.json(); - }).then(jsonProfile => { - this.accessToken = json.access_token; - this.name = jsonProfile.name; - this.id = jsonProfile.id; - saveRefreshAccounts(); - }); - }); - } -} - -export function findAccountByMcName(name) { - return activeAccounts.find(it => it.name.toLowerCase() === name.toLowerCase()); -} - -export function findAccountByMs(username) { - return getActiveAccounts().find(it => it.msUser === username); -} - -function addActiveAccount(acc) { - activeAccounts.push(acc) - saveRefreshAccounts() -} - -export function loginMc(user, pass) { - const clientToken = uuid.v4(); +// Mojang account +function loginMc(user, pass) { + var clientToken = uuid.v4(); fetch(getCorsProxy() + "https://authserver.mojang.com/authenticate", { method: "post", body: JSON.stringify({ @@ -231,74 +40,123 @@ export function loginMc(user, pass) { }), headers: {"content-type": "application/json"} }).then(checkFetchSuccess("code")) - .then(r => r.json()) - .then(data => { - let acc = new MojangAccount(data.selectedProfile.id, data.selectedProfile.name, data.accessToken, data.clientToken); - addActiveAccount(acc); - return acc; - }).catch(e => addToast("Failed to login", e)); + .then(r => r.json()) + .then(data => { + storeMcAccount(data.accessToken, data.clientToken, data.selectedProfile.name, data.selectedProfile.id); + }).catch(e => addToast("Failed to login", e)); $("#form_add_mc input").val(""); } -// https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code -const azureClientId = "a370fff9-7648-4dbf-b96e-2b4f8d539ac2"; -const whitelistedOrigin = [ - "https://via-login.geyserconnect.net", - "https://via.re.yt.nom.br", - "https://viaaas.noxt.cf" -]; -const loginRequest = {scopes: ["XboxLive.signin"]}; -let redirectUrl = "https://viaversion.github.io/VIAaaS/src/main/resources/web/"; -if (location.hostname === "localhost" || whitelistedOrigin.includes(location.origin)) { - redirectUrl = location.origin + location.pathname; -} - -const msalConfig = { - auth: { - clientId: azureClientId, - authority: "https://login.microsoftonline.com/consumers/", - redirectUri: redirectUrl, - }, - cache: { - cacheLocation: "sessionStorage", - storeAuthStateInCookie: false, - } -}; - -const myMSALObj = new msal.PublicClientApplication(msalConfig); - -export function loginMs() { - myMSALObj.loginRedirect(loginRequest); -} - -$(() => myMSALObj.handleRedirectPromise().then((resp) => { - if (resp) { - let found = findAccountByMs(resp.account.username) - if (!found) { - let accNew = new MicrosoftAccount("", "", "", resp.account.username); - accNew.refresh() - .then(() => addActiveAccount(accNew)) - .catch(e => addToast("Failed to get token", e)); - } else { - found.refresh() - .catch(e => addToast("Failed to refresh token", e)); - } - } -})); - -function getTokenPopup(username, request) { - /** - * See here for more info on account retrieval: - * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md - */ - request.account = myMSALObj.getAccountByUsername(username); - return myMSALObj.acquireTokenSilent(request).catch(error => { - console.warn("silent token acquisition fails."); - if (error instanceof msal.InteractionRequiredAuthError) { - // fallback to interaction when silent call fails - return myMSALObj.acquireTokenPopup(request).catch(error => console.error(error)); - } else { - console.warn(error); - } +function logoutMojang(id) { + getMcAccounts().filter(isMojang).filter(it => it.id == id).forEach(it => { + fetch(getCorsProxy() + "https://authserver.mojang.com/invalidate", {method: "post", + body: JSON.stringify({ + accessToken: it.accessToken, + clientToken: it.clientToken + }), + headers: {"content-type": "application/json"} + }) + .then(checkFetchSuccess("not success logout")) + .finally(() => removeMcAccount(id)); }); -} \ No newline at end of file +} + +function refreshMojangAccount(it) { + console.log("refreshing " + it.id); + return fetch(getCorsProxy() + "https://authserver.mojang.com/refresh", { + method: "post", + body: JSON.stringify({ + accessToken: it.accessToken, + clientToken: it.clientToken + }), + headers: {"content-type": "application/json"}, + }).then(checkFetchSuccess("code")) + .then(r => r.json()) + .then(json => { + console.log("refreshed " + json.selectedProfile.id); + removeMcAccount(json.selectedProfile.id); + return storeMcAccount(json.accessToken, json.clientToken, json.selectedProfile.name, json.selectedProfile.id); + }); +} + +// Generic +function getMcUserToken(account) { + return validateToken(account.accessToken, account.clientToken || undefined).then(data => { + if (!isSuccess(data.status)) { + if (isMojang(account)) { + return refreshMojangAccount(account); + } else { + return refreshTokenMs(account.msUser); + } + } + return account; + }).catch(e => addToast("Failed to refresh token!", e)); +} + +function validateToken(accessToken, clientToken) { + return fetch(getCorsProxy() + "https://authserver.mojang.com/validate", { + method: "post", + body: JSON.stringify({ + accessToken: accessToken, + clientToken: clientToken + }), + headers: {"content-type": "application/json"} + }); +} + +function joinGame(token, id, hash) { + return fetch(getCorsProxy() + "https://sessionserver.mojang.com/session/minecraft/join", { + method: "post", + body: JSON.stringify({ + accessToken: token, + selectedProfile: id, + serverId: hash + }), + headers: {"content-type": "application/json"} + }); +} + +// Microsoft auth +function refreshTokenMs(username) { + return getTokenPopup(username, loginRequest) + .then(response => { + // this supports CORS + return fetch("https://user.auth.xboxlive.com/user/authenticate", {method: "post", + body: JSON.stringify({Properties: {AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", + RpsTicket: "d=" + response.accessToken}, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT"}), + headers: {"content-type": "application/json"}}) + .then(checkFetchSuccess("xbox response not success")) + .then(r => r.json()); + }).then(json => { + return fetch("https://xsts.auth.xboxlive.com/xsts/authorize", {method: "post", + body: JSON.stringify({Properties: {SandboxId: "RETAIL", UserTokens: [json.Token]}, + RelyingParty: "rp://api.minecraftservices.com/", TokenType: "JWT"}), + headers: {"content-type": "application/json"}}) + .then(checkFetchSuccess("xsts response not success")) + .then(r => r.json()); + }).then(json => { + return fetch(getCorsProxy() + "https://api.minecraftservices.com/authentication/login_with_xbox", {method: "post", + body: JSON.stringify({identityToken: "XBL3.0 x=" + json.DisplayClaims.xui[0].uhs + ";" + json.Token}), + headers: {"content-type": "application/json"}}) + .then(checkFetchSuccess("mc response not success")) + .then(r => r.json()); + }).then(json => { + return fetch(getCorsProxy() + "https://api.minecraftservices.com/minecraft/profile", { + method: "get", headers: {"content-type": "application/json", "authorization": "Bearer " + json.access_token}}).then(profile => { + if (profile.status == 404) return {id: "MHF_Exclamation", name: "[DEMO]"}; + if (!isSuccess(profile.status)) throw "profile response not success"; + return profile.json(); + }).then(jsonProfile => { + removeMcAccount(jsonProfile.id); + return storeMcAccount(json.access_token, null, jsonProfile.name, jsonProfile.id, username); + }); + }); +} + +function isMojang(it) { + return !!it.clientToken; +} + +function isNotMojang(it) { + return !isMojang(it); +} diff --git a/src/main/resources/web/js/auth_ms.js b/src/main/resources/web/js/auth_ms.js new file mode 100644 index 0000000..0fbdc27 --- /dev/null +++ b/src/main/resources/web/js/auth_ms.js @@ -0,0 +1,65 @@ +// https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code + +const azureClientId = "a370fff9-7648-4dbf-b96e-2b4f8d539ac2"; +const whitelistedOrigin = ["https://localhost:25543", "https://via-login.geyserconnect.net", "https://via.re.yt.nom.br", "https://viaaas.noxt.cf"]; +let redirectUrl = "https://viaversion.github.io/VIAaaS/src/main/resources/web/"; +if (whitelistedOrigin.includes(location.origin)) { + redirectUrl = location.origin + location.pathname; +} + +const msalConfig = { + auth: { + clientId: azureClientId, + authority: "https://login.microsoftonline.com/consumers/", + redirectUri: redirectUrl, + }, + cache: { + cacheLocation: "sessionStorage", + storeAuthStateInCookie: false, + } +}; + +const myMSALObj = new msal.PublicClientApplication(msalConfig); + +const loginRequest = { + scopes: ["XboxLive.signin"] +}; + +function loginMs() { + myMSALObj.loginRedirect(loginRequest); +} + +$(() => myMSALObj.handleRedirectPromise().then((resp) => { + if (resp) { + refreshTokenMs(resp.account.username).catch(e => addToast("Failed to get token", e)); + refreshAccountList(); + } +})); + +function getTokenPopup(username, request) { + /** + * See here for more info on account retrieval: + * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md + */ + request.account = myMSALObj.getAccountByUsername(username); + return myMSALObj.acquireTokenSilent(request).catch(error => { + console.warn("silent token acquisition fails."); + if (error instanceof msal.InteractionRequiredAuthError) { + // fallback to interaction when silent call fails + return myMSALObj.acquireTokenPopup(request).catch(error => console.error(error)); + } else { + console.warn(error); + } + }); +} + +function logoutMs(username) { + let mcAcc = findAccountByMs(username) || {}; + removeMcAccount(mcAcc.id); + + const logoutRequest = { + account: myMSALObj.getAccountByUsername(username) + }; + + myMSALObj.logout(logoutRequest); +} diff --git a/src/main/resources/web/js/cors_proxy.js b/src/main/resources/web/js/cors_proxy.js index f32552e..80610b6 100644 --- a/src/main/resources/web/js/cors_proxy.js +++ b/src/main/resources/web/js/cors_proxy.js @@ -1,14 +1,10 @@ -import {refreshCorsStatus} from "./page.js"; - function defaultCors() { return "https://crp123-cors.herokuapp.com/"; } - -export function getCorsProxy() { +function getCorsProxy() { return localStorage.getItem("viaaas_cors_proxy") || defaultCors(); } - -export function setCorsProxy(url) { +function setCorsProxy(url) { localStorage.setItem("viaaas_cors_proxy", url); refreshCorsStatus(); } diff --git a/src/main/resources/web/js/minecraft_id.js b/src/main/resources/web/js/minecraft_id.js new file mode 100644 index 0000000..b63e923 --- /dev/null +++ b/src/main/resources/web/js/minecraft_id.js @@ -0,0 +1,19 @@ +// Minecraft.id +var mcIdUsername = null; +var mcauth_code = null; +var mcauth_success = null; + +$(() => { + let urlParams = new URLSearchParams(); + window.location.hash.substr(1).split("?").map(it => new URLSearchParams(it).forEach((a, b) => urlParams.append(b, a))); + mcIdUsername = urlParams.get("username"); + mcauth_code = urlParams.get("mcauth_code"); + mcauth_success = urlParams.get("mcauth_success"); + if (mcauth_success == "false") { + addToast("Couldn't authenticate with Minecraft.ID", urlParams.get("mcauth_msg")); + } + if (mcauth_code != null) { + history.replaceState(null, null, "#"); + renderActions(); + } +}); \ No newline at end of file diff --git a/src/main/resources/web/js/notification.js b/src/main/resources/web/js/notification.js index 910ce3b..465ebe4 100644 --- a/src/main/resources/web/js/notification.js +++ b/src/main/resources/web/js/notification.js @@ -1,8 +1,7 @@ // Notification -let notificationCallbacks = {}; +var notificationCallbacks = {}; $(() => { - new BroadcastChannel("viaaas-notification") - .addEventListener("message", handleSWMsg); + new BroadcastChannel("viaaas-notification").addEventListener("message", handleSWMsg); }) function handleSWMsg(event) { @@ -14,8 +13,8 @@ function handleSWMsg(event) { callback(data.action); } -export function authNotification(msg, yes, no) { - if (!navigator.serviceWorker || Notification.permission !== "granted") { +function authNotification(msg, yes, no) { + if (!navigator.serviceWorker || Notification.permission != "granted") { if (confirm(msg)) yes(); else no(); return; } @@ -24,21 +23,21 @@ export function authNotification(msg, yes, no) { r.showNotification("Click to allow auth impersionation", { body: msg, tag: tag, - vibrate: [200, 10, 100, 200, 100, 10, 100, 10, 200], + vibrate: [200,10,100,200,100,10,100,10,200], actions: [ {action: "reject", title: "Reject"}, {action: "confirm", title: "Confirm"} ] }); notificationCallbacks[tag] = action => { - if (action === "reject") { + if (action == "reject") { no(); - } else if (!action || action === "confirm") { + } else if (!action || action == "confirm") { yes(); + } else { + return; } }; - setTimeout(() => { - delete notificationCallbacks[tag] - }, 30 * 1000); + setTimeout(() => { delete notificationCallbacks[tag] }, 30 * 1000); }); } diff --git a/src/main/resources/web/js/page.js b/src/main/resources/web/js/page.js index be5cc98..9e8d7fc 100644 --- a/src/main/resources/web/js/page.js +++ b/src/main/resources/web/js/page.js @@ -1,67 +1,35 @@ -// Minecraft.id -import {icanhazepoch, icanhazip} from "./util.js"; -import {getCorsProxy, setCorsProxy} from "./cors_proxy.js"; -import { - findAccountByMs, - getActiveAccounts, - getMicrosoftUsers, - loginMc, - loginMs, MicrosoftAccount, - MojangAccount -} from "./account_manager.js"; -import {connect, getWsUrl, removeToken, sendSocket, setWsUrl, unlisten} from "./websocket.js"; - -let mcIdUsername = null; -let mcauth_code = null; -let mcauth_success = null; - -$(() => { - let urlParams = new URLSearchParams(); - window.location.hash.substr(1).split("?") - .map(it => new URLSearchParams(it) - .forEach((a, b) => urlParams.append(b, a))); - mcIdUsername = urlParams.get("username"); - mcauth_code = urlParams.get("mcauth_code"); - mcauth_success = urlParams.get("mcauth_success"); - if (mcauth_success === "false") { - addToast("Couldn't authenticate with Minecraft.ID", urlParams.get("mcauth_msg")); - } - if (mcauth_code != null) { - history.replaceState(null, null, "#"); - renderActions(); - } -}); - -let connectionStatus = document.getElementById("connection_status"); -let corsStatus = document.getElementById("cors_status"); -let listening = document.getElementById("listening"); -let actions = document.getElementById("actions"); -let accounts = document.getElementById("accounts-list"); -let cors_proxy_txt = document.getElementById("cors-proxy"); -let ws_url_txt = document.getElementById("ws-url"); -let listenVisible = false; -let workers = []; +var connectionStatus = document.getElementById("connection_status"); +var corsStatus = document.getElementById("cors_status"); +var listening = document.getElementById("listening"); +var actions = document.getElementById("actions"); +var accounts = document.getElementById("accounts-list"); +var listenVisible = false; +var workers = []; $(() => workers = new Array(navigator.hardwareConcurrency).fill(null).map(() => new Worker("js/worker.js"))); window.addEventListener('beforeinstallprompt', e => { - e.preventDefault(); + e.preventDefault(); }); // On load $(() => { if (navigator.serviceWorker) { - navigator.serviceWorker.register("sw.js").then(() => { - swCacheFiles(); - }); + navigator.serviceWorker.register("sw.js"); + navigator.serviceWorker.ready.then(ready => ready.active.postMessage({ + action: "cache", + urls: performance.getEntriesByType("resource") + .map(it => it.name) + .filter(it => it.endsWith(".js") || it.endsWith(".css") || it.endsWith(".png")) + })); // https://stackoverflow.com/questions/46830493/is-there-any-way-to-cache-all-files-of-defined-folder-path-in-service-worker } ohNo(); - cors_proxy_txt.value = getCorsProxy(); - ws_url_txt.value = getWsUrl(); + $("#cors-proxy").val(getCorsProxy()); + $("#ws-url").val(getWsUrl()); $("form").on("submit", e => e.preventDefault()); - $("#form_add_mc").on("submit", () => loginMc($("#email").val(), $("#password").val())); - $("#form_add_ms").on("submit", () => loginMs()); - $("#form_ws_url").on("submit", () => setWsUrl($("#ws-url").val())); - $("#form_cors_proxy").on("submit", () => setCorsProxy($("#cors-proxy").val())); + $("#form_add_mc").on("submit", e => loginMc($("#email").val(), $("#password").val())); + $("#form_add_ms").on("submit", e => loginMs()); + $("#form_ws_url").on("submit", e => setWsUrl($("#ws-url").val())); + $("#form_cors_proxy").on("submit", e => setCorsProxy($("#cors-proxy").val())); $(".css_async").attr("disabled", null); workers.forEach(it => it.onmessage = onWorkerMsg); @@ -73,31 +41,14 @@ $(() => { connect(); }); -function swCacheFiles() { - navigator.serviceWorker.ready.then(ready => ready.active.postMessage({ - action: "cache", - urls: performance.getEntriesByType("resource") - .map(it => it.name) - .filter(it => it.endsWith(".js") || it.endsWith(".css") || it.endsWith(".png")) - })); // https://stackoverflow.com/questions/46830493/is-there-any-way-to-cache-all-files-of-defined-folder-path-in-service-worker -} - -export function setWsStatus(txt) { - connectionStatus.innerText = txt; -} - -export function setListenVisible(visible) { - listenVisible = visible; -} - -export function refreshCorsStatus() { +function refreshCorsStatus() { corsStatus.innerText = "..."; icanhazip(true).then(ip => { - return icanhazip(false).then(ip2 => corsStatus.innerText = "OK " + ip + (ip !== ip2 ? " (different IP)" : "")); - }).catch(e => corsStatus.innerText = "error: " + e); + return icanhazip(false).then(ip2 => corsStatus.innerText = "OK " + ip + (ip != ip2 ? " (different IP)" : "")); + }).catch(e => corsStatus.innerText = "error: " + e); } -function addMcAccountToList(account) { +function addMcAccountToList(id, name, msUser = null) { let p = document.createElement("li"); p.className = "input-group d-flex"; let shead = document.createElement("span"); @@ -108,15 +59,19 @@ function addMcAccountToList(account) { n.className = "form-control"; let remove = document.createElement("a"); remove.className = "btn btn-danger"; - n.innerText = " " + account.name + " " + (account instanceof MicrosoftAccount ? "(" + account.msUser + ") " : ""); + n.innerText = " " + name + " " + (msUser == null ? "" : "(" + msUser + ") "); remove.innerText = "Logout"; remove.href = "javascript:"; remove.onclick = () => { - account.logout(); + if (msUser == null) { + logoutMojang(id); + } else { + logoutMs(msUser); + } }; - head.width = 24; - head.alt = account.name + "'s head"; - head.src = "https://crafthead.net/helm/" + account.id; + head.width = "24"; + head.alt = name + "'s head"; + head.src = "https://crafthead.net/helm/" + id; //(id.length == 36 || id.length == 32) ? "https://crafatar.com/avatars/" + id + "?overlay" : "https://crafthead.net/helm/" + id; p.append(shead); p.append(n); @@ -124,35 +79,28 @@ function addMcAccountToList(account) { accounts.appendChild(p); } -export function refreshAccountList() { +function refreshAccountList() { accounts.innerHTML = ""; - getActiveAccounts() - .filter(it => it instanceof MojangAccount) - .sort((a, b) => a.name.localeCompare(b.name)) - .forEach(it => addMcAccountToList(it)); - getMicrosoftUsers() - .sort((a, b) => a.localeCompare(b)) - .forEach(username => { - let mcAcc = findAccountByMs(username); - if (!mcAcc) return; - addMcAccountToList(mcAcc); - }); + getMcAccounts().filter(isMojang).sort((a, b) => a.name.localeCompare(b.name)).forEach(it => addMcAccountToList(it.id, it.name)); + (myMSALObj.getAllAccounts() || []).sort((a, b) => a.username.localeCompare(b.username)).forEach(msAccount => { + let mcAcc = findAccountByMs(msAccount.username) || {id: "MHF_Question", name: "..."}; + addMcAccountToList(mcAcc.id, mcAcc.name, msAccount.username); + }); } -export function renderActions() { +function renderActions() { actions.innerHTML = ""; - if (Notification.permission === "default") { + if (Notification.permission == "default") { actions.innerHTML += '

Enable notifications

'; - $("#notificate").on("click", () => Notification.requestPermission().then(renderActions)); // i'm lazy + $("#notificate").on("click", e => Notification.requestPermission().then(renderActions)); // i'm lazy } if (listenVisible) { if (mcIdUsername != null && mcauth_code != null) { addAction("Listen to " + mcIdUsername, () => { - sendSocket(JSON.stringify({ + socket.send(JSON.stringify({ "action": "minecraft_id_login", "username": mcIdUsername, - "code": mcauth_code - })); + "code": mcauth_code})); mcauth_code = null; renderActions(); }); @@ -163,7 +111,7 @@ export function renderActions() { let callbackUrl = new URL(location); callbackUrl.search = ""; callbackUrl.hash = "#username=" + encodeURIComponent(user); - location.href = "https://api.minecraft.id/gateway/start/" + encodeURIComponent(user) + location = "https://api.minecraft.id/gateway/start/" + encodeURIComponent(user) + "?callback=" + encodeURIComponent(callbackUrl); }); addAction("Listen to frontend offline login in VIAaaS instance", () => { @@ -178,13 +126,13 @@ export function renderActions() { function onWorkerMsg(e) { console.log(e); - if (e.data.action === "completed_pow") onCompletedPoW(e); + if (e.data.action == "completed_pow") onCompletedPoW(e); } function onCompletedPoW(e) { addToast("Offline username", "Completed proof of work"); workers.forEach(it => it.postMessage({action: "cancel", id: e.data.id})); - sendSocket(e.data.msg); + socket.send(e.data.msg); } function addAction(text, onClick) { @@ -197,7 +145,7 @@ function addAction(text, onClick) { actions.appendChild(p); } -export function addListeningList(user, token) { +function addListeningList(user, token) { let p = document.createElement("p"); let head = document.createElement("img"); let n = document.createElement("span"); @@ -210,7 +158,7 @@ export function addListeningList(user, token) { listening.removeChild(p); unlisten(user); }; - head.width = 24; + head.width = "24"; head.alt = user + "'s head"; head.src = "https://crafthead.net/helm/" + user; p.append(head); @@ -219,7 +167,7 @@ export function addListeningList(user, token) { listening.appendChild(p); } -export function addToast(title, msg) { +function addToast(title, msg) { let toast = document.createElement("div"); document.getElementById("toasts").prepend(toast); $(toast) @@ -240,7 +188,7 @@ export function addToast(title, msg) { new bootstrap.Toast(toast).show(); } -export function resetHtml() { +function resetHtml() { listening.innerHTML = ""; listenVisible = false; renderActions(); @@ -248,16 +196,13 @@ export function resetHtml() { function ohNo() { try { - icanhazepoch().then(sec => { - if (Math.abs(Date.now() / 1000 - sec) > 15) { - addToast("Time isn't synchronized", "Please synchronize your computer time to NTP servers"); - } else { - console.log("time seems synchronized"); - } - }) - new Date().getDay() === 3 && console.log("it's snapshot day 🐸 my dudes"); - new Date().getDate() === 1 && new Date().getMonth() === 3 && addToast("WARNING", "Your ViaVersion has expired, please renew it at https://viaversion.com/ for $99"); - } catch (e) { - console.log(e); - } + icanhazepoch().then(sec => { + if (Math.abs(Date.now() / 1000 - sec) > 15) { + addToast("Time isn't synchronized", "Please synchronize your computer time to NTP servers"); + } else { + console.log("time seems synchronized"); + } + }) + new Date().getDay() == 3 && console.log("it's snapshot day 🐸 my dudes"); new Date().getDate() == 1 && new Date().getMonth() == 3 && addToast("WARNING", "Your ViaVersion has expired, please renew it at https://viaversion.com/ for $99"); + } catch (e) { console.log(e); } } diff --git a/src/main/resources/web/js/util.js b/src/main/resources/web/js/util.js index b58930c..873b8c3 100644 --- a/src/main/resources/web/js/util.js +++ b/src/main/resources/web/js/util.js @@ -1,30 +1,24 @@ -import {getCorsProxy} from "./cors_proxy.js"; - -export function isSuccess(status) { +function isSuccess(status) { return status >= 200 && status < 300; } -export function checkFetchSuccess(msg) { +function checkFetchSuccess(msg) { return r => { if (!isSuccess(r.status)) throw r.status + " " + msg; return r; }; } -export function icanhazip(cors) { +function icanhazip(cors) { return fetch((cors ? getCorsProxy() : "") + "https://ipv4.icanhazip.com") .then(checkFetchSuccess("code")) .then(r => r.text()) .then(it => it.trim()); } -export function icanhazepoch() { +function icanhazepoch() { return fetch("https://icanhazepoch.com") .then(checkFetchSuccess("code")) .then(r => r.text()) .then(it => parseInt(it.trim())) -} - -export function filterNot(array, item) { - return array.filter(it => it !== item); } \ No newline at end of file diff --git a/src/main/resources/web/js/websocket.js b/src/main/resources/web/js/websocket.js index fca033d..ead5810 100644 --- a/src/main/resources/web/js/websocket.js +++ b/src/main/resources/web/js/websocket.js @@ -1,30 +1,23 @@ -import {authNotification} from "./notification.js"; -import {checkFetchSuccess} from "./util.js"; -import {findAccountByMcName} from "./account_manager.js"; -import {addListeningList, addToast, renderActions, resetHtml, setListenVisible, setWsStatus} from "./page.js"; - -let wsUrl = getWsUrl(); -let socket = null; +var wsUrl = getWsUrl(); +var socket = null; // WS url function defaultWs() { let url = new URL("ws", new URL(location)); url.protocol = "wss"; - return window.location.host.endsWith("github.io") || !window.location.protocol.startsWith("http") - ? "wss://localhost:25543/ws" : url.toString(); + return window.location.host == "viaversion.github.io" || !window.location.host ? "wss://localhost:25543/ws" : url.toString(); } -export function getWsUrl() { +function getWsUrl() { return localStorage.getItem("viaaas_ws_url") || defaultWs(); } - -export function setWsUrl(url) { +function setWsUrl(url) { localStorage.setItem("viaaas_ws_url", url); location.reload(); } // Tokens -export function saveToken(token) { +function saveToken(token) { let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {}; let tokens = getTokens(); tokens.push(token); @@ -32,28 +25,28 @@ export function saveToken(token) { localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens)); } -export function removeToken(token) { +function removeToken(token) { let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {}; let tokens = getTokens(); - tokens = tokens.filter(it => it !== token); + tokens = tokens.filter(it => it != token); hTokens[wsUrl] = tokens; localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens)); } -export function getTokens() { +function getTokens() { return (JSON.parse(localStorage.getItem("viaaas_tokens")) || {})[wsUrl] || []; } // Websocket -export function listen(token) { +function listen(token) { socket.send(JSON.stringify({"action": "listen_login_requests", "token": token})); } -export function unlisten(id) { +function unlisten(id) { socket.send(JSON.stringify({"action": "unlisten_login_requests", "uuid": id})); } -export function confirmJoin(hash) { +function confirmJoin(hash) { socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash})); } @@ -63,10 +56,12 @@ function handleJoinRequest(parsed) { + parsed.message.split(/[\r\n]+/).map(it => "> " + it).join('\n'), () => { let account = findAccountByMcName(parsed.user); if (account) { - account.joinGame(parsed.session_hash) - .then(checkFetchSuccess("code")) - .finally(() => confirmJoin(parsed.session_hash)) - .catch((e) => addToast("Couldn't contact session server", "Error: " + e)); + getMcUserToken(account).then(data => { + return joinGame(data.accessToken, data.id, parsed.session_hash); + }) + .then(checkFetchSuccess("code")) + .finally(() => confirmJoin(parsed.session_hash)) + .catch((e) => addToast("Couldn't contact session server", "Error: " + e)); } else { confirmJoin(parsed.session_hash); addToast("Couldn't find account", "Couldn't find " + parsed.user + ", check Accounts tab"); @@ -76,51 +71,51 @@ function handleJoinRequest(parsed) { function onSocketMsg(event) { let parsed = JSON.parse(event.data); - if (parsed.action === "ad_minecraft_id_login") { - setListenVisible(true); + if (parsed.action == "ad_minecraft_id_login") { + listenVisible = true; renderActions(); - } else if (parsed.action === "login_result") { + } else if (parsed.action == "login_result") { if (!parsed.success) { addToast("Couldn't verify Minecraft account", "VIAaaS returned failed response"); } else { listen(parsed.token); saveToken(parsed.token); } - } else if (parsed.action === "listen_login_requests_result") { + } else if (parsed.action == "listen_login_requests_result") { if (parsed.success) { addListeningList(parsed.user, parsed.token); } else { removeToken(parsed.token); } - } else if (parsed.action === "session_hash_request") { + } else if (parsed.action == "session_hash_request") { handleJoinRequest(parsed); } } -export function listenStoredTokens() { +function listenStoredTokens() { getTokens().forEach(listen); } function onConnect() { - setWsStatus("connected"); + connectionStatus.innerText = "connected"; resetHtml(); listenStoredTokens(); } function onWsError(e) { console.log(e); - setWsStatus("socket error"); + connectionStatus.innerText = "socket error"; resetHtml(); } function onDisconnect(evt) { - setWsStatus("disconnected with close code " + evt.code + " and reason: " + evt.reason); + connectionStatus.innerText = "disconnected with close code " + evt.code + " and reason: " + evt.reason; resetHtml(); setTimeout(connect, 5000); } -export function connect() { - setWsStatus("connecting..."); +function connect() { + connectionStatus.innerText = "connecting..."; socket = new WebSocket(wsUrl); socket.onerror = onWsError; @@ -128,11 +123,3 @@ export function connect() { socket.onclose = onDisconnect socket.onmessage = onSocketMsg; } - -export function sendSocket(msg) { - if (!socket) { - console.error("couldn't send msg, socket isn't set"); - return - } - socket.send(msg); -} \ No newline at end of file diff --git a/src/main/resources/web/js/worker.js b/src/main/resources/web/js/worker.js index 69779db..995adb6 100644 --- a/src/main/resources/web/js/worker.js +++ b/src/main/resources/web/js/worker.js @@ -1,43 +1,43 @@ importScripts("https://cdnjs.cloudflare.com/ajax/libs/js-sha512/0.8.0/sha512.min.js"); -let pending = []; +var pending = []; -onmessage = function (e) { - if (e.data.action === "listen_pow") startPoW(e); - if (e.data.action === "cancel") removePending(e.data.id); +onmessage = function(e) { + if (e.data.action == "listen_pow") startPoW(e); + if (e.data.action == "cancel") removePending(e.data.id); } function removePending(id) { - console.log("removing task" + id); - pending = pending.filter(it => it !== id); + console.log("removing task" + id); + pending = pending.filter(it => it != id); } function startPoW(e) { - pending.push(e.data.id); - listenPoW(e); + pending.push(e.data.id); + listenPoW(e); } function listenPoW(e) { - let user = e.data.user; - let msg = null; - let endTime = Date.now() + 1000; - do { - if (!pending.includes(e.data.id)) return; // cancelled + var user = e.data.user; + let msg = null; + var endTime = Date.now() + 1000; + do { + if (!pending.includes(e.data.id)) return; // cancelled - msg = JSON.stringify({ - action: "offline_login", - username: user, - date: Date.now(), - rand: Math.random() - }); + msg = JSON.stringify({ + action: "offline_login", + username: user, + date: Date.now(), + rand: Math.random() + }); - if (Date.now() >= endTime) { - setTimeout(() => listenPoW(e), 0); - return; - } - } while (!sha512(msg).startsWith("00000")); + if (Date.now() >= endTime) { + setTimeout(() => listenPoW(e), 0); + return; + } + } while (!sha512(msg).startsWith("00000")); - postMessage({id: e.data.id, action: "completed_pow", msg: msg}); + postMessage({id: e.data.id, action: "completed_pow", msg: msg}); } /* function sha512(s) {