From 6317697154245c447eeee142208367726c9d7bca Mon Sep 17 00:00:00 2001 From: Percs <83934299+Percslol@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:09:44 -0600 Subject: [PATCH] backport ui and auth --- src/auth.ts | 4 +- src/index.ts | 5 +- src/ui.ts | 456 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 280 insertions(+), 185 deletions(-) diff --git a/src/auth.ts b/src/auth.ts index edc0668..df97363 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -19,7 +19,7 @@ export interface CapeInfo extends AccessoryInfo { alias: string; } -const CLIENT_ID = "a370fff9-7648-4dbf-b96e-2b4f8d539ac2"; +const CLIENT_ID = "c36a9fb6-4f2a-41ff-90bd-ae7cc92031eb"; interface OAuthResponse { access_token: string; @@ -268,4 +268,4 @@ export async function joinServer( }), } ); -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 6fb4e83..7f93184 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,18 +6,19 @@ const nativeFetch = fetch; export type AuthStore = { user: UserInfo | null; yggToken: string; - yggRefresh: string; + msToken: string; }; export type TokenStore = { username: string; token: string; + ms: string; }; export let authstore: AuthStore = { user: null, yggToken: "", - yggRefresh: "", + msToken: "", }; if (localStorage["wispcraft_accounts"]) { diff --git a/src/ui.ts b/src/ui.ts index 9817dcb..eeea35e 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,21 +1,21 @@ import { deviceCodeAuth, getProfile, minecraftAuth } from "./auth"; -import { reconnect, set_wisp_server, wisp } from "./connection/epoxy"; +import { reconnect, set_wisp_server } from "./connection/epoxy"; import { authstore, TokenStore } from "."; - -let keydownListeners: Array = []; -const nativeAddEventListener = window.addEventListener; -window.addEventListener = ( - type: string, - listener: EventListenerOrEventListenerObject -) => { - if (type == "keydown") { - keydownListeners.push(listener); - } - nativeAddEventListener(type, listener); -}; +import encodeQR from "@paulmillr/qr"; export function createUI() { - const ui = ` + let keydownListeners: Array = []; + const nativeAddEventListener = window.addEventListener; + window.addEventListener = ( + type: string, + listener: EventListenerOrEventListenerObject, + ) => { + if (type == "keydown") { + keydownListeners.push(listener); + } + nativeAddEventListener(type, listener); + }; + const ui = ` @@ -257,7 +282,7 @@ export function createUI() { Auth -
+

Wisp Server

@@ -271,182 +296,251 @@ export function createUI() {

Microsoft Accounts

+
`; - document.body.insertAdjacentHTML("beforeend", ui); - - const settings = document.querySelector("#settings") as HTMLDivElement; - const auth = document.querySelector("#auth") as HTMLDivElement; - - const settingsTab = document.querySelector( - "#settings_tab" - ) as HTMLSpanElement; - const authTab = document.querySelector("#auth_tab") as HTMLSpanElement; - - const wispInput = document.querySelector("#wisp_url") as HTMLInputElement; - - wispInput.addEventListener("focusin", () => - keydownListeners.map((listener) => - window.removeEventListener("keydown", listener) - ) - ); - - wispInput.addEventListener("focusout", () => - keydownListeners.map((listener) => - nativeAddEventListener("keydown", listener) - ) - ); - const saveButton = document.querySelector( - "#save_button" - ) as HTMLButtonElement; - const saveStatus = document.querySelector( - "#save_status" - ) as HTMLButtonElement; - - const accountSelect = document.querySelector( - "#account_select" - ) as HTMLSelectElement; - const addButton = document.querySelector("#addbutton") as HTMLButtonElement; - const accountStatus = document.querySelector( - "#account_status" - ) as HTMLSpanElement; - - if (localStorage["wispcraft_wispurl"]) { - wispInput.value = localStorage["wispcraft_wispurl"] as string; - } - - if (localStorage["wispcraft_accounts"]) { - const accounts = JSON.parse( - localStorage["wispcraft_accounts"] - ) as TokenStore[]; - for (const account of accounts) { - const option = document.createElement("option"); - option.value = account.username; - option.innerText = account.username; - accountSelect.add(option); - } - } - - if (localStorage["wispcraft_last_used_account"]) { - const option = document.querySelector( - `option[value="${localStorage["wispcraft_last_used_account"]}"]` - ) as HTMLOptionElement; - option.selected = true; - } - - saveButton.onclick = async () => { + document.body.insertAdjacentHTML("beforeend", ui); + + const settings = document.querySelector("#settings") as HTMLDivElement; + const auth = document.querySelector("#auth") as HTMLDivElement; + + const settingsTab = document.querySelector( + "#settings_tab", + ) as HTMLSpanElement; + const authTab = document.querySelector("#auth_tab") as HTMLSpanElement; + + const wispInput = document.querySelector("#wisp_url") as HTMLInputElement; + + wispInput.addEventListener("focusin", () => + keydownListeners.map((listener) => + window.removeEventListener("keydown", listener), + ), + ); + + wispInput.addEventListener("focusout", () => + keydownListeners.map((listener) => + nativeAddEventListener("keydown", listener), + ), + ); + const saveButton = document.querySelector( + "#save_button", + ) as HTMLButtonElement; + const saveStatus = document.querySelector( + "#save_status", + ) as HTMLButtonElement; + + const accountSelect = document.querySelector( + "#account_select", + ) as HTMLSelectElement; + const addButton = document.querySelector("#addbutton") as HTMLButtonElement; + const removeButton = document.querySelector("#removebutton") as HTMLButtonElement; + const accountStatus = document.querySelector( + "#account_status", + ) as HTMLParagraphElement; + + if (localStorage["wispcraft_wispurl"]) { + wispInput.value = localStorage["wispcraft_wispurl"] as string; + } + + if (localStorage["wispcraft_accounts"]) { + const accounts = JSON.parse( + localStorage["wispcraft_accounts"], + ) as TokenStore[]; + for (const account of accounts) { + const option = document.createElement("option"); + option.value = account.username; + option.innerText = account.username; + accountSelect.add(option); + } + } + + if (localStorage["wispcraft_last_used_account"]) { + accountSelect.value = localStorage["wispcraft_last_used_account"]; + } + + saveButton.onclick = async () => { try { const value = wispInput.value; localStorage.setItem("wispcraft_wispurl", value); set_wisp_server(value); await reconnect(); - saveStatus.innerText = `Wisp server set successfully!` + saveStatus.innerText = `Wisp server set successfully!`; } catch (e) { saveStatus.innerText = `An error occured: ${new String(e).toString()}`; } - }; - - settingsTab.onclick = () => { - const tabs = document.querySelectorAll(".tabs span"); - const pages = document.querySelectorAll(".settings-ui .content"); - - for (const tab of tabs) { - tab.classList.remove("selected"); - } - - for (const page of pages) { - page.classList.remove("shown"); - page.classList.add("hidden"); - } - - settings.classList.remove("hidden"); - settings.classList.add("shown"); - settingsTab.classList.add("selected"); - }; - - accountSelect.onchange = async () => { - const accounts = JSON.parse( - localStorage["wispcraft_accounts"] - ) as TokenStore[]; - const account = accounts.find( - (account) => account.username === accountSelect.value - ); - if (account) { - authstore.yggToken = await minecraftAuth(account.token); - authstore.user = await getProfile(authstore.yggToken); - localStorage["wispcraft_last_used_account"] = authstore.user.name; - } - }; - - addButton.onclick = async () => { - try { - addButton.disabled = true; - const codeGenerator = await deviceCodeAuth(); - accountStatus.innerText = `Use code ${codeGenerator.code} for logging in.`; - const auth = window.open( - `https://microsoft.com/link`, - "", - "height=500,width=350" - ); - await codeGenerator.token; - auth?.close(); - - const token = await codeGenerator.token; - authstore.yggToken = await minecraftAuth(token); - authstore.user = await getProfile(authstore.yggToken); - const localAuthStore = localStorage["wispcraft_accounts"]; - if (!localAuthStore) { - localStorage["wispcraft_accounts"] = JSON.stringify([ - { username: authstore.user.name, token }, - ]); - } else { - const accounts = JSON.parse(localAuthStore); - accounts.push({ username: authstore.user.name, token }); - localStorage["wispcraft_accounts"] = JSON.stringify(accounts); - } - const selector = document.createElement("option"); - selector.value = authstore.user.name; - selector.innerText = authstore.user.name; - accountSelect.add(selector); - accountStatus.innerText = ""; - accountSelect.value = authstore.user.name; - addButton.disabled = false; - localStorage["wispcraft_last_used_account"] = authstore.user.name; - } catch (e) { - accountStatus.innerText = `An error occured: ${new String(e).toString()}`; - } - }; - - authTab.onclick = () => { - const tabs = document.querySelectorAll(".tabs span"); - const pages = document.querySelectorAll(".settings-ui .content"); - - for (const tab of tabs) { - tab.classList.remove("selected"); - } - - for (const page of pages) { - page.classList.remove("shown"); - page.classList.add("hidden"); - } - - auth.classList.remove("hidden"); - auth.classList.add("shown"); - authTab.classList.add("selected"); - }; + }; + + settingsTab.onclick = () => { + const tabs = document.querySelectorAll(".tabs span"); + const pages = document.querySelectorAll(".settings-ui .content"); + + for (const tab of tabs) { + tab.classList.remove("selected"); + } + + for (const page of pages) { + page.classList.remove("shown"); + page.classList.add("hidden"); + } + + settings.classList.remove("hidden"); + settings.classList.add("shown"); + settingsTab.classList.add("selected"); + }; + + accountSelect.onchange = async () => { + if (accountSelect.value === "no-account") { + authstore.user = null; + authstore.yggToken = ""; + localStorage["wispcraft_last_used_account"] = "no-account"; + removeButton.disabled = true; + return; + } + const accounts = JSON.parse( + localStorage["wispcraft_accounts"], + ) as TokenStore[]; + const account = accounts.find( + (account) => account.username === accountSelect.value, + ); + if (account) { + try { + try { + authstore.msToken = account.ms; + authstore.yggToken = account.token; + authstore.user = await getProfile(authstore.yggToken); + } catch (e) { + authstore.yggToken = await minecraftAuth(authstore.msToken); + authstore.user = await getProfile(authstore.yggToken); + } + localStorage["wispcraft_last_used_account"] = authstore.user.name; + removeButton.disabled = false; + return; + } catch (e) { + console.error(e); + removeAcc(); + } + } + accountSelect.value = "no-account"; + authstore.user = null; + authstore.yggToken = ""; + localStorage["wispcraft_last_used_account"] = "no-account"; + removeButton.disabled = true; + }; + + const removeAcc = () => { + if (accountSelect.value === "no-account") { + return; + } + const localAuthStore = localStorage["wispcraft_accounts"]; + if (!localAuthStore) { + return; + } + const accounts = JSON.parse(localAuthStore); + const existingAccount = accounts.findIndex((account: { username: string | undefined; }) => account.username === accountSelect.value); + if (existingAccount == -1) { + return; + } + accounts.splice(existingAccount, 1); + localStorage["wispcraft_accounts"] = JSON.stringify(accounts); + accountSelect.remove(accountSelect.selectedIndex); + }; + + removeButton.onclick = removeAcc; + + addButton.onclick = async () => { + try { + addButton.disabled = true; + const codeGenerator = await deviceCodeAuth(); + const linkUrl = "https://microsoft.com/link?otc=" + codeGenerator.code; + const qrSvg = encodeQR(linkUrl, "svg", { + scale: 6, + border: 1 + }); + accountStatus.innerHTML = `Click this link and use code for logging in.

${qrSvg}
`; + const authCodeBox = document.querySelector("#auth_code") as HTMLInputElement; + authCodeBox.onclick = () => { + authCodeBox.select(); + authCodeBox.setSelectionRange(0, authCodeBox.value.length); + navigator.clipboard.writeText(authCodeBox.value); + }; + const auth = window.open( + linkUrl, + "", + "height=500,width=350", + ); + await codeGenerator.token; + auth?.close(); + accountStatus.innerHTML = "Authenticating..."; + + const token = await codeGenerator.token; + authstore.msToken = token; + authstore.yggToken = await minecraftAuth(authstore.msToken); + authstore.user = await getProfile(authstore.yggToken); + const localAuthStore = localStorage["wispcraft_accounts"]; + const newAccEntry = { + username: authstore.user.name, + token: authstore.yggToken, + ms: authstore.msToken + } as TokenStore; + if (!localAuthStore) { + localStorage["wispcraft_accounts"] = JSON.stringify([ + newAccEntry, + ]); + } else { + const accounts = JSON.parse(localAuthStore); + const existingAccount = accounts.findIndex((account: { username: string | undefined; }) => account.username === authstore.user?.name); + if (existingAccount != -1) { + accounts.splice(existingAccount, 1, newAccEntry); + } else { + accounts.push(newAccEntry); + } + localStorage["wispcraft_accounts"] = JSON.stringify(accounts); + } + const selector = document.createElement("option"); + selector.value = authstore.user.name; + selector.innerText = authstore.user.name; + accountSelect.add(selector); + accountStatus.innerHTML = ""; + accountSelect.value = authstore.user.name; + addButton.disabled = false; + localStorage["wispcraft_last_used_account"] = authstore.user.name; + } catch (e) { + accountStatus.innerHTML = `An error occured: ${new String(e).toString()}`; + addButton.disabled = false; + } + }; + + authTab.onclick = () => { + const tabs = document.querySelectorAll(".tabs span"); + const pages = document.querySelectorAll(".settings-ui .content"); + + for (const tab of tabs) { + tab.classList.remove("selected"); + } + + for (const page of pages) { + page.classList.remove("shown"); + page.classList.add("hidden"); + } + + auth.classList.remove("hidden"); + auth.classList.add("shown"); + authTab.classList.add("selected"); + }; } export function showUI() { - const settingsUi = document.querySelector(".settings-ui"); - if (!settingsUi) { - createUI(); - return showUI(); - } - settingsUi.classList.remove("hidden"); - document.querySelector(".backdrop-blur")!.classList.remove("hidden"); -} + const settingsUi = document.querySelector(".settings-ui"); + if (!settingsUi) { + createUI(); + return showUI(); + } + settingsUi.classList.remove("hidden"); + document.querySelector(".backdrop-blur")!.classList.remove("hidden"); +} \ No newline at end of file