diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 178c8c47..15979d71 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -24,7 +24,7 @@ **Основные правила:** -1. Все коммиты должны быть на русском языке. +1. Все коммиты должны быть на английском языке. 2. Запрещено использовать прошедшее время. 3. Обязательно должен быть использован префикс. 4. В конце не должно быть лишнего знака препинания. @@ -38,10 +38,10 @@ | Префикс | Значение | Пример | | ------- | -------- | ------ | -| **[FIX]** | Всё, что касается исправления багов | [FIX] Баг с неудачной авторизацией | -| **[DOCS]** | Всё, что касается документации | [DOCS] Документирование API авторизации | -| **[FEATURE]** | Всё, что касается новых возможностей | [FEATURE] 2FA при авторизации | -| **[STYLE]** | Всё, что касается опечаток и форматирования | [STYLE] Опечатки в модуле авторизации | -| **[REFACTOR]** | Всё, что касается рефакторинга | [REFACTOR] Переход на EDA в модуле авторизации | -| **[TEST]** | Всё, что касается тестирования | [TEST] Покрытие модуля авторизации тестами | -| **[ANY]** | Всё, что не подходит к предыдущему. | [ANY] Подключение Travis CI | +| **[FIX]** | Всё, что касается исправления багов | [FIX] Bug with failed authorization | +| **[DOCS]** | Всё, что касается документации | [DOCS] Documenting Authorization API | +| **[FEATURE]** | Всё, что касается новых возможностей | [FEATURE] 2FA on authorization | +| **[STYLE]** | Всё, что касается опечаток и форматирования | [STYLE] Typos in the authorization module | +| **[REFACTOR]** | Всё, что касается рефакторинга | [REFACTOR] Switching to EDA in the authorization module | +| **[TEST]** | Всё, что касается тестирования | [TEST] Coverage of the authorization module with tests | +| **[ANY]** | Всё, что не подходит к предыдущему. | [ANY] Connecting Travis CI | diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 968ffaee..d4c88e81 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -3,9 +3,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.events.RequestEvent; +import pro.gravit.launcher.events.request.ProfilesRequestEvent; import pro.gravit.launcher.managers.ConfigManager; import pro.gravit.launcher.modules.events.ClosePhase; import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.launcher.request.Request; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider; import pro.gravit.launchserver.binary.EXEL4JLauncherBinary; @@ -19,7 +22,9 @@ import pro.gravit.launchserver.manangers.hook.AuthHookManager; import pro.gravit.launchserver.modules.events.*; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; +import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler; +import pro.gravit.launchserver.socket.response.auth.ProfilesResponse; import pro.gravit.launchserver.socket.response.auth.RestoreResponse; import pro.gravit.utils.command.Command; import pro.gravit.utils.command.CommandHandler; @@ -374,6 +379,24 @@ public void syncProfilesDir() throws IOException { // Sort and set new profiles newProfies.sort(Comparator.comparing(a -> a)); profilesList = Set.copyOf(newProfies); + if(config.netty.sendProfileUpdatesEvent) { + sendUpdateProfilesEvent(); + } + } + + private void sendUpdateProfilesEvent() { + if(nettyServerSocketHandler == null || nettyServerSocketHandler.nettyServer == null || nettyServerSocketHandler.nettyServer.service == null) { + return; + } + nettyServerSocketHandler.nettyServer.service.forEachActiveChannels((ch, handler) -> { + Client client = handler.getClient(); + if(client == null || !client.isAuth) { + return; + } + ProfilesRequestEvent event = new ProfilesRequestEvent(ProfilesResponse.getListVisibleProfiles(this, client)); + event.requestUUID = RequestEvent.eventUUID; + handler.service.sendObject(ch, event); + }); } public void syncUpdatesDir(Collection dirs) throws IOException { 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 index 27d9c5de..b204d2ab 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/HttpAuthCoreProvider.java @@ -13,6 +13,7 @@ import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.core.interfaces.UserHardware; import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware; +import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRemoteClientAccess; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportProperties; import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures; @@ -25,7 +26,7 @@ import java.io.IOException; import java.util.*; -public class HttpAuthCoreProvider extends AuthCoreProvider implements AuthSupportHardware { +public class HttpAuthCoreProvider extends AuthCoreProvider implements AuthSupportHardware, AuthSupportRemoteClientAccess { private transient final Logger logger = LogManager.getLogger(); private transient HttpRequester requester; public String bearerToken; @@ -49,6 +50,8 @@ public class HttpAuthCoreProvider extends AuthCoreProvider implements AuthSuppor public String getUsersByHardwareInfoUrl; public String banHardwareUrl; public String unbanHardwareUrl; + public String apiUrl; + public List apiFeatures; @Override public User getUserByUsername(String username) { @@ -267,6 +270,16 @@ public void unbanHardware(UserHardware hardware) { } } + @Override + public String getClientApiUrl() { + return apiUrl; + } + + @Override + public List getClientApiFeatures() { + return apiFeatures; + } + public record HttpAuthReport(String minecraftAccessToken, String oauthAccessToken, String oauthRefreshToken, long oauthExpire, HttpUserSession session) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRemoteClientAccess.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRemoteClientAccess.java new file mode 100644 index 00000000..5b5b0b64 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/core/interfaces/provider/AuthSupportRemoteClientAccess.java @@ -0,0 +1,8 @@ +package pro.gravit.launchserver.auth.core.interfaces.provider; + +import java.util.List; + +public interface AuthSupportRemoteClientAccess { + String getClientApiUrl(); + List getClientApiFeatures(); +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/BCryptPasswordVerifier.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/BCryptPasswordVerifier.java new file mode 100644 index 00000000..b7df788f --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/BCryptPasswordVerifier.java @@ -0,0 +1,17 @@ +package pro.gravit.launchserver.auth.password; + +import org.bouncycastle.crypto.generators.OpenBSDBCrypt; +import pro.gravit.utils.helper.SecurityHelper; + +public class BCryptPasswordVerifier extends PasswordVerifier { + public int cost = 10; + @Override + public boolean check(String encryptedPassword, String password) { + return OpenBSDBCrypt.checkPassword(encryptedPassword, password.toCharArray()); + } + + @Override + public String encrypt(String password) { + return OpenBSDBCrypt.generate(password.toCharArray(), SecurityHelper.randomBytes(16), cost); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/PasswordVerifier.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/PasswordVerifier.java index 30c352e9..abf70f77 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/PasswordVerifier.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/password/PasswordVerifier.java @@ -12,6 +12,7 @@ public static void registerProviders() { providers.register("digest", DigestPasswordVerifier.class); providers.register("doubleDigest", DoubleDigestPasswordVerifier.class); providers.register("json", JsonPasswordVerifier.class); + providers.register("bcrypt", BCryptPasswordVerifier.class); providers.register("accept", AcceptPasswordVerifier.class); providers.register("reject", RejectPasswordVerifier.class); registeredProviders = true; 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 33fb67a1..875dc460 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -281,6 +281,7 @@ public static class NettyConfig { public boolean ipForwarding; public boolean disableWebApiInterface; public boolean showHiddenFiles; + public boolean sendProfileUpdatesEvent = true; public String launcherURL; public String downloadURL; public String launcherEXEURL; 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 25f0007d..c89f29aa 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 @@ -3,6 +3,7 @@ import io.netty.channel.ChannelHandlerContext; import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent; import pro.gravit.launchserver.auth.AuthProviderPair; +import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRemoteClientAccess; import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.SimpleResponse; @@ -19,8 +20,14 @@ public String getType() { 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.core.getDetails(client))); + var rca = pair.isSupport(AuthSupportRemoteClientAccess.class); + if(rca != null) { + list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName, + pair.core.getDetails(client), rca.getClientApiUrl(), rca.getClientApiFeatures())); + } else { + list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName, + pair.core.getDetails(client))); + } } sendResult(new GetAvailabilityAuthRequestEvent(list)); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java index c22f1603..ec602d7f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java @@ -3,6 +3,7 @@ import io.netty.channel.ChannelHandlerContext; import pro.gravit.launcher.events.request.ProfilesRequestEvent; import pro.gravit.launcher.profiles.ClientProfile; +import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler; import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.response.SimpleResponse; @@ -23,7 +24,10 @@ public void execute(ChannelHandlerContext ctx, Client client) { sendError("Access denied"); return; } + sendResult(new ProfilesRequestEvent(getListVisibleProfiles(server, client))); + } + public static List getListVisibleProfiles(LaunchServer server, Client client) { List profileList; Set serverProfiles = server.getProfiles(); if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) { @@ -36,6 +40,6 @@ public void execute(ChannelHandlerContext ctx, Client client) { } else { profileList = List.copyOf(serverProfiles); } - sendResult(new ProfilesRequestEvent(profileList)); + return profileList; } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java index 930ec3f9..3a81326c 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetAvailabilityAuthRequestEvent.java @@ -45,11 +45,23 @@ public static class AuthAvailability { public String name; @LauncherNetworkAPI public String displayName; + @LauncherNetworkAPI + public String apiUrl; + @LauncherNetworkAPI + public List apiFeatures; public AuthAvailability(String name, String displayName, List details) { this.name = name; this.displayName = displayName; this.details = details; } + + public AuthAvailability(String name, String displayName, List details, String apiUrl, List apiFeatures) { + this.details = details; + this.name = name; + this.displayName = displayName; + this.apiUrl = apiUrl; + this.apiFeatures = apiFeatures; + } } } diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/hasher/HashedFile.java b/LauncherCore/src/main/java/pro/gravit/launcher/hasher/HashedFile.java index 396265e7..3f84ceb1 100644 --- a/LauncherCore/src/main/java/pro/gravit/launcher/hasher/HashedFile.java +++ b/LauncherCore/src/main/java/pro/gravit/launcher/hasher/HashedFile.java @@ -69,6 +69,10 @@ public long size() { return size; } + public byte[] getDigest() { + return digest; + } + @Override public void write(HOutput output) throws IOException { output.writeVarLong(size); diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 6b9b5d5f..0075fce5 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -6,7 +6,7 @@ public final class Version implements Comparable { public static final int MAJOR = 5; public static final int MINOR = 3; - public static final int PATCH = 0; + public static final int PATCH = 1; public static final int BUILD = 1; public static final Version.Type RELEASE = Type.STABLE; public final int major; diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/InstallAuthlib.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/InstallAuthlib.java index b880d880..c671b706 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/InstallAuthlib.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/InstallAuthlib.java @@ -20,6 +20,7 @@ public class InstallAuthlib { modifierMap.put("META-INF/libraries.list", new LibrariesLstModifier()); modifierMap.put("patch.properties", new PatchPropertiesModifier()); modifierMap.put("META-INF/download-context", new DownloadContextModifier()); + modifierMap.put("META-INF/patches.list", new PatchesLstModifier()); } public void run(String... args) throws Exception { boolean deleteAuthlibAfterInstall = false; diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/PatchesLstModifier.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/PatchesLstModifier.java new file mode 100644 index 00000000..51eaa516 --- /dev/null +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/authlib/PatchesLstModifier.java @@ -0,0 +1,29 @@ +package pro.gravit.launcher.server.authlib; + +import pro.gravit.utils.helper.LogHelper; +import pro.gravit.utils.helper.SecurityHelper; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PatchesLstModifier implements LibrariesHashFileModifier { + @Override + public byte[] apply(byte[] data, InstallAuthlib.InstallAuthlibContext context) throws IOException { + String[] lines = new String(data).split("\n"); + for(int i=0;i