diff --git a/launcher/pom.xml b/launcher/pom.xml
index a08d5b7..1e2bee9 100644
--- a/launcher/pom.xml
+++ b/launcher/pom.xml
@@ -13,6 +13,9 @@
21
21
UTF-8
+ ZernMC
+ 2026
+ ZernMC Launcher - just a minimalistic launcher by SashegDev
me.sashegdev.zernmc.launcher.Main
diff --git a/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java b/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
index 508ea7d..b88c960 100644
--- a/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
+++ b/launcher/src/main/java/me/sashegdev/zernmc/launcher/auth/AuthManager.java
@@ -1,44 +1,40 @@
package me.sashegdev.zernmc.launcher.auth;
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import me.sashegdev.zernmc.launcher.utils.Config;
import me.sashegdev.zernmc.launcher.utils.ZAnsi;
import me.sashegdev.zernmc.launcher.utils.ZHttpClient;
import java.io.IOException;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.time.Duration;
import java.util.List;
public class AuthManager {
private static final Path AUTH_FILE = Config.getConfigDir().resolve("auth.json");
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
- private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
- .connectTimeout(Duration.ofSeconds(15))
- .build();
private static volatile AuthSession session = null;
private static volatile UserInfo userInfo = null;
- // === Роли (для совместимости) ===
+ // === Роли ===
public static final int ROLE_USER = 0;
public static final int ROLE_PASS_HOLDER = 1;
public static final int ROLE_MODERATOR = 2;
public static final int ROLE_ELDER = 3;
public static final int ROLE_CREATOR = 4;
- // === Права доступа (синхронизировано с сервером) ===
+ // === Права доступа ===
public static final String PERM_VIEW_PACKS = "view_packs";
public static final String PERM_DOWNLOAD_PACK = "download_pack";
- public static final String PERM_REQUEST_PASS = "request_pass";
public static boolean loadSavedSession() {
if (!Files.exists(AUTH_FILE)) return false;
@@ -48,10 +44,7 @@ public class AuthManager {
if (loaded == null || loaded.accessToken == null) return false;
session = loaded;
-
- if (session.username != null) {
- userInfo = fetchUserInfo();
- }
+ userInfo = fetchUserInfo();
if (isAccessTokenExpired()) {
return tryRefresh();
@@ -62,6 +55,7 @@ public class AuthManager {
}
}
+ // ====================== АВТОРИЗАЦИЯ ======================
public static AuthResult login(String username, String password) {
return authRequest("/auth/login", username, password);
}
@@ -72,36 +66,22 @@ public class AuthManager {
private static AuthResult authRequest(String endpoint, String username, String password) {
try {
- JsonObject body = new JsonObject();
- body.addProperty("username", username);
- body.addProperty("password", password);
+ String body = GSON.toJson(new LoginRequest(username, password));
+ SimpleHttpResponse resp = post(endpoint, body);
- String jsonBody = GSON.toJson(body);
-
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(ZHttpClient.getBaseUrl() + endpoint))
- .timeout(Duration.ofSeconds(15))
- .header("Content-Type", "application/json")
- .header("Accept", "application/json")
- .header("User-Agent", "ZernMC-Launcher/1.0")
- .POST(HttpRequest.BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
- .build();
-
- HttpResponse response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
-
- if (response.statusCode() == 200) {
- session = GSON.fromJson(response.body(), AuthSession.class);
+ if (resp.statusCode() == 200) {
+ session = GSON.fromJson(resp.body(), AuthSession.class);
session.expiresAt = System.currentTimeMillis() / 1000L + session.expiresIn;
saveSession();
-
userInfo = fetchUserInfo();
-
return AuthResult.ok();
+ } else if (resp.statusCode() == 422) {
+ return AuthResult.fail("Ошибка валидации: " + extractError(resp.body()));
} else {
- String error = extractError(response.body());
- return AuthResult.fail(error);
+ return AuthResult.fail(extractError(resp.body()));
}
} catch (Exception e) {
+ e.printStackTrace();
return AuthResult.fail("Ошибка соединения: " + e.getMessage());
}
}
@@ -109,17 +89,7 @@ public class AuthManager {
public static void logout() {
if (session != null && session.refreshToken != null) {
try {
- JsonObject body = new JsonObject();
- body.addProperty("refresh_token", session.refreshToken);
-
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(ZHttpClient.getBaseUrl() + "/auth/logout"))
- .timeout(Duration.ofSeconds(10))
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(body)))
- .build();
-
- HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
+ post("/auth/logout", "{\"refresh_token\":\"" + session.refreshToken + "\"}");
} catch (Exception ignored) {}
}
session = null;
@@ -139,68 +109,12 @@ public class AuthManager {
return session != null ? session.uuid : "00000000-0000-0000-0000-000000000000";
}
- public static int getRole() {
- return session != null ? session.role : ROLE_USER;
- }
-
- public static String getRoleName() {
- return session != null ? session.roleName : "Игрок";
- }
-
- // === Основные проверки ===
- public static boolean hasPass() {
- if (userInfo != null) return userInfo.has_pass;
- return getRole() >= ROLE_PASS_HOLDER;
- }
-
- public static boolean hasPermission(String permission) {
- if (userInfo != null && userInfo.permissions != null) {
- return userInfo.permissions.contains(permission);
- }
- // Fallback на старую систему
- if (PERM_VIEW_PACKS.equals(permission) || PERM_DOWNLOAD_PACK.equals(permission)) {
- return hasPass();
- }
- return false;
- }
-
- public static boolean canViewPacks() {
- return hasPermission(PERM_VIEW_PACKS);
- }
-
- public static boolean canDownloadPacks() {
- return hasPermission(PERM_DOWNLOAD_PACK);
- }
-
public static String getAccessToken() {
- if (session == null) return null;
+ if (session == null) return "0";
if (isAccessTokenExpired()) {
tryRefresh();
}
- return session != null ? session.accessToken : null;
- }
-
- private static UserInfo fetchUserInfo() {
- if (!isLoggedIn()) return null;
-
- try {
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(ZHttpClient.getBaseUrl() + "/admin/me"))
- .timeout(Duration.ofSeconds(10))
- .header("Authorization", "Bearer " + session.accessToken)
- .header("Accept", "application/json")
- .GET()
- .build();
-
- HttpResponse response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
-
- if (response.statusCode() == 200) {
- return GSON.fromJson(response.body(), UserInfo.class);
- }
- } catch (Exception e) {
- System.err.println("Не удалось получить информацию о пользователе: " + e.getMessage());
- }
- return null;
+ return session != null && session.accessToken != null ? session.accessToken : "0";
}
private static boolean isAccessTokenExpired() {
@@ -210,33 +124,19 @@ public class AuthManager {
private static boolean tryRefresh() {
if (session == null || session.refreshToken == null) return false;
-
try {
- JsonObject body = new JsonObject();
- body.addProperty("refresh_token", session.refreshToken);
+ String body = "{\"refresh_token\":\"" + session.refreshToken + "\"}";
+ SimpleHttpResponse resp = post("/auth/refresh", body);
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(ZHttpClient.getBaseUrl() + "/auth/refresh"))
- .timeout(Duration.ofSeconds(15))
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(body)))
- .build();
-
- HttpResponse response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
-
- if (response.statusCode() == 200) {
- JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
- String newAccessToken = json.get("access_token").getAsString();
- int expiresIn = json.get("expires_in").getAsInt();
-
- session.accessToken = newAccessToken;
- session.expiresAt = System.currentTimeMillis() / 1000L + expiresIn;
+ if (resp.statusCode() == 200) {
+ AuthSession newSession = GSON.fromJson(resp.body(), AuthSession.class);
+ newSession.expiresAt = System.currentTimeMillis() / 1000L + newSession.expiresIn;
+ session = newSession;
+ userInfo = fetchUserInfo();
saveSession();
- userInfo = fetchUserInfo(); // обновляем информацию после рефреша
return true;
}
} catch (Exception ignored) {}
-
session = null;
userInfo = null;
try { Files.deleteIfExists(AUTH_FILE); } catch (Exception ignored) {}
@@ -252,19 +152,122 @@ public class AuthManager {
}
}
+ // ==================== ПОЛУЧЕНИЕ ИНФОРМАЦИИ О ПОЛЬЗОВАТЕЛЕ ====================
+ private static UserInfo fetchUserInfo() {
+ if (!isLoggedIn() || session.accessToken == null) return null;
+
+ try {
+ // Используем существующий метод ZHttpClient.get() + вручную добавляем токен
+ java.net.HttpURLConnection conn = null;
+ try {
+ URL url = new URL(ZHttpClient.getBaseUrl() + "/admin/me");
+ conn = (java.net.HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setRequestProperty("Accept", "application/json");
+ conn.setRequestProperty("Authorization", "Bearer " + session.accessToken);
+ conn.setConnectTimeout(10000);
+ conn.setReadTimeout(10000);
+
+ int responseCode = conn.getResponseCode();
+ if (responseCode != 200) return null;
+
+ StringBuilder response = new StringBuilder();
+ try (var reader = new java.io.BufferedReader(
+ new java.io.InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line);
+ }
+ }
+ return GSON.fromJson(response.toString(), UserInfo.class);
+ } finally {
+ if (conn != null) conn.disconnect();
+ }
+ } catch (Exception e) {
+ System.err.println("Не удалось получить UserInfo: " + e.getMessage());
+ return null;
+ }
+ }
+
+ // ==================== ПРОВЕРКИ ПРАВ ====================
+ public static boolean hasPass() {
+ if (userInfo != null) return userInfo.has_pass;
+ return getRole() >= ROLE_PASS_HOLDER;
+ }
+
+ public static boolean canViewPacks() {
+ if (userInfo != null && userInfo.permissions != null) {
+ return userInfo.permissions.contains(PERM_VIEW_PACKS);
+ }
+ return hasPass(); // fallback для старых аккаунтов
+ }
+
+ public static boolean canDownloadPacks() {
+ if (userInfo != null && userInfo.permissions != null) {
+ return userInfo.permissions.contains(PERM_DOWNLOAD_PACK);
+ }
+ return hasPass(); // fallback
+ }
+
+ public static int getRole() {
+ return session != null ? session.role : ROLE_USER;
+ }
+
+ // ====================== POST ======================
+ private static SimpleHttpResponse post(String endpoint, String jsonBody) throws Exception {
+ String fullUrl = ZHttpClient.getBaseUrl() + endpoint;
+ HttpURLConnection conn = null;
+
+ try {
+ URL url = new URL(fullUrl);
+ conn = (HttpURLConnection) url.openConnection();
+
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
+ conn.setRequestProperty("Accept", "application/json");
+ conn.setRequestProperty("User-Agent", "ZernMC-Launcher/1.0");
+ conn.setRequestProperty("Connection", "close");
+
+ if (session != null && session.accessToken != null) {
+ conn.setRequestProperty("Authorization", "Bearer " + session.accessToken);
+ }
+
+ conn.setDoOutput(true);
+ conn.setConnectTimeout(15000);
+ conn.setReadTimeout(15000);
+
+ byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8);
+ conn.setFixedLengthStreamingMode(input.length);
+
+ try (var os = conn.getOutputStream()) {
+ os.write(input);
+ os.flush();
+ }
+
+ int statusCode = conn.getResponseCode();
+ var is = (statusCode >= 200 && statusCode < 300) ? conn.getInputStream() : conn.getErrorStream();
+
+ String responseBody;
+ try (var scanner = new java.util.Scanner(is, StandardCharsets.UTF_8.name())) {
+ responseBody = scanner.useDelimiter("\\A").hasNext() ? scanner.next() : "";
+ }
+
+ return new SimpleHttpResponse(statusCode, responseBody);
+
+ } finally {
+ if (conn != null) conn.disconnect();
+ }
+ }
+
private static String extractError(String body) {
try {
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
if (json.has("detail")) {
if (json.get("detail").isJsonArray()) {
- return json.getAsJsonArray("detail").get(0).getAsJsonObject()
- .get("msg").getAsString();
+ return json.getAsJsonArray("detail").get(0).getAsJsonObject().get("msg").getAsString();
}
return json.get("detail").getAsString();
}
- if (json.has("error")) {
- return json.get("error").getAsString();
- }
} catch (Exception ignored) {}
return body.length() > 200 ? body.substring(0, 200) + "..." : body;
}
@@ -278,7 +281,6 @@ public class AuthManager {
public String username;
public String uuid;
public int role;
- @SerializedName("role_name") public String roleName;
}
public static class UserInfo {
@@ -287,13 +289,20 @@ public class AuthManager {
public String uuid;
public int role;
public String role_name;
- public long created_at;
- public Long last_login;
public boolean has_pass;
public List permissions;
- public boolean hasPermission(String permission) {
- return permissions != null && permissions.contains(permission);
+ public boolean hasPermission(String perm) {
+ return permissions != null && permissions.contains(perm);
+ }
+ }
+
+ private static class LoginRequest {
+ final String username;
+ final String password;
+ LoginRequest(String u, String p) {
+ this.username = u;
+ this.password = p;
}
}
@@ -304,4 +313,18 @@ public class AuthManager {
public static AuthResult ok() { return new AuthResult(true, null); }
public static AuthResult fail(String msg) { return new AuthResult(false, msg); }
}
+}
+
+// ====================== ВСПОМОГАТЕЛЬНЫЙ КЛАСС ======================
+class SimpleHttpResponse {
+ final int statusCode;
+ final String body;
+
+ SimpleHttpResponse(int statusCode, String body) {
+ this.statusCode = statusCode;
+ this.body = body;
+ }
+
+ int statusCode() { return statusCode; }
+ String body() { return body; }
}
\ No newline at end of file