diff --git a/src/actions/index.ts b/src/actions/index.ts
index 44c2968..496749e 100644
--- a/src/actions/index.ts
+++ b/src/actions/index.ts
@@ -6,6 +6,7 @@ import { team } from './team.ts';
import { settings } from './settings.ts';
import { feedback } from './feedback.ts';
import { report } from './report.ts';
+import { tools } from './tools.ts';
export const server = {
admin,
@@ -15,5 +16,6 @@ export const server = {
user,
report,
feedback,
- settings
+ settings,
+ tools
};
diff --git a/src/actions/tools.ts b/src/actions/tools.ts
new file mode 100644
index 0000000..3afc5ca
--- /dev/null
+++ b/src/actions/tools.ts
@@ -0,0 +1,57 @@
+import { ActionError, defineAction } from 'astro:actions';
+import { Session } from '@util/session.ts';
+import { Permissions } from '@util/permissions.ts';
+import { z } from 'astro:schema';
+import { getBedrockUuid, getJavaUuid } from '@util/minecraft.ts';
+
+export const tools = {
+ uuidFromUsername: defineAction({
+ input: z.object({
+ edition: z.enum(['java', 'bedrock']),
+ username: z.string()
+ }),
+ handler: async (input, context) => {
+ Session.actionSessionFromCookies(context.cookies, Permissions.Tools);
+
+ let uuid = null;
+ switch (input.edition) {
+ case 'java':
+ try {
+ uuid = await getJavaUuid(input.username);
+ } catch (_) {
+ throw new ActionError({
+ code: 'NOT_FOUND',
+ message: `Der Username ${input.username} existiert nicht`
+ });
+ }
+ if (uuid == null) {
+ throw new ActionError({
+ code: 'BAD_REQUEST',
+ message: `Während der Anfrage zur Mojang API ist ein Fehler aufgetreten`
+ });
+ }
+ break;
+ case 'bedrock':
+ try {
+ uuid = await getBedrockUuid(input.username);
+ } catch (_) {
+ throw new ActionError({
+ code: 'NOT_FOUND',
+ message: `Der Username ${input.username} existiert nicht`
+ });
+ }
+ if (uuid == null) {
+ throw new ActionError({
+ code: 'BAD_REQUEST',
+ message: `Während der Anfrage zum Username Resolver ist ein Fehler aufgetreten`
+ });
+ }
+ break;
+ }
+
+ return {
+ uuid: uuid
+ };
+ }
+ })
+};
diff --git a/src/app/admin/tools/AccountUuidFinder.svelte b/src/app/admin/tools/AccountUuidFinder.svelte
new file mode 100644
index 0000000..c341328
--- /dev/null
+++ b/src/app/admin/tools/AccountUuidFinder.svelte
@@ -0,0 +1,29 @@
+
+
+
diff --git a/src/app/admin/tools/Tools.svelte b/src/app/admin/tools/Tools.svelte
new file mode 100644
index 0000000..1e98dba
--- /dev/null
+++ b/src/app/admin/tools/Tools.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/src/app/admin/tools/tools.ts b/src/app/admin/tools/tools.ts
new file mode 100644
index 0000000..9b9d622
--- /dev/null
+++ b/src/app/admin/tools/tools.ts
@@ -0,0 +1,12 @@
+import { actions } from 'astro:actions';
+import { actionErrorPopup } from '@util/action.ts';
+
+export async function uuidFromUsername(edition: 'java' | 'bedrock', username: string) {
+ const { data, error } = await actions.tools.uuidFromUsername({ edition: edition, username: username });
+ if (error) {
+ actionErrorPopup(error);
+ return null;
+ }
+
+ return data.uuid;
+}
diff --git a/src/layouts/admin/AdminLayout.astro b/src/layouts/admin/AdminLayout.astro
index 20ab456..83ed98c 100644
--- a/src/layouts/admin/AdminLayout.astro
+++ b/src/layouts/admin/AdminLayout.astro
@@ -72,6 +72,12 @@ const adminTabs = [
name: 'Einstellungen',
icon: 'heroicons:adjustments-horizontal',
enabled: session?.permissions.settings
+ },
+ {
+ href: 'admin/tools',
+ name: 'Tools',
+ icon: 'heroicons:wrench-screwdriver',
+ enabled: session?.permissions.tools
}
];
---
diff --git a/src/pages/admin/tools/index.astro b/src/pages/admin/tools/index.astro
new file mode 100644
index 0000000..da7dc1d
--- /dev/null
+++ b/src/pages/admin/tools/index.astro
@@ -0,0 +1,14 @@
+---
+import { Session } from '@util/session';
+import { Permissions } from '@util/permissions';
+import { BASE_PATH } from 'astro:env/server';
+import AdminLayout from '@layouts/admin/AdminLayout.astro';
+import Tools from '@app/admin/tools/Tools.svelte';
+
+const session = Session.sessionFromCookies(Astro.cookies, Permissions.Tools);
+if (!session) return Astro.redirect(`${BASE_PATH}/admin`);
+---
+
+
+
+
diff --git a/src/util/minecraft.ts b/src/util/minecraft.ts
index a14fa3a..c6239a0 100644
--- a/src/util/minecraft.ts
+++ b/src/util/minecraft.ts
@@ -12,3 +12,46 @@ export async function getJavaUuid(username: string) {
// prettier-ignore
return `${id.substring(0, 8)}-${id.substring(8, 12)}-${id.substring(12, 16)}-${id.substring(16, 20)}-${id.substring(20)}`;
}
+
+// https://github.com/carlop3333/XUIDGrabber/blob/main/grabber.js
+export async function getBedrockUuid(username: string): Promise {
+ const initialPageResponse = await fetch('https://cxkes.me/xbox/xuid');
+ const initialPageContent = await initialPageResponse.text();
+ const token = /name="_token"\svalue="(?\w+)"/.exec(initialPageContent)?.groups?.token;
+
+ const cookies = initialPageResponse.headers.get('set-cookie')?.split(' ');
+ if (token === undefined || cookies === undefined || cookies.length < 11) return null;
+
+ const requestBody = new URLSearchParams();
+ requestBody.set('_token', token);
+ requestBody.set('gamertag', username);
+
+ const resultPageResponse = await fetch('https://cxkes.me/xbox/xuid', {
+ method: 'post',
+ body: requestBody,
+ // prettier-ignore
+ headers: {
+ 'Host': 'www.cxkes.me',
+ 'Accept-Encoding': 'gzip, deflate,br',
+ 'Content-Length': Buffer.byteLength(requestBody.toString()).toString(),
+ 'Origin': 'https://www.cxkes.me',
+ 'DNT': '1',
+ 'Connection': 'keep-alive',
+ 'Referer': 'https://www.cxkes.me/xbox/xuid',
+ 'Cookie': `${cookies[0]} ${cookies[10].slice(0, cookies[10].length - 1)}`,
+ 'Upgrade-Insecure-Requests': '1',
+ 'Sec-Fectch-Dest': 'document',
+ 'Sec-Fetch-Mode': 'navigate',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-User': '?1',
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
+ 'Accept-Language': 'en-US,es;q=0.8,en-US;q=0.5,en;q=0.3',
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }
+ });
+ const resultPageContent = await resultPageResponse.text();
+ let xuid: string | undefined;
+ if ((xuid = /id="xuidHex">(?\w+)