From d1bc03664beddc17658f6633733162fd04dc93eb Mon Sep 17 00:00:00 2001 From: BartolomeoDR Date: Sat, 16 Oct 2021 14:27:48 +0300 Subject: [PATCH 1/7] Update Client.java Added ability to customize refCount value of a client --- .../main/java/pro/gravit/launchserver/socket/Client.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java index 4ce6a1ad..382496c8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -36,9 +36,14 @@ public class Client { public Map serializableProperties; - public transient AtomicInteger refCount = new AtomicInteger(1); + public transient AtomicInteger refCount; public Client(UUID session) { + this(session, 1); + } + + public Client(UUID session, int initialRefCount) { + refCount = new AtomicInteger(initialRefCount); this.session = session; timestamp = System.currentTimeMillis(); type = null; From af2155c4bf95bddc2a20584660239e2a54e1d745 Mon Sep 17 00:00:00 2001 From: BartolomeoDR Date: Sat, 16 Oct 2021 14:32:57 +0300 Subject: [PATCH 2/7] [FIX] Fixed user is unable to play after logout Right now refCount value is set to 1, and inside handler.setClient its being incremented to 2. Because of that refCount check never goes to 0, and so current session is never stored ( as only single handler has this client, and not two ). --- .../gravit/launchserver/socket/response/auth/ExitResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java index 94effdc4..82e17f7f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ExitResponse.java @@ -45,7 +45,7 @@ public void execute(ChannelHandlerContext ctx, Client client) { sendError("Exit internal error"); return; } - Client newClient = new Client(null); + Client newClient = new Client(null, 0); newClient.checkSign = client.checkSign; handler.setClient(newClient); AuthSupportExit supportExit = client.auth.core.isSupport(AuthSupportExit.class); From e5b603e2a91e1a6cd5e3b86c2ca58a5e03bf9d4b Mon Sep 17 00:00:00 2001 From: Gravita Date: Sun, 17 Oct 2021 16:53:33 +0700 Subject: [PATCH 3/7] [FEATURE] Use UUID for checkServer token --- .../gravit/launchserver/command/service/TokenCommand.java | 6 +++--- .../pro/gravit/launchserver/manangers/AuthManager.java | 2 +- .../java/pro/gravit/launcher/server/ServerWrapper.java | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java index 646fe1ce..178c2088 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/TokenCommand.java @@ -28,7 +28,7 @@ public void invoke(String... args) throws Exception { AuthProviderPair pair = args.length > 1 ? server.config.getAuthProviderPair(args[1]) : server.config.getAuthProviderPair(); ClientProfile profile = null; for(ClientProfile p : server.getProfiles()) { - if(p.getTitle().equals(args[0])) { + if(p.getTitle().equals(args[0]) || p.getUUID().toString().equals(args[0])) { profile = p; break; } @@ -40,7 +40,7 @@ public void invoke(String... args) throws Exception { logger.error("AuthId {} not found", args[1]); return; } - String token = server.authManager.newCheckServerToken(args[0], pair.name); + String token = server.authManager.newCheckServerToken(profile != null ? profile.getUUID().toString() : args[0], pair.name); logger.info("Server token {} authId {}: {}", args[0], pair.name, token); } }); @@ -48,7 +48,7 @@ public void invoke(String... args) throws Exception { @Override public String getArgsDescription() { - return "[new/info/token name] [args]"; + return "[server/info/token name] [args]"; } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java index 7d3a3960..ce23b57d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -86,7 +86,7 @@ public boolean accept(Client client, AuthProviderPair pair, String extendedToken client.auth = server.config.getAuthProviderPair(info.authId); if(client.permissions == null) client.permissions = new ClientPermissions(); client.permissions.addPerm("launchserver.checkserver"); - client.permissions.addPerm(String.format("launchserver.profiles.%s.show", info.serverName)); + client.permissions.addPerm(String.format("launchserver.profile.%s.show", info.serverName)); return true; } } diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java index b775aa40..22e1f27b 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java @@ -163,7 +163,7 @@ public void run(String... args) throws Throwable { LogHelper.error(e); } }; - LogHelper.info("ServerWrapper: Project %s, LaunchServer address: %s. Title: %s", config.projectname, config.address, Launcher.profile != null ? Launcher.profile.getTitle() : "unknown"); + LogHelper.info("ServerWrapper: LaunchServer address: %s. Title: %s", config.address, Launcher.profile != null ? Launcher.profile.getTitle() : "unknown"); LogHelper.info("Minecraft Version (for profile): %s", wrapper.profile == null ? "unknown" : wrapper.profile.getVersion().name); LogHelper.info("Start Minecraft Server"); LogHelper.debug("Invoke main method %s", mainClass.getName()); @@ -181,8 +181,7 @@ public void run(String... args) throws Throwable { } public void updateLauncherConfig() { - - LauncherConfig cfg = new LauncherConfig(config.address, null, null, new HashMap<>(), config.projectname); + LauncherConfig cfg = new LauncherConfig(config.address, null, null, new HashMap<>(), "ServerWrapper"); Launcher.setConfig(cfg); } @@ -200,7 +199,6 @@ public void setConfig(Config config) { public Config getDefaultConfig() { Config newConfig = new Config(); newConfig.serverName = "your server name"; - newConfig.projectname = "MineCraft"; newConfig.mainclass = ""; newConfig.extendedTokens = new HashMap<>(); newConfig.args = new ArrayList<>(); @@ -211,6 +209,7 @@ public Config getDefaultConfig() { } public static final class Config { + @Deprecated public String projectname; public String address; public String serverName; From 618e981de52ede5d8a5f75fc522876751ccf45da Mon Sep 17 00:00:00 2001 From: Gravita Date: Mon, 18 Oct 2021 14:44:35 +0700 Subject: [PATCH 4/7] [FIX] AuthProviderPair logger is null --- .../java/pro/gravit/launchserver/auth/AuthProviderPair.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java index 28afb86c..ab71c7e7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java @@ -25,6 +25,9 @@ public final class AuthProviderPair { public String displayName; private transient boolean warnOAuthShow = false; + public AuthProviderPair() { + } + public AuthProviderPair(AuthCoreProvider core, TextureProvider textureProvider) { this.core = core; this.textureProvider = textureProvider; From 15da924aa699f7498f63a93767d6ad2fbb282200 Mon Sep 17 00:00:00 2001 From: Gravita Date: Sat, 23 Oct 2021 17:27:08 +0700 Subject: [PATCH 5/7] [FIX] AcceptPasswordVerifier --- .../launchserver/auth/password/AcceptPasswordVerifier.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/AcceptPasswordVerifier.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/AcceptPasswordVerifier.java index 18e56713..d1274d9d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/AcceptPasswordVerifier.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/AcceptPasswordVerifier.java @@ -5,4 +5,9 @@ public class AcceptPasswordVerifier extends PasswordVerifier { public boolean check(String encryptedPassword, String password) { return true; } + + @Override + public String encrypt(String password) { + return ""; + } } From 2a2c2f6b936f19e05620510e7f8e67aacff87dc2 Mon Sep 17 00:00:00 2001 From: Gravita Date: Fri, 5 Nov 2021 22:19:00 +0700 Subject: [PATCH 6/7] [FEATURE] AuthCoreProvider rework --- .../gravit/launchserver/HttpRequester.java | 94 ++++ .../launchserver/auth/AuthException.java | 22 + .../launchserver/auth/AuthProviderPair.java | 25 -- .../auth/core/AuthCoreProvider.java | 91 ++-- .../auth/core/AuthSocialProvider.java | 61 --- .../auth/core/HttpAuthCoreProvider.java | 333 ++++++++++++++ .../auth/core/JsonCoreProvider.java | 410 ------------------ .../auth/core/MemoryAuthCoreProvider.java | 212 +++++++++ .../auth/core/MySQLCoreProvider.java | 66 ++- .../auth/core/RejectAuthCoreProvider.java | 9 +- .../provider/AuthSupportHardware.java | 3 +- .../auth/password/JsonPasswordVerifier.java | 51 ++- .../auth/protect/AdvancedProtectHandler.java | 4 +- .../config/LaunchServerConfig.java | 2 - .../launchserver/manangers/AuthManager.java | 76 +--- .../socket/response/auth/AuthResponse.java | 6 +- .../auth/GetAvailabilityAuthResponse.java | 2 +- build.gradle | 2 +- modules | 2 +- 19 files changed, 822 insertions(+), 649 deletions(-) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java delete mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthSocialProvider.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java delete mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/JsonCoreProvider.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java b/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java new file mode 100644 index 00000000..fae7b1c4 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/HttpRequester.java @@ -0,0 +1,94 @@ +package pro.gravit.launchserver; + +import com.google.gson.JsonElement; +import pro.gravit.launcher.Launcher; +import pro.gravit.launchserver.helper.HttpHelper; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.time.Duration; + +public class HttpRequester { + private transient final HttpClient httpClient = HttpClient.newBuilder().build(); + + public HttpRequester() { + } + + public static class SimpleErrorHandler implements HttpHelper.HttpJsonErrorHandler { + private final Type type; + + private SimpleErrorHandler(Type type) { + this.type = type; + } + + @Override + public HttpHelper.HttpOptional applyJson(JsonElement response, int statusCode) { + if(statusCode < 200 || statusCode >= 300) { + return new HttpHelper.HttpOptional<>(null, Launcher.gsonManager.gson.fromJson(response, SimpleError.class), statusCode); + } + return new HttpHelper.HttpOptional<>(Launcher.gsonManager.gson.fromJson(response, type), null, statusCode); + } + } + + public SimpleErrorHandler makeEH(Class clazz) { + return new SimpleErrorHandler<>(clazz); + } + + public HttpRequest get(String url, String token) { + try { + var requestBuilder = HttpRequest.newBuilder() + .method("GET", HttpRequest.BodyPublishers.noBody()) + .uri(new URI(url)) + .header("Content-Type", "application/json; charset=UTF-8") + .header("Accept", "application/json") + .timeout(Duration.ofMillis(10000)); + if(token != null) { + requestBuilder.header("Authorization", "Bearer ".concat(token)); + } + return requestBuilder.build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public HttpRequest post(String url, T request, String token) { + try { + var requestBuilder = HttpRequest.newBuilder() + .method("POST", HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request))) + .uri(new URI(url)) + .header("Content-Type", "application/json; charset=UTF-8") + .header("Accept", "application/json") + .timeout(Duration.ofMillis(10000)); + if(token != null) { + requestBuilder.header("Authorization", "Bearer ".concat(token)); + } + return requestBuilder.build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public HttpHelper.HttpOptional send(HttpRequest request, Class clazz) throws IOException { + return HttpHelper.send(httpClient, request, makeEH(clazz)); + } + + public static class SimpleError { + public String error; + public int code; + + public SimpleError(String error) { + this.error = error; + } + + @Override + public String toString() { + return "SimpleError{" + + "error='" + error + '\'' + + ", code=" + code + + '}'; + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java index 13a6aae5..83e81014 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthException.java @@ -1,6 +1,10 @@ package pro.gravit.launchserver.auth; +import pro.gravit.launcher.events.request.AuthRequestEvent; + import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; public final class AuthException extends IOException { private static final long serialVersionUID = -2586107832847245863L; @@ -10,6 +14,24 @@ public AuthException(String message) { super(message); } + public static AuthException need2FA() { + return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE); + } + + public static AuthException needMFA(List factors) { + String message = AuthRequestEvent.ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX + .concat(factors.stream().map(String::valueOf).collect(Collectors.joining("."))); + return new AuthException(message); + } + + public static AuthException wrongPassword() { + return new AuthException(AuthRequestEvent.WRONG_PASSWORD_ERROR_MESSAGE); + } + + public static AuthException userNotFound() { + return new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE); + } + @Override public String toString() { return getMessage(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java index ab71c7e7..ff58cc50 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/AuthProviderPair.java @@ -4,7 +4,6 @@ import org.apache.logging.log4j.Logger; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.core.AuthCoreProvider; -import pro.gravit.launchserver.auth.core.AuthSocialProvider; import pro.gravit.launchserver.auth.core.MySQLCoreProvider; import pro.gravit.launchserver.auth.texture.TextureProvider; @@ -17,7 +16,6 @@ public final class AuthProviderPair { private transient final Logger logger = LogManager.getLogger(); public boolean isDefault = true; public AuthCoreProvider core; - public AuthSocialProvider social; public TextureProvider textureProvider; public Map links; public transient String name; @@ -33,17 +31,6 @@ public AuthProviderPair(AuthCoreProvider core, TextureProvider textureProvider) this.textureProvider = textureProvider; } - public AuthProviderPair(AuthCoreProvider core, AuthSocialProvider social) { - this.core = core; - this.social = social; - } - - public AuthProviderPair(AuthCoreProvider core, AuthSocialProvider social, TextureProvider textureProvider) { - this.core = core; - this.social = social; - this.textureProvider = textureProvider; - } - public static Set getFeatures(Class clazz) { Set list = new HashSet<>(); getFeatures(clazz, list); @@ -79,7 +66,6 @@ public static void getFeatures(Class clazz, Set list) { public final T isSupport(Class clazz) { if (core == null) return null; T result = null; - if (social != null) result = social.isSupport(clazz); if (result == null) result = core.isSupport(clazz); return result; } @@ -90,10 +76,6 @@ public final void init(LaunchServer srv, String name) { core.init(srv); features = new HashSet<>(); getFeatures(core.getClass(), features); - if (social != null) { - social.init(srv, core); - getFeatures(social.getClass(), features); - } } public final void link(LaunchServer srv) { @@ -111,16 +93,9 @@ public final void link(LaunchServer srv) { } public final void close() throws IOException { - if (social != null) { - social.close(); - } core.close(); if (textureProvider != null) { textureProvider.close(); } } - - public final boolean isUseSocial() { - return core != null && social != null; - } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java index 58585117..bffceb7e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/AuthCoreProvider.java @@ -45,7 +45,8 @@ public static void registerProviders() { if (!registredProviders) { providers.register("reject", RejectAuthCoreProvider.class); providers.register("mysql", MySQLCoreProvider.class); - providers.register("json", JsonCoreProvider.class); + providers.register("memory", MemoryAuthCoreProvider.class); + providers.register("http", HttpAuthCoreProvider.class); registredProviders = true; } } @@ -62,16 +63,22 @@ public User getUserByLogin(String login) { public abstract AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context /* may be null */); - public abstract void verifyAuth(AuthResponse.AuthContext context) throws AuthException; + public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { + // None + } - public abstract PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password); + public abstract AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context /* may be null */, AuthRequest.AuthPasswordInterface password /* may be null */, boolean minecraftAccess) throws IOException; - public abstract AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context /* may be null */, PasswordVerifyReport report /* may be null */, boolean minecraftAccess) throws IOException; + public AuthManager.AuthReport authorize(User user, AuthResponse.AuthContext context /* may be null */, AuthRequest.AuthPasswordInterface password /* may be null */, boolean minecraftAccess) throws IOException { + return authorize(user.getUsername(), context, password, minecraftAccess); + } public abstract void init(LaunchServer server); // Auth Handler methods - protected abstract boolean updateServerID(User user, String serverID) throws IOException; + protected boolean updateServerID(User user, String serverID) throws IOException { + throw new UnsupportedOperationException(); + } public List getDetails(Client client) { return List.of(new AuthPasswordDetails()); @@ -80,32 +87,28 @@ public List getDetails( @Override public Map getCommands() { Map map = defaultCommandsMap(); - map.put("checkpassword", new SubCommand("[username] [json/plain password data]", "check password") { + map.put("auth", new SubCommand("[login] (json/plain password data)", "Test auth") { @Override public void invoke(String... args) throws Exception { - verifyArgs(args, 2); - User user = getUserByUsername(args[0]); - if (user == null) throw new CommandException("User not found"); - AuthRequest.AuthPasswordInterface password; - if (args[1].startsWith("{")) { - password = Launcher.gsonManager.gson.fromJson(args[1], AuthRequest.AuthPasswordInterface.class); - } else { - password = new AuthPlainPassword(args[1]); - } - PasswordVerifyReport report = verifyPassword(user, password); - if (report.success) { - logger.info("Password correct"); - } else { - if (report.needMoreFactors) { - if (report.factors.size() == 1 && report.factors.get(0) == -1) { - logger.info("Password not correct: Required 2FA"); - } else { - logger.info("Password not correct: Required more factors: {}", report.factors.toString()); - } + verifyArgs(args, 1); + AuthRequest.AuthPasswordInterface password = null; + if(args.length > 1) { + if (args[1].startsWith("{")) { + password = Launcher.gsonManager.gson.fromJson(args[1], AuthRequest.AuthPasswordInterface.class); } else { - logger.info("Password incorrect"); + password = new AuthPlainPassword(args[1]); } } + var report = authorize(args[0], null, password, false); + if (report.isUsingOAuth()) { + logger.info("OAuth: AccessToken: {} RefreshToken: {} MinecraftAccessToken: {}", report.oauthAccessToken(), report.oauthRefreshToken(), report.minecraftAccessToken()); + if (report.session() != null) { + logger.info("UserSession: id {} expire {} user {}", report.session().getID(), report.session().getExpireIn(), report.session().getUser() == null ? "null" : "found"); + logger.info(report.session().toString()); + } + } else { + logger.info("Basic: MinecraftAccessToken: {}", report.minecraftAccessToken()); + } } }); map.put("getuserbyusername", new SubCommand("[username]", "get user by username") { @@ -132,32 +135,6 @@ public void invoke(String... args) throws Exception { } } }); - map.put("createsession", new SubCommand("[username] (true/false)", "create user session with/without minecraft access") { - @Override - public void invoke(String... args) throws Exception { - verifyArgs(args, 1); - User user = getUserByUsername(args[0]); - if (user == null) { - logger.info("User {} not found", args[0]); - return; - } - boolean minecraftAccess = args.length > 1 && Boolean.parseBoolean(args[1]); - AuthManager.AuthReport report = createOAuthSession(user, null, null, minecraftAccess); - if (report == null) { - logger.error("Method createOAuthSession return null"); - return; - } - if (report.isUsingOAuth()) { - logger.info("OAuth: AccessToken: {} RefreshToken: {} MinecraftAccessToken: {}", report.oauthAccessToken(), report.oauthRefreshToken(), report.minecraftAccessToken()); - if (report.session() != null) { - logger.info("UserSession: id {} expire {} user {}", report.session().getID(), report.session().getExpireIn(), report.session().getUser() == null ? "null" : "found"); - logger.info(report.session().toString()); - } - } else { - logger.info("Basic: MinecraftAccessToken: {}", report.minecraftAccessToken()); - } - } - }); { var instance = isSupport(AuthSupportGetAllUsers.class); if (instance != null) { @@ -355,6 +332,12 @@ public PasswordVerifyReport(boolean success) { this.factors = List.of(); } + public PasswordVerifyReport(AuthManager.AuthReport report) { + this.success = true; + this.needMoreFactors = false; + this.factors = List.of(); + } + public PasswordVerifyReport(int nextFactor) { this.success = false; this.needMoreFactors = true; @@ -372,6 +355,10 @@ private PasswordVerifyReport(boolean success, boolean needMoreFactors, List providers = new ProviderMap<>("AuthSocialProvider"); - private static final Logger logger = LogManager.getLogger(); - private static boolean registredProviders = false; - - public static void registerProviders() { - if (!registredProviders) { - registredProviders = true; - } - } - - public abstract void init(LaunchServer server, AuthCoreProvider provider); - - public abstract List getDetails(Client client); - - public abstract SocialResult preAuth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException; - - @SuppressWarnings("unchecked") - public T isSupport(Class clazz) { - if (clazz.isAssignableFrom(getClass())) return (T) this; - return null; - } - - @Override - public abstract void close() throws IOException; - - public static class SocialResult { - public String login; - public AuthRequest.AuthPasswordInterface password; - public User user; - - public SocialResult(String login, AuthRequest.AuthPasswordInterface password, User user) { - this.login = login; - this.password = password; - this.user = user; - } - - public static SocialResult ofLoginAndPassword(String login, AuthRequest.AuthPasswordInterface password) { - return new SocialResult(login, password, null); - } - - public static SocialResult ofUser(User user) { - return new SocialResult(null, null, user); - } - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java new file mode 100644 index 00000000..732f8b95 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java @@ -0,0 +1,333 @@ +package pro.gravit.launchserver.auth.core; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.events.request.AuthRequestEvent; +import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.profiles.Texture; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launchserver.HttpRequester; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures; +import pro.gravit.launchserver.helper.HttpHelper; +import pro.gravit.launchserver.manangers.AuthManager; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.utils.helper.CommonHelper; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class HttpAuthCoreProvider extends AuthCoreProvider { + private transient final Logger logger = LogManager.getLogger(); + private transient HttpRequester requester; + public String bearerToken; + public String getUserByUsernameUrl; + public String getUserByLoginUrl; + public String getUserByUUIDUrl; + public String getUserByTokenUrl; + public String getAuthDetails; + public String refreshTokenUrl; + public String authorizeUrl; + public String joinServerUrl; + public String checkServerUrl; + public String updateServerIdUrl; + @Override + public User getUserByUsername(String username) { + try { + return requester.send(requester.get(CommonHelper.replace(getUserByUsernameUrl, "username", username), null), HttpUser.class).getOrThrow(); + } catch (IOException e) { + logger.error(e); + return null; + } + } + + @Override + public User getUserByLogin(String login) { + if(getUserByLoginUrl != null) { + try { + return requester.send(requester.get(CommonHelper.replace(getUserByLoginUrl, "login", login), null), HttpUser.class).getOrThrow(); + } catch (IOException e) { + logger.error(e); + return null; + } + } + return super.getUserByLogin(login); + } + + @Override + public User getUserByUUID(UUID uuid) { + try { + return requester.send(requester.get(CommonHelper.replace(getUserByUUIDUrl, "uuid", uuid.toString()), null), HttpUser.class).getOrThrow(); + } catch (IOException e) { + logger.error(e); + return null; + } + } + + @Override + public List getDetails(Client client) { + if(getAuthDetails == null) { + return super.getDetails(client); + } + try { + var result = requester.send(requester.get(getAuthDetails, bearerToken), GetAuthDetailsResponse.class).getOrThrow(); + return result.details; + } catch (IOException e) { + logger.error(e); + return super.getDetails(client); + } + } + + @Override + public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { + if(getUserByTokenUrl == null) { + return null; + } + try { + var result = requester.send(requester.get(getUserByTokenUrl, accessToken), HttpUserSession.class); + if(!result.isSuccessful()) { + var error = result.error().error; + if(error.equals(AuthRequestEvent.OAUTH_TOKEN_EXPIRE)) { + throw new OAuthAccessTokenExpired(); + } + return null; + } + return result.getOrThrow(); + } catch (IOException e) { + logger.error(e); + return null; + } + } + + @Override + public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { + if(refreshTokenUrl == null) { + return null; + } + try { + return requester.send(requester.post(refreshTokenUrl, new RefreshTokenRequest(refreshToken, context), + null), AuthManager.AuthReport.class).getOrThrow(); + } catch (IOException e) { + logger.error(e); + return null; + } + } + + @Override + public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { + var result = requester.send(requester.post(authorizeUrl, new AuthorizeRequest(login, context, password, minecraftAccess), + bearerToken), AuthManager.AuthReport.class); + if(!result.isSuccessful()) { + var error = result.error().error; + if(error != null) { + throw new AuthException(error); + } + } + return result.getOrThrow(); + } + + @Override + protected boolean updateServerID(User user, String serverID) throws IOException { + var result = requester.send(requester.post(updateServerIdUrl, new UpdateServerIdRequest(user.getUsername(), user.getUUID(), serverID), + null), Void.class); + return result.isSuccessful(); + } + + @Override + public User checkServer(Client client, String username, String serverID) throws IOException { + return requester.send(requester.post(checkServerUrl, new CheckServerRequest(username, serverID), null), HttpUser.class).getOrThrow(); + } + + @Override + public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { + var result = requester.send(requester.post(joinServerUrl, new JoinServerRequest(username, accessToken, serverID), null), Void.class); + return result.isSuccessful(); + } + + public static class UpdateServerIdRequest { + public String username; + public UUID uuid; + public String serverId; + + public UpdateServerIdRequest(String username, UUID uuid, String serverId) { + this.username = username; + this.uuid = uuid; + this.serverId = serverId; + } + } + + public static class CheckServerRequest { + public String username; + public String serverId; + + public CheckServerRequest(String username, String serverId) { + this.username = username; + this.serverId = serverId; + } + } + + public static class GetAuthDetailsResponse { + public List details; + } + + public static class JoinServerRequest { + public String username; + public String accessToken; + public String serverId; + + public JoinServerRequest(String username, String accessToken, String serverId) { + this.username = username; + this.accessToken = accessToken; + this.serverId = serverId; + } + } + + @Override + public void init(LaunchServer server) { + requester = new HttpRequester(); + if(getUserByUsernameUrl == null) { + throw new IllegalArgumentException("'getUserByUsernameUrl' can't be null"); + } + if(getUserByUUIDUrl == null) { + throw new IllegalArgumentException("'getUserByUUIDUrl' can't be null"); + } + if(authorizeUrl == null) { + throw new IllegalArgumentException("'authorizeUrl' can't be null"); + } + if((checkServerUrl == null && joinServerUrl == null) || updateServerIdUrl == null) { + throw new IllegalArgumentException("Please set 'checkServerUrl' and 'joinServerUrl' or 'updateServerIdUrl'"); + } + } + + @Override + public void close() throws IOException { + + } + + public static class AuthorizeRequest { + public String login; + public AuthResponse.AuthContext context; + public AuthRequest.AuthPasswordInterface password; + public boolean minecraftAccess; + + public AuthorizeRequest() { + } + + public AuthorizeRequest(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) { + this.login = login; + this.context = context; + this.password = password; + this.minecraftAccess = minecraftAccess; + } + } + + public static class RefreshTokenRequest { + public String refreshToken; + public AuthResponse.AuthContext context; + + public RefreshTokenRequest(String refreshToken, AuthResponse.AuthContext context) { + this.refreshToken = refreshToken; + this.context = context; + } + } + + public static class HttpUser implements User, UserSupportTextures { + private String username; + private UUID uuid; + private String serverId; + private String accessToken; + private ClientPermissions permissions; + private Texture skin; + private Texture cloak; + + public HttpUser() { + } + + public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions) { + this.username = username; + this.uuid = uuid; + this.serverId = serverId; + this.accessToken = accessToken; + this.permissions = permissions; + } + + public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak) { + this.username = username; + this.uuid = uuid; + this.serverId = serverId; + this.accessToken = accessToken; + this.permissions = permissions; + this.skin = skin; + this.cloak = cloak; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public String getServerId() { + return serverId; + } + + @Override + public String getAccessToken() { + return accessToken; + } + + @Override + public ClientPermissions getPermissions() { + return permissions; + } + + @Override + public Texture getSkinTexture() { + return skin; + } + + @Override + public Texture getCloakTexture() { + return cloak; + } + } + + public static class HttpUserSession implements UserSession { + private String id; + private User user; + private long expireIn; + + public HttpUserSession() { + } + + public HttpUserSession(String id, User user, long expireIn) { + this.id = id; + this.user = user; + this.expireIn = expireIn; + } + + @Override + public String getID() { + return id; + } + + @Override + public User getUser() { + return user; + } + + @Override + public long getExpireIn() { + return expireIn; + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/JsonCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/JsonCoreProvider.java deleted file mode 100644 index 5cb8e255..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/JsonCoreProvider.java +++ /dev/null @@ -1,410 +0,0 @@ -package pro.gravit.launchserver.auth.core; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import pro.gravit.launcher.ClientPermissions; -import pro.gravit.launcher.Launcher; -import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; -import pro.gravit.launcher.request.auth.AuthRequest; -import pro.gravit.launcher.request.auth.password.AuthPlainPassword; -import pro.gravit.launchserver.LaunchServer; -import pro.gravit.launchserver.auth.AuthException; -import pro.gravit.launchserver.auth.password.PasswordVerifier; -import pro.gravit.launchserver.manangers.AuthManager; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.launchserver.socket.response.auth.AuthResponse; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; -import java.util.List; -import java.util.UUID; - -public class JsonCoreProvider extends AuthCoreProvider { - private static transient final Logger logger = LogManager.getLogger(); - public String getUserByUsernameUrl; - public String getUserByLoginUrl; - public String getUserByUUIDUrl; - public String getUserSessionByOAuthAccessTokenUrl; - public String getAuthDetailsUrl; - public String refreshAccessTokenUrl; - public String verifyPasswordUrl; - public String createOAuthSessionUrl; - public String updateServerIdUrl; - public String joinServerUrl; - public String checkServerUrl; - public String bearerToken; - public PasswordVerifier passwordVerifier; - private transient HttpClient client; - - public static R jsonRequest(T request, String url, String bearerToken, Class clazz, HttpClient client) { - HttpRequest.BodyPublisher publisher; - if (request != null) { - publisher = HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request)); - } else { - publisher = HttpRequest.BodyPublishers.noBody(); - } - try { - HttpRequest.Builder request1 = HttpRequest.newBuilder() - .method("POST", publisher) - .uri(new URI(url)) - .header("Content-Type", "application/json; charset=UTF-8") - .header("Accept", "application/json") - .timeout(Duration.ofMillis(10000)); - if (bearerToken != null) { - request1.header("Authorization", "Bearer ".concat(bearerToken)); - } - HttpResponse response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream()); - int statusCode = response.statusCode(); - if (200 > statusCode || statusCode > 300) { - if (statusCode >= 500) { - logger.error("JsonCoreProvider: {} return {}", url, statusCode); - } else if (statusCode >= 300 && statusCode <= 400) { - logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown")); - } else if (statusCode == 403 || statusCode == 401) { - logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode); - } - return null; - } - try (Reader reader = new InputStreamReader(response.body())) { - return Launcher.gsonManager.gson.fromJson(reader, clazz); - } - } catch (Exception e) { - return null; - } - } - - @Override - public User getUserByUsername(String username) { - return jsonRequest(new JsonGetUserByUsername(username), getUserByUsernameUrl, JsonUser.class); - } - - @Override - public User getUserByLogin(String login) { - if (getUserByLoginUrl != null) { - return jsonRequest(new JsonGetUserByUsername(login), getUserByLoginUrl, JsonUser.class); - } - return super.getUserByLogin(login); - } - - @Override - public User getUserByUUID(UUID uuid) { - return jsonRequest(new JsonGetUserByUUID(uuid), getUserByUUIDUrl, JsonUser.class); - } - - @Override - public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { - if (getUserSessionByOAuthAccessTokenUrl == null) { - return null; - } - JsonGetUserSessionByOAuthTokenResponse response = jsonRequest(new JsonGetUserSessionByAccessToken(accessToken), getUserSessionByOAuthAccessTokenUrl, JsonGetUserSessionByOAuthTokenResponse.class); - if (response == null) return null; - if (!response.expired) throw new OAuthAccessTokenExpired(); - return response.session; - } - - @Override - public List getDetails(Client client) { - if (getAuthDetailsUrl != null) { - JsonGetDetailsResponse response = jsonRequest(new JsonGetDetails(), getAuthDetailsUrl, JsonGetDetailsResponse.class); - if (response == null) return super.getDetails(client); - return response.details; - } - return super.getDetails(client); - } - - @Override - public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { - JsonAuthReportResponse response = jsonRequest(new JsonRefreshToken(refreshToken, context.ip), this.refreshAccessTokenUrl, JsonAuthReportResponse.class); - return response == null ? null : response.toAuthReport(); - } - - @Override - public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { - - } - - @Override - public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) { - JsonUser jsonUser = (JsonUser) user; - if (password instanceof AuthPlainPassword && jsonUser.password != null && passwordVerifier != null) { - if (passwordVerifier.check(jsonUser.password, ((AuthPlainPassword) password).password)) { - return PasswordVerifyReport.OK; - } else { - return PasswordVerifyReport.FAILED; - } - } - if (user == null) { - return jsonRequest(new JsonPasswordVerify(null, null, password), verifyPasswordUrl, PasswordVerifyReport.class); - } - return jsonRequest(new JsonPasswordVerify(user.getUsername(), user.getUUID(), password), verifyPasswordUrl, PasswordVerifyReport.class); - } - - @Override - public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException { - JsonAuthReportResponse response = jsonRequest(new JsonCreateOAuthSession(user == null ? null : user.getUsername(), user == null ? null : user.getUUID(), minecraftAccess), createOAuthSessionUrl, JsonAuthReportResponse.class); - if (response == null) return null; - if (response.error != null) throw new AuthException(response.error); - JsonUser user1 = (JsonUser) user; - user1.accessToken = response.minecraftAccessToken; - return response.toAuthReport(); - } - - @Override - public void init(LaunchServer server) { - client = HttpClient.newBuilder().build(); - } - - @Override - public User checkServer(Client client, String username, String serverID) throws IOException { - if (checkServerUrl == null) { - return super.checkServer(client, username, serverID); - } - return jsonRequest(new JsonCheckServer(username, serverID), checkServerUrl, JsonUser.class); - } - - @Override - public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { - if (joinServerUrl == null) { - return super.joinServer(client, username, accessToken, serverID); - } - return jsonRequest(new JsonJoinServer(username, accessToken, serverID), joinServerUrl, JsonSuccessResponse.class).success; - } - - @Override - protected boolean updateServerID(User user, String serverID) throws IOException { - JsonUser jsonUser = (JsonUser) user; - if (updateServerIdUrl == null) { - return false; - } - jsonUser.serverId = serverID; - JsonSuccessResponse successResponse = jsonRequest(new JsonUpdateServerId(user.getUsername(), user.getUUID(), serverID), updateServerIdUrl, JsonSuccessResponse.class); - if (successResponse == null) return false; - return successResponse.success; - } - - @Override - public void close() throws IOException { - - } - - public R jsonRequest(T request, String url, Class clazz) { - return jsonRequest(request, url, bearerToken, clazz, client); - } - - public static class JsonGetUserByUsername { - public String username; - - public JsonGetUserByUsername(String username) { - this.username = username; - } - } - - public static class JsonCheckServer { - public String username; - public String serverId; - - public JsonCheckServer(String username, String serverId) { - this.username = username; - this.serverId = serverId; - } - } - - public static class JsonJoinServer { - public String username; - public String accessToken; - public String serverId; - - public JsonJoinServer(String username, String accessToken, String serverId) { - this.username = username; - this.accessToken = accessToken; - this.serverId = serverId; - } - } - - public static class JsonGetUserByUUID { - public UUID uuid; - - public JsonGetUserByUUID(UUID uuid) { - this.uuid = uuid; - } - } - - public static class JsonGetUserSessionByAccessToken { - public String accessToken; - - public JsonGetUserSessionByAccessToken(String accessToken) { - this.accessToken = accessToken; - } - } - - public static class JsonRefreshToken { - public String refreshToken; - public String ip; - - public JsonRefreshToken(String refreshToken, String ip) { - this.refreshToken = refreshToken; - this.ip = ip; - } - } - - public static class JsonAuthReportResponse { - public String minecraftAccessToken; - public String oauthAccessToken; - public String oauthRefreshToken; - public long oauthExpire; - public JsonUserSession session; - public String error; - - public AuthManager.AuthReport toAuthReport() { - return new AuthManager.AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session); - } - } - - public static class JsonPasswordVerify { - public String username; - public UUID uuid; - public AuthRequest.AuthPasswordInterface password; - - public JsonPasswordVerify(String username, UUID uuid, AuthRequest.AuthPasswordInterface password) { - this.username = username; - this.uuid = uuid; - this.password = password; - } - } - - public static class JsonCreateOAuthSession { - public String username; - public UUID uuid; - public boolean minecraftAccess; - - public JsonCreateOAuthSession(String username, UUID uuid, boolean minecraftAccess) { - this.username = username; - this.uuid = uuid; - this.minecraftAccess = minecraftAccess; - } - } - - public static class JsonUpdateServerId { - public String username; - public UUID uuid; - public String serverId; - - public JsonUpdateServerId(String username, UUID uuid, String serverId) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - } - } - - public static class JsonSuccessResponse { - public boolean success; - } - - public static class JsonGetUserSessionByOAuthTokenResponse { - public boolean expired; - public JsonUserSession session; - - public JsonGetUserSessionByOAuthTokenResponse() { - } - } - - public static class JsonGetDetails { - - } - - public static class JsonGetDetailsResponse { - public List details; - } - - public static class JsonUser implements User { - private String username; - private UUID uuid; - private String serverId; - private String accessToken; - private ClientPermissions permissions; - private String password; - - public JsonUser() { - } - - public JsonUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, String password) { - this.username = username; - this.uuid = uuid; - this.serverId = serverId; - this.accessToken = accessToken; - this.permissions = permissions; - this.password = password; - } - - @Override - public String getUsername() { - return username; - } - - @Override - public UUID getUUID() { - return uuid; - } - - @Override - public String getServerId() { - return serverId; - } - - @Override - public String getAccessToken() { - return accessToken; - } - - @Override - public ClientPermissions getPermissions() { - return permissions; - } - - @Override - public String toString() { - return "JsonUser{" + - "username='" + username + '\'' + - ", uuid=" + uuid + - ", permissions=" + permissions + - '}'; - } - } - - public static class JsonUserSession implements UserSession { - public String id; - public JsonUser user; - public long expireIn; - - @Override - public String getID() { - return id; - } - - @Override - public User getUser() { - return user; - } - - @Override - public long getExpireIn() { - return expireIn; - } - - @Override - public String toString() { - return "JsonUserSession{" + - "id='" + id + '\'' + - "user='" + (user == null ? null : user.getUsername()) + '\'' + - ", expireIn=" + expireIn + - '}'; - } - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java new file mode 100644 index 00000000..c3c83db6 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MemoryAuthCoreProvider.java @@ -0,0 +1,212 @@ +package pro.gravit.launchserver.auth.core; + +import pro.gravit.launcher.ClientPermissions; +import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.AuthException; +import pro.gravit.launchserver.manangers.AuthManager; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.utils.helper.SecurityHelper; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class MemoryAuthCoreProvider extends AuthCoreProvider { + private transient final List memory = new ArrayList<>(16); + @Override + public User getUserByUsername(String username) { + synchronized (memory) { + for(MemoryUser u : memory) { + if(u.username.equals(username)) { + return u; + } + } + var result = new MemoryUser(username); + memory.add(result); + return result; + } + } + + @Override + public List getDetails(Client client) { + return List.of(new AuthLoginOnlyDetails()); + } + + @Override + public User getUserByUUID(UUID uuid) { + synchronized (memory) { + for(MemoryUser u : memory) { + if(u.uuid.equals(uuid)) { + return u; + } + } + } + return null; + } + + @Override + public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired { + synchronized (memory) { + for(MemoryUser u : memory) { + if(u.accessToken.equals(accessToken)) { + return new MemoryUserSession(u); + } + } + } + return null; + } + + @Override + public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) { + return null; + } + + @Override + public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { + if(login == null) { + throw AuthException.userNotFound(); + } + MemoryUser user = null; + synchronized (memory) { + for(MemoryUser u : memory) { + if(u.username.equals(login)) { + user = u; + break; + } + } + if(user == null) { + user = new MemoryUser(login); + memory.add(user); + } + } + if(minecraftAccess) { + return AuthManager.AuthReport.ofOAuth(user.accessToken, null, 0, new MemoryUserSession(user)); + } else { + return AuthManager.AuthReport.ofOAuthWithMinecraft(user.accessToken, user.accessToken, null, 0, new MemoryUserSession(user)); + } + } + + @Override + protected boolean updateServerID(User user, String serverID) throws IOException { + MemoryUser memoryUser = (MemoryUser) user; + memoryUser.serverId = serverID; + return true; + } + + @Override + public User checkServer(Client client, String username, String serverID) throws IOException { + synchronized (memory) { + for(MemoryUser u : memory) { + if(u.username.equals(username)) { + return u; + } + } + var result = new MemoryUser(username); + memory.add(result); + return result; + } + } + + @Override + public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException { + return true; + } + + @Override + public void init(LaunchServer server) { + + } + + @Override + public void close() throws IOException { + + } + + public static class MemoryUser implements User { + private String username; + private UUID uuid; + private String serverId; + private String accessToken; + private ClientPermissions permissions; + + public MemoryUser(String username) { + this.username = username; + this.uuid = makeUuidFromUsername(username); + this.accessToken = SecurityHelper.randomStringToken(); + this.permissions = new ClientPermissions(); + } + + private static UUID makeUuidFromUsername(String username) { + return UUID.nameUUIDFromBytes(username.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public String getServerId() { + return serverId; + } + + @Override + public String getAccessToken() { + return accessToken; + } + + @Override + public ClientPermissions getPermissions() { + return permissions; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MemoryUser that = (MemoryUser) o; + return uuid.equals(that.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } + } + + public static class MemoryUserSession implements UserSession { + private String id; + private MemoryUser user; + private long expireIn; + + public MemoryUserSession(MemoryUser user) { + this.id = SecurityHelper.randomStringToken(); + this.user = user; + this.expireIn = 0; + } + + @Override + public String getID() { + return id; + } + + @Override + public User getUser() { + return user; + } + + @Override + public long getExpireIn() { + return expireIn; + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java index 2046769e..7842058c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/MySQLCoreProvider.java @@ -105,27 +105,27 @@ public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthRespon } @Override - public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { - - } - - @Override - public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) { - if (passwordVerifier.check(((MySQLUser) user).password, ((AuthPlainPassword) password).password)) { - return PasswordVerifyReport.OK; - } else { - return PasswordVerifyReport.FAILED; + public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { + MySQLUser mySQLUser = (MySQLUser) getUserByLogin(login); + if(mySQLUser == null) { + throw AuthException.wrongPassword(); } - } - - @Override - public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException { + if(context != null) { + AuthPlainPassword plainPassword = (AuthPlainPassword) password; + if(plainPassword == null) { + throw AuthException.wrongPassword(); + } + if(!passwordVerifier.check(mySQLUser.password, plainPassword.password)) { + throw AuthException.wrongPassword(); + } + } + MySQLUserSession session = new MySQLUserSession(mySQLUser); if (minecraftAccess) { String minecraftAccessToken = SecurityHelper.randomStringToken(); - updateAuth(user, minecraftAccessToken); - return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken); + updateAuth(mySQLUser, minecraftAccessToken); + return AuthManager.AuthReport.ofMinecraftAccessToken(minecraftAccessToken, session); } else { - return AuthManager.AuthReport.ofMinecraftAccessToken(null); + return AuthManager.AuthReport.ofMinecraftAccessToken(null, session); } } @@ -333,13 +333,14 @@ public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo hardwa } @Override - public void connectUserAndHardware(User user, UserHardware hardware) { - MySQLUser mySQLUser = (MySQLUser) user; + public void connectUserAndHardware(UserSession userSession, UserHardware hardware) { + MySQLUserSession mySQLUserSession = (MySQLUserSession) userSession; + MySQLUser mySQLUser = mySQLUserSession.user; MySQLUserHardware mySQLUserHardware = (MySQLUserHardware) hardware; if (mySQLUser.hwidId == mySQLUserHardware.id) return; mySQLUser.hwidId = mySQLUserHardware.id; try (Connection connection = mySQLHolder.getConnection()) { - setUserHardwareId(connection, user.getUUID(), mySQLUserHardware.id); + setUserHardwareId(connection, mySQLUser.getUUID(), mySQLUserHardware.id); } catch (SQLException throwables) { logger.error("SQL Error", throwables); } @@ -513,4 +514,29 @@ public String toString() { '}'; } } + + public static class MySQLUserSession implements UserSession { + private final MySQLUser user; + private final String id; + + public MySQLUserSession(MySQLUser user) { + this.user = user; + this.id = user.username; + } + + @Override + public String getID() { + return id; + } + + @Override + public User getUser() { + return user; + } + + @Override + public long getExpireIn() { + return 0; + } + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java index 6f211353..6db40500 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/RejectAuthCoreProvider.java @@ -36,13 +36,8 @@ public void verifyAuth(AuthResponse.AuthContext context) throws AuthException { } @Override - public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) { - return PasswordVerifyReport.FAILED; - } - - @Override - public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException { - return null; + public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException { + throw new AuthException("Please configure AuthCoreProvider"); } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportHardware.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportHardware.java index e8daa0e8..60ba8353 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportHardware.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportHardware.java @@ -2,6 +2,7 @@ import pro.gravit.launcher.request.secure.HardwareReportRequest; import pro.gravit.launchserver.auth.core.User; +import pro.gravit.launchserver.auth.core.UserSession; import pro.gravit.launchserver.auth.core.interfaces.UserHardware; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware; import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider; @@ -18,7 +19,7 @@ public interface AuthSupportHardware extends AuthSupport { UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey); - void connectUserAndHardware(User user, UserHardware hardware); + void connectUserAndHardware(UserSession userSession, UserHardware hardware); void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/JsonPasswordVerifier.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/JsonPasswordVerifier.java index d712fd10..171a5769 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/JsonPasswordVerifier.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/JsonPasswordVerifier.java @@ -1,17 +1,27 @@ package pro.gravit.launchserver.auth.password; -import pro.gravit.launchserver.auth.core.JsonCoreProvider; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launcher.Launcher; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URI; import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; public class JsonPasswordVerifier extends PasswordVerifier { + private static transient final Logger logger = LogManager.getLogger(); private transient final HttpClient client = HttpClient.newBuilder().build(); public String url; public String bearerToken; @Override public boolean check(String encryptedPassword, String password) { - JsonPasswordResponse response = JsonCoreProvider.jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client); + JsonPasswordResponse response = jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client); if (response != null) { return response.success; } @@ -31,4 +41,41 @@ public JsonPasswordRequest(String encryptedPassword, String password) { public static class JsonPasswordResponse { public boolean success; } + + public static R jsonRequest(T request, String url, String bearerToken, Class clazz, HttpClient client) { + HttpRequest.BodyPublisher publisher; + if (request != null) { + publisher = HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request)); + } else { + publisher = HttpRequest.BodyPublishers.noBody(); + } + try { + HttpRequest.Builder request1 = HttpRequest.newBuilder() + .method("POST", publisher) + .uri(new URI(url)) + .header("Content-Type", "application/json; charset=UTF-8") + .header("Accept", "application/json") + .timeout(Duration.ofMillis(10000)); + if (bearerToken != null) { + request1.header("Authorization", "Bearer ".concat(bearerToken)); + } + HttpResponse response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream()); + int statusCode = response.statusCode(); + if (200 > statusCode || statusCode > 300) { + if (statusCode >= 500) { + logger.error("JsonCoreProvider: {} return {}", url, statusCode); + } else if (statusCode >= 300 && statusCode <= 400) { + logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown")); + } else if (statusCode == 403 || statusCode == 401) { + logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode); + } + return null; + } + try (Reader reader = new InputStreamReader(response.body())) { + return Launcher.gsonManager.gson.fromJson(reader, clazz); + } + } catch (Exception e) { + return null; + } + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java index a440e330..520cc9ce 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java @@ -76,7 +76,7 @@ public void onHardwareReport(HardwareReportResponse response, Client client) { } else { authSupportHardware.addPublicKeyToHardwareInfo(hardware, client.trustLevel.publicKey); } - authSupportHardware.connectUserAndHardware(client.getUser(), hardware); + authSupportHardware.connectUserAndHardware(client.sessionObject, hardware); if (hardware.isBanned()) { throw new SecurityException("Your hardware banned"); } @@ -108,7 +108,7 @@ public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) { throw new SecurityException("Your hardware banned"); } client.trustLevel.hardwareInfo = hardware.getHardwareInfo(); - authSupportHardware.connectUserAndHardware(client.getUser(), hardware); + authSupportHardware.connectUserAndHardware(client.sessionObject, hardware); } else if (provider == null) { logger.warn("HWIDProvider null. HardwareInfo not checked!"); } else { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index a44831dd..3ba63457 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -192,7 +192,6 @@ public void init(LaunchServer.ReloadType type) { if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) { for (AuthProviderPair pair : auth.values()) { server.registerObject("auth.".concat(pair.name).concat(".core"), pair.core); - server.registerObject("auth.".concat(pair.name).concat(".social"), pair.social); server.registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider); } } @@ -203,7 +202,6 @@ public void close(LaunchServer.ReloadType type) { try { if (!type.equals(LaunchServer.ReloadType.NO_AUTH)) { for (AuthProviderPair pair : auth.values()) { - server.unregisterObject("auth.".concat(pair.name).concat(".social"), pair.social); server.unregisterObject("auth.".concat(pair.name).concat(".core"), pair.core); server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider); pair.close(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java index ce23b57d..1da9a340 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/AuthManager.java @@ -14,7 +14,6 @@ import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.core.AuthCoreProvider; -import pro.gravit.launchserver.auth.core.AuthSocialProvider; import pro.gravit.launchserver.auth.core.User; import pro.gravit.launchserver.auth.core.UserSession; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures; @@ -31,7 +30,6 @@ import java.util.List; import java.util.Objects; import java.util.UUID; -import java.util.stream.Collectors; public class AuthManager { private transient final LaunchServer server; @@ -143,62 +141,27 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor context.client.sessionObject = session; internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), true); if (context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) { - return AuthReport.ofMinecraftAccessToken(user.getAccessToken()); + return AuthReport.ofMinecraftAccessToken(user.getAccessToken(), session); } - return AuthReport.ofMinecraftAccessToken(null); + return AuthReport.ofMinecraftAccessToken(null, session); } - User user = null; - boolean skipPasswordCheck = false; String login = context.login; - if (context.pair.social != null) { - AuthSocialProvider.SocialResult result = context.pair.social.preAuth(context, password); - if (result != null) { - if (result.user != null) user = result.user; - if (result.login != null) login = result.login; - if (result.password != null) password = result.password; - if (result.user != null && result.password == null) skipPasswordCheck = true; - } - } - if (user == null && login != null) { - user = provider.getUserByLogin(context.login); - if (user == null) { - throw new AuthException(AuthRequestEvent.USER_NOT_FOUND_ERROR_MESSAGE); - } - } - AuthCoreProvider.PasswordVerifyReport report = null; - if (!skipPasswordCheck) { - report = provider.verifyPassword(user, password); - } - if (skipPasswordCheck || report.success) { - AuthReport result; - try { - result = provider.createOAuthSession(user, context, report, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)); - } catch (IOException e) { - if (e instanceof AuthException) throw (AuthException) e; - logger.error(e); + try { + AuthReport result = provider.authorize(login, context, password, context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)); + if(result == null || result.session == null || result.session.getUser() == null) { + logger.error("AuthCoreProvider {} method 'authorize' return null", context.pair.name); throw new AuthException("Internal Auth Error"); } - if (user == null) { - if (result.session != null) { - user = result.session.getUser(); - } else { - logger.error("AuthCoreProvider {} method createOAuthSession returns null session with login null", context.pair.name); - throw new AuthException("Internal Auth Error"); - } - } + var session = result.session; + var user = session.getUser(); context.client.coreObject = user; + context.client.sessionObject = session; internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), result.isUsingOAuth()); return result; - } else { - if (report.needMoreFactors) { - if (report.factors.size() == 1 && report.factors.get(0) == -1) { - throw new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE); - } - String message = AuthRequestEvent.ONE_FACTOR_NEED_ERROR_MESSAGE_PREFIX - .concat(report.factors.stream().map(String::valueOf).collect(Collectors.joining("."))); - throw new AuthException(message); - } - throw new AuthException(AuthRequestEvent.WRONG_PASSWORD_ERROR_MESSAGE); + } catch (IOException e) { + if (e instanceof AuthException) throw (AuthException) e; + logger.error(e); + throw new AuthException("Internal Auth Error"); } } @@ -217,7 +180,6 @@ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, Auth client.type = authType; client.uuid = uuid; client.useOAuth = oauth; - client.coreObject = pair.core.getUserByUUID(uuid); } public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException { @@ -374,24 +336,16 @@ public record AuthReport(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) { - public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire) { - return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire, null); - } - public static AuthReport ofOAuth(String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) { return new AuthReport(null, oauthAccessToken, oauthRefreshToken, oauthExpire, session); } - public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire) { - return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, null); - } - public static AuthReport ofOAuthWithMinecraft(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire, UserSession session) { return new AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session); } - public static AuthReport ofMinecraftAccessToken(String minecraftAccessToken) { - return new AuthReport(minecraftAccessToken, null, null, 0, null); + public static AuthReport ofMinecraftAccessToken(String minecraftAccessToken, UserSession session) { + return new AuthReport(minecraftAccessToken, null, null, 0, session); } public boolean isUsingOAuth() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java index ffc9ab88..4e66c5da 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java @@ -76,9 +76,9 @@ public static class AuthContext { public final String profileName; public final String ip; public final ConnectTypes authType; - public final Client client; - public final AuthProviderPair pair; - public AuthManager.AuthReport report; + public transient final Client client; + public transient final AuthProviderPair pair; + public transient AuthManager.AuthReport report; public AuthContext(Client client, String login, String profileName, String ip, ConnectTypes authType, AuthProviderPair pair) { this.client = client; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java index 8df28870..25f0007d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/GetAvailabilityAuthResponse.java @@ -20,7 +20,7 @@ public void execute(ChannelHandlerContext ctx, Client client) { List list = new ArrayList<>(); for (AuthProviderPair pair : server.config.auth.values()) { list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName, - pair.isUseSocial() ? pair.social.getDetails(client) : pair.core.getDetails(client))); + pair.core.getDetails(client))); } sendResult(new GetAvailabilityAuthRequestEvent(list)); } diff --git a/build.gradle b/build.gradle index 43827ff9..01b09609 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ id 'org.openjfx.javafxplugin' version '0.0.10' apply false } group = 'pro.gravit.launcher' -version = '5.2.4' +version = '5.2.5-SNAPSHOT' apply from: 'props.gradle' diff --git a/modules b/modules index fd75e8df..dced1548 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit fd75e8dfa26a3103f03e4e6e6e3eb1c6e6a4ba1a +Subproject commit dced154854c59d8b1e816ebfb1f51baaaeafabfb From 2ef3ca732409ad5342c0139be3a4d701c04da26c Mon Sep 17 00:00:00 2001 From: Gravita Date: Fri, 5 Nov 2021 22:23:59 +0700 Subject: [PATCH 7/7] [ANY] 5.2.5 stable --- LauncherCore/src/main/java/pro/gravit/utils/Version.java | 4 ++-- build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index b684fb3c..601a65bf 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -6,8 +6,8 @@ public final class Version implements Comparable { public static final int MAJOR = 5; public static final int MINOR = 2; - public static final int PATCH = 4; - public static final int BUILD = 2; + public static final int PATCH = 5; + public static final int BUILD = 1; public static final Version.Type RELEASE = Type.STABLE; public final int major; public final int minor; diff --git a/build.gradle b/build.gradle index 01b09609..3cdcbab6 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ id 'org.openjfx.javafxplugin' version '0.0.10' apply false } group = 'pro.gravit.launcher' -version = '5.2.5-SNAPSHOT' +version = '5.2.5' apply from: 'props.gradle'