js code cleanup

This commit is contained in:
creeper123123321 2021-02-09 17:54:30 -03:00
parent a4f38f9288
commit f789dfea8f

View File

@ -1,15 +1,16 @@
// Minecraft.id
let urlParams = new URLSearchParams();
window.location.hash.substr(1).split("?").map(it => new URLSearchParams(it).forEach((a, b) => urlParams.append(b, a)));
var username = urlParams.get("username");
var mcIdUsername = urlParams.get("username");
var mcauth_code = urlParams.get("mcauth_code");
if (urlParams.get("mcauth_success") == "false") {
alert("Couldn't authenticate with Minecraft.ID: " + urlParams.get("mcauth_msg"));
}
// WS
function defaultWs() {
return window.location.host == "viaversion.github.io" || !window.location.host ? "wss://localhost:25543/ws" : "wss://" + window.location.host + "/ws";
}
function getWsUrl() {
let url = localStorage.getItem("ws-url") || defaultWs();
localStorage.setItem("ws-url", url);
@ -17,7 +18,6 @@ function getWsUrl() {
}
var wsUrl = getWsUrl();
var socket = null;
var connectionStatus = document.getElementById("connection_status");
var corsStatus = document.getElementById("cors_status");
@ -26,42 +26,65 @@ var actions = document.getElementById("actions");
var accounts = document.getElementById("accounts-list");
var listenVisible = false;
// Util
isMojang = it => !!it.clientToken;
isNotMojang = it => !it.clientToken;
isSuccess = status => status >= 200 && status < 300;
// Proxy
function getCorsProxy() {
return localStorage.getItem("cors-proxy") || "https://crp123-cors.herokuapp.com/";
}
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;
});
}
function icanhazip(cors) {
return fetch((cors ? getCorsProxy() : "") + "https://ipv4.icanhazip.com")
.then(it => {
if (!isSuccess(it.status)) throw "not success " + it.status
return it.text();
}).then(it => it.trim());
}
function setCorsProxy(url) {
localStorage.setItem("cors-proxy", url);
refreshCorsStatus();
}
// Heroku sleeps in 30 minutes, let's call it every 10 minutes to keep the same address, so Mojang see it as less suspect
setInterval(refreshCorsStatus, 10 * 60 * 1000);
refreshCorsStatus();
// Tokens
function saveToken(token) {
let hTokens = JSON.parse(localStorage.getItem("tokens")) || {};
let tokens = hTokens[wsUrl] || [];
tokens.push(token);
hTokens[wsUrl] = tokens;
localStorage.setItem("tokens", JSON.stringify(hTokens));
}
function removeToken(token) {
let hTokens = JSON.parse(localStorage.getItem("tokens")) || {};
let tokens = hTokens[wsUrl] || [];
tokens = tokens.filter(it => it != token);
hTokens[wsUrl] = tokens;
localStorage.setItem("tokens", JSON.stringify(hTokens));
}
function getTokens() {
return (JSON.parse(localStorage.getItem("tokens")) || {})[wsUrl] || [];
}
// Accounts
function storeMcAccount(accessToken, clientToken, name, id, msUser = null) {
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
let account = {accessToken: accessToken, clientToken: clientToken, name: name, id: id, msUser: msUser};
accounts.push(account);
localStorage.setItem("mc_accounts", JSON.stringify(accounts));
refreshAccountList();
return account;
}
function removeMcAccount(id) {
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
accounts = accounts.filter(it => it.id != id);
localStorage.setItem("mc_accounts", JSON.stringify(accounts));
refreshAccountList();
}
function getMcAccounts() {
return JSON.parse(localStorage.getItem("mc_accounts")) || [];
}
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);
}
// Mojang account
function loginMc(user, pass) {
var clientToken = uuid.v4();
fetch(getCorsProxy() + "https://authserver.mojang.com/authenticate", {
@ -82,34 +105,6 @@ function loginMc(user, pass) {
$("#email").val("");
$("#password").val("");
}
function storeMcAccount(accessToken, clientToken, name, id, msUser = null) {
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
let account = {accessToken: accessToken, clientToken: clientToken, name: name, id: id, msUser: msUser};
accounts.push(account);
localStorage.setItem("mc_accounts", JSON.stringify(accounts));
refreshAccountList();
return account;
}
function removeMcAccount(id) {
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
accounts = accounts.filter(it => it.id != id);
localStorage.setItem("mc_accounts", JSON.stringify(accounts));
refreshAccountList();
}
isMojang = it => !!it.clientToken;
isNotMojang = it => !it.clientToken;
function getMcAccounts() {
return JSON.parse(localStorage.getItem("mc_accounts")) || [];
}
function findAccountByMs(username) {
return getMcAccounts().filter(isNotMojang).find(it => it.msUser == username);
}
function logoutMojang(id) {
getMcAccounts().filter(isMojang).filter(it => it.id == id).forEach(it => {
fetch(getCorsProxy() + "https://authserver.mojang.com/invalidate", {method: "post",
@ -128,7 +123,83 @@ function logoutMojang(id) {
});
});
}
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(data => {
if (!isSuccess(data.status)) throw "not success " + data.status;
return data.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);
});
}
// Minecraft api
function getMcUserToken(account) {
return validateToken(account).then((data) => {
if (!isSuccess(data.status)) {
if (isMojang(account)) {
return refreshMojangAccount(account);
} else {
return refreshTokenMs(account.msUser);
}
}
return account;
}).catch((e) => {
alert("failed to refresh token! " + e);
});
}
function validateToken(account) {
return fetch(getCorsProxy() + "https://authserver.mojang.com/validate", {method: "post",
body: JSON.stringify({
accessToken: account.accessToken,
clientToken: account.clientToken || undefined
}),
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"}
});
}
// Proxy status
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;
});
}
function icanhazip(cors) {
return fetch((cors ? getCorsProxy() : "") + "https://ipv4.icanhazip.com")
.then(it => {
if (!isSuccess(it.status)) throw "not success " + it.status
return it.text();
}).then(it => it.trim());
}
// HTML
function addMcAccountToList(id, name, msUser = null) {
let p = document.createElement("p");
let head = document.createElement("img");
@ -152,7 +223,6 @@ function addMcAccountToList(id, name, msUser = null) {
p.append(remove);
accounts.appendChild(p);
}
function refreshAccountList() {
accounts.innerHTML = "";
getMcAccounts().filter(isMojang).forEach(it => addMcAccountToList(it.id, it.name));
@ -161,99 +231,14 @@ function refreshAccountList() {
addMcAccountToList(mcAcc.id, mcAcc.name, msAccount.username);
});
}
function validateToken(account) {
return fetch(getCorsProxy() + "https://authserver.mojang.com/validate", {method: "post",
body: JSON.stringify({
accessToken: account.accessToken,
clientToken: account.clientToken || undefined
}),
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"}
});
}
function getMcUserToken(account) {
return validateToken(account).then((data) => {
if (!isSuccess(data.status)) {
if (isMojang(account)) {
return refreshMojangAccount(account);
} else {
return refreshTokenMs(account.msUser);
}
}
return account;
}).catch((e) => {
alert("failed to refresh token! " + e);
});
}
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(data => {
if (!isSuccess(data.status)) throw "not success " + data.status;
return data.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);
});
}
function listen(token) {
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
}
function confirmJoin(hash) {
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
}
function saveToken(token) {
let hTokens = JSON.parse(localStorage.getItem("tokens")) || {};
let tokens = hTokens[wsUrl] || [];
tokens.push(token);
hTokens[wsUrl] = tokens;
localStorage.setItem("tokens", JSON.stringify(hTokens));
}
function removeToken(token) {
let hTokens = JSON.parse(localStorage.getItem("tokens")) || {};
let tokens = hTokens[wsUrl] || [];
tokens = tokens.filter(it => it != token);
hTokens[wsUrl] = tokens;
localStorage.setItem("tokens", JSON.stringify(hTokens));
}
function getTokens() {
return (JSON.parse(localStorage.getItem("tokens")) || {})[wsUrl] || [];
}
function renderActions() {
actions.innerHTML = "";
if (listenVisible) {
if (username != null && mcauth_code != null) {
addAction("Listen to " + username, () => {
if (mcIdUsername != null && mcauth_code != null) {
addAction("Listen to " + mcIdUsername, () => {
socket.send(JSON.stringify({
"action": "minecraft_id_login",
"username": username,
"username": mcIdUsername,
"code": mcauth_code}));
mcauth_code = null;
});
@ -268,11 +253,10 @@ function renderActions() {
addAction("Listen to offline login in VIAaaS instance", () => {
let user = prompt("Offline username (case-sensitive):", "");
if (!user) return;
socket.send(JSON.stringify({"action": "offline_login", "username": user}));
socket.send(JSON.stringify({action: "offline_login", username: user}));
});
}
}
function addAction(text, onClick) {
let p = document.createElement("p");
let link = document.createElement("a");
@ -282,13 +266,46 @@ function addAction(text, onClick) {
link.onclick = onClick;
actions.appendChild(p);
}
function findAccountByMcName(name) {
return getMcAccounts().reverse().find(it => it.name.toLowerCase() == name.toLowerCase());
function addListeningList(user) {
let msg = document.createElement("p");
msg.innerText = "Listening to login: " + user;
listening.appendChild(msg);
}
function resetHtml() {
listening.innerHTML = "";
listenVisible = false;
renderActions();
}
// Websocket
function listen(token) {
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
}
function confirmJoin(hash) {
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
}
function handleJoinRequest(parsed) {
if (confirm("Allow auth impersonation from VIAaaS instance? info: " + JSON.stringify(parsed))) {
let account = findAccountByMcName(parsed.user);
if (account) {
getMcUserToken(account).then(data => {
return joinGame(data.accessToken, data.id, parsed.session_hash);
}).then(data => {
if (!isSuccess(data.status)) throw "not success join " + data.status;
}).finally(() => confirmJoin(parsed.session_hash))
.catch((e) => {
confirmJoin(parsed.session_hash);
alert("Couldn't contact session server for " + parsed.user + " account in browser. error: " + e);
});
} else {
alert("Couldn't find " + parsed.user + " account in browser.");
confirmJoin(parsed.session_hash);
}
} else {
confirmJoin(parsed.session_hash);
}
}
function onSocketMsg(event) {
console.log(event.data.toString());
let parsed = JSON.parse(event.data);
if (parsed.action == "ad_minecraft_id_login") {
listenVisible = true;
@ -302,68 +319,43 @@ function onSocketMsg(event) {
}
} else if (parsed.action == "listen_login_requests_result") {
if (parsed.success) {
let msg = document.createElement("p");
msg.innerText = "Listening to login: " + parsed.user;
listening.appendChild(msg);
addListeningList(parsed.user);
} else {
removeToken(parsed.token);
}
} else if (parsed.action == "session_hash_request") {
if (confirm("Allow auth impersonation from VIAaaS instance? info: " + JSON.stringify(parsed))) {
let account = findAccountByMcName(parsed.user);
if (account) {
getMcUserToken(account).then((data) => {
return joinGame(data.accessToken, data.id, parsed.session_hash);
}).then((data) => {
if (!isSuccess(data.status)) throw "not success join " + data.status;
}).finally(() => confirmJoin(parsed.session_hash))
.catch((e) => {
confirmJoin(parsed.session_hash);
alert("Couldn't contact session server for " + parsed.user + " account in browser. error: " + e);
});
} else {
alert("Couldn't find " + parsed.user + " account in browser.");
confirmJoin(parsed.session_hash);
}
} else {
confirmJoin(parsed.session_hash);
}
handleJoinRequest(parsed);
}
}
function reset() {
listening.innerHTML = "";
listenVisible = false;
renderActions();
function listenStoredTokens() {
getTokens().forEach(listen);
}
function onConnect() {
connectionStatus.innerText = "connected";
resetHtml();
listenStoredTokens();
}
function onWsError(e) {
console.log(e);
connectionStatus.innerText = "socket error";
resetHtml();
}
function onDisconnect(evt) {
connectionStatus.innerText = "disconnected with close code " + evt.code + " and reason: " + evt.reason;
resetHtml();
setTimeout(connect, 5000);
}
function connect() {
connectionStatus.innerText = "connecting...";
socket = new WebSocket(wsUrl);
socket.onerror = e => {
console.log(e);
connectionStatus.innerText = "socket error";
reset();
};
socket.onopen = () => {
connectionStatus.innerText = "connected";
reset();
getTokens().forEach(listen);
};
socket.onclose = evt => {
connectionStatus.innerText = "disconnected with close code " + evt.code + " and reason: " + evt.reason;
reset();
setTimeout(connect, 5000);
};
socket.onerror = onWsError;
socket.onopen = onConnect;
socket.onclose = onDisconnect
socket.onmessage = onSocketMsg;
}
// On load
$(() => {
$("#cors-proxy").on("change", () => setCorsProxy($("#cors-proxy").val()));
$("#cors-proxy").val(getCorsProxy());
@ -376,6 +368,9 @@ $(() => {
$("#login_submit_ms").on("click", loginMs);
refreshAccountList();
// Heroku sleeps in 30 minutes, let's call it every 10 minutes to keep the same address, so Mojang see it as less suspect
setInterval(refreshCorsStatus, 10 * 60 * 1000);
refreshCorsStatus();
connect();
});