From 68ee20f35c927f12bea7ef9db4d2f4ff85dd3aeb Mon Sep 17 00:00:00 2001 From: Nico Meister Date: Mon, 26 Oct 2026 20:47:17 +0100 Subject: [PATCH] =?UTF-8?q?v3.0.8:=20Admin-Pr=C3=BCfung=20mit=20den=20Toke?= =?UTF-8?q?ns=20aus=20dem=20Konto-Dienst=20(lokal=20gelesen,=20per=20HTTPS?= =?UTF-8?q?=20vom=20Server=20gepr=C3=BCft)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- Makefile | 2 +- source/admin.c | 53 ++++++++++++++++++++------------------------------ 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index c69fed0..e71427b 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ SOURCES := source INCLUDES := source # Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer -VERSION := 3.0.7 +VERSION := 3.0.8 APP_TITLE := MBMNET APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk diff --git a/source/admin.c b/source/admin.c index 4ebb560..cc2f3db 100644 --- a/source/admin.c +++ b/source/admin.c @@ -1,8 +1,8 @@ // Entwickler-Werkzeuge nur für Admins - und nur, wenn der Server es gerade bestätigt hat: -// 1. Der Konto-Dienst (act) holt beim MBMNET-Account-Server einen signierten Anmelde-Nachweis (Service-Token) -// für das angemeldete MBMNET-Konto. Den kann nur ausstellen, wer mit diesem Konto angemeldet ist. -// 2. Die App schickt ihn per HTTPS (MBMNET-CA) an /mbmnet/admin-check. Der Server prüft die Signatur und -// antwortet admin=1 nur für Admins. +// 1. Die App liest aus dem Konto-Dienst (act) die Tokens des angemeldeten MBMNET-Kontos. Die hat nur ein 3DS, +// auf dem man sich wirklich mit diesem Konto angemeldet hat (ausgestellt vom MBMNET-Account-Server). +// 2. Sie schickt sie per HTTPS (MBMNET-CA) an /mbmnet/admin-check. Der Server prüft sie gegen seine +// Datenbank und antwortet admin=1 nur für Admins. // Nichts wird gemerkt: Ohne Antwort vom Server (offline, Nintendo aktiv, kein MBMNET-Konto) keine Werkzeuge. #include <3ds.h> #include @@ -12,8 +12,6 @@ #include "https.h" #define OLD_CACHE_FILE "sdmc:/3ds/mbmnet/admin" // gemerkte Antwort älterer Versionen (wird gelöscht) -// Client-ID für den Nachweis (die von Miiverse; der MBMNET-Server nimmt jede) -static char CLIENT_ID[] = "87cd32617f1985439ea608c2746e4610"; static volatile bool isAdmin; static char server[64]; @@ -21,41 +19,32 @@ static char why[96] = "Werkzeuge: kein MBMNET-Konto angemeldet."; // warum (no static Result lastAct; // letzter Fehler von act (für die Wiederholung) static bool wanted; // MBMNET-Konto angemeldet: prüfen -// Holt den Nachweis und lässt ihn prüfen. Läuft im Auffrischen-Thread (main.c) direkt nach dem Konto-Abgleich: -// act bearbeitet nur eine Server-Anfrage auf einmal, gleichzeitig gab es "ungültiger Zustand" (C8A14F4B). +// Liest die Tokens des angemeldeten Kontos aus dem Konto-Dienst (lokal, ohne Server-Anfrage von act) und lässt +// sie vom MBMNET-Server prüfen. Die Tokens hat dieser Server beim Anmelden ausgestellt, er kann sie selbst prüfen. +// (Früher: Service-Token über act angefordert - act lehnte das mit "ungültiger Zustand" ab, C8A14F4B.) static void check_once(void) { - // 1. Anmelde-Nachweis vom Konto-Dienst (für das gerade angemeldete Konto). "shared": danach für jeden - // Prozess abholbar - nur für diesen Prozess angefordert, gab act ihn nicht heraus (E0A14CCE). - Handle done; - snprintf(why, sizeof(why), "Werkzeuge: Server prüft noch ..."); - if (R_FAILED(svcCreateEvent(&done, RESET_ONESHOT))) return; - u32 pid = 0; - svcGetProcessId(&pid, CUR_PROCESS_HANDLE); - Result rc = ACT_AcquireIndependentServiceToken(0xFE, CLIENT_ID, 0, false, true, pid, done); - Result wait = R_SUCCEEDED(rc) ? svcWaitSynchronization(done, 15ULL * 1000 * 1000 * 1000) : rc; - svcCloseHandle(done); lastAct = 0; - if (wait != 0) { lastAct = wait; snprintf(why, sizeof(why), "Werkzeuge: Anmelde-Nachweis nicht erhalten (%08lX).", (unsigned long)wait); return; } - // Ergebnis der Anfrage beim Account-Server (z. B. abgelehnt oder keine Verbindung) - Result result = ACT_GetLastResponseResult(); - static IndependentServiceTokenV1 tok; - memset(&tok, 0, sizeof(tok)); - rc = ACT_GetIndependentServiceToken(&tok); - // Notlösung: aus dem Zwischenspeicher von act (gerade eben geholt) - if (R_FAILED(rc) || !tok.token[0]) rc = ACT_GetCachedIndependentServiceToken(&tok, 0xFE, CLIENT_ID, 3600, false, true); - if (R_FAILED(rc) || !tok.token[0]) { - lastAct = R_FAILED(result) ? result : rc; - snprintf(why, sizeof(why), "Werkzeuge: kein Anmelde-Nachweis vom Server (%08lX).", (unsigned long)lastAct); + u8 slot = 0; + ACT_GetCommonInfo(&slot, sizeof(slot), INFO_TYPE_COMMON_CURRENT_ACCOUNT_SLOT); + static AccountAccessToken at; + memset(&at, 0, sizeof(at)); + Result rc = ACT_GetAccountInfo(&at, sizeof(at), slot, INFO_TYPE_ACCOUNT_ACCESS_TOKEN); + if (R_FAILED(rc) || (!at.accessToken[0] && !at.refreshToken[0])) { + lastAct = rc; + snprintf(why, sizeof(why), "Werkzeuge: keine Anmeldung im Konto-Dienst (%08lX).\nEinmal online gehen und neu öffnen.", (unsigned long)rc); return; } + static char tokens[0x50]; + snprintf(tokens, sizeof(tokens), "%s %s", at.accessToken[0] ? at.accessToken : "-", at.refreshToken); + memset(&at, 0, sizeof(at)); - // 2. Vom Server prüfen lassen (nur HTTPS) + // Vom Server prüfen lassen (nur HTTPS, MBMNET-CA) char body[32]; u32 len = 0; Result hrc = 0; - u32 code = https_request(server, "/mbmnet/admin-check", NULL, "X-Service-Token", tok.token, body, sizeof(body), &len, NULL, 0, &hrc); - memset(&tok, 0, sizeof(tok)); + u32 code = https_request(server, "/mbmnet/admin-check", NULL, "X-NN-Tokens", tokens, body, sizeof(body), &len, NULL, 0, &hrc); + memset(tokens, 0, sizeof(tokens)); isAdmin = code == 200 && strncmp(body, "admin=1", 7) == 0; if (isAdmin) why[0] = 0; else if (code == 200) snprintf(why, sizeof(why), "Werkzeuge gibt es nur für Admins.");