diff --git a/LaunchServer/src/main/resources/experimental-build.json b/LaunchServer/src/main/resources/experimental-build.json index ab148d00..8f5e3d65 100644 --- a/LaunchServer/src/main/resources/experimental-build.json +++ b/LaunchServer/src/main/resources/experimental-build.json @@ -1,4 +1,4 @@ { - "features": [], + "features": ["new-api"], "info": [] } \ No newline at end of file diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/ClientPermissions.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/ClientPermissions.java index bfa23a50..fdd718b8 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/ClientPermissions.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/ClientPermissions.java @@ -1,10 +1,11 @@ package pro.gravit.launcher.base; import pro.gravit.launcher.core.LauncherNetworkAPI; +import pro.gravit.launcher.core.api.model.UserPermissions; import java.util.*; -public class ClientPermissions { +public class ClientPermissions implements UserPermissions { public static final ClientPermissions DEFAULT = new ClientPermissions(); @LauncherNetworkAPI private List roles; @@ -28,6 +29,7 @@ public static ClientPermissions getSuperuserAccount() { return perm; } + @Override public boolean hasRole(String role) { return roles != null && roles.contains(role); } @@ -46,6 +48,7 @@ public synchronized void compile() { } } + @Override public boolean hasPerm(String action) { if (available == null) { compile(); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/AuthRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/AuthRequestEvent.java index a03007d3..7f6c5f61 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/AuthRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/AuthRequestEvent.java @@ -1,6 +1,7 @@ package pro.gravit.launcher.base.events.request; import pro.gravit.launcher.base.ClientPermissions; +import pro.gravit.launcher.core.api.features.AuthFeatureAPI; import pro.gravit.launcher.core.LauncherNetworkAPI; import pro.gravit.launcher.base.events.RequestEvent; import pro.gravit.launcher.base.profiles.PlayerProfile; @@ -67,7 +68,15 @@ public String getType() { return "auth"; } - public static class OAuthRequestEvent { + public CurrentUserRequestEvent.UserInfo makeUserInfo() { + var userInfo = new CurrentUserRequestEvent.UserInfo(); + userInfo.accessToken = accessToken; + userInfo.permissions = permissions; + userInfo.playerProfile = playerProfile; + return userInfo; + } + + public static class OAuthRequestEvent implements AuthFeatureAPI.AuthToken { public final String accessToken; public final String refreshToken; public final long expire; @@ -77,5 +86,20 @@ public OAuthRequestEvent(String accessToken, String refreshToken, long expire) { this.refreshToken = refreshToken; this.expire = expire; } + + @Override + public String getAccessToken() { + return accessToken; + } + + @Override + public String getRefreshToken() { + return refreshToken; + } + + @Override + public long getExpire() { + return expire; + } } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/CurrentUserRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/CurrentUserRequestEvent.java index f9c67018..3f9f9f3c 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/CurrentUserRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/CurrentUserRequestEvent.java @@ -3,6 +3,11 @@ import pro.gravit.launcher.base.ClientPermissions; import pro.gravit.launcher.base.events.RequestEvent; import pro.gravit.launcher.base.profiles.PlayerProfile; +import pro.gravit.launcher.core.api.model.SelfUser; +import pro.gravit.launcher.core.api.model.Texture; + +import java.util.Map; +import java.util.UUID; public class CurrentUserRequestEvent extends RequestEvent { public final UserInfo userInfo; @@ -16,9 +21,40 @@ public String getType() { return "currentUser"; } - public static class UserInfo { + public static class UserInfo implements SelfUser { public ClientPermissions permissions; public String accessToken; public PlayerProfile playerProfile; + + @Override + public String getAccessToken() { + return accessToken; + } + + @Override + public ClientPermissions getPermissions() { + return permissions; + } + + @Override + public String getUsername() { + return playerProfile.getUsername(); + } + + @Override + public UUID getUUID() { + return playerProfile.getUUID(); + } + + @SuppressWarnings("unchecked") + @Override + public Map getAssets() { + return (Map) playerProfile.getAssets(); + } + + @Override + public Map getProperties() { + return playerProfile.getProperties(); + } } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetAvailabilityAuthRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetAvailabilityAuthRequestEvent.java index efe0fbca..25169ec4 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetAvailabilityAuthRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetAvailabilityAuthRequestEvent.java @@ -1,9 +1,16 @@ package pro.gravit.launcher.base.events.request; +import pro.gravit.launcher.base.request.auth.details.AuthLoginOnlyDetails; +import pro.gravit.launcher.base.request.auth.details.AuthWebViewDetails; import pro.gravit.launcher.core.LauncherNetworkAPI; import pro.gravit.launcher.base.events.RequestEvent; +import pro.gravit.launcher.core.api.method.AuthMethod; +import pro.gravit.launcher.core.api.method.AuthMethodDetails; +import pro.gravit.launcher.core.api.method.details.AuthPasswordDetails; +import pro.gravit.launcher.core.api.method.details.AuthWebDetails; import pro.gravit.utils.TypeSerializeInterface; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -37,10 +44,11 @@ public enum ServerFeature { } } - public interface AuthAvailabilityDetails extends TypeSerializeInterface { + public interface AuthAvailabilityDetails extends AuthMethodDetails, TypeSerializeInterface { + AuthMethodDetails toAuthMethodDetails(); } - public static class AuthAvailability { + public static class AuthAvailability implements AuthMethod { public final List details; @LauncherNetworkAPI public String name; @@ -59,5 +67,34 @@ public AuthAvailability(List details, String name, Stri this.visible = visible; this.features = features; } + + @Override + public List getDetails() { + List convert = new ArrayList<>(); + for(var e : details) { + convert.add(e.toAuthMethodDetails()); + } + return convert; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDisplayName() { + return displayName; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public Set getFeatures() { + return features; + } } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java index 5d55896d..04dcc2f7 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java @@ -6,6 +6,7 @@ import pro.gravit.launcher.base.profiles.optional.OptionalDepend; import pro.gravit.launcher.base.profiles.optional.OptionalFile; import pro.gravit.launcher.base.profiles.optional.triggers.OptionalTrigger; +import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.launch.LaunchOptions; @@ -15,7 +16,7 @@ import java.nio.file.Path; import java.util.*; -public final class ClientProfile implements Comparable { +public final class ClientProfile implements Comparable, ProfileFeatureAPI.ClientProfile { private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher( new String[0], new String[]{"indexes", "objects"}, new String[0]); private transient Path profileFilePath; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/PlayerProfile.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/PlayerProfile.java index e0190993..00862e54 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/PlayerProfile.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/PlayerProfile.java @@ -1,5 +1,6 @@ package pro.gravit.launcher.base.profiles; +import pro.gravit.launcher.core.api.model.User; import pro.gravit.utils.helper.IOHelper; import java.util.HashMap; @@ -7,7 +8,7 @@ import java.util.Objects; import java.util.UUID; -public final class PlayerProfile { +public final class PlayerProfile implements User { public final UUID uuid; public final String username; @@ -49,4 +50,23 @@ public static UUID offlineUUID(String username) { return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username)); } + @Override + public String getUsername() { + return username; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public Map getAssets() { + return assets; + } + + @Override + public Map getProperties() { + return properties; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/Texture.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/Texture.java index 568f1d14..dee9b732 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/Texture.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/Texture.java @@ -14,7 +14,7 @@ import java.util.Arrays; import java.util.Map; -public final class Texture extends StreamObject { +public final class Texture extends StreamObject implements pro.gravit.launcher.core.api.model.Texture { private static final SecurityHelper.DigestAlgorithm DIGEST_ALGO = SecurityHelper.DigestAlgorithm.SHA256; // Instance @@ -85,4 +85,19 @@ public String toString() { ", metadata=" + metadata + '}'; } + + @Override + public String getUrl() { + return url; + } + + @Override + public String getHash() { + return SecurityHelper.toHex(digest); + } + + @Override + public Map getMetadata() { + return metadata; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestCoreFeatureAPIImpl.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestCoreFeatureAPIImpl.java new file mode 100644 index 00000000..66d54a9c --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestCoreFeatureAPIImpl.java @@ -0,0 +1,31 @@ +package pro.gravit.launcher.base.request; + +import pro.gravit.launcher.base.request.auth.GetAvailabilityAuthRequest; +import pro.gravit.launcher.base.request.update.LauncherRequest; +import pro.gravit.launcher.core.api.features.CoreFeatureAPI; +import pro.gravit.launcher.core.api.method.AuthMethod; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class RequestCoreFeatureAPIImpl implements CoreFeatureAPI { + private final RequestService request; + + public RequestCoreFeatureAPIImpl(RequestService request) { + this.request = request; + } + + + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public CompletableFuture> getAuthMethods() { + return request.request(new GetAvailabilityAuthRequest()).thenApply(response -> (List) response.list); + } + + @Override + public CompletableFuture checkUpdates() { + return request.request(new LauncherRequest()).thenApply(response -> new LauncherUpdateInfo(response.url, + "Unknown", response.needUpdate, response.needUpdate)); + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java new file mode 100644 index 00000000..b8a9d53c --- /dev/null +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java @@ -0,0 +1,169 @@ +package pro.gravit.launcher.base.request; + +import pro.gravit.launcher.base.Launcher; +import pro.gravit.launcher.base.request.auth.*; +import pro.gravit.launcher.base.request.auth.password.*; +import pro.gravit.launcher.base.request.update.ProfilesRequest; +import pro.gravit.launcher.base.request.update.UpdateRequest; +import pro.gravit.launcher.base.request.uuid.ProfileByUUIDRequest; +import pro.gravit.launcher.base.request.uuid.ProfileByUsernameRequest; +import pro.gravit.launcher.core.api.features.AuthFeatureAPI; +import pro.gravit.launcher.core.api.features.UserFeatureAPI; +import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; +import pro.gravit.launcher.core.api.method.AuthMethodPassword; +import pro.gravit.launcher.core.api.method.password.AuthChainPassword; +import pro.gravit.launcher.core.api.method.password.AuthOAuthPassword; +import pro.gravit.launcher.core.api.method.password.AuthPlainPassword; +import pro.gravit.launcher.core.api.method.password.AuthTotpPassword; +import pro.gravit.launcher.core.api.model.SelfUser; +import pro.gravit.launcher.core.api.model.User; +import pro.gravit.launcher.core.hasher.HashedDir; +import pro.gravit.utils.helper.SecurityHelper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class RequestFeatureAPIImpl implements AuthFeatureAPI, UserFeatureAPI, ProfileFeatureAPI { + private final RequestService request; + private final String authId; + + public RequestFeatureAPIImpl(RequestService request, String authId) { + this.request = request; + this.authId = authId; + } + + @Override + public CompletableFuture getCurrentUser() { + return request.request(new CurrentUserRequest()).thenApply(response -> response.userInfo); + } + + @Override + public CompletableFuture auth(String login, AuthMethodPassword password) { + return request.request(new AuthRequest(login, convertAuthPasswordAll(password), authId, false, AuthRequest.ConnectTypes.CLIENT)) + .thenApply(response -> new AuthResponse(response.makeUserInfo(), response.oauth)); + } + + private AuthRequest.AuthPasswordInterface convertAuthPasswordAll(AuthMethodPassword password) { + AuthRequest.AuthPasswordInterface requestPassword; + if(password instanceof AuthChainPassword chain) { + if(chain.list().size() == 1) { + requestPassword = convertAuthPassword(chain.list().get(0)); + } else if(chain.list().size() == 2) { + requestPassword = new Auth2FAPassword(convertAuthPassword(chain.list().get(0)), + convertAuthPassword(chain.list().get(1))); + } else { + var multi = new AuthMultiPassword(); + for(var e : chain.list()) { + multi.list.add(convertAuthPassword(e)); + } + requestPassword = multi; + } + } else { + requestPassword = convertAuthPassword(password); + } + return requestPassword; + } + + private AuthRequest.AuthPasswordInterface convertAuthPassword(AuthMethodPassword password) { + if(password instanceof AuthPlainPassword plain) { + String encryptKey = Launcher.getConfig().passwordEncryptKey; + if(encryptKey != null) { + try { + return new AuthAESPassword(SecurityHelper.encrypt(encryptKey, plain.value())); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + return new pro.gravit.launcher.base.request.auth.password.AuthPlainPassword(plain.value()); + } + } else if(password instanceof AuthTotpPassword totp) { + return new AuthTOTPPassword(totp.value()); + } else if(password instanceof AuthOAuthPassword oauth) { + return new AuthCodePassword(oauth.redirectUrl()); + } else if(password instanceof AuthRequest.AuthPasswordInterface custom) { + return custom; + } + else { + throw new UnsupportedOperationException(); + } + } + + @Override + public CompletableFuture getUserByUsername(String username) { + return request.request(new ProfileByUsernameRequest(username)).thenApply(response -> response.playerProfile); + } + + @Override + public CompletableFuture getUserByUUID(UUID uuid) { + return request.request(new ProfileByUUIDRequest(uuid)).thenApply(response -> response.playerProfile); + } + + @Override + public CompletableFuture joinServer(String username, String accessToken, String serverID) { + return request.request(new JoinServerRequest(username, accessToken, serverID)).thenCompose(response -> { + if(response.allow) { + return CompletableFuture.completedFuture(null); + } else { + return CompletableFuture.failedFuture(new RequestException("Not allowed")); + } + }); + } + + @Override + public CompletableFuture joinServer(UUID uuid, String accessToken, String serverID) { + return request.request(new JoinServerRequest(uuid, accessToken, serverID)).thenCompose(response -> { + if(response.allow) { + return CompletableFuture.completedFuture(null); + } else { + return CompletableFuture.failedFuture(new RequestException("Not allowed")); + } + }); + } + + @Override + public CompletableFuture checkServer(String username, String serverID, boolean extended) { + return request.request(new CheckServerRequest(username, serverID, extended, extended)) + .thenApply(response -> new CheckServerResponse(response.playerProfile, response.hardwareId, + response.sessionId, response.sessionProperties)); + } + + @Override + public CompletableFuture refreshToken(String refreshToken) { + return request.request(new RefreshTokenRequest(authId, refreshToken)).thenApply(response -> response.oauth); + } + + @Override + public CompletableFuture restore(String accessToken, boolean fetchUser) { + Map extended = new HashMap<>(); + if(Request.getExtendedTokens() != null) { // TODO: Control extended token + for(var e : Request.getExtendedTokens().entrySet()) { + extended.put(e.getKey(), e.getValue().token); + } + } + return request.request(new RestoreRequest(authId, accessToken, extended, fetchUser)).thenApply(e -> { + // TODO: invalidToken process + return e.userInfo; + }); + } + + @Override + public CompletableFuture exit() { + return request.request(new ExitRequest()).thenApply(response -> null); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public CompletableFuture> getProfiles() { + return request.request(new ProfilesRequest()).thenApply(response -> (List) response.profiles); + } + + @Override + public CompletableFuture fetchUpdateInfo(String dirName) { + return request.request(new UpdateRequest(dirName)).thenApply(response -> new UpdateInfoData(response.hdir, response.url)); + } + + public record UpdateInfoData(HashedDir hdir, String url) implements ProfileFeatureAPI.UpdateInfo {} +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestService.java index bad2ebd1..643c98f1 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestService.java @@ -5,7 +5,7 @@ import java.util.concurrent.ExecutionException; public interface RequestService { - CompletableFuture request(Request request) throws IOException; + CompletableFuture request(Request request); void open() throws Exception; void registerEventHandler(EventHandler handler); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/AuthRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/AuthRequest.java index 5cbc489f..59ab371b 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/AuthRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/AuthRequest.java @@ -5,6 +5,7 @@ import pro.gravit.launcher.base.request.Request; import pro.gravit.launcher.base.request.auth.password.*; import pro.gravit.launcher.base.request.websockets.WebSocketRequest; +import pro.gravit.launcher.core.api.method.AuthMethodPassword; import pro.gravit.utils.ProviderMap; public final class AuthRequest extends Request implements WebSocketRequest { @@ -64,7 +65,7 @@ public enum ConnectTypes { API } - public interface AuthPasswordInterface { + public interface AuthPasswordInterface extends AuthMethodPassword { boolean check(); default boolean isAllowSave() { diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthLoginOnlyDetails.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthLoginOnlyDetails.java index a5813a17..68630ac3 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthLoginOnlyDetails.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthLoginOnlyDetails.java @@ -1,10 +1,16 @@ package pro.gravit.launcher.base.request.auth.details; import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.core.api.method.AuthMethodDetails; public class AuthLoginOnlyDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails { @Override public String getType() { return "loginonly"; } + + @Override + public AuthMethodDetails toAuthMethodDetails() { + return new pro.gravit.launcher.core.api.method.details.AuthLoginOnlyDetails(); + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthPasswordDetails.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthPasswordDetails.java index 825fa36f..2cbc66bb 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthPasswordDetails.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthPasswordDetails.java @@ -1,6 +1,7 @@ package pro.gravit.launcher.base.request.auth.details; import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.core.api.method.AuthMethodDetails; public class AuthPasswordDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails { @Override @@ -9,4 +10,8 @@ public String getType() { } + @Override + public AuthMethodDetails toAuthMethodDetails() { + return new pro.gravit.launcher.core.api.method.details.AuthPasswordDetails(); + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthTotpDetails.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthTotpDetails.java index 80c4048e..fdbce796 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthTotpDetails.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthTotpDetails.java @@ -1,6 +1,7 @@ package pro.gravit.launcher.base.request.auth.details; import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.core.api.method.AuthMethodDetails; public class AuthTotpDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails { public final String alg; @@ -20,4 +21,9 @@ public AuthTotpDetails(String alg) { public String getType() { return "totp"; } + + @Override + public AuthMethodDetails toAuthMethodDetails() { + return new pro.gravit.launcher.core.api.method.details.AuthTotpDetails(maxKeyLength); + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthWebViewDetails.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthWebViewDetails.java index 3090d251..8b4a6593 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthWebViewDetails.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/details/AuthWebViewDetails.java @@ -1,6 +1,8 @@ package pro.gravit.launcher.base.request.auth.details; import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent; +import pro.gravit.launcher.core.api.method.AuthMethodDetails; +import pro.gravit.launcher.core.api.method.details.AuthWebDetails; public class AuthWebViewDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails { public final String url; @@ -26,4 +28,9 @@ public AuthWebViewDetails(String url, String redirectUrl) { public String getType() { return "webview"; } + + @Override + public AuthMethodDetails toAuthMethodDetails() { + return new AuthWebDetails(url, redirectUrl, canBrowser); + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/Auth2FAPassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/Auth2FAPassword.java index 05672942..9732d69f 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/Auth2FAPassword.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/Auth2FAPassword.java @@ -6,6 +6,14 @@ public class Auth2FAPassword implements AuthRequest.AuthPasswordInterface { public AuthRequest.AuthPasswordInterface firstPassword; public AuthRequest.AuthPasswordInterface secondPassword; + public Auth2FAPassword() { + } + + public Auth2FAPassword(AuthRequest.AuthPasswordInterface firstPassword, AuthRequest.AuthPasswordInterface secondPassword) { + this.firstPassword = firstPassword; + this.secondPassword = secondPassword; + } + @Override public boolean check() { return firstPassword != null && firstPassword.check() && secondPassword != null && secondPassword.check(); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/AuthTOTPPassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/AuthTOTPPassword.java index 4ddccec6..00c2aec1 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/AuthTOTPPassword.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/auth/password/AuthTOTPPassword.java @@ -5,6 +5,13 @@ public class AuthTOTPPassword implements AuthRequest.AuthPasswordInterface { public String totp; + public AuthTOTPPassword() { + } + + public AuthTOTPPassword(String totp) { + this.totp = totp; + } + @Override public boolean check() { return true; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/websockets/StdWebSocketService.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/websockets/StdWebSocketService.java index fe6dade9..76c979b0 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/websockets/StdWebSocketService.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/websockets/StdWebSocketService.java @@ -98,10 +98,14 @@ public void eventHandle(T webSocketEvent) { processEventHandlers(webSocketEvent); } - public CompletableFuture request(Request request) throws IOException { + public CompletableFuture request(Request request) { CompletableFuture result = new CompletableFuture<>(); futureMap.put(request.requestUUID, result); - sendObject(request, WebSocketRequest.class); + try { + sendObject(request, WebSocketRequest.class); + } catch (IOException e) { + return CompletableFuture.failedFuture(e); + } return result; } diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/LauncherBackendAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/LauncherBackendAPI.java new file mode 100644 index 00000000..f41dbab0 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/LauncherBackendAPI.java @@ -0,0 +1,109 @@ +package pro.gravit.launcher.core; + +import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; +import pro.gravit.launcher.core.api.method.AuthMethod; +import pro.gravit.launcher.core.api.method.AuthMethodPassword; +import pro.gravit.launcher.core.api.model.SelfUser; +import pro.gravit.launcher.core.api.model.Texture; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public interface LauncherBackendAPI { + void setCallback(MainCallback callback); + CompletableFuture init(); + void selectAuthMethod(AuthMethod method); + CompletableFuture tryAuthorize(); + CompletableFuture authorize(String login, AuthMethodPassword password); + CompletableFuture> fetchProfiles(); + ClientProfileSettings makeClientProfileSettings(ProfileFeatureAPI.ClientProfile profile); + CompletableFuture downloadProfile(ProfileFeatureAPI.ClientProfile profile, ClientProfileSettings settings, DownloadCallback callback); + // Tools + CompletableFuture fetchTexture(Texture texture); + + record LauncherInitData(List methods) {} + + interface ReadyProfile { + ProfileFeatureAPI.ClientProfile getClientProfile(); + ClientProfileSettings getSettings(); + void run(RunCallback callback) throws Exception; + } + + interface ClientProfileSettings { + long getReservedMemoryBytes(); + long getMaxMemoryBytes(); + void setReservedMemoryBytes(long value); + List getFlags(); + boolean hasFlag(Flag flag); + void addFlag(Flag flag); + void removeFlag(Flag flag); + List getEnabledOptionals(); + void enableOptional(ProfileFeatureAPI.OptionalMod mod, ChangedOptionalStatusCallback callback); + void disableOptional(ProfileFeatureAPI.OptionalMod mod, ChangedOptionalStatusCallback callback); + + enum Flag { + + } + + interface ChangedOptionalStatusCallback { + void onChanged(ProfileFeatureAPI.OptionalMod mod, boolean enabled); + } + } + + // Callbacks + + class MainCallback { + // On any request + public void onChangeStatus(String status) { + + } + + public void onProfiles(List profiles) { + + } + + public void onAuthorize(SelfUser selfUser) { + + } + + public void onNotify(String header, String description) { + + } + } + + class RunCallback { + public void onStarted() { + + } + + public void onFinished(int code) { + + } + + public void onNormalOutput(byte[] buf, int offset, int size) { + + } + + public void onErrorOutput(byte[] buf, int offset, int size) { + + } + } + + class DownloadCallback { + public void onStage(String stage) { + + } + + public void onCanCancel(Runnable cancel) { + + } + + public void onTotalDownload(long total) { + + } + + public void onCurrentDownloaded(long current) { + + } + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPI.java new file mode 100644 index 00000000..206c27d7 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPI.java @@ -0,0 +1,34 @@ +package pro.gravit.launcher.core.api; + +import pro.gravit.launcher.core.api.features.AuthFeatureAPI; +import pro.gravit.launcher.core.api.features.FeatureAPI; +import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; +import pro.gravit.launcher.core.api.features.UserFeatureAPI; + +import java.util.HashMap; +import java.util.Map; + +public class LauncherAPI { + private final Map, FeatureAPI> map; + + public LauncherAPI(Map, FeatureAPI> map) { + this.map = new HashMap<>(map); + } + + public AuthFeatureAPI auth() { + return get(AuthFeatureAPI.class); + } + + public UserFeatureAPI user() { + return get(UserFeatureAPI.class); + } + + public ProfileFeatureAPI profile() { + return get(ProfileFeatureAPI.class); + } + + @SuppressWarnings("unchecked") + public T get(Class clazz) { + return (T) map.get(clazz); + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPIHolder.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPIHolder.java new file mode 100644 index 00000000..048281e7 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/LauncherAPIHolder.java @@ -0,0 +1,70 @@ +package pro.gravit.launcher.core.api; + +import pro.gravit.launcher.core.api.features.AuthFeatureAPI; +import pro.gravit.launcher.core.api.features.CoreFeatureAPI; +import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; +import pro.gravit.launcher.core.api.features.UserFeatureAPI; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +public final class LauncherAPIHolder { + private static volatile CoreFeatureAPI coreAPI; + private static volatile LauncherAPI api; + private static volatile Function createApiFactory; + private static final Map map = new ConcurrentHashMap<>(); + + public static void setCoreAPI(CoreFeatureAPI coreAPI) { + LauncherAPIHolder.coreAPI = coreAPI; + } + + public static void setApi(LauncherAPI api) { + LauncherAPIHolder.api = api; + } + + public static void setCreateApiFactory(Function createApiFactory) { + LauncherAPIHolder.createApiFactory = createApiFactory; + } + + public static void changeAuthId(String authId) { + LauncherAPIHolder.api = map.computeIfAbsent(authId, createApiFactory); + } + + public static LauncherAPI get() { + return api; + } + + public static LauncherAPI get(String authId) { + return map.computeIfAbsent(authId, createApiFactory); + } + + public static CoreFeatureAPI core() { + return coreAPI; + } + + public static AuthFeatureAPI auth() { + if(api == null) { + throw new UnsupportedOperationException(); + } + return api.auth(); + } + + public static UserFeatureAPI user() { + if(api == null) { + throw new UnsupportedOperationException(); + } + return api.user(); + } + + public static ProfileFeatureAPI profile() { + if(api == null) { + throw new UnsupportedOperationException(); + } + return api.profile(); + } + + public static void set(LauncherAPI api) { + LauncherAPIHolder.api = api; + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/AuthFeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/AuthFeatureAPI.java new file mode 100644 index 00000000..04375268 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/AuthFeatureAPI.java @@ -0,0 +1,24 @@ +package pro.gravit.launcher.core.api.features; + +import pro.gravit.launcher.core.api.method.AuthMethod; +import pro.gravit.launcher.core.api.method.AuthMethodPassword; +import pro.gravit.launcher.core.api.model.SelfUser; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public interface AuthFeatureAPI extends FeatureAPI { + CompletableFuture getCurrentUser(); + CompletableFuture auth(String login, AuthMethodPassword password); + CompletableFuture refreshToken(String refreshToken); + CompletableFuture restore(String accessToken, boolean fetchUser); + CompletableFuture exit(); + + record AuthResponse(SelfUser user, AuthToken authToken) {} + + interface AuthToken { + String getAccessToken(); + String getRefreshToken(); + long getExpire(); + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/CoreFeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/CoreFeatureAPI.java new file mode 100644 index 00000000..1b1c241f --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/CoreFeatureAPI.java @@ -0,0 +1,13 @@ +package pro.gravit.launcher.core.api.features; + +import pro.gravit.launcher.core.api.method.AuthMethod; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public interface CoreFeatureAPI { + CompletableFuture> getAuthMethods(); + CompletableFuture checkUpdates(); + + record LauncherUpdateInfo(String url, String version, boolean available, boolean required) {} +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/FeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/FeatureAPI.java new file mode 100644 index 00000000..2a71e92c --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/FeatureAPI.java @@ -0,0 +1,4 @@ +package pro.gravit.launcher.core.api.features; + +public interface FeatureAPI { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/ProfileFeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/ProfileFeatureAPI.java new file mode 100644 index 00000000..b751de40 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/ProfileFeatureAPI.java @@ -0,0 +1,26 @@ +package pro.gravit.launcher.core.api.features; + +import pro.gravit.launcher.core.hasher.HashedDir; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public interface ProfileFeatureAPI extends FeatureAPI { + CompletableFuture> getProfiles(); + CompletableFuture fetchUpdateInfo(String dirName); + + interface UpdateInfo {} + + interface ClientProfile { + String getName(); + UUID getUUID(); + List getOptionalMods(); + } + + interface OptionalMod { + String getName(); + String getDescription(); + String getCategory(); + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/UserFeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/UserFeatureAPI.java new file mode 100644 index 00000000..7fec7265 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/UserFeatureAPI.java @@ -0,0 +1,37 @@ +package pro.gravit.launcher.core.api.features; + +import pro.gravit.launcher.core.api.model.User; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public interface UserFeatureAPI extends FeatureAPI { + CompletableFuture getUserByUsername(String username); + CompletableFuture getUserByUUID(UUID uuid); + CompletableFuture joinServer(String username, String accessToken, String serverID); + CompletableFuture joinServer(UUID uuid, String accessToken, String serverID); + CompletableFuture checkServer(String username, String serverID, boolean extended); + default CompletableFuture> getUsersByUsernames(List usernames) { + List> list = new ArrayList<>(); + for(var username : usernames) { + list.add(getUserByUsername(username)); + } + return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)).thenApply(x -> { + List r = new ArrayList<>(); + for(var e : list) { + try { + r.add(e.get()); + } catch (InterruptedException | ExecutionException ex) { + r.add(null); + } + } + return r; + }); + } + + record CheckServerResponse(User user, String hardwareId, String sessionId, Map sessionProperties) {} +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethod.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethod.java new file mode 100644 index 00000000..e4881074 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethod.java @@ -0,0 +1,12 @@ +package pro.gravit.launcher.core.api.method; + +import java.util.List; +import java.util.Set; + +public interface AuthMethod { + List getDetails(); + String getName(); + String getDisplayName(); + boolean isVisible(); + Set getFeatures(); +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodDetails.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodDetails.java new file mode 100644 index 00000000..27cbed00 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodDetails.java @@ -0,0 +1,4 @@ +package pro.gravit.launcher.core.api.method; + +public interface AuthMethodDetails { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodPassword.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodPassword.java new file mode 100644 index 00000000..de8854d1 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/AuthMethodPassword.java @@ -0,0 +1,4 @@ +package pro.gravit.launcher.core.api.method; + +public interface AuthMethodPassword { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthLoginOnlyDetails.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthLoginOnlyDetails.java new file mode 100644 index 00000000..535d5d3f --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthLoginOnlyDetails.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.details; + +import pro.gravit.launcher.core.api.method.AuthMethodDetails; + +public class AuthLoginOnlyDetails implements AuthMethodDetails { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthPasswordDetails.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthPasswordDetails.java new file mode 100644 index 00000000..36e519a4 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthPasswordDetails.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.details; + +import pro.gravit.launcher.core.api.method.AuthMethodDetails; + +public class AuthPasswordDetails implements AuthMethodDetails { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthTotpDetails.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthTotpDetails.java new file mode 100644 index 00000000..ee4f1899 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthTotpDetails.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.details; + +import pro.gravit.launcher.core.api.method.AuthMethodDetails; + +public record AuthTotpDetails(int length) implements AuthMethodDetails { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthWebDetails.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthWebDetails.java new file mode 100644 index 00000000..6dba7293 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/details/AuthWebDetails.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.details; + +import pro.gravit.launcher.core.api.method.AuthMethodDetails; + +public record AuthWebDetails(String url, String redirectUrl, boolean externalBrowserSupport) implements AuthMethodDetails { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthChainPassword.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthChainPassword.java new file mode 100644 index 00000000..f95f7773 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthChainPassword.java @@ -0,0 +1,8 @@ +package pro.gravit.launcher.core.api.method.password; + +import pro.gravit.launcher.core.api.method.AuthMethodPassword; + +import java.util.List; + +public record AuthChainPassword(List list) implements AuthMethodPassword { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthOAuthPassword.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthOAuthPassword.java new file mode 100644 index 00000000..40af34e0 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthOAuthPassword.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.password; + +import pro.gravit.launcher.core.api.method.AuthMethodPassword; + +public record AuthOAuthPassword(String redirectUrl) implements AuthMethodPassword { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthPlainPassword.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthPlainPassword.java new file mode 100644 index 00000000..d0d1fbf7 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthPlainPassword.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.password; + +import pro.gravit.launcher.core.api.method.AuthMethodPassword; + +public record AuthPlainPassword(String value) implements AuthMethodPassword { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthTotpPassword.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthTotpPassword.java new file mode 100644 index 00000000..e63f4f37 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/method/password/AuthTotpPassword.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.method.password; + +import pro.gravit.launcher.core.api.method.AuthMethodPassword; + +public record AuthTotpPassword(String value) implements AuthMethodPassword { +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/SelfUser.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/SelfUser.java new file mode 100644 index 00000000..3345be64 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/SelfUser.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.model; + +public interface SelfUser extends User { + String getAccessToken(); + UserPermissions getPermissions(); +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/Texture.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/Texture.java new file mode 100644 index 00000000..4fd79f98 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/Texture.java @@ -0,0 +1,9 @@ +package pro.gravit.launcher.core.api.model; + +import java.util.Map; + +public interface Texture { + String getUrl(); + String getHash(); + Map getMetadata(); +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/User.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/User.java new file mode 100644 index 00000000..5d1fbd07 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/User.java @@ -0,0 +1,11 @@ +package pro.gravit.launcher.core.api.model; + +import java.util.Map; +import java.util.UUID; + +public interface User { + String getUsername(); + UUID getUUID(); + Map getAssets(); + Map getProperties(); +} diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/UserPermissions.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/UserPermissions.java new file mode 100644 index 00000000..6f6520e8 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/model/UserPermissions.java @@ -0,0 +1,6 @@ +package pro.gravit.launcher.core.api.model; + +public interface UserPermissions { + boolean hasRole(String role); + boolean hasPerm(String action); +} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 6c9a7360..60b56f14 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -5,10 +5,10 @@ public final class Version implements Comparable { public static final int MAJOR = 5; - public static final int MINOR = 6; - public static final int PATCH = 3; + public static final int MINOR = 7; + public static final int PATCH = 0; public static final int BUILD = 1; - public static final Version.Type RELEASE = Type.DEV; + public static final Version.Type RELEASE = Type.EXPERIMENTAL; public final int major; public final int minor; public final int patch; 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 a1c7e6d5..082cbf7b 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java @@ -29,10 +29,13 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Type; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class ServerWrapper extends JsonConfigurable { public static final Path configFile = Paths.get(System.getProperty("serverwrapper.configFile", "ServerWrapperConfig.json")); @@ -187,14 +190,30 @@ public void run(String... args) throws Throwable { System.load(Paths.get(config.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString()); } } + List classpath = config.classpath; + if(config.resolveClassPath) { + classpath = new ArrayList<>(); + for(var cp : config.classpath) { + Path p = Paths.get(cp); + if(Files.isDirectory(p)) { + try(Stream files = Files.walk(p, FileVisitOption.FOLLOW_LINKS)) { + var resolved = files.filter(e -> !Files.isDirectory(e)) + .filter(e -> e.getFileName().toString().endsWith(".jar")).map(e -> e.toAbsolutePath().toString()).toList(); + classpath.addAll(resolved); + } + } else { + classpath.add(p.toAbsolutePath().toString()); + } + } + } switch (config.classLoaderConfig) { case LAUNCHER: launch = new LegacyLaunch(); - System.setProperty("java.class.path", String.join(File.pathSeparator, config.classpath)); + System.setProperty("java.class.path", String.join(File.pathSeparator, classpath)); break; case MODULE: launch = new ModuleLaunch(); - System.setProperty("java.class.path", String.join(File.pathSeparator, config.classpath)); + System.setProperty("java.class.path", String.join(File.pathSeparator, classpath)); break; default: if(ServerAgent.isAgentStarted()) { @@ -207,7 +226,7 @@ public void run(String... args) throws Throwable { LaunchOptions options = new LaunchOptions(); options.enableHacks = config.enableHacks; options.moduleConf = config.moduleConf; - classLoaderControl = launch.init(config.classpath.stream().map(Paths::get).collect(Collectors.toCollection(ArrayList::new)), config.nativesDir, options); + classLoaderControl = launch.init(classpath.stream().map(Paths::get).collect(Collectors.toCollection(ArrayList::new)), config.nativesDir, options); if(ServerAgent.isAgentStarted()) { ClientService.instrumentation = ServerAgent.inst; } @@ -269,6 +288,7 @@ public static final class Config { public String address; public String serverName; public boolean autoloadLibraries; + public boolean resolveClassPath = true; public String logFile; public List classpath; public ClientProfile.ClassLoaderConfig classLoaderConfig;