mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE][EXPERIMENTAL] New API
This commit is contained in:
parent
7f6a645dd7
commit
f6b3a62497
44 changed files with 838 additions and 19 deletions
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"features": [],
|
"features": ["new-api"],
|
||||||
"info": []
|
"info": []
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package pro.gravit.launcher.base;
|
package pro.gravit.launcher.base;
|
||||||
|
|
||||||
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
||||||
|
import pro.gravit.launcher.core.api.model.UserPermissions;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ClientPermissions {
|
public class ClientPermissions implements UserPermissions {
|
||||||
public static final ClientPermissions DEFAULT = new ClientPermissions();
|
public static final ClientPermissions DEFAULT = new ClientPermissions();
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private List<String> roles;
|
private List<String> roles;
|
||||||
|
@ -28,6 +29,7 @@ public static ClientPermissions getSuperuserAccount() {
|
||||||
return perm;
|
return perm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean hasRole(String role) {
|
public boolean hasRole(String role) {
|
||||||
return roles != null && roles.contains(role);
|
return roles != null && roles.contains(role);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +48,7 @@ public synchronized void compile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean hasPerm(String action) {
|
public boolean hasPerm(String action) {
|
||||||
if (available == null) {
|
if (available == null) {
|
||||||
compile();
|
compile();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launcher.base.events.request;
|
package pro.gravit.launcher.base.events.request;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.ClientPermissions;
|
import pro.gravit.launcher.base.ClientPermissions;
|
||||||
|
import pro.gravit.launcher.core.api.features.AuthFeatureAPI;
|
||||||
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
import pro.gravit.launcher.core.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.base.events.RequestEvent;
|
import pro.gravit.launcher.base.events.RequestEvent;
|
||||||
import pro.gravit.launcher.base.profiles.PlayerProfile;
|
import pro.gravit.launcher.base.profiles.PlayerProfile;
|
||||||
|
@ -67,7 +68,15 @@ public String getType() {
|
||||||
return "auth";
|
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 accessToken;
|
||||||
public final String refreshToken;
|
public final String refreshToken;
|
||||||
public final long expire;
|
public final long expire;
|
||||||
|
@ -77,5 +86,20 @@ public OAuthRequestEvent(String accessToken, String refreshToken, long expire) {
|
||||||
this.refreshToken = refreshToken;
|
this.refreshToken = refreshToken;
|
||||||
this.expire = expire;
|
this.expire = expire;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getExpire() {
|
||||||
|
return expire;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
import pro.gravit.launcher.base.ClientPermissions;
|
import pro.gravit.launcher.base.ClientPermissions;
|
||||||
import pro.gravit.launcher.base.events.RequestEvent;
|
import pro.gravit.launcher.base.events.RequestEvent;
|
||||||
import pro.gravit.launcher.base.profiles.PlayerProfile;
|
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 class CurrentUserRequestEvent extends RequestEvent {
|
||||||
public final UserInfo userInfo;
|
public final UserInfo userInfo;
|
||||||
|
@ -16,9 +21,40 @@ public String getType() {
|
||||||
return "currentUser";
|
return "currentUser";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UserInfo {
|
public static class UserInfo implements SelfUser {
|
||||||
public ClientPermissions permissions;
|
public ClientPermissions permissions;
|
||||||
public String accessToken;
|
public String accessToken;
|
||||||
public PlayerProfile playerProfile;
|
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<String, Texture> getAssets() {
|
||||||
|
return (Map) playerProfile.getAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getProperties() {
|
||||||
|
return playerProfile.getProperties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
package pro.gravit.launcher.base.events.request;
|
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.core.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.base.events.RequestEvent;
|
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 pro.gravit.utils.TypeSerializeInterface;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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<AuthAvailabilityDetails> details;
|
public final List<AuthAvailabilityDetails> details;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String name;
|
public String name;
|
||||||
|
@ -59,5 +67,34 @@ public AuthAvailability(List<AuthAvailabilityDetails> details, String name, Stri
|
||||||
this.visible = visible;
|
this.visible = visible;
|
||||||
this.features = features;
|
this.features = features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AuthMethodDetails> getDetails() {
|
||||||
|
List<AuthMethodDetails> 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<String> getFeatures() {
|
||||||
|
return features;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import pro.gravit.launcher.base.profiles.optional.OptionalDepend;
|
import pro.gravit.launcher.base.profiles.optional.OptionalDepend;
|
||||||
import pro.gravit.launcher.base.profiles.optional.OptionalFile;
|
import pro.gravit.launcher.base.profiles.optional.OptionalFile;
|
||||||
import pro.gravit.launcher.base.profiles.optional.triggers.OptionalTrigger;
|
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.IOHelper;
|
||||||
import pro.gravit.utils.helper.VerifyHelper;
|
import pro.gravit.utils.helper.VerifyHelper;
|
||||||
import pro.gravit.utils.launch.LaunchOptions;
|
import pro.gravit.utils.launch.LaunchOptions;
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public final class ClientProfile implements Comparable<ClientProfile> {
|
public final class ClientProfile implements Comparable<ClientProfile>, ProfileFeatureAPI.ClientProfile {
|
||||||
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
||||||
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
||||||
private transient Path profileFilePath;
|
private transient Path profileFilePath;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.launcher.base.profiles;
|
package pro.gravit.launcher.base.profiles;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.core.api.model.User;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -7,7 +8,7 @@
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public final class PlayerProfile {
|
public final class PlayerProfile implements User {
|
||||||
|
|
||||||
public final UUID uuid;
|
public final UUID uuid;
|
||||||
public final String username;
|
public final String username;
|
||||||
|
@ -49,4 +50,23 @@ public static UUID offlineUUID(String username) {
|
||||||
return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
|
return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUUID() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Texture> getAssets() {
|
||||||
|
return assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
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;
|
private static final SecurityHelper.DigestAlgorithm DIGEST_ALGO = SecurityHelper.DigestAlgorithm.SHA256;
|
||||||
|
|
||||||
// Instance
|
// Instance
|
||||||
|
@ -85,4 +85,19 @@ public String toString() {
|
||||||
", metadata=" + metadata +
|
", metadata=" + metadata +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHash() {
|
||||||
|
return SecurityHelper.toHex(digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<List<AuthMethod>> getAuthMethods() {
|
||||||
|
return request.request(new GetAvailabilityAuthRequest()).thenApply(response -> (List) response.list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<LauncherUpdateInfo> checkUpdates() {
|
||||||
|
return request.request(new LauncherRequest()).thenApply(response -> new LauncherUpdateInfo(response.url,
|
||||||
|
"Unknown", response.needUpdate, response.needUpdate));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<SelfUser> getCurrentUser() {
|
||||||
|
return request.request(new CurrentUserRequest()).thenApply(response -> response.userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<AuthResponse> 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<User> getUserByUsername(String username) {
|
||||||
|
return request.request(new ProfileByUsernameRequest(username)).thenApply(response -> response.playerProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<User> getUserByUUID(UUID uuid) {
|
||||||
|
return request.request(new ProfileByUUIDRequest(uuid)).thenApply(response -> response.playerProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> 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<Void> 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<CheckServerResponse> 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<AuthToken> refreshToken(String refreshToken) {
|
||||||
|
return request.request(new RefreshTokenRequest(authId, refreshToken)).thenApply(response -> response.oauth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<SelfUser> restore(String accessToken, boolean fetchUser) {
|
||||||
|
Map<String, String> 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<Void> exit() {
|
||||||
|
return request.request(new ExitRequest()).thenApply(response -> null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<List<ProfileFeatureAPI.ClientProfile>> getProfiles() {
|
||||||
|
return request.request(new ProfilesRequest()).thenApply(response -> (List) response.profiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<UpdateInfo> 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 {}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public interface RequestService {
|
public interface RequestService {
|
||||||
<T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException;
|
<T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request);
|
||||||
void open() throws Exception;
|
void open() throws Exception;
|
||||||
|
|
||||||
void registerEventHandler(EventHandler handler);
|
void registerEventHandler(EventHandler handler);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import pro.gravit.launcher.base.request.Request;
|
import pro.gravit.launcher.base.request.Request;
|
||||||
import pro.gravit.launcher.base.request.auth.password.*;
|
import pro.gravit.launcher.base.request.auth.password.*;
|
||||||
import pro.gravit.launcher.base.request.websockets.WebSocketRequest;
|
import pro.gravit.launcher.base.request.websockets.WebSocketRequest;
|
||||||
|
import pro.gravit.launcher.core.api.method.AuthMethodPassword;
|
||||||
import pro.gravit.utils.ProviderMap;
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
|
||||||
public final class AuthRequest extends Request<AuthRequestEvent> implements WebSocketRequest {
|
public final class AuthRequest extends Request<AuthRequestEvent> implements WebSocketRequest {
|
||||||
|
@ -64,7 +65,7 @@ public enum ConnectTypes {
|
||||||
API
|
API
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface AuthPasswordInterface {
|
public interface AuthPasswordInterface extends AuthMethodPassword {
|
||||||
boolean check();
|
boolean check();
|
||||||
|
|
||||||
default boolean isAllowSave() {
|
default boolean isAllowSave() {
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
package pro.gravit.launcher.base.request.auth.details;
|
package pro.gravit.launcher.base.request.auth.details;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.core.api.method.AuthMethodDetails;
|
||||||
|
|
||||||
public class AuthLoginOnlyDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
public class AuthLoginOnlyDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "loginonly";
|
return "loginonly";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthMethodDetails toAuthMethodDetails() {
|
||||||
|
return new pro.gravit.launcher.core.api.method.details.AuthLoginOnlyDetails();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launcher.base.request.auth.details;
|
package pro.gravit.launcher.base.request.auth.details;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.core.api.method.AuthMethodDetails;
|
||||||
|
|
||||||
public class AuthPasswordDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
public class AuthPasswordDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
||||||
@Override
|
@Override
|
||||||
|
@ -9,4 +10,8 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthMethodDetails toAuthMethodDetails() {
|
||||||
|
return new pro.gravit.launcher.core.api.method.details.AuthPasswordDetails();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launcher.base.request.auth.details;
|
package pro.gravit.launcher.base.request.auth.details;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
|
import pro.gravit.launcher.core.api.method.AuthMethodDetails;
|
||||||
|
|
||||||
public class AuthTotpDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
public class AuthTotpDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
||||||
public final String alg;
|
public final String alg;
|
||||||
|
@ -20,4 +21,9 @@ public AuthTotpDetails(String alg) {
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "totp";
|
return "totp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthMethodDetails toAuthMethodDetails() {
|
||||||
|
return new pro.gravit.launcher.core.api.method.details.AuthTotpDetails(maxKeyLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package pro.gravit.launcher.base.request.auth.details;
|
package pro.gravit.launcher.base.request.auth.details;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
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 class AuthWebViewDetails implements GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails {
|
||||||
public final String url;
|
public final String url;
|
||||||
|
@ -26,4 +28,9 @@ public AuthWebViewDetails(String url, String redirectUrl) {
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "webview";
|
return "webview";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthMethodDetails toAuthMethodDetails() {
|
||||||
|
return new AuthWebDetails(url, redirectUrl, canBrowser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,14 @@ public class Auth2FAPassword implements AuthRequest.AuthPasswordInterface {
|
||||||
public AuthRequest.AuthPasswordInterface firstPassword;
|
public AuthRequest.AuthPasswordInterface firstPassword;
|
||||||
public AuthRequest.AuthPasswordInterface secondPassword;
|
public AuthRequest.AuthPasswordInterface secondPassword;
|
||||||
|
|
||||||
|
public Auth2FAPassword() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auth2FAPassword(AuthRequest.AuthPasswordInterface firstPassword, AuthRequest.AuthPasswordInterface secondPassword) {
|
||||||
|
this.firstPassword = firstPassword;
|
||||||
|
this.secondPassword = secondPassword;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check() {
|
public boolean check() {
|
||||||
return firstPassword != null && firstPassword.check() && secondPassword != null && secondPassword.check();
|
return firstPassword != null && firstPassword.check() && secondPassword != null && secondPassword.check();
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
public class AuthTOTPPassword implements AuthRequest.AuthPasswordInterface {
|
public class AuthTOTPPassword implements AuthRequest.AuthPasswordInterface {
|
||||||
public String totp;
|
public String totp;
|
||||||
|
|
||||||
|
public AuthTOTPPassword() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthTOTPPassword(String totp) {
|
||||||
|
this.totp = totp;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check() {
|
public boolean check() {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -98,10 +98,14 @@ public <T extends WebSocketEvent> void eventHandle(T webSocketEvent) {
|
||||||
processEventHandlers(webSocketEvent);
|
processEventHandlers(webSocketEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException {
|
public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) {
|
||||||
CompletableFuture<T> result = new CompletableFuture<>();
|
CompletableFuture<T> result = new CompletableFuture<>();
|
||||||
futureMap.put(request.requestUUID, result);
|
futureMap.put(request.requestUUID, result);
|
||||||
sendObject(request, WebSocketRequest.class);
|
try {
|
||||||
|
sendObject(request, WebSocketRequest.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return CompletableFuture.failedFuture(e);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<LauncherInitData> init();
|
||||||
|
void selectAuthMethod(AuthMethod method);
|
||||||
|
CompletableFuture<SelfUser> tryAuthorize();
|
||||||
|
CompletableFuture<SelfUser> authorize(String login, AuthMethodPassword password);
|
||||||
|
CompletableFuture<List<ProfileFeatureAPI.ClientProfile>> fetchProfiles();
|
||||||
|
ClientProfileSettings makeClientProfileSettings(ProfileFeatureAPI.ClientProfile profile);
|
||||||
|
CompletableFuture<ReadyProfile> downloadProfile(ProfileFeatureAPI.ClientProfile profile, ClientProfileSettings settings, DownloadCallback callback);
|
||||||
|
// Tools
|
||||||
|
CompletableFuture<byte[]> fetchTexture(Texture texture);
|
||||||
|
|
||||||
|
record LauncherInitData(List<AuthMethod> 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<Flag> getFlags();
|
||||||
|
boolean hasFlag(Flag flag);
|
||||||
|
void addFlag(Flag flag);
|
||||||
|
void removeFlag(Flag flag);
|
||||||
|
List<ProfileFeatureAPI.OptionalMod> 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<ProfileFeatureAPI.ClientProfile> 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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Class<? extends FeatureAPI>, FeatureAPI> map;
|
||||||
|
|
||||||
|
public LauncherAPI(Map<Class<? extends FeatureAPI>, 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 extends FeatureAPI> T get(Class<T> clazz) {
|
||||||
|
return (T) map.get(clazz);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String, LauncherAPI> createApiFactory;
|
||||||
|
private static final Map<String, LauncherAPI> 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<String, LauncherAPI> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<SelfUser> getCurrentUser();
|
||||||
|
CompletableFuture<AuthResponse> auth(String login, AuthMethodPassword password);
|
||||||
|
CompletableFuture<AuthToken> refreshToken(String refreshToken);
|
||||||
|
CompletableFuture<SelfUser> restore(String accessToken, boolean fetchUser);
|
||||||
|
CompletableFuture<Void> exit();
|
||||||
|
|
||||||
|
record AuthResponse(SelfUser user, AuthToken authToken) {}
|
||||||
|
|
||||||
|
interface AuthToken {
|
||||||
|
String getAccessToken();
|
||||||
|
String getRefreshToken();
|
||||||
|
long getExpire();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<List<AuthMethod>> getAuthMethods();
|
||||||
|
CompletableFuture<LauncherUpdateInfo> checkUpdates();
|
||||||
|
|
||||||
|
record LauncherUpdateInfo(String url, String version, boolean available, boolean required) {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launcher.core.api.features;
|
||||||
|
|
||||||
|
public interface FeatureAPI {
|
||||||
|
}
|
|
@ -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<List<ClientProfile>> getProfiles();
|
||||||
|
CompletableFuture<UpdateInfo> fetchUpdateInfo(String dirName);
|
||||||
|
|
||||||
|
interface UpdateInfo {}
|
||||||
|
|
||||||
|
interface ClientProfile {
|
||||||
|
String getName();
|
||||||
|
UUID getUUID();
|
||||||
|
List<OptionalMod> getOptionalMods();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptionalMod {
|
||||||
|
String getName();
|
||||||
|
String getDescription();
|
||||||
|
String getCategory();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<User> getUserByUsername(String username);
|
||||||
|
CompletableFuture<User> getUserByUUID(UUID uuid);
|
||||||
|
CompletableFuture<Void> joinServer(String username, String accessToken, String serverID);
|
||||||
|
CompletableFuture<Void> joinServer(UUID uuid, String accessToken, String serverID);
|
||||||
|
CompletableFuture<CheckServerResponse> checkServer(String username, String serverID, boolean extended);
|
||||||
|
default CompletableFuture<List<User>> getUsersByUsernames(List<String> usernames) {
|
||||||
|
List<CompletableFuture<User>> list = new ArrayList<>();
|
||||||
|
for(var username : usernames) {
|
||||||
|
list.add(getUserByUsername(username));
|
||||||
|
}
|
||||||
|
return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)).thenApply(x -> {
|
||||||
|
List<User> 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<String, String> sessionProperties) {}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package pro.gravit.launcher.core.api.method;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface AuthMethod {
|
||||||
|
List<AuthMethodDetails> getDetails();
|
||||||
|
String getName();
|
||||||
|
String getDisplayName();
|
||||||
|
boolean isVisible();
|
||||||
|
Set<String> getFeatures();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launcher.core.api.method;
|
||||||
|
|
||||||
|
public interface AuthMethodDetails {
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launcher.core.api.method;
|
||||||
|
|
||||||
|
public interface AuthMethodPassword {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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<AuthMethodPassword> list) implements AuthMethodPassword {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package pro.gravit.launcher.core.api.model;
|
||||||
|
|
||||||
|
public interface SelfUser extends User {
|
||||||
|
String getAccessToken();
|
||||||
|
UserPermissions getPermissions();
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package pro.gravit.launcher.core.api.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface Texture {
|
||||||
|
String getUrl();
|
||||||
|
String getHash();
|
||||||
|
Map<String, String> getMetadata();
|
||||||
|
}
|
|
@ -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<String, Texture> getAssets();
|
||||||
|
Map<String, String> getProperties();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package pro.gravit.launcher.core.api.model;
|
||||||
|
|
||||||
|
public interface UserPermissions {
|
||||||
|
boolean hasRole(String role);
|
||||||
|
boolean hasPerm(String action);
|
||||||
|
}
|
|
@ -5,10 +5,10 @@
|
||||||
public final class Version implements Comparable<Version> {
|
public final class Version implements Comparable<Version> {
|
||||||
|
|
||||||
public static final int MAJOR = 5;
|
public static final int MAJOR = 5;
|
||||||
public static final int MINOR = 6;
|
public static final int MINOR = 7;
|
||||||
public static final int PATCH = 3;
|
public static final int PATCH = 0;
|
||||||
public static final int BUILD = 1;
|
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 major;
|
||||||
public final int minor;
|
public final int minor;
|
||||||
public final int patch;
|
public final int patch;
|
||||||
|
|
|
@ -29,10 +29,13 @@
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
||||||
public static final Path configFile = Paths.get(System.getProperty("serverwrapper.configFile", "ServerWrapperConfig.json"));
|
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());
|
System.load(Paths.get(config.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
List<String> 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<Path> 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) {
|
switch (config.classLoaderConfig) {
|
||||||
case LAUNCHER:
|
case LAUNCHER:
|
||||||
launch = new LegacyLaunch();
|
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;
|
break;
|
||||||
case MODULE:
|
case MODULE:
|
||||||
launch = new ModuleLaunch();
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
if(ServerAgent.isAgentStarted()) {
|
if(ServerAgent.isAgentStarted()) {
|
||||||
|
@ -207,7 +226,7 @@ public void run(String... args) throws Throwable {
|
||||||
LaunchOptions options = new LaunchOptions();
|
LaunchOptions options = new LaunchOptions();
|
||||||
options.enableHacks = config.enableHacks;
|
options.enableHacks = config.enableHacks;
|
||||||
options.moduleConf = config.moduleConf;
|
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()) {
|
if(ServerAgent.isAgentStarted()) {
|
||||||
ClientService.instrumentation = ServerAgent.inst;
|
ClientService.instrumentation = ServerAgent.inst;
|
||||||
}
|
}
|
||||||
|
@ -269,6 +288,7 @@ public static final class Config {
|
||||||
public String address;
|
public String address;
|
||||||
public String serverName;
|
public String serverName;
|
||||||
public boolean autoloadLibraries;
|
public boolean autoloadLibraries;
|
||||||
|
public boolean resolveClassPath = true;
|
||||||
public String logFile;
|
public String logFile;
|
||||||
public List<String> classpath;
|
public List<String> classpath;
|
||||||
public ClientProfile.ClassLoaderConfig classLoaderConfig;
|
public ClientProfile.ClassLoaderConfig classLoaderConfig;
|
||||||
|
|
Loading…
Reference in a new issue