mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-11-15 10:55:27 +01:00
merge javascript files, update html deps
This commit is contained in:
parent
57643283ec
commit
591015db83
@ -23,9 +23,30 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*.
|
||||
<meta content="no-referrer" name="referrer">
|
||||
<meta content="noindex" name="robots">
|
||||
<meta content="#0468a1" name="theme-color">
|
||||
|
||||
<!-- https://www.srihash.org/ -->
|
||||
<link class="css_async" disabled rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" integrity="sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
||||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.2/js/bootstrap.bundle.min.js" integrity="sha512-72WD92hLs7T5FAXn3vkNZflWG6pglUDDpm87TeQmfSg8KnrymL2G30R7as4FmTwhgu9H7eSzDCX3mjitSecKnw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<link class="css_async" disabled rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/css/bootstrap.min.css"
|
||||
integrity="sha512-F7WyTLiiiPqvu2pGumDR15med0MDkUIo5VTVyyfECR5DZmCnDhti9q5VID02ItWjq6fvDfMaBaDl2J3WdL1uxA=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"/>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/js/bootstrap.bundle.min.js"
|
||||
integrity="sha512-PqRelaJGXVuQ81N6wjUrRQelCDR7z8RvKGiR9SbSxKHPIt15eJDmIVv9EJgwq0XvgylszsjzvQ0+VyI2WtIshQ=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/js-polyfills/0.1.43/polyfill.min.js"
|
||||
integrity="sha512-lvWiOP+aMKHllm4THsjzNleVuGOh0WGniJ3lgu/nvCbex1LlaQSxySUjAu/LTJw9FhnSL/PVYoQcckg1Q03+fQ=="
|
||||
crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.slim.min.js"
|
||||
integrity="sha512-6ORWJX/LrnSjBzwefdNUyLCMTIsGoNP6NftMy2UAm1JBm6PRZCO1d7OHBStWpVFZLO+RerTvqX/Z9mBFfCJZ4A=="
|
||||
crossorigin="anonymous"></script>
|
||||
<script defer crossorigin="anonymous"
|
||||
integrity="sha512-UNM1njAgOFUa74Z0bADwAq8gbTcqZC8Ej4xPSzpnh0l6KMevwvkBvbldF9uR++qKeJ+MOZHRjV1HZjoRvjDfNQ=="
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.2/uuid.min.js"></script>
|
||||
<script defer src="https://alcdn.msauth.net/browser/2.15.0/js/msal-browser.min.js"
|
||||
integrity="sha384-/weuqUPkC0P9JxnstihEV1GHdWrheU9Qo3MbdTuxxKJM8l/cSTE5zGP5VBIM4TZN"
|
||||
crossorigin="anonymous"></script>
|
||||
<script defer src="js/page.js"></script>
|
||||
<link rel="prefetch" href="js/worker.js" as="worker">
|
||||
<link rel="prefetch" href="sw.js" as="serviceworker">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-2">
|
||||
@ -78,16 +99,16 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*.
|
||||
<div class="mb-3">
|
||||
<p>See <a href="https://github.com/ViaVersion/VIAaaS/">README</a> for more details.</p>
|
||||
<form class="input-group" id="form_cors_proxy">
|
||||
<label class="input-group-text" for="cors-proxy">CORS Proxy URL Prefix</label>
|
||||
<input class="form-control" id="cors-proxy" placeholder="http://localhost:8080/" type="url">
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
<label class="input-group-text" for="cors-proxy">CORS Proxy URL Prefix</label>
|
||||
<input class="form-control" id="cors-proxy" placeholder="http://localhost:8080/" type="url">
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<form class="input-group" id="form_ws_url">
|
||||
<label class="input-group-text" for="ws-url">WebSocket URL</label>
|
||||
<input class="form-control" id="ws-url" placeholder="wss://viaaas.example.com/ws" type="url">
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
<label class="input-group-text" for="ws-url">WebSocket URL</label>
|
||||
<input class="form-control" id="ws-url" placeholder="wss://viaaas.example.com/ws" type="url">
|
||||
<button class="btn btn-primary" type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -99,20 +120,22 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*.
|
||||
</div>
|
||||
<div id="add-account">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="login_submit_ms">Add Microsoft account</label>
|
||||
<form class="row" id="form_add_ms">
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-primary" id="login_submit_ms" type="submit">Login with Microsoft</button>
|
||||
</div>
|
||||
</form>
|
||||
<label class="form-label" for="login_submit_ms">Add Microsoft account</label>
|
||||
<form class="row" id="form_add_ms">
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-primary" id="login_submit_ms" type="submit">Login with Microsoft</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="email">Add Mojang account</label>
|
||||
<form class="input-group" id="form_add_mc">
|
||||
<input aria-label="Email/Username" class="form-control" id="email" name="email" placeholder="mc@example.com" type="text">
|
||||
<input aria-label="Password" class="form-control" id="password" name="password" placeholder="password" type="password">
|
||||
<button class="btn btn-primary" id="login_submit_mc" type="submit">Login with Mojang</button>
|
||||
</form>
|
||||
<label class="form-label" for="email">Add Mojang account</label>
|
||||
<form class="input-group" id="form_add_mc">
|
||||
<input aria-label="Email/Username" class="form-control" id="email" name="email"
|
||||
placeholder="mc@example.com" type="text">
|
||||
<input aria-label="Password" class="form-control" id="password" name="password"
|
||||
placeholder="password" type="password">
|
||||
<button class="btn btn-primary" id="login_submit_mc" type="submit">Login with Mojang</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,26 +150,32 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*.
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Design somewhat stolen/inspired from Gnome -->
|
||||
<img src="https://cdn.discordapp.com/attachments/316218802155028482/850014925622476820/unknown.png" class="mx-auto d-block" alt="VIAaaS logo" width="150">
|
||||
<img src="https://cdn.discordapp.com/attachments/316218802155028482/850014925622476820/unknown.png"
|
||||
class="mx-auto d-block" alt="VIAaaS logo" width="150">
|
||||
<div class="text-center mb-3">
|
||||
<h5>ViaVersion as a Service</h5>
|
||||
<h6>Standalone ViaVersion Proxy</h6>
|
||||
<h5>ViaVersion as a Service</h5>
|
||||
<h6>Standalone ViaVersion Proxy</h6>
|
||||
</div>
|
||||
<div class="text-center mb-3">
|
||||
<p class="mb-1">Copyright © 2020-2021 <a href="https://github.com/creeper123123321">creeper123123321</a></p>
|
||||
<p class="mb-1">Copyright © 2021 <a href="https://github.com/ViaVersion/VIAaaS/graphs/contributors">contributors</a></p>
|
||||
<p class="mb-1">Copyright © 2020-2021 <a
|
||||
href="https://github.com/creeper123123321">creeper123123321</a></p>
|
||||
<p class="mb-1">Copyright © 2021 <a href="https://github.com/ViaVersion/VIAaaS/graphs/contributors">contributors</a>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>VIAaaS is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
Affero General Public License as published by the Free Software Foundation, either version 3 of the
|
||||
License,
|
||||
or (at your option) any later version.</p>
|
||||
<p>VIAaaS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
||||
General
|
||||
Public License for more details.</p>
|
||||
<p>You should have received a copy of the GNU Affero General Public License along with this program. If
|
||||
not, see <a href="https://gnu.org/licenses">https://gnu.org/licenses/</a>.</p>
|
||||
<p>VIAaaS is free software: you can redistribute it and/or modify it under the terms of the GNU
|
||||
Affero General Public License as published by the Free Software Foundation, either version 3 of
|
||||
the
|
||||
License,
|
||||
or (at your option) any later version.</p>
|
||||
<p>VIAaaS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Affero
|
||||
General
|
||||
Public License for more details.</p>
|
||||
<p>You should have received a copy of the GNU Affero General Public License along with this program.
|
||||
If
|
||||
not, see <a href="https://gnu.org/licenses">https://gnu.org/licenses/</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@ -159,19 +188,5 @@ script-src 'self' https://*.cloudflare.com/ https://alcdn.msauth.net/ https://*.
|
||||
</div>
|
||||
|
||||
<div class="toast-container position-absolute top-0 end-0 p-3" id="toasts"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-polyfills/0.1.43/polyfill.min.js"
|
||||
integrity="sha512-lvWiOP+aMKHllm4THsjzNleVuGOh0WGniJ3lgu/nvCbex1LlaQSxySUjAu/LTJw9FhnSL/PVYoQcckg1Q03+fQ=="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.slim.min.js"
|
||||
integrity="sha512-6ORWJX/LrnSjBzwefdNUyLCMTIsGoNP6NftMy2UAm1JBm6PRZCO1d7OHBStWpVFZLO+RerTvqX/Z9mBFfCJZ4A=="
|
||||
crossorigin="anonymous"></script>
|
||||
<script crossorigin="anonymous"
|
||||
integrity="sha512-UNM1njAgOFUa74Z0bADwAq8gbTcqZC8Ej4xPSzpnh0l6KMevwvkBvbldF9uR++qKeJ+MOZHRjV1HZjoRvjDfNQ=="
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.2/uuid.min.js"></script>
|
||||
<script src="https://alcdn.msauth.net/browser/2.15.0/js/msal-browser.min.js" integrity="sha384-/weuqUPkC0P9JxnstihEV1GHdWrheU9Qo3MbdTuxxKJM8l/cSTE5zGP5VBIM4TZN"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<script type="module" src="js/page.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,304 +0,0 @@
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(() => loadAccounts());
|
||||
|
||||
function saveRefreshAccounts() {
|
||||
localStorage.setItem("viaaas_mc_accounts", JSON.stringify(getActiveAccounts()))
|
||||
refreshAccountList()
|
||||
}
|
||||
|
||||
export function getActiveAccounts() {
|
||||
return activeAccounts;
|
||||
}
|
||||
|
||||
export function getMicrosoftUsers() {
|
||||
return (myMSALObj.getAllAccounts() || []).map(it => it.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.selectedProfile.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();
|
||||
fetch(getCorsProxy() + "https://authserver.mojang.com/authenticate", {
|
||||
method: "post",
|
||||
body: JSON.stringify({
|
||||
agent: {name: "Minecraft", version: 1},
|
||||
username: user,
|
||||
password: pass,
|
||||
clientToken: clientToken,
|
||||
}),
|
||||
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));
|
||||
$("#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);
|
||||
}
|
||||
});
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import {refreshCorsStatus} from "./page.js";
|
||||
|
||||
function defaultCors() {
|
||||
return "https://crp123-cors.herokuapp.com/";
|
||||
}
|
||||
|
||||
export function getCorsProxy() {
|
||||
return localStorage.getItem("viaaas_cors_proxy") || defaultCors();
|
||||
}
|
||||
|
||||
export function setCorsProxy(url) {
|
||||
localStorage.setItem("viaaas_cors_proxy", url);
|
||||
refreshCorsStatus();
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Notification
|
||||
let notificationCallbacks = {};
|
||||
$(() => {
|
||||
new BroadcastChannel("viaaas-notification")
|
||||
.addEventListener("message", handleSWMsg);
|
||||
})
|
||||
|
||||
function handleSWMsg(event) {
|
||||
console.log("sw msg: " + event);
|
||||
let data = event.data;
|
||||
let callback = notificationCallbacks[data.tag];
|
||||
delete notificationCallbacks[data.tag];
|
||||
if (callback == null) return;
|
||||
callback(data.action);
|
||||
}
|
||||
|
||||
export function authNotification(msg, yes, no) {
|
||||
if (!navigator.serviceWorker || Notification.permission !== "granted") {
|
||||
if (confirm(msg)) yes(); else no();
|
||||
return;
|
||||
}
|
||||
let tag = uuid.v4();
|
||||
navigator.serviceWorker.ready.then(r => {
|
||||
r.showNotification("Click to allow auth impersionation", {
|
||||
body: msg,
|
||||
tag: tag,
|
||||
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") {
|
||||
no();
|
||||
} else if (!action || action === "confirm") {
|
||||
yes();
|
||||
}
|
||||
};
|
||||
setTimeout(() => {
|
||||
delete notificationCallbacks[tag]
|
||||
}, 30 * 1000);
|
||||
});
|
||||
}
|
@ -1,16 +1,4 @@
|
||||
// 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;
|
||||
@ -32,6 +20,7 @@ $(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// Page
|
||||
let connectionStatus = document.getElementById("connection_status");
|
||||
let corsStatus = document.getElementById("cors_status");
|
||||
let listening = document.getElementById("listening");
|
||||
@ -41,19 +30,22 @@ let cors_proxy_txt = document.getElementById("cors-proxy");
|
||||
let ws_url_txt = document.getElementById("ws-url");
|
||||
let listenVisible = false;
|
||||
let workers = [];
|
||||
$(() => workers = new Array(navigator.hardwareConcurrency).fill(null).map(() => new Worker("js/worker.js")));
|
||||
window.addEventListener('beforeinstallprompt', e => {
|
||||
e.preventDefault();
|
||||
$(() => {
|
||||
workers = new Array(navigator.hardwareConcurrency)
|
||||
.fill(null)
|
||||
.map(() => new Worker("js/worker.js"))
|
||||
workers.forEach(it => it.onmessage = onWorkerMsg);
|
||||
});
|
||||
|
||||
// On load
|
||||
$(() => {
|
||||
if (navigator.serviceWorker) {
|
||||
navigator.serviceWorker.register("sw.js").then(() => {
|
||||
swCacheFiles();
|
||||
});
|
||||
navigator.serviceWorker.register("sw.js")
|
||||
.then(() => swCacheFiles());
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('beforeinstallprompt', e => e.preventDefault());
|
||||
|
||||
$(() => {
|
||||
ohNo();
|
||||
cors_proxy_txt.value = getCorsProxy();
|
||||
ws_url_txt.value = getWsUrl();
|
||||
@ -64,7 +56,6 @@ $(() => {
|
||||
$("#form_cors_proxy").on("submit", () => setCorsProxy($("#cors-proxy").val()));
|
||||
$(".css_async").attr("disabled", null);
|
||||
|
||||
workers.forEach(it => it.onmessage = onWorkerMsg);
|
||||
refreshAccountList();
|
||||
setInterval(refreshCorsStatus, 10 * 60 * 1000); // Heroku auto sleeps in 30 min
|
||||
refreshCorsStatus();
|
||||
@ -82,15 +73,15 @@ function swCacheFiles() {
|
||||
})); // https://stackoverflow.com/questions/46830493/is-there-any-way-to-cache-all-files-of-defined-folder-path-in-service-worker
|
||||
}
|
||||
|
||||
export function setWsStatus(txt) {
|
||||
function setWsStatus(txt) {
|
||||
connectionStatus.innerText = txt;
|
||||
}
|
||||
|
||||
export function setListenVisible(visible) {
|
||||
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)" : ""));
|
||||
@ -124,7 +115,7 @@ function addMcAccountToList(account) {
|
||||
accounts.appendChild(p);
|
||||
}
|
||||
|
||||
export function refreshAccountList() {
|
||||
function refreshAccountList() {
|
||||
accounts.innerHTML = "";
|
||||
getActiveAccounts()
|
||||
.filter(it => it instanceof MojangAccount)
|
||||
@ -139,7 +130,7 @@ export function refreshAccountList() {
|
||||
});
|
||||
}
|
||||
|
||||
export function renderActions() {
|
||||
function renderActions() {
|
||||
actions.innerHTML = "";
|
||||
if (Notification.permission === "default") {
|
||||
actions.innerHTML += '<p><a href="javascript:" id="notificate">Enable notifications</a></p>';
|
||||
@ -197,7 +188,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");
|
||||
@ -219,7 +210,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 +231,7 @@ export function addToast(title, msg) {
|
||||
new bootstrap.Toast(toast).show();
|
||||
}
|
||||
|
||||
export function resetHtml() {
|
||||
function resetHtml() {
|
||||
listening.innerHTML = "";
|
||||
listenVisible = false;
|
||||
renderActions();
|
||||
@ -261,3 +252,528 @@ function ohNo() {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Util
|
||||
function isSuccess(status) {
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
|
||||
function checkFetchSuccess(msg) {
|
||||
return r => {
|
||||
if (!isSuccess(r.status)) throw r.status + " " + msg;
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
function icanhazip(cors) {
|
||||
return fetch((cors ? getCorsProxy() : "") + "https://ipv4.icanhazip.com")
|
||||
.then(checkFetchSuccess("code"))
|
||||
.then(r => r.text())
|
||||
.then(it => it.trim());
|
||||
}
|
||||
|
||||
function icanhazepoch() {
|
||||
return fetch("https://icanhazepoch.com")
|
||||
.then(checkFetchSuccess("code"))
|
||||
.then(r => r.text())
|
||||
.then(it => parseInt(it.trim()))
|
||||
}
|
||||
|
||||
function filterNot(array, item) {
|
||||
return array.filter(it => it !== item);
|
||||
}
|
||||
|
||||
// Notification
|
||||
let notificationCallbacks = {};
|
||||
$(() => {
|
||||
new BroadcastChannel("viaaas-notification")
|
||||
.addEventListener("message", handleSWMsg);
|
||||
})
|
||||
|
||||
function handleSWMsg(event) {
|
||||
console.log("sw msg: " + event);
|
||||
let data = event.data;
|
||||
let callback = notificationCallbacks[data.tag];
|
||||
delete notificationCallbacks[data.tag];
|
||||
if (callback == null) return;
|
||||
callback(data.action);
|
||||
}
|
||||
|
||||
function authNotification(msg, yes, no) {
|
||||
if (!navigator.serviceWorker || Notification.permission !== "granted") {
|
||||
if (confirm(msg)) yes(); else no();
|
||||
return;
|
||||
}
|
||||
let tag = uuid.v4();
|
||||
navigator.serviceWorker.ready.then(r => {
|
||||
r.showNotification("Click to allow auth impersionation", {
|
||||
body: msg,
|
||||
tag: tag,
|
||||
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") {
|
||||
no();
|
||||
} else if (!action || action === "confirm") {
|
||||
yes();
|
||||
}
|
||||
};
|
||||
setTimeout(() => {
|
||||
delete notificationCallbacks[tag]
|
||||
}, 30 * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// Cors proxy
|
||||
function defaultCors() {
|
||||
return "https://crp123-cors.herokuapp.com/";
|
||||
}
|
||||
|
||||
function getCorsProxy() {
|
||||
return localStorage.getItem("viaaas_cors_proxy") || defaultCors();
|
||||
}
|
||||
|
||||
function setCorsProxy(url) {
|
||||
localStorage.setItem("viaaas_cors_proxy", url);
|
||||
refreshCorsStatus();
|
||||
}
|
||||
|
||||
// Account manager
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(() => loadAccounts());
|
||||
|
||||
function saveRefreshAccounts() {
|
||||
localStorage.setItem("viaaas_mc_accounts", JSON.stringify(getActiveAccounts()))
|
||||
refreshAccountList()
|
||||
}
|
||||
|
||||
function getActiveAccounts() {
|
||||
return activeAccounts;
|
||||
}
|
||||
|
||||
function getMicrosoftUsers() {
|
||||
return (myMSALObj.getAllAccounts() || []).map(it => it.username);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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.selectedProfile.id;
|
||||
saveRefreshAccounts();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 => 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 => 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 => 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 => 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();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function findAccountByMcName(name) {
|
||||
return activeAccounts.find(it => it.name.toLowerCase() === name.toLowerCase());
|
||||
}
|
||||
|
||||
function findAccountByMs(username) {
|
||||
return getActiveAccounts().find(it => it.msUser === username);
|
||||
}
|
||||
|
||||
function addActiveAccount(acc) {
|
||||
activeAccounts.push(acc)
|
||||
saveRefreshAccounts()
|
||||
}
|
||||
|
||||
function loginMc(user, pass) {
|
||||
const clientToken = uuid.v4();
|
||||
fetch(getCorsProxy() + "https://authserver.mojang.com/authenticate", {
|
||||
method: "post",
|
||||
body: JSON.stringify({
|
||||
agent: {name: "Minecraft", version: 1},
|
||||
username: user,
|
||||
password: pass,
|
||||
clientToken: clientToken,
|
||||
}),
|
||||
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));
|
||||
$("#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);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Websocket
|
||||
let wsUrl = getWsUrl();
|
||||
let socket = null;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
function getWsUrl() {
|
||||
return localStorage.getItem("viaaas_ws_url") || defaultWs();
|
||||
}
|
||||
|
||||
function setWsUrl(url) {
|
||||
localStorage.setItem("viaaas_ws_url", url);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// Tokens
|
||||
function saveToken(token) {
|
||||
let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {};
|
||||
let tokens = getTokens();
|
||||
tokens.push(token);
|
||||
hTokens[wsUrl] = tokens;
|
||||
localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens));
|
||||
}
|
||||
|
||||
function removeToken(token) {
|
||||
let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {};
|
||||
let tokens = getTokens();
|
||||
tokens = tokens.filter(it => it !== token);
|
||||
hTokens[wsUrl] = tokens;
|
||||
localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens));
|
||||
}
|
||||
|
||||
function getTokens() {
|
||||
return (JSON.parse(localStorage.getItem("viaaas_tokens")) || {})[wsUrl] || [];
|
||||
}
|
||||
|
||||
// Websocket
|
||||
function listen(token) {
|
||||
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
|
||||
}
|
||||
|
||||
function unlisten(id) {
|
||||
socket.send(JSON.stringify({"action": "unlisten_login_requests", "uuid": id}));
|
||||
}
|
||||
|
||||
function confirmJoin(hash) {
|
||||
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
|
||||
}
|
||||
|
||||
function handleJoinRequest(parsed) {
|
||||
authNotification("Allow auth impersonation from VIAaaS instance?\nAccount: "
|
||||
+ parsed.user + "\nServer Message: \n"
|
||||
+ 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));
|
||||
} else {
|
||||
confirmJoin(parsed.session_hash);
|
||||
addToast("Couldn't find account", "Couldn't find " + parsed.user + ", check Accounts tab");
|
||||
}
|
||||
}, () => confirmJoin(parsed.session_hash));
|
||||
}
|
||||
|
||||
function onSocketMsg(event) {
|
||||
let parsed = JSON.parse(event.data);
|
||||
if (parsed.action === "ad_minecraft_id_login") {
|
||||
setListenVisible(true);
|
||||
renderActions();
|
||||
} 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") {
|
||||
if (parsed.success) {
|
||||
addListeningList(parsed.user, parsed.token);
|
||||
} else {
|
||||
removeToken(parsed.token);
|
||||
}
|
||||
} else if (parsed.action === "session_hash_request") {
|
||||
handleJoinRequest(parsed);
|
||||
}
|
||||
}
|
||||
|
||||
function listenStoredTokens() {
|
||||
getTokens().forEach(listen);
|
||||
}
|
||||
|
||||
function onConnect() {
|
||||
setWsStatus("connected");
|
||||
resetHtml();
|
||||
listenStoredTokens();
|
||||
}
|
||||
|
||||
function onWsError(e) {
|
||||
console.log(e);
|
||||
setWsStatus("socket error");
|
||||
resetHtml();
|
||||
}
|
||||
|
||||
function onDisconnect(evt) {
|
||||
setWsStatus("disconnected with close code " + evt.code + " and reason: " + evt.reason);
|
||||
resetHtml();
|
||||
setTimeout(connect, 5000);
|
||||
}
|
||||
|
||||
function connect() {
|
||||
setWsStatus("connecting...");
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.onerror = onWsError;
|
||||
socket.onopen = onConnect;
|
||||
socket.onclose = onDisconnect
|
||||
socket.onmessage = onSocketMsg;
|
||||
}
|
||||
|
||||
function sendSocket(msg) {
|
||||
if (!socket) {
|
||||
console.error("couldn't send msg, socket isn't set");
|
||||
return
|
||||
}
|
||||
socket.send(msg);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import {getCorsProxy} from "./cors_proxy.js";
|
||||
|
||||
export function isSuccess(status) {
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
|
||||
export function checkFetchSuccess(msg) {
|
||||
return r => {
|
||||
if (!isSuccess(r.status)) throw r.status + " " + msg;
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
export 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() {
|
||||
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);
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
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;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
export function getWsUrl() {
|
||||
return localStorage.getItem("viaaas_ws_url") || defaultWs();
|
||||
}
|
||||
|
||||
export function setWsUrl(url) {
|
||||
localStorage.setItem("viaaas_ws_url", url);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// Tokens
|
||||
export function saveToken(token) {
|
||||
let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {};
|
||||
let tokens = getTokens();
|
||||
tokens.push(token);
|
||||
hTokens[wsUrl] = tokens;
|
||||
localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens));
|
||||
}
|
||||
|
||||
export function removeToken(token) {
|
||||
let hTokens = JSON.parse(localStorage.getItem("viaaas_tokens")) || {};
|
||||
let tokens = getTokens();
|
||||
tokens = tokens.filter(it => it !== token);
|
||||
hTokens[wsUrl] = tokens;
|
||||
localStorage.setItem("viaaas_tokens", JSON.stringify(hTokens));
|
||||
}
|
||||
|
||||
export function getTokens() {
|
||||
return (JSON.parse(localStorage.getItem("viaaas_tokens")) || {})[wsUrl] || [];
|
||||
}
|
||||
|
||||
// Websocket
|
||||
export function listen(token) {
|
||||
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
|
||||
}
|
||||
|
||||
export function unlisten(id) {
|
||||
socket.send(JSON.stringify({"action": "unlisten_login_requests", "uuid": id}));
|
||||
}
|
||||
|
||||
export function confirmJoin(hash) {
|
||||
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
|
||||
}
|
||||
|
||||
function handleJoinRequest(parsed) {
|
||||
authNotification("Allow auth impersonation from VIAaaS instance?\nAccount: "
|
||||
+ parsed.user + "\nServer Message: \n"
|
||||
+ 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));
|
||||
} else {
|
||||
confirmJoin(parsed.session_hash);
|
||||
addToast("Couldn't find account", "Couldn't find " + parsed.user + ", check Accounts tab");
|
||||
}
|
||||
}, () => confirmJoin(parsed.session_hash));
|
||||
}
|
||||
|
||||
function onSocketMsg(event) {
|
||||
let parsed = JSON.parse(event.data);
|
||||
if (parsed.action === "ad_minecraft_id_login") {
|
||||
setListenVisible(true);
|
||||
renderActions();
|
||||
} 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") {
|
||||
if (parsed.success) {
|
||||
addListeningList(parsed.user, parsed.token);
|
||||
} else {
|
||||
removeToken(parsed.token);
|
||||
}
|
||||
} else if (parsed.action === "session_hash_request") {
|
||||
handleJoinRequest(parsed);
|
||||
}
|
||||
}
|
||||
|
||||
export function listenStoredTokens() {
|
||||
getTokens().forEach(listen);
|
||||
}
|
||||
|
||||
function onConnect() {
|
||||
setWsStatus("connected");
|
||||
resetHtml();
|
||||
listenStoredTokens();
|
||||
}
|
||||
|
||||
function onWsError(e) {
|
||||
console.log(e);
|
||||
setWsStatus("socket error");
|
||||
resetHtml();
|
||||
}
|
||||
|
||||
function onDisconnect(evt) {
|
||||
setWsStatus("disconnected with close code " + evt.code + " and reason: " + evt.reason);
|
||||
resetHtml();
|
||||
setTimeout(connect, 5000);
|
||||
}
|
||||
|
||||
export function connect() {
|
||||
setWsStatus("connecting...");
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.onerror = onWsError;
|
||||
socket.onopen = onConnect;
|
||||
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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user