mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-11-21 11:55:15 +01:00
replace minecraft.id with kick code
also simplify text on the web page closes #39
This commit is contained in:
parent
ee58150767
commit
e6676c93d9
@ -13,6 +13,7 @@ import com.viaversion.aas.handler.forward
|
||||
import com.viaversion.aas.handler.setCompression
|
||||
import com.viaversion.aas.util.IntendedState
|
||||
import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.aas.web.TempLoginInfo
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
@ -281,7 +282,8 @@ class LoginState : ConnectionState {
|
||||
frontOnline = info.frontOnline
|
||||
info.backName?.also { backName = info.backName }
|
||||
}
|
||||
if (VIAaaSConfig.forceOnlineMode) frontOnline = true
|
||||
val isLink = backAddress!!.host == "link"
|
||||
if (VIAaaSConfig.forceOnlineMode || isLink) frontOnline = true
|
||||
if (frontOnline != null) {
|
||||
when (frontOnline) {
|
||||
false -> callbackPlayerId.complete(generateOfflinePlayerUuid(frontName))
|
||||
@ -290,6 +292,7 @@ class LoginState : ConnectionState {
|
||||
}
|
||||
val id = callbackPlayerId.await()
|
||||
mcLogger.info("Login: {} {} {}", handler.endRemoteAddress, frontName, id)
|
||||
if (isLink) return@launch handleTempCode(handler, frontName, id)
|
||||
}
|
||||
connectBack(
|
||||
handler,
|
||||
@ -308,6 +311,12 @@ class LoginState : ConnectionState {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleTempCode(handler: MinecraftHandler, name: String, id: UUID) {
|
||||
val info = TempLoginInfo(secureRandom.nextInt().toUInt().toString(36), name, id)
|
||||
AspirinServer.viaWebServer.tempCodes.put(name.lowercase(), info)
|
||||
handler.disconnect("Your temp code is: ${info.tempCode}")
|
||||
}
|
||||
|
||||
override fun disconnect(handler: MinecraftHandler, msg: String) {
|
||||
super.disconnect(handler, msg)
|
||||
|
||||
|
@ -76,7 +76,9 @@ class StatusState : ConnectionState {
|
||||
handler.data.frontChannel.setAutoRead(false)
|
||||
handler.coroutineScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
if (address != null) {
|
||||
if (address?.host == "link") {
|
||||
handler.disconnect("Join to link your account")
|
||||
} else if (address != null) {
|
||||
connectBack(handler, address!!, IntendedState.STATUS)
|
||||
} else {
|
||||
handler.disconnect("VIAaaS")
|
||||
|
5
src/main/kotlin/com/viaversion/aas/web/TempLoginInfo.kt
Normal file
5
src/main/kotlin/com/viaversion/aas/web/TempLoginInfo.kt
Normal file
@ -0,0 +1,5 @@
|
||||
package com.viaversion.aas.web
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class TempLoginInfo(val tempCode: String, val username: String, val id: UUID)
|
@ -9,11 +9,7 @@ import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.websocket.*
|
||||
import kotlinx.coroutines.future.await
|
||||
import java.net.URLEncoder
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
@ -31,7 +27,7 @@ class WebLogin : WebState {
|
||||
|
||||
when (obj["action"].asString) {
|
||||
"offline_login" -> handleOfflineLogin(webClient, msg, obj)
|
||||
"minecraft_id_login" -> handleMcIdLogin(webClient, obj)
|
||||
"temp_code_login" -> handleTempCodeLogin(webClient, obj)
|
||||
"listen_login_requests" -> handleListenLogins(webClient, obj)
|
||||
"unlisten_login_requests" -> handleUnlisten(webClient, obj)
|
||||
"session_hash_response" -> handleSessionResponse(webClient, obj)
|
||||
@ -83,25 +79,22 @@ class WebLogin : WebState {
|
||||
webLogger.info("Token gen: {}: offline {} {}", webClient.id, username, uuid)
|
||||
}
|
||||
|
||||
private suspend fun handleMcIdLogin(webClient: WebClient, obj: JsonObject) {
|
||||
private suspend fun handleTempCodeLogin(webClient: WebClient, obj: JsonObject) {
|
||||
val username = obj["username"].asString
|
||||
val code = obj["code"].asString
|
||||
|
||||
val check = AspirinServer.httpClient.submitForm(
|
||||
"https://api.minecraft.id/gateway/verify/${URLEncoder.encode(username, Charsets.UTF_8)}",
|
||||
formParameters = parametersOf("code", code),
|
||||
).body<JsonObject>()
|
||||
val cacheKey = username.lowercase()
|
||||
val check = webClient.server.tempCodes.getIfPresent(cacheKey)
|
||||
|
||||
if (check["valid"].asBoolean) {
|
||||
val mcIdUser = check["username"].asString
|
||||
val uuid = check["uuid"]?.asString?.let { parseUndashedId(it.replace("-", "")) }
|
||||
?: webClient.server.usernameToIdCache[mcIdUser].await()
|
||||
?: throw StacklessException("Failed to get UUID from minecraft.id")
|
||||
if (check != null && check.tempCode == code) {
|
||||
webClient.server.tempCodes.invalidate(cacheKey)
|
||||
val mcIdUser = check.username
|
||||
val uuid = check.id
|
||||
|
||||
val token = webClient.server.generateToken(uuid, mcIdUser)
|
||||
webClient.ws.sendSerialized(loginSuccessJson(mcIdUser, uuid, token))
|
||||
|
||||
webLogger.info("Token gen: {}: {} {}", webClient.id, mcIdUser, uuid)
|
||||
webLogger.info("Token gen: {}: temp code {} {}", webClient.id, mcIdUser, uuid)
|
||||
} else {
|
||||
webClient.ws.sendSerialized(loginNotSuccess())
|
||||
webLogger.info("Token gen fail: {}: {}", webClient.id, username)
|
||||
|
@ -75,6 +75,9 @@ class WebServer {
|
||||
val minecraftAccessTokens = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(10, TimeUnit.MINUTES)
|
||||
.build<UUID, String>()
|
||||
val tempCodes = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build<String, TempLoginInfo>() // lowercase username
|
||||
|
||||
fun generateToken(account: UUID, username: String): String {
|
||||
return JWT.create()
|
||||
|
@ -97,9 +97,6 @@ frame-src 'self' https://login.microsoftonline.com/ https://login.live.com/"
|
||||
<ul class="list-group" id="listening"></ul>
|
||||
</div>
|
||||
<div id="actions">
|
||||
<button type="button" class="btn btn-primary" id="listen_continue">Listen to <span
|
||||
id="mcIdUsername"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal"
|
||||
data-bs-target="#listenModal"
|
||||
id="listen_open">Listen to logins
|
||||
@ -348,11 +345,7 @@ frame-src 'self' https://login.microsoftonline.com/ https://login.live.com/"
|
||||
<button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>The instance will send impersonation requests to this page. Please note
|
||||
that they're verified by UUID, so offline and online accounts
|
||||
are considered different.</p>
|
||||
<p>VIAaaS will also request the address parameters when they're not specified.
|
||||
They're verified by username. Online-mode listeners have priority.</p>
|
||||
<p>The instance will send auth requests and address parameters to this page.</p>
|
||||
<div class="mb-3">
|
||||
<label for="listen_username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="listen_username">
|
||||
@ -361,6 +354,11 @@ frame-src 'self' https://login.microsoftonline.com/ https://login.live.com/"
|
||||
<input type="checkbox" class="form-check-input" id="listen_online" checked>
|
||||
<label for="listen_online" class="form-check-label">Online Mode</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="listen_code" class="form-label">Temp Code</label>
|
||||
<p>Join <span id="link_address" class="font-monospace"></span> to get the temporary code</p>
|
||||
<input type="text" class="form-control" id="listen_code">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary" data-bs-dismiss="modal">Listen</button>
|
||||
@ -379,12 +377,9 @@ frame-src 'self' https://login.microsoftonline.com/ https://login.live.com/"
|
||||
<button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>The instance will cache your Minecraft access token for some minutes, allowing you to connect
|
||||
<p>The instance will cache your Minecraft access token, usually for some minutes, allowing you to connect
|
||||
without keeping this page open.</p>
|
||||
<p>Note that the access token are valid for ~1 day and a compromised instance may be used to access
|
||||
your account.</p>
|
||||
<p>You'll need to connect as online-mode in the front-end. It's not possible to use the cached
|
||||
token when changing the backend username</p>
|
||||
<p>You'll need to connect as online-mode in the front-end.</p>
|
||||
<div class="input-group mb-3">
|
||||
<label class="input-group-text" for="send_token_user">Account</label>
|
||||
<select class="form-select" id="send_token_user">
|
||||
|
@ -12,4 +12,3 @@ const whitelistedOrigin = [
|
||||
var defaultCorsProxy = "https://cors.re.yt.nom.br/";
|
||||
// Default instance suffix, in format "viaaas.example.com[:25565]", null to use the page hostname;
|
||||
var defaultInstanceSuffix = null;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHlwZXNjcmlwdC9qcy9jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9HQUFvRztBQUNwRyxzRkFBc0Y7QUFDdEYsdURBQXVEO0FBRXZELGtCQUFrQjtBQUNsQixNQUFNLGFBQWEsR0FBVyxzQ0FBc0MsQ0FBQztBQUNyRSxrRkFBa0Y7QUFDbEYsTUFBTSxpQkFBaUIsR0FBYTtJQUNoQywwQkFBMEI7Q0FDN0IsQ0FBQztBQUNGLDRCQUE0QjtBQUM1QixJQUFJLGdCQUFnQixHQUFrQiw0QkFBNEIsQ0FBQztBQUNuRSxrR0FBa0c7QUFDbEcsSUFBSSxxQkFBcUIsR0FBa0IsSUFBSSxDQUFDIn0=
|
File diff suppressed because one or more lines are too long
@ -41,4 +41,3 @@ function listenPoW(e) {
|
||||
postMessage({ id: e.data.id, action: "completed_pow", msg: msg });
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHlwZXNjcmlwdC9qcy93b3JrZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDO0FBQ2IsYUFBYSxDQUFDLHNFQUFzRSxDQUFDLENBQUM7QUFFdEYsSUFBSSxPQUFPLEdBQUcsRUFBRSxDQUFDO0FBRWpCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLEVBQUU7SUFDakMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxZQUFZO1FBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hELElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUTtRQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQzdELENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxhQUFhLENBQUMsRUFBRTtJQUNyQixPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUM5QyxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsQ0FBQztJQUNmLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4QixTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakIsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEVBQUU7SUFDakIsT0FBTyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ2hDLENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxDQUFDO0lBQ2hCLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3ZCLElBQUksR0FBRyxHQUFHLElBQUksQ0FBQztJQUNmLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDaEMsR0FBRztRQUNDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFBRSxPQUFPLENBQUMsWUFBWTtRQUUvQyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUNqQixNQUFNLEVBQUUsZUFBZTtZQUN2QixRQUFRLEVBQUUsSUFBSTtZQUNkLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTO1lBQ25DLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFO1NBQ3RCLENBQUMsQ0FBQztRQUVILElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLE9BQU8sRUFBRTtZQUN2QixVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsT0FBTztTQUNWO0tBQ0osUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUU7SUFFM0MsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNaLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFBRSxPQUFPO1FBQ2xDLFdBQVcsQ0FBQyxFQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsZUFBZSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUMsQ0FBQyxDQUFDO0lBQ3BFLENBQUMsQ0FBQyxDQUFBO0FBQ04sQ0FBQyJ9
|
@ -1,24 +1,6 @@
|
||||
/// <reference path='config.ts' />
|
||||
// Note that some APIs only work on HTTPS
|
||||
|
||||
// Minecraft.id
|
||||
let urlParams = new URLSearchParams();
|
||||
window.location.hash.substring(1).split("?")
|
||||
.map(it => new URLSearchParams(it)
|
||||
.forEach((a, b) => urlParams.append(b, a)));
|
||||
let mcIdUsername = urlParams.get("username");
|
||||
let mcIdCode = urlParams.get("mcauth_code");
|
||||
let mcIdSuccess = urlParams.get("mcauth_success");
|
||||
|
||||
$(() => {
|
||||
if (mcIdSuccess === "false") {
|
||||
addToast("Couldn't authenticate with Minecraft.ID", urlParams.get("mcauth_msg") ?? "");
|
||||
}
|
||||
if (mcIdCode != null) {
|
||||
history.replaceState(null, "", "#");
|
||||
}
|
||||
});
|
||||
|
||||
// Page
|
||||
let connectionStatus = document.getElementById("connection_status")!!;
|
||||
let corsStatus = document.getElementById("cors_status")!!;
|
||||
@ -68,9 +50,10 @@ $(() => {
|
||||
$("#form_listen").on("submit", () => submittedListen());
|
||||
$("#form_send_token").on("submit", () => submittedSendToken());
|
||||
$("#en_notifications").on("click", () => Notification.requestPermission().then(renderActions));
|
||||
$("#listen_continue").on("click", () => clickedListenContinue());
|
||||
$("#address_info_form").on("input", () => generateAddress());
|
||||
$("#generated_address").on("click", () => copyGeneratedAddress());
|
||||
$("#listen_online").on("change", () => updateTempCodeVisibility());
|
||||
$("#link_address").text("link." + instance_suffix_input.value);
|
||||
$(window).on("beforeinstallprompt", e => e.preventDefault());
|
||||
|
||||
ohNo();
|
||||
@ -161,17 +144,16 @@ function generateAddress() {
|
||||
}
|
||||
}
|
||||
|
||||
$("#mcIdUsername").text(mcIdUsername ?? "");
|
||||
|
||||
function submittedListen() {
|
||||
let user = $("#listen_username").val() as string;
|
||||
if (!user) return;
|
||||
if (($("#listen_online")[0] as HTMLInputElement).checked) {
|
||||
let callbackUrl = new URL(location.href);
|
||||
callbackUrl.search = "";
|
||||
callbackUrl.hash = "#username=" + encodeURIComponent(user);
|
||||
location.href = "https://api.minecraft.id/gateway/start/" + encodeURIComponent(user)
|
||||
+ "?callback=" + encodeURIComponent(callbackUrl.toString());
|
||||
sendSocket(JSON.stringify({
|
||||
action: "temp_code_login",
|
||||
username: user,
|
||||
code: $("#listen_code").val()
|
||||
}));
|
||||
// todo
|
||||
} else {
|
||||
let taskId = Math.random();
|
||||
workers.forEach(it => it.postMessage({action: "listen_pow", user: user, id: taskId, deltaTime: deltaTime}));
|
||||
@ -192,19 +174,8 @@ function submittedSendToken() {
|
||||
.catch(e => addToast("Failed to send access token", e));
|
||||
}
|
||||
|
||||
function clickedListenContinue() {
|
||||
sendSocket(JSON.stringify({
|
||||
"action": "minecraft_id_login",
|
||||
"username": mcIdUsername,
|
||||
"code": mcIdCode
|
||||
}));
|
||||
mcIdCode = null;
|
||||
renderActions();
|
||||
}
|
||||
|
||||
function renderActions() {
|
||||
$("#en_notifications").hide();
|
||||
$("#listen_continue").hide();
|
||||
$("#listen_open").hide();
|
||||
$("#send_token_open").hide();
|
||||
|
||||
@ -212,14 +183,20 @@ function renderActions() {
|
||||
$("#en_notifications").show();
|
||||
}
|
||||
if (listenVisible) {
|
||||
if (mcIdUsername != null && mcIdCode != null) {
|
||||
$("#listen_continue").show();
|
||||
}
|
||||
$("#listen_open").show();
|
||||
$("#send_token_open").show();
|
||||
}
|
||||
}
|
||||
|
||||
function updateTempCodeVisibility() {
|
||||
let tmpCode = $("#listen_code");
|
||||
if (($("#listen_online")[0] as HTMLInputElement).checked) {
|
||||
tmpCode.prop("disabled", false);
|
||||
} else {
|
||||
tmpCode.prop("disabled", true);
|
||||
}
|
||||
}
|
||||
|
||||
function onWorkerMsg(e: MessageEvent) {
|
||||
if (e.data.action === "completed_pow") onCompletedPoW(e);
|
||||
}
|
||||
@ -356,22 +333,22 @@ function handleSWMsg(event: MessageEvent) {
|
||||
|
||||
function authNotification(msg: string, yes: () => void, no: () => void) {
|
||||
if (!navigator.serviceWorker || Notification.permission !== "granted") {
|
||||
addToast("Allow auth impersonation?", msg, yes, no);
|
||||
addToast("Allow auth?", msg, yes, no);
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
let tag = uuid.v4();
|
||||
navigator.serviceWorker.ready.then(r => {
|
||||
let options = {
|
||||
body: msg,
|
||||
tag: tag,
|
||||
vibrate: [200, 10, 100, 200, 100, 10, 100, 10, 200],
|
||||
actions: [
|
||||
{action: "reject", title: "Reject"},
|
||||
{action: "confirm", title: "Confirm"}
|
||||
]
|
||||
}
|
||||
r.showNotification("Click to allow auth impersonation", options).then(() => {
|
||||
body: msg,
|
||||
tag: tag,
|
||||
vibrate: [200, 10, 100, 200, 100, 10, 100, 10, 200],
|
||||
actions: [
|
||||
{action: "reject", title: "Reject"},
|
||||
{action: "confirm", title: "Confirm"}
|
||||
]
|
||||
}
|
||||
r.showNotification("Click to allow auth", options).then(() => {
|
||||
});
|
||||
notificationCallbacks.set(tag, action => {
|
||||
if (action === "reject") {
|
||||
@ -704,7 +681,7 @@ function confirmJoin(hash: string) {
|
||||
}
|
||||
|
||||
function handleJoinRequest(parsed: any) {
|
||||
authNotification("Allow auth impersonation from VIAaaS instance?\nAccount: "
|
||||
authNotification("Allow auth from VIAaaS instance?\nAccount: "
|
||||
+ parsed.user + "\nServer Message: \n"
|
||||
+ parsed.message.split(/[\r\n]+/).map((it: string) => "> " + it).join('\n'), () => {
|
||||
let account = findAccountByMcName(parsed.user);
|
||||
|
@ -15,7 +15,6 @@
|
||||
"alwaysStrict": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"inlineSourceMap": true,
|
||||
"outDir": "src/main/resources/web/js"
|
||||
},
|
||||
"include": [
|
||||
|
Loading…
Reference in New Issue
Block a user