mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-11-22 12:05:45 +01:00
wip microsoft account login
This commit is contained in:
parent
5a3ff3b073
commit
8a61235db7
@ -72,126 +72,6 @@ class ViaWebApp {
|
||||
}
|
||||
}
|
||||
|
||||
// todo xbox auth
|
||||
/*
|
||||
val redirectUrl = "https://localhost:25543/xbox-auth/ms-callback"
|
||||
val siteKey = "9e95fd56-0f45-42f9-af28-9b803645da22"
|
||||
val secretKey = "redacted"
|
||||
val azureClientId = "a370fff9-7648-4dbf-b96e-2b4f8d539ac2"
|
||||
val azureClientSecret = "redacted"
|
||||
|
||||
get("/xbox-auth/") {
|
||||
call.respondText(contentType = ContentType.parse("text/html")) {
|
||||
"""<script src="https://hcaptcha.com/1/api.js"></script>
|
||||
<form action="/xbox-auth/ms-login" method="POST" id="form">
|
||||
<div class="h-captcha" data-sitekey="$siteKey" data-callback="hc"></div>
|
||||
</form>
|
||||
<script>function hc() { document.getElementById("form").submit(); }
|
||||
window.onload = () => hcaptcha.execute();</script>
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val validTokens = Collections.newSetFromMap<UUID>(ConcurrentHashMap())
|
||||
|
||||
post("/xbox-auth/ms-login") {
|
||||
val multipart = call.receiveParameters()
|
||||
|
||||
val hcaptchaResponse = httpClient.submitForm<JsonObject>(
|
||||
"https://hcaptcha.com/siteverify",
|
||||
parametersOf(
|
||||
"response" to listOf(multipart["h-captcha-response"]!!),
|
||||
"secret" to listOf(secretKey),
|
||||
"siteKey" to listOf(siteKey)
|
||||
)
|
||||
)
|
||||
|
||||
if (!hcaptchaResponse.get("success").asBoolean) {
|
||||
call.respondText(status = HttpStatusCode.Forbidden) { "hcaptcha failed" }
|
||||
return@post
|
||||
}
|
||||
|
||||
call.respondRedirect(permanent = false) {
|
||||
takeFrom(
|
||||
"https://login.live.com/oauth20_authorize.srf" +
|
||||
"?client_id=$azureClientId" +
|
||||
"&response_type=code" +
|
||||
"&redirect_uri=${URLEncoder.encode(redirectUrl, Charsets.UTF_8)}" +
|
||||
"&scope=XboxLive.signin" +
|
||||
"&state=${UUID.randomUUID().also { validTokens.add(it) }}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
get("/xbox-auth/ms-callback") {
|
||||
val authCode = call.request.queryParameters.getOrFail("code")
|
||||
val state = call.request.queryParameters.getOrFail("state")
|
||||
|
||||
if (!validTokens.remove(UUID.fromString(state))) {
|
||||
call.respondText(status = HttpStatusCode.Forbidden) { "failed state token" }
|
||||
return@get
|
||||
}
|
||||
val authToken = httpClient.submitForm<JsonObject>(
|
||||
"https://login.live.com/oauth20_token.srf",
|
||||
parametersOf(
|
||||
"client_id" to listOf(azureClientId),
|
||||
"client_secret" to listOf(azureClientSecret),
|
||||
"code" to listOf(authCode),
|
||||
"grant_type" to listOf("authorization_code"),
|
||||
"redirect_uri" to listOf(redirectUrl)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
val xboxLiveAuthResult = httpClient.post<JsonObject> {
|
||||
url("https://user.auth.xboxlive.com/user/authenticate")
|
||||
body = JsonObject().also {
|
||||
it.add("Properties", JsonObject().also {
|
||||
it.addProperty("AuthMethod", "RPS")
|
||||
it.addProperty("SiteName", "user.auth.xboxlive.com")
|
||||
it.addProperty("RpsTicket", authToken.get("access_token").asString)
|
||||
})
|
||||
it.addProperty("TokenType", "JWT")
|
||||
it.addProperty("RelyingParty", "http://auth.xboxlive.com")
|
||||
}
|
||||
header("content-type", "application/json")
|
||||
header("accept", "application/json")
|
||||
}
|
||||
|
||||
val xstsAuth = httpClient.post<JsonObject> {
|
||||
url("https://xsts.auth.xboxlive.com/xsts/authorize")
|
||||
body = JsonObject().also {
|
||||
it.add("Properties", JsonObject().also {
|
||||
it.addProperty("SandboxId", "RETAIL")
|
||||
it.add(
|
||||
"UserTokens",
|
||||
JsonArray().also { it.add(xboxLiveAuthResult.get("Token").asString) })
|
||||
})
|
||||
it.addProperty("TokenType", "JWT")
|
||||
it.addProperty("RelyingParty", "rp://api.minecraftservices.com/")
|
||||
}
|
||||
header("content-type", "application/json")
|
||||
header("accept", "application/json")
|
||||
}
|
||||
|
||||
val mcToken = httpClient.post<JsonObject> {
|
||||
url("https://api.minecraftservices.com/authentication/login_with_xbox")
|
||||
body = JsonObject().also {
|
||||
it.addProperty(
|
||||
"identityToken",
|
||||
"XBL3.0 x=${
|
||||
xstsAuth.getAsJsonObject("DisplayClaims").getAsJsonArray("xui")
|
||||
.first { it.asJsonObject.has("uhs") }.asJsonObject.get("uhs").asString
|
||||
};${xstsAuth.get("Token").asString}"
|
||||
)
|
||||
}
|
||||
header("content-type", "application/json")
|
||||
header("accept", "application/json")
|
||||
}
|
||||
|
||||
call.respondText { mcToken.get("access_token").asString }
|
||||
} */
|
||||
|
||||
static {
|
||||
defaultResource("index.html", "web")
|
||||
resources("web")
|
||||
|
@ -11,14 +11,15 @@
|
||||
<meta property="og:image" content="https://raw.githubusercontent.com/ViaVersion/ViaVersion/a13c417352298c2269aed8736a76205f0040b705/fabric/src/main/resources/assets/viaversion/textures/squarelogo.png">
|
||||
<meta property="og:type" content="game">
|
||||
<link rel="icon" href="https://raw.githubusercontent.com/ViaVersion/ViaVersion/a13c417352298c2269aed8736a76205f0040b705/fabric/src/main/resources/assets/viaversion/textures/squarelogo.png">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://cdnjs.cloudflare.com/; img-src https://*; connect-src 'self' http://localhost:*/ https: ws: wss:">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://cdnjs.cloudflare.com/ https://alcdn.msauth.net/; img-src https://*; connect-src 'self' http://localhost:*/ https: ws: wss:">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<!-- only accept http from localhost -->
|
||||
<title>VIAaaS Authenticator</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.1/uuid.min.js"></script>
|
||||
<script src="auth.js"></script>
|
||||
<script type="text/javascript" src="https://alcdn.msauth.net/browser/2.0.0-beta.4/js/msal-browser.js" integrity="sha384-7sxY2tN3GMVE5jXH2RL9AdbO6s46vUh9lUid4yNCHJMUzDoj+0N4ve6rLOmR88yN" crossorigin="anonymous"></script>
|
||||
<script src="auth_ms.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="browser_accounts">
|
||||
@ -29,6 +30,8 @@
|
||||
<input type="url" id="cors-proxy" name="cors-proxy" value="">
|
||||
</p></div>
|
||||
<div id="add-account"><form><p>
|
||||
<input id="login_submit_ms" type="button" value="Login with Microsoft">
|
||||
<br>
|
||||
<label for="email">Email/Username:</label>
|
||||
<br>
|
||||
<input type="text" id="email" name="email" value="">
|
||||
@ -50,5 +53,6 @@
|
||||
<hr>
|
||||
<p><span id="content"></span></p>
|
||||
</div>
|
||||
<script src="auth.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,279 +1,308 @@
|
||||
$(() => {
|
||||
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 mcauth_code = urlParams.get("mcauth_code");
|
||||
if (urlParams.get("mcauth_success") == "false") {
|
||||
alert("Couldn't authenticate with Minecraft.ID: " + urlParams.get("mcauth_msg"));
|
||||
}
|
||||
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 mcauth_code = urlParams.get("mcauth_code");
|
||||
if (urlParams.get("mcauth_success") == "false") {
|
||||
alert("Couldn't authenticate with Minecraft.ID: " + urlParams.get("mcauth_msg"));
|
||||
}
|
||||
|
||||
var wsUrl = window.location.host == "viaversion.github.io" ? prompt("VIAaaS instance WS URL") : "wss://" + window.location.host + "/ws";
|
||||
var wsUrl = window.location.host == "viaversion.github.io" ? prompt("VIAaaS instance WS URL") : "wss://" + window.location.host + "/ws";
|
||||
|
||||
var socket = null;
|
||||
var connectionStatus = document.getElementById("connection_status");
|
||||
var content = document.getElementById("content");
|
||||
var acounts = document.getElementById("accounts");
|
||||
var socket = null;
|
||||
var connectionStatus = document.getElementById("connection_status");
|
||||
var content = document.getElementById("content");
|
||||
var acounts = document.getElementById("accounts");
|
||||
|
||||
$("#cors-proxy").on("change", () => localStorage.setItem('cors-proxy', $("#cors-proxy").val()));
|
||||
$("#cors-proxy").val(localStorage.getItem("cors-proxy"));
|
||||
$("#login_submit_mc").on("click", loginMc);
|
||||
function getCorsProxy() {
|
||||
return localStorage.getItem("cors-proxy") || "http://localhost:8080/";
|
||||
}
|
||||
|
||||
function loginMc() {
|
||||
var clientToken = uuid.v4();
|
||||
function loginMc() {
|
||||
var clientToken = uuid.v4();
|
||||
$.ajax({type: "post",
|
||||
url: getCorsProxy() + "https://authserver.mojang.com/authenticate",
|
||||
data: JSON.stringify({
|
||||
agent: {name: "Minecraft", version: 1},
|
||||
username: $("#email").val(),
|
||||
password: $("#password").val(),
|
||||
clientToken: clientToken,
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
storeMcAccount(data.accessToken, data.clientToken, data.selectedProfile.name, data.selectedProfile.id);
|
||||
}).fail(() => alert("Failed to login"));
|
||||
$("#email").val("");
|
||||
$("#password").val("");
|
||||
}
|
||||
|
||||
function storeMcAccount(accessToken, clientToken, name, id) {
|
||||
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
|
||||
let account = {accessToken: accessToken, clientToken: clientToken, name: name, id: id};
|
||||
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 logout(id) {
|
||||
getMcAccounts().filter(it => it.id == id).forEach(it => {
|
||||
$.ajax({type: "post",
|
||||
url: localStorage.getItem("cors-proxy") + "https://authserver.mojang.com/authenticate",
|
||||
data: JSON.stringify({
|
||||
agent: {name: "Minecraft", version: 1},
|
||||
username: $("#email").val(),
|
||||
password: $("#password").val(),
|
||||
clientToken: clientToken,
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
storeMcAccount(data.accessToken, data.clientToken, data.selectedProfile.name, data.selectedProfile.id);
|
||||
}).fail(() => alert("Failed to login"));
|
||||
$("#email").val("");
|
||||
$("#password").val("");
|
||||
}
|
||||
|
||||
function storeMcAccount(accessToken, clientToken, name, id) {
|
||||
let accounts = JSON.parse(localStorage.getItem("mc_accounts")) || [];
|
||||
let account = {accessToken: accessToken, clientToken: clientToken, name: name, id: id};
|
||||
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 logout(id) {
|
||||
getMcAccounts().filter(it => it.id == id).forEach(it => {
|
||||
$.ajax({type: "post",
|
||||
url: localStorage.getItem("cors-proxy") + "https://authserver.mojang.com/invalidate",
|
||||
data: JSON.stringify({
|
||||
accessToken: it.accessToken,
|
||||
clientToken: it.clientToken
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
removeMcAccount(id);
|
||||
}).fail(() => {
|
||||
if (confirm("failed to invalidate token! remove account?")) {
|
||||
removeMcAccount(id);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addMcAccountToList(id, name) {
|
||||
let p = document.createElement("p");
|
||||
let head = document.createElement("img");
|
||||
let n = document.createElement("span");
|
||||
let remove = document.createElement("a");
|
||||
n.innerText = " " + name + " ";
|
||||
remove.innerText = "Remove";
|
||||
remove.href = "#";
|
||||
remove.onclick = () => {
|
||||
logout(id);
|
||||
};
|
||||
head.className = "account_head";
|
||||
head.alt = name + "'s head";
|
||||
head.src = "https://crafthead.net/helm/" + id;
|
||||
p.append(head);
|
||||
p.append(n);
|
||||
p.append(remove);
|
||||
accounts.appendChild(p);
|
||||
}
|
||||
|
||||
function refreshAccountList() {
|
||||
accounts.innerHTML = "";
|
||||
getMcAccounts().forEach(it => addMcAccountToList(it.id, it.name));
|
||||
}
|
||||
|
||||
function refreshAccountIfNeeded(it, doneCallback, failCallback) {
|
||||
$.ajax({type: "post",
|
||||
url: localStorage.getItem("cors-proxy") + "https://authserver.mojang.com/validate",
|
||||
url: getCorsProxy() + "https://authserver.mojang.com/invalidate",
|
||||
data: JSON.stringify({
|
||||
accessToken: it.accessToken,
|
||||
clientToken: it.clientToken
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
})
|
||||
.done(() => doneCallback(it))
|
||||
.fail(() => {
|
||||
// Needs refresh
|
||||
console.log("refreshing " + it.id);
|
||||
$.ajax({type: "post",
|
||||
url: localStorage.getItem("cors-proxy") + "https://authserver.mojang.com/refresh",
|
||||
data: JSON.stringify({
|
||||
accessToken: it.accessToken,
|
||||
clientToken: it.clientToken
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
console.log("refreshed " + data.selectedProfile.id);
|
||||
removeMcAccount(data.selectedProfile.id);
|
||||
doneCallback(storeMcAccount(data.accessToken, data.clientToken, data.selectedProfile.name, data.selectedProfile.id));
|
||||
}).fail(() => {
|
||||
if (confirm("failed to refresh token! remove account?")) {
|
||||
removeMcAccount(it.id);
|
||||
}
|
||||
failCallback();
|
||||
});
|
||||
}).done((data) => {
|
||||
removeMcAccount(id);
|
||||
}).fail(() => {
|
||||
if (confirm("failed to invalidate token! remove account?")) {
|
||||
removeMcAccount(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshAccountList();
|
||||
function addMcAccountToList(id, name) {
|
||||
let p = document.createElement("p");
|
||||
let head = document.createElement("img");
|
||||
let n = document.createElement("span");
|
||||
let remove = document.createElement("a");
|
||||
n.innerText = " " + name + " ";
|
||||
remove.innerText = "Remove";
|
||||
remove.href = "#";
|
||||
remove.onclick = () => {
|
||||
logout(id);
|
||||
};
|
||||
head.className = "account_head";
|
||||
head.alt = name + "'s head";
|
||||
head.src = "https://crafthead.net/helm/" + id;
|
||||
p.append(head);
|
||||
p.append(n);
|
||||
p.append(remove);
|
||||
accounts.appendChild(p);
|
||||
}
|
||||
|
||||
function listen(token) {
|
||||
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
|
||||
}
|
||||
function addMsAccountToList(id, name, msUser) {
|
||||
let p = document.createElement("p");
|
||||
let head = document.createElement("img");
|
||||
let n = document.createElement("span");
|
||||
let remove = document.createElement("a");
|
||||
n.innerText = " " + name + "(MS: " + msUser + ") ";
|
||||
remove.innerText = "Logout";
|
||||
remove.href = "#";
|
||||
remove.onclick = () => {
|
||||
signOut(msUser);
|
||||
};
|
||||
head.className = "account_head";
|
||||
head.alt = name + "'s head";
|
||||
head.src = "https://crafthead.net/helm/" + id;
|
||||
p.append(head);
|
||||
p.append(n);
|
||||
p.append(remove);
|
||||
accounts.appendChild(p);
|
||||
}
|
||||
|
||||
function confirmJoin(hash) {
|
||||
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
|
||||
}
|
||||
function refreshAccountList() {
|
||||
accounts.innerHTML = "";
|
||||
getMcAccounts().forEach(it => addMcAccountToList(it.id, it.name));
|
||||
(myMSALObj.getAllAccounts() || []).forEach(it => addMsAccountToList("TODO", "TODO", it.username))
|
||||
}
|
||||
|
||||
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 refreshAccountIfNeeded(it, doneCallback, failCallback) {
|
||||
$.ajax({type: "post",
|
||||
url: getCorsProxy() + "https://authserver.mojang.com/validate",
|
||||
data: JSON.stringify({
|
||||
accessToken: it.accessToken,
|
||||
clientToken: it.clientToken
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
})
|
||||
.done(() => doneCallback(it))
|
||||
.fail(() => {
|
||||
// Needs refresh
|
||||
console.log("refreshing " + it.id);
|
||||
$.ajax({type: "post",
|
||||
url: getCorsProxy() + "https://authserver.mojang.com/refresh",
|
||||
data: JSON.stringify({
|
||||
accessToken: it.accessToken,
|
||||
clientToken: it.clientToken
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
console.log("refreshed " + data.selectedProfile.id);
|
||||
removeMcAccount(data.selectedProfile.id);
|
||||
doneCallback(storeMcAccount(data.accessToken, data.clientToken, data.selectedProfile.name, data.selectedProfile.id));
|
||||
}).fail(() => {
|
||||
if (confirm("failed to refresh token! remove account?")) {
|
||||
removeMcAccount(it.id);
|
||||
}
|
||||
failCallback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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 listen(token) {
|
||||
socket.send(JSON.stringify({"action": "listen_login_requests", "token": token}));
|
||||
}
|
||||
|
||||
function getTokens() {
|
||||
return (JSON.parse(localStorage.getItem("tokens")) || {})[wsUrl] || [];
|
||||
}
|
||||
function confirmJoin(hash) {
|
||||
socket.send(JSON.stringify({action: "session_hash_response", session_hash: hash}));
|
||||
}
|
||||
|
||||
function showListenAccount() {
|
||||
if (username != null && mcauth_code != null) {
|
||||
let p = document.createElement("p");
|
||||
let add = document.createElement("a");
|
||||
p.appendChild(add);
|
||||
add.innerText = "Listen to " + username;
|
||||
add.href = "#";
|
||||
add.onclick = () => {
|
||||
socket.send(JSON.stringify({
|
||||
"action": "minecraft_id_login",
|
||||
"username": username,
|
||||
"code": mcauth_code}));
|
||||
};
|
||||
content.appendChild(p);
|
||||
}
|
||||
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 showListenAccount() {
|
||||
if (username != null && mcauth_code != null) {
|
||||
let p = document.createElement("p");
|
||||
let link = document.createElement("a");
|
||||
p.appendChild(link);
|
||||
link.innerText = "Listen to username in VIAaaS instance";
|
||||
link.href = "#";
|
||||
link.onclick = () => {
|
||||
let user = prompt("Username (Minecraft.ID is case-sensitive): ", "");
|
||||
let callbackUrl = new URL(location.origin + location.pathname + "#username=" + encodeURIComponent(user));
|
||||
location = "https://api.minecraft.id/gateway/start/" + encodeURIComponent(user) + "?callback=" + encodeURIComponent(callbackUrl);
|
||||
let add = document.createElement("a");
|
||||
p.appendChild(add);
|
||||
add.innerText = "Listen to " + username;
|
||||
add.href = "#";
|
||||
add.onclick = () => {
|
||||
socket.send(JSON.stringify({
|
||||
"action": "minecraft_id_login",
|
||||
"username": username,
|
||||
"code": mcauth_code}));
|
||||
};
|
||||
content.appendChild(p);
|
||||
}
|
||||
let p = document.createElement("p");
|
||||
let link = document.createElement("a");
|
||||
p.appendChild(link);
|
||||
link.innerText = "Listen to username in VIAaaS instance";
|
||||
link.href = "#";
|
||||
link.onclick = () => {
|
||||
let user = prompt("Username (Minecraft.ID is case-sensitive): ", "");
|
||||
let callbackUrl = new URL(location.origin + location.pathname + "#username=" + encodeURIComponent(user));
|
||||
location = "https://api.minecraft.id/gateway/start/" + encodeURIComponent(user) + "?callback=" + encodeURIComponent(callbackUrl);
|
||||
};
|
||||
content.appendChild(p);
|
||||
}
|
||||
|
||||
function connect() {
|
||||
connectionStatus.innerText = "connecting...";
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.onerror = e => {
|
||||
console.log(e);
|
||||
connectionStatus.innerText = "socket error";
|
||||
content.innerHTML = "";
|
||||
};
|
||||
|
||||
socket.onopen = () => {
|
||||
connectionStatus.innerText = "connected";
|
||||
content.innerHTML = "";
|
||||
|
||||
getTokens().forEach(listen);
|
||||
};
|
||||
|
||||
socket.onclose = evt => {
|
||||
connectionStatus.innerText = "disconnected with close code " + evt.code + " and reason: " + evt.reason;
|
||||
content.innerHTML = "";
|
||||
setTimeout(connect, 5000);
|
||||
};
|
||||
|
||||
socket.onmessage = event => {
|
||||
console.log(event.data.toString());
|
||||
let parsed = JSON.parse(event.data);
|
||||
if (parsed.action == "ad_minecraft_id_login") {
|
||||
showListenAccount();
|
||||
} else if (parsed.action == "minecraft_id_result") {
|
||||
if (!parsed.success) {
|
||||
alert("VIAaaS instance couldn't verify account via Minecraft.ID");
|
||||
} else {
|
||||
listen(parsed.token);
|
||||
saveToken(parsed.token);
|
||||
}
|
||||
} else if (parsed.action == "listen_login_requests_result") {
|
||||
if (parsed.success) {
|
||||
let msg = document.createElement("p");
|
||||
msg.innerText = "Listening to login: " + parsed.user;
|
||||
content.appendChild(msg);
|
||||
} 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 = getMcAccounts().reverse().find(it => it.name.toLowerCase() == parsed.user.toLowerCase());
|
||||
if (account) {
|
||||
refreshAccountIfNeeded(account, (data) => {
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: localStorage.getItem("cors-proxy") + "https://sessionserver.mojang.com/session/minecraft/join",
|
||||
data: JSON.stringify({
|
||||
accessToken: data.accessToken,
|
||||
selectedProfile: data.id,
|
||||
serverId: parsed.session_hash
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
confirmJoin(parsed.session_hash);
|
||||
}).fail((e) => {
|
||||
console.log(e);
|
||||
confirmJoin(parsed.session_hash);
|
||||
alert("Failed to contact session server!");
|
||||
});
|
||||
}, () => {
|
||||
confirmJoin(parsed.session_hash);
|
||||
alert("Couldn't refresh " + parsed.user + " account in browser.");
|
||||
});
|
||||
} else {
|
||||
alert("Couldn't find " + parsed.user + " account in browser.");
|
||||
function onSocketMsg(event) {
|
||||
console.log(event.data.toString());
|
||||
let parsed = JSON.parse(event.data);
|
||||
if (parsed.action == "ad_minecraft_id_login") {
|
||||
showListenAccount();
|
||||
} else if (parsed.action == "minecraft_id_result") {
|
||||
if (!parsed.success) {
|
||||
alert("VIAaaS instance couldn't verify account via Minecraft.ID");
|
||||
} else {
|
||||
listen(parsed.token);
|
||||
saveToken(parsed.token);
|
||||
}
|
||||
} else if (parsed.action == "listen_login_requests_result") {
|
||||
if (parsed.success) {
|
||||
let msg = document.createElement("p");
|
||||
msg.innerText = "Listening to login: " + parsed.user;
|
||||
content.appendChild(msg);
|
||||
} 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 = getMcAccounts().reverse().find(it => it.name.toLowerCase() == parsed.user.toLowerCase());
|
||||
if (account) {
|
||||
refreshAccountIfNeeded(account, (data) => {
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: getCorsProxy() + "https://sessionserver.mojang.com/session/minecraft/join",
|
||||
data: JSON.stringify({
|
||||
accessToken: data.accessToken,
|
||||
selectedProfile: data.id,
|
||||
serverId: parsed.session_hash
|
||||
}),
|
||||
contentType: "application/json",
|
||||
dataType: "json"
|
||||
}).done((data) => {
|
||||
confirmJoin(parsed.session_hash);
|
||||
}
|
||||
} else if (confirm("Continue without authentication (works on LAN worlds)?")) {
|
||||
}).fail((e) => {
|
||||
console.log(e);
|
||||
confirmJoin(parsed.session_hash);
|
||||
alert("Failed to contact session server!");
|
||||
});
|
||||
}, () => {
|
||||
confirmJoin(parsed.session_hash);
|
||||
}
|
||||
alert("Couldn't refresh " + parsed.user + " account in browser.");
|
||||
});
|
||||
} else {
|
||||
alert("Couldn't find " + parsed.user + " account in browser.");
|
||||
confirmJoin(parsed.session_hash);
|
||||
}
|
||||
};
|
||||
} else if (confirm("Continue without authentication (works on LAN worlds)?")) {
|
||||
confirmJoin(parsed.session_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connect() {
|
||||
connectionStatus.innerText = "connecting...";
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.onerror = e => {
|
||||
console.log(e);
|
||||
connectionStatus.innerText = "socket error";
|
||||
content.innerHTML = "";
|
||||
};
|
||||
|
||||
socket.onopen = () => {
|
||||
connectionStatus.innerText = "connected";
|
||||
content.innerHTML = "";
|
||||
|
||||
getTokens().forEach(listen);
|
||||
};
|
||||
|
||||
socket.onclose = evt => {
|
||||
connectionStatus.innerText = "disconnected with close code " + evt.code + " and reason: " + evt.reason;
|
||||
content.innerHTML = "";
|
||||
setTimeout(connect, 5000);
|
||||
};
|
||||
|
||||
socket.onmessage = onSocketMsg;
|
||||
}
|
||||
|
||||
|
||||
$(() => {
|
||||
$("#cors-proxy").on("change", () => localStorage.setItem('cors-proxy', $("#cors-proxy").val()));
|
||||
$("#cors-proxy").val(getCorsProxy());
|
||||
$("#login_submit_mc").on("click", loginMc);
|
||||
$("#login_submit_ms").on("click", loginMs);
|
||||
|
||||
refreshAccountList();
|
||||
|
||||
connect();
|
||||
});
|
||||
|
84
src/main/resources/web/auth_ms.js
Normal file
84
src/main/resources/web/auth_ms.js
Normal file
@ -0,0 +1,84 @@
|
||||
// https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-javascript-auth-code
|
||||
|
||||
// Config object to be passed to Msal on creation
|
||||
const msalConfig = {
|
||||
auth: {
|
||||
clientId: "a370fff9-7648-4dbf-b96e-2b4f8d539ac2",
|
||||
authority: "https://login.microsoftonline.com/consumers/",
|
||||
redirectUri: new URL(location.origin + location.pathname).toString(),
|
||||
},
|
||||
cache: {
|
||||
cacheLocation: "sessionStorage", // This configures where your cache will be stored
|
||||
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
|
||||
}
|
||||
};
|
||||
|
||||
const myMSALObj = new msal.PublicClientApplication(msalConfig);
|
||||
|
||||
// Add scopes for the id token to be used at Microsoft identity platform endpoints.
|
||||
const loginRequest = {
|
||||
scopes: ["XboxLive.signin"]
|
||||
};
|
||||
|
||||
function loginMs() {
|
||||
myMSALObj.loginPopup(loginRequest).then(response => refreshAccountList());
|
||||
}
|
||||
|
||||
function getMcToken(username) {
|
||||
return getTokenPopup(username, loginRequest)
|
||||
.then((response) => {
|
||||
// this supports CORS
|
||||
return fetch("https://user.auth.xboxlive.com/user/authenticate", {method: "post",
|
||||
data: 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(xboxResponse => {
|
||||
if (xboxResponse != 200) throw "xbox response not 200: " + xboxResponse;
|
||||
// We need CORS proxy
|
||||
return fetch(getCorsProxy() + "https://xsts.auth.xboxlive.com/xsts/authorize", {method: "post",
|
||||
data: JSON.stringify({"Properties": {"SandboxId": "RETAIL", "UserTokens": [xboxResponse.json().Token]},
|
||||
"RelyingParty": "rp://api.minecraftservices.com/", "TokenType": "JWT"}),
|
||||
headers: {"content-type": "application/json"}});
|
||||
}).then(xstsResponse => {
|
||||
// Need CORS proxy here too
|
||||
return fetch(getCorsProxy() + "https://api.minecraftservices.com/authentication/login_with_xbox", {
|
||||
data: JSON.stringify({"identityToken": "XBL3.0 x=" + xstsResponse.json().DisplayClaims.xui.uhs + ";"
|
||||
+ xstsResponse.json().Token}), headers: {"content-type": "application/json"}});
|
||||
}).then(mcResponse => {
|
||||
console.log(mcResponse); // finally!!!.. todo
|
||||
return mcResponse;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
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. acquiring token using redirect");
|
||||
if (error instanceof msal.InteractionRequiredAuthError) {
|
||||
// fallback to interaction when silent call fails
|
||||
return myMSALObj.acquireTokenPopup(request).then(tokenResponse => {
|
||||
console.log(tokenResponse);
|
||||
|
||||
return tokenResponse;
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
} else {
|
||||
console.warn(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function signOut(username) {
|
||||
const logoutRequest = {
|
||||
account: myMSALObj.getAccountByUsername(username)
|
||||
};
|
||||
|
||||
myMSALObj.logout(logoutRequest);
|
||||
}
|
Loading…
Reference in New Issue
Block a user