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 new file mode 100644 index 00000000..d4932430 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/AdvancedProtectHandler.java @@ -0,0 +1,44 @@ +package pro.gravit.launchserver.auth.protect; + +import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent; +import pro.gravit.launchserver.auth.protect.interfaces.SecureProtectHandler; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.auth.AuthResponse; +import pro.gravit.utils.helper.SecurityHelper; + +public class AdvancedProtectHandler extends ProtectHandler implements SecureProtectHandler { + @Override + public String generateSecureToken(AuthResponse.AuthContext context) { + return SecurityHelper.randomStringToken(); + } + + @Override + public String generateClientSecureToken() { + return SecurityHelper.randomStringToken(); + } + + @Override + public boolean verifyClientSecureToken(String token, String secureKey) { + return true; + } + + @Override + public boolean allowGetAccessToken(AuthResponse.AuthContext context) { + return (context.authType == AuthResponse.ConnectTypes.CLIENT) && context.client.isSecure; + } + + @Override + public void checkLaunchServerLicense() { + + } + + @Override + public GetSecureLevelInfoRequestEvent onGetSecureLevelInfo(GetSecureLevelInfoRequestEvent event) { + return event; + } + + @Override + public boolean allowGetSecureLevelInfo(Client client) { + return client.isSecure; + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java index 5707c281..40777ec9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/ProtectHandler.java @@ -12,6 +12,7 @@ public static void registerHandlers() { if (!registredHandl) { providers.register("none", NoProtectHandler.class); providers.register("std", StdProtectHandler.class); + providers.register("advanced", AdvancedProtectHandler.class); registredHandl = true; } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/SecureProtectHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/SecureProtectHandler.java new file mode 100644 index 00000000..1fd49654 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/protect/interfaces/SecureProtectHandler.java @@ -0,0 +1,23 @@ +package pro.gravit.launchserver.auth.protect.interfaces; + +import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.utils.helper.SecurityHelper; + +import java.security.SignatureException; +import java.security.interfaces.ECPublicKey; +import java.security.spec.InvalidKeySpecException; + +public interface SecureProtectHandler { + default byte[] generateSecureLevelKey() + { + return SecurityHelper.randomBytes(128); + } + default void verifySecureLevelKey(byte[] publicKey, byte[] signature) throws InvalidKeySpecException, SignatureException { + if(publicKey == null || signature == null) throw new InvalidKeySpecException(); + ECPublicKey pubKey = SecurityHelper.toPublicECKey(publicKey); + SecurityHelper.newECVerifySignature(pubKey).update(signature); + } + GetSecureLevelInfoRequestEvent onGetSecureLevelInfo(GetSecureLevelInfoRequestEvent event); + boolean allowGetSecureLevelInfo(Client client); +} 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 a6ee1cd8..c3a2a323 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/Client.java @@ -19,6 +19,7 @@ public class Client { public ClientPermissions permissions; public String username; public String verifyToken; + public TrustLevel trustLevel; public transient LogHelper.OutputEnity logOutput; public transient AuthProviderPair auth; @@ -48,4 +49,8 @@ public enum Type { SERVER, USER } + public static class TrustLevel + { + public byte[] verifySecureKey; + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java index 3c060a60..2005c7d8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/WebSocketService.java @@ -21,8 +21,8 @@ import pro.gravit.launchserver.socket.response.profile.BatchProfileByUsername; import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse; import pro.gravit.launchserver.socket.response.profile.ProfileByUsername; -import pro.gravit.launchserver.socket.response.secure.GetSecureTokenResponse; -import pro.gravit.launchserver.socket.response.secure.VerifySecureTokenResponse; +import pro.gravit.launchserver.socket.response.secure.GetSecureLevelInfoResponse; +import pro.gravit.launchserver.socket.response.secure.VerifySecureLevelKeyResponse; import pro.gravit.launchserver.socket.response.update.LauncherResponse; import pro.gravit.launchserver.socket.response.update.UpdateListResponse; import pro.gravit.launchserver.socket.response.update.UpdateResponse; @@ -123,12 +123,12 @@ public static void registerResponses() { providers.register("batchProfileByUsername", BatchProfileByUsername.class); providers.register("profileByUsername", ProfileByUsername.class); providers.register("profileByUUID", ProfileByUUIDResponse.class); - providers.register("getSecureToken", GetSecureTokenResponse.class); - providers.register("verifySecureToken", VerifySecureTokenResponse.class); providers.register("getAvailabilityAuth", GetAvailabilityAuthResponse.class); providers.register("register", RegisterResponse.class); providers.register("setPassword", SetPasswordResponse.class); providers.register("exit", ExitResponse.class); + providers.register("getSecureLevelInfo", GetSecureLevelInfoResponse.class); + providers.register("verifySecureLevelKey", VerifySecureLevelKeyResponse.class); } public void sendObject(ChannelHandlerContext ctx, Object obj) { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureLevelInfoResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureLevelInfoResponse.java new file mode 100644 index 00000000..5380ffa6 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureLevelInfoResponse.java @@ -0,0 +1,35 @@ +package pro.gravit.launchserver.socket.response.secure; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent; +import pro.gravit.launchserver.auth.protect.interfaces.SecureProtectHandler; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +public class GetSecureLevelInfoResponse extends SimpleResponse { + @Override + public String getType() { + return "getSecureLevelInfo"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + if(!(server.config.protectHandler instanceof SecureProtectHandler)) + { + GetSecureLevelInfoRequestEvent response = new GetSecureLevelInfoRequestEvent(null); + response.enabled = false; + sendResult(response); + } + SecureProtectHandler secureProtectHandler = (SecureProtectHandler) server.config.protectHandler; + if(!secureProtectHandler.allowGetSecureLevelInfo(client)) + { + sendError("Permissions denied"); + return; + } + if(client.trustLevel == null) client.trustLevel = new Client.TrustLevel(); + if(client.trustLevel.verifySecureKey == null) client.trustLevel.verifySecureKey = secureProtectHandler.generateSecureLevelKey(); + GetSecureLevelInfoRequestEvent response = new GetSecureLevelInfoRequestEvent(client.trustLevel.verifySecureKey); + response.enabled = true; + sendResult(secureProtectHandler.onGetSecureLevelInfo(response)); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureTokenResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureTokenResponse.java deleted file mode 100644 index 9beb1ec5..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/GetSecureTokenResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package pro.gravit.launchserver.socket.response.secure; - -import io.netty.channel.ChannelHandlerContext; -import pro.gravit.launcher.events.request.GetSecureTokenRequestEvent; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.launchserver.socket.response.SimpleResponse; - -public class GetSecureTokenResponse extends SimpleResponse { - @Override - public String getType() { - return "getSecureToken"; - } - - @Override - public void execute(ChannelHandlerContext ctx, Client client) { - String secureToken = server.config.protectHandler.generateClientSecureToken(); - client.verifyToken = secureToken; - sendResult(new GetSecureTokenRequestEvent(secureToken)); - } -} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureLevelKeyResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureLevelKeyResponse.java new file mode 100644 index 00000000..14ad3afc --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureLevelKeyResponse.java @@ -0,0 +1,41 @@ +package pro.gravit.launchserver.socket.response.secure; + +import io.netty.channel.ChannelHandlerContext; +import pro.gravit.launcher.events.request.VerifySecureLevelKeyRequestEvent; +import pro.gravit.launchserver.auth.protect.interfaces.SecureProtectHandler; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.launchserver.socket.response.SimpleResponse; + +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; + +public class VerifySecureLevelKeyResponse extends SimpleResponse { + public byte[] publicKey; + public byte[] signature; + @Override + public String getType() { + return "verifySecureLevelKey"; + } + + @Override + public void execute(ChannelHandlerContext ctx, Client client) throws Exception { + if(!(server.config.protectHandler instanceof SecureProtectHandler)) + { + sendError("This method not allowed"); + return; + } + SecureProtectHandler secureProtectHandler = (SecureProtectHandler) server.config.protectHandler; + try { + secureProtectHandler.verifySecureLevelKey(publicKey, signature); + } catch (InvalidKeySpecException e) + { + sendError("Invalid public key"); + return; + } catch (SignatureException e) + { + sendError("Invalid signature"); + return; + } + sendResult(new VerifySecureLevelKeyRequestEvent()); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureTokenResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureTokenResponse.java deleted file mode 100644 index e59170c5..00000000 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/secure/VerifySecureTokenResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -package pro.gravit.launchserver.socket.response.secure; - -import io.netty.channel.ChannelHandlerContext; -import pro.gravit.launcher.events.request.VerifySecureTokenRequestEvent; -import pro.gravit.launchserver.socket.Client; -import pro.gravit.launchserver.socket.response.SimpleResponse; - -public class VerifySecureTokenResponse extends SimpleResponse { - public String secureToken; - - @Override - public String getType() { - return "verifySecureToken"; - } - - @Override - public void execute(ChannelHandlerContext ctx, Client client) { - boolean success = server.config.protectHandler.verifyClientSecureToken(secureToken, client.verifyToken); - if (success) client.isSecure = true; - sendResult(new VerifySecureTokenRequestEvent(success)); - } -} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureLevelInfoRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureLevelInfoRequestEvent.java new file mode 100644 index 00000000..bd5bbf6e --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureLevelInfoRequestEvent.java @@ -0,0 +1,17 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +public class GetSecureLevelInfoRequestEvent extends RequestEvent { + public final byte[] verifySecureKey; + public boolean enabled; + + public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey) { + this.verifySecureKey = verifySecureKey; + } + + @Override + public String getType() { + return "getSecureLevelInfo"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureTokenRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureTokenRequestEvent.java deleted file mode 100644 index e221b76c..00000000 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/GetSecureTokenRequestEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package pro.gravit.launcher.events.request; - -import pro.gravit.launcher.LauncherNetworkAPI; -import pro.gravit.launcher.events.RequestEvent; - -public class GetSecureTokenRequestEvent extends RequestEvent { - @LauncherNetworkAPI - public final String secureToken; - - @Override - public String getType() { - return "GetSecureToken"; - } - - public GetSecureTokenRequestEvent(String secureToken) { - this.secureToken = secureToken; - } -} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java new file mode 100644 index 00000000..785c3f53 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureLevelKeyRequestEvent.java @@ -0,0 +1,10 @@ +package pro.gravit.launcher.events.request; + +import pro.gravit.launcher.events.RequestEvent; + +public class VerifySecureLevelKeyRequestEvent extends RequestEvent { + @Override + public String getType() { + return "verifySecureLevelKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureTokenRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureTokenRequestEvent.java deleted file mode 100644 index 276000b7..00000000 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/events/request/VerifySecureTokenRequestEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package pro.gravit.launcher.events.request; - -import pro.gravit.launcher.LauncherNetworkAPI; -import pro.gravit.launcher.events.RequestEvent; - -public class VerifySecureTokenRequestEvent extends RequestEvent { - @LauncherNetworkAPI - public final boolean success; - - @Override - public String getType() { - return "verifySecureToken"; - } - - public VerifySecureTokenRequestEvent(boolean success) { - this.success = success; - } -} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/GetSecureLevelInfoRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/GetSecureLevelInfoRequest.java new file mode 100644 index 00000000..47eb594e --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/GetSecureLevelInfoRequest.java @@ -0,0 +1,11 @@ +package pro.gravit.launcher.request.secure; + +import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent; +import pro.gravit.launcher.request.Request; + +public class GetSecureLevelInfoRequest extends Request { + @Override + public String getType() { + return "getSecureLevelInfo"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/VerifySecureLevelKeyRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/VerifySecureLevelKeyRequest.java new file mode 100644 index 00000000..b1d0bdb9 --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/secure/VerifySecureLevelKeyRequest.java @@ -0,0 +1,19 @@ +package pro.gravit.launcher.request.secure; + +import pro.gravit.launcher.events.request.VerifySecureLevelKeyRequestEvent; +import pro.gravit.launcher.request.Request; + +public class VerifySecureLevelKeyRequest extends Request { + public final byte[] publicKey; + public final byte[] signature; + + public VerifySecureLevelKeyRequest(byte[] publicKey, byte[] signature) { + this.publicKey = publicKey; + this.signature = signature; + } + + @Override + public String getType() { + return "verifySecureLevelKey"; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java index c6604048..1d5da0d6 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/websockets/ClientWebSocketService.java @@ -11,6 +11,7 @@ import pro.gravit.launcher.hasher.HashedEntryAdapter; import pro.gravit.launcher.request.WebSocketEvent; import pro.gravit.launcher.request.auth.AuthRequest; +import pro.gravit.launcher.request.secure.VerifySecureLevelKeyRequest; import pro.gravit.utils.ProviderMap; import pro.gravit.utils.UniversalJsonAdapter; import pro.gravit.utils.helper.LogHelper; @@ -97,8 +98,6 @@ public void registerResults() { results.register("error", ErrorRequestEvent.class); results.register("update", UpdateRequestEvent.class); results.register("restoreSession", RestoreSessionRequestEvent.class); - results.register("getSecureToken", GetSecureTokenRequestEvent.class); - results.register("verifySecureToken", VerifySecureTokenRequestEvent.class); results.register("log", LogEvent.class); results.register("cmdExec", ExecCommandRequestEvent.class); results.register("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class); @@ -108,6 +107,8 @@ public void registerResults() { results.register("notification", NotificationEvent.class); results.register("signal", SignalEvent.class); results.register("exit", ExitRequestEvent.class); + results.register("getSecureLevelInfo", GetSecureLevelInfoRequestEvent.class); + results.register("verifySecureLevelKey", VerifySecureLevelKeyRequestEvent.class); } public void waitIfNotConnected() {