mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
Merge branch 'release/5.5.0'
This commit is contained in:
commit
1df283d659
153 changed files with 1901 additions and 1994 deletions
4
.github/workflows/push.yml
vendored
4
.github/workflows/push.yml
vendored
|
@ -16,10 +16,10 @@ jobs:
|
|||
path: ~/.gradle/caches
|
||||
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
sourceCompatibility = '17'
|
||||
targetCompatibility = '17'
|
||||
sourceCompatibility = '21'
|
||||
targetCompatibility = '21'
|
||||
|
||||
configurations {
|
||||
compileOnlyA
|
||||
|
@ -75,6 +75,7 @@
|
|||
|
||||
dependencies {
|
||||
pack project(':LauncherAPI')
|
||||
pack project(':LauncherModernCore')
|
||||
bundle group: 'me.tongfei', name: 'progressbar', version: '0.9.2'
|
||||
bundle group: 'com.github.Marcono1234', name: 'gson-record-type-adapter-factory', version: 'v0.2.0'
|
||||
bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
||||
|
@ -85,7 +86,7 @@ pack project(':LauncherAPI')
|
|||
bundle group: 'org.ow2.asm', name: 'asm-commons', version: rootProject['verAsm']
|
||||
bundle group: 'io.netty', name: 'netty-all', version: rootProject['verNetty']
|
||||
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||
bundle group: 'mysql', name: 'mysql-connector-java', version: rootProject['verMySQLConn']
|
||||
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
||||
bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn']
|
||||
bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard']
|
||||
bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j']
|
||||
|
@ -93,6 +94,7 @@ pack project(':LauncherAPI')
|
|||
bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt']
|
||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
|
||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
|
||||
annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'])
|
||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||
|
||||
hikari 'io.micrometer:micrometer-core:1.8.4'
|
||||
|
|
|
@ -21,6 +21,10 @@ public <T> SimpleErrorHandler<T> makeEH(Class<T> clazz) {
|
|||
return new SimpleErrorHandler<>(clazz);
|
||||
}
|
||||
|
||||
public <T> SimpleErrorHandler<T> makeEH(Type clazz) {
|
||||
return new SimpleErrorHandler<>(clazz);
|
||||
}
|
||||
|
||||
public <T> HttpRequest get(String url, String token) {
|
||||
try {
|
||||
var requestBuilder = HttpRequest.newBuilder()
|
||||
|
@ -59,6 +63,10 @@ public <T> HttpHelper.HttpOptional<T, SimpleError> send(HttpRequest request, Cla
|
|||
return HttpHelper.send(httpClient, request, makeEH(clazz));
|
||||
}
|
||||
|
||||
public <T> HttpHelper.HttpOptional<T, SimpleError> send(HttpRequest request, Type type) throws IOException {
|
||||
return HttpHelper.send(httpClient, request, makeEH(type));
|
||||
}
|
||||
|
||||
|
||||
public static class SimpleErrorHandler<T> implements HttpHelper.HttpJsonErrorHandler<T, SimpleError> {
|
||||
private final Type type;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import pro.gravit.launchserver.binary.LauncherBinary;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.helper.SignHelper;
|
||||
import pro.gravit.launchserver.launchermodules.LauncherModuleLoader;
|
||||
import pro.gravit.launchserver.manangers.*;
|
||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||
|
@ -36,13 +37,15 @@
|
|||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.ProcessBuilder.Redirect;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.KeyStore;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
|
@ -185,6 +188,10 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
}
|
||||
launcherModuleLoader.init();
|
||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||
if(config.sign.checkCertificateExpired) {
|
||||
checkCertificateExpired();
|
||||
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
||||
}
|
||||
// post init modules
|
||||
modulesManager.invokeEvent(new LaunchServerPostInitPhase(this));
|
||||
}
|
||||
|
@ -234,7 +241,6 @@ public void invoke(String... args) throws Exception {
|
|||
}
|
||||
switch (args[0]) {
|
||||
case "full" -> reload(ReloadType.FULL);
|
||||
case "no_auth" -> reload(ReloadType.NO_AUTH);
|
||||
case "no_components" -> reload(ReloadType.NO_COMPONENTS);
|
||||
default -> reload(ReloadType.NO_AUTH);
|
||||
}
|
||||
|
@ -269,6 +275,25 @@ public void invoke(String... args) throws Exception {
|
|||
return commands;
|
||||
}
|
||||
|
||||
public void checkCertificateExpired() {
|
||||
if(!config.sign.enabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
KeyStore keyStore = SignHelper.getStore(Paths.get(config.sign.keyStore), config.sign.keyStorePass, config.sign.keyStoreType);
|
||||
Instant date = SignHelper.getCertificateExpired(keyStore, config.sign.keyAlias);
|
||||
if(date == null) {
|
||||
logger.debug("The certificate will expire at unlimited");
|
||||
} else if(date.minus(Duration.ofDays(30)).isBefore(Instant.now())) {
|
||||
logger.warn("The certificate will expire at {}", date.toString());
|
||||
} else {
|
||||
logger.debug("The certificate will expire at {}", date.toString());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Can't get certificate expire date", e);
|
||||
}
|
||||
}
|
||||
|
||||
private LauncherBinary binary() {
|
||||
LaunchServerLauncherExeInit event = new LaunchServerLauncherExeInit(this, null);
|
||||
modulesManager.invokeEvent(event);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
|
@ -212,6 +213,7 @@ public static void registerAll() {
|
|||
GetAvailabilityAuthRequest.registerProviders();
|
||||
OptionalAction.registerProviders();
|
||||
OptionalTrigger.registerProviders();
|
||||
MixProvider.registerProviders();
|
||||
}
|
||||
|
||||
private static void printExperimentalBranch() {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class InjectClassAcceptor implements MainBuildTask.ASMTransformer {
|
||||
|
|
|
@ -149,10 +149,7 @@ public static int opcodeEmulation(AbstractInsnNode e) {
|
|||
break;
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKESPECIAL:
|
||||
case INVOKEINTERFACE:
|
||||
stackSize += doMethodEmulation(((MethodInsnNode) e).desc);
|
||||
break;
|
||||
case INVOKESTATIC:
|
||||
case INVOKEINTERFACE, INVOKESTATIC:
|
||||
stackSize += doMethodEmulation(((MethodInsnNode) e).desc);
|
||||
break;
|
||||
case INVOKEDYNAMIC:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -16,6 +17,7 @@ public final class AuthProviderPair {
|
|||
public boolean isDefault = true;
|
||||
public AuthCoreProvider core;
|
||||
public TextureProvider textureProvider;
|
||||
public Map<String, MixProvider> mixes;
|
||||
public Map<String, String> links;
|
||||
public transient String name;
|
||||
public transient Set<String> features;
|
||||
|
@ -36,12 +38,14 @@ public static Set<String> getFeatures(Class<?> clazz) {
|
|||
return list;
|
||||
}
|
||||
|
||||
public Set<String> getFeatures() {
|
||||
return features;
|
||||
}
|
||||
|
||||
public static void getFeatures(Class<?> clazz, Set<String> list) {
|
||||
Features features = clazz.getAnnotation(Features.class);
|
||||
if (features != null) {
|
||||
for (Feature feature : features.value()) {
|
||||
list.add(feature.value());
|
||||
}
|
||||
Feature[] features = clazz.getAnnotationsByType(Feature.class);
|
||||
for (Feature feature : features) {
|
||||
list.add(feature.value());
|
||||
}
|
||||
Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass != null && superClass != Object.class) {
|
||||
|
@ -55,8 +59,15 @@ public static void getFeatures(Class<?> clazz, Set<String> list) {
|
|||
|
||||
public final <T> T isSupport(Class<T> clazz) {
|
||||
if (core == null) return null;
|
||||
T result = null;
|
||||
if (result == null) result = core.isSupport(clazz);
|
||||
T result = core.isSupport(clazz);
|
||||
if (result == null && mixes != null) {
|
||||
for(var m : mixes.values()) {
|
||||
result = m.isSupport(clazz);
|
||||
if(result != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -66,6 +77,12 @@ public final void init(LaunchServer srv, String name) {
|
|||
core.init(srv);
|
||||
features = new HashSet<>();
|
||||
getFeatures(core.getClass(), features);
|
||||
if(mixes != null) {
|
||||
for(var m : mixes.values()) {
|
||||
m.init(srv, core);
|
||||
getFeatures(m.getClass(), features);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void link(LaunchServer srv) {
|
||||
|
@ -87,5 +104,10 @@ public final void close() throws IOException {
|
|||
if (textureProvider != null) {
|
||||
textureProvider.close();
|
||||
}
|
||||
if(mixes != null) {
|
||||
for(var m : mixes.values()) {
|
||||
m.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||
import pro.gravit.launchserver.helper.LegacySessionHelper;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
|
@ -162,6 +163,25 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
SQLUser user = (SQLUser) getUserByUsername(username);
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) {
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
|
||||
SQLUser user = (SQLUser) client.getUser();
|
||||
if (user == null) return false;
|
||||
return user.getUsername().equals(username) && user.getAccessToken().equals(accessToken) && updateServerID(user, serverID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
this.server = server;
|
||||
|
@ -225,7 +245,6 @@ protected void updateAuth(User user, String accessToken) throws IOException {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||
try (Connection c = getSQLConfig().getConnection()) {
|
||||
SQLUser SQLUser = (SQLUser) user;
|
||||
|
@ -328,12 +347,10 @@ public UUID getUUID() {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
@ -372,6 +389,11 @@ public User getUser() {
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMinecraftAccessToken() {
|
||||
return user.getAccessToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpireIn() {
|
||||
return 0;
|
||||
|
|
|
@ -45,7 +45,6 @@ public static void registerProviders() {
|
|||
providers.register("mysql", MySQLCoreProvider.class);
|
||||
providers.register("postgresql", PostgresSQLCoreProvider.class);
|
||||
providers.register("memory", MemoryAuthCoreProvider.class);
|
||||
providers.register("http", HttpAuthCoreProvider.class);
|
||||
providers.register("merge", MergeAuthCoreProvider.class);
|
||||
registredProviders = true;
|
||||
}
|
||||
|
@ -75,11 +74,6 @@ public AuthManager.AuthReport authorize(User user, AuthResponse.AuthContext cont
|
|||
|
||||
public abstract void init(LaunchServer server);
|
||||
|
||||
// Auth Handler methods
|
||||
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||
return List.of(new AuthPasswordDetails());
|
||||
}
|
||||
|
@ -292,22 +286,9 @@ public void invoke(String... args) throws Exception {
|
|||
return map;
|
||||
}
|
||||
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
User user = getUserByUsername(username);
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) {
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public abstract User checkServer(Client client, String username, String serverID) throws IOException;
|
||||
|
||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
||||
User user = client.getUser();
|
||||
if (user == null) return false;
|
||||
return user.getUsername().equals(username) && user.getAccessToken().equals(accessToken) && updateServerID(user, serverID);
|
||||
}
|
||||
public abstract boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T isSupport(Class<T> clazz) {
|
||||
|
|
|
@ -1,646 +0,0 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.HttpRequester;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRemoteClientAccess;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportProperties;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportTextures;
|
||||
import pro.gravit.launchserver.helper.HttpHelper;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.utils.helper.CommonHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class HttpAuthCoreProvider extends AuthCoreProvider implements AuthSupportHardware, AuthSupportRemoteClientAccess {
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
public String bearerToken;
|
||||
public String getUserByUsernameUrl;
|
||||
public String getUserByLoginUrl;
|
||||
public String getUserByUUIDUrl;
|
||||
public String getUserByTokenUrl;
|
||||
public String getAuthDetailsUrl;
|
||||
public String refreshTokenUrl;
|
||||
public String authorizeUrl;
|
||||
public String joinServerUrl;
|
||||
public String checkServerUrl;
|
||||
public String updateServerIdUrl;
|
||||
//below fields can be empty if advanced protect handler disabled
|
||||
public String getHardwareInfoByPublicKeyUrl;
|
||||
public String getHardwareInfoByDataUrl;
|
||||
public String getHardwareInfoByIdUrl;
|
||||
public String createHardwareInfoUrl;
|
||||
public String connectUserAndHardwareUrl;
|
||||
public String addPublicKeyToHardwareInfoUrl;
|
||||
public String getUsersByHardwareInfoUrl;
|
||||
public String banHardwareUrl;
|
||||
public String unbanHardwareUrl;
|
||||
public String apiUrl;
|
||||
public List<String> apiFeatures;
|
||||
private transient HttpRequester requester;
|
||||
|
||||
@Override
|
||||
public User getUserByUsername(String username) {
|
||||
try {
|
||||
return requester.send(requester.get(CommonHelper.replace(getUserByUsernameUrl, "username", username), null), HttpUser.class).getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByLogin(String login) {
|
||||
if (getUserByLoginUrl != null) {
|
||||
try {
|
||||
return requester.send(requester.get(CommonHelper.replace(getUserByLoginUrl, "login", login), null), HttpUser.class).getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return super.getUserByLogin(login);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByUUID(UUID uuid) {
|
||||
try {
|
||||
return requester.send(requester.get(CommonHelper.replace(getUserByUUIDUrl, "uuid", uuid.toString()), null), HttpUser.class).getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||
if (getAuthDetailsUrl == null) {
|
||||
return super.getDetails(client);
|
||||
}
|
||||
try {
|
||||
var result = requester.send(requester.get(getAuthDetailsUrl, bearerToken), GetAuthDetailsResponse.class).getOrThrow();
|
||||
return result.details;
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return super.getDetails(client);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
|
||||
if (getUserByTokenUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
var result = requester.send(requester.get(getUserByTokenUrl, accessToken), HttpUserSession.class);
|
||||
if (!result.isSuccessful()) {
|
||||
var error = result.error().error;
|
||||
if (error.equals(AuthRequestEvent.OAUTH_TOKEN_EXPIRE)) {
|
||||
throw new OAuthAccessTokenExpired();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return result.getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
|
||||
if (refreshTokenUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return requester.send(requester.post(refreshTokenUrl, new RefreshTokenRequest(refreshToken, context),
|
||||
null), HttpAuthReport.class).getOrThrow().toAuthReport();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||
var result = requester.send(requester.post(authorizeUrl, new AuthorizeRequest(login, context, password, minecraftAccess),
|
||||
bearerToken), HttpAuthReport.class);
|
||||
if (!result.isSuccessful()) {
|
||||
var error = result.error().error;
|
||||
if (error != null) {
|
||||
throw new AuthException(error);
|
||||
}
|
||||
}
|
||||
return result.getOrThrow().toAuthReport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardwareInfoByPublicKey(byte[] publicKey) {
|
||||
if (getHardwareInfoByPublicKeyUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return requester.send(requester.post(getHardwareInfoByPublicKeyUrl, new HardwareRequest(publicKey),
|
||||
bearerToken), HttpUserHardware.class).getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info) {
|
||||
if (getHardwareInfoByDataUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
HardwareRequest request = new HardwareRequest(new HttpUserHardware(info));
|
||||
HttpHelper.HttpOptional<HttpUserHardware, HttpRequester.SimpleError> hardware =
|
||||
requester.send(requester.post(getHardwareInfoByDataUrl, request,
|
||||
bearerToken), HttpUserHardware.class);
|
||||
//should return null if not found
|
||||
return hardware.isSuccessful() ? hardware.getOrThrow() : null;
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardwareInfoById(String id) {
|
||||
if (getHardwareInfoByIdUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return requester.send(requester.post(getHardwareInfoByIdUrl, new HardwareRequest(new HttpUserHardware(Long.parseLong(id))),
|
||||
bearerToken), HttpUserHardware.class).getOrThrow();
|
||||
} catch (IOException | NumberFormatException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey) {
|
||||
if (createHardwareInfoUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return requester.send(requester.post(createHardwareInfoUrl, new HardwareRequest(new HttpUserHardware(info,
|
||||
publicKey, false)), bearerToken), HttpUserHardware.class).getOrThrow();
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectUserAndHardware(UserSession userSession, UserHardware hardware) {
|
||||
if (connectUserAndHardwareUrl == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requester.send(requester.post(connectUserAndHardwareUrl, new HardwareRequest((HttpUserHardware) hardware, (HttpUserSession) userSession), bearerToken), Void.class);
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey) {
|
||||
if (addPublicKeyToHardwareInfoUrl == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requester.send(requester.post(addPublicKeyToHardwareInfoUrl, new HardwareRequest((HttpUserHardware) hardware, publicKey), bearerToken), Void.class);
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public Iterable<User> getUsersByHardwareInfo(UserHardware hardware) {
|
||||
if (getUsersByHardwareInfoUrl == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (List<User>) (List) requester.send(requester
|
||||
.post(getUsersByHardwareInfoUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), GetHardwareListResponse.class).getOrThrow().list;
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void banHardware(UserHardware hardware) {
|
||||
if (banHardwareUrl == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requester.send(requester.post(banHardwareUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), Void.class);
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbanHardware(UserHardware hardware) {
|
||||
if (unbanHardwareUrl == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requester.send(requester.post(unbanHardwareUrl, new HardwareRequest((HttpUserHardware) hardware), bearerToken), Void.class);
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientApiUrl() {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getClientApiFeatures() {
|
||||
return apiFeatures;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean updateServerID(User user, String serverID) throws IOException {
|
||||
var result = requester.send(requester.post(updateServerIdUrl, new UpdateServerIdRequest(user.getUsername(), user.getUUID(), serverID),
|
||||
null), Void.class);
|
||||
return result.isSuccessful();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
return requester.send(requester.post(checkServerUrl, new CheckServerRequest(username, serverID), bearerToken), HttpUser.class).getOrThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
||||
var result = requester.send(requester.post(joinServerUrl, new JoinServerRequest(username, accessToken, serverID), bearerToken), Void.class);
|
||||
return result.isSuccessful();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
requester = new HttpRequester();
|
||||
if (getUserByUsernameUrl == null) {
|
||||
throw new IllegalArgumentException("'getUserByUsernameUrl' can't be null");
|
||||
}
|
||||
if (getUserByUUIDUrl == null) {
|
||||
throw new IllegalArgumentException("'getUserByUUIDUrl' can't be null");
|
||||
}
|
||||
if (authorizeUrl == null) {
|
||||
throw new IllegalArgumentException("'authorizeUrl' can't be null");
|
||||
}
|
||||
if (checkServerUrl == null && joinServerUrl == null && updateServerIdUrl == null) {
|
||||
throw new IllegalArgumentException("Please set 'checkServerUrl' and 'joinServerUrl' or 'updateServerIdUrl'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
public record HttpAuthReport(String minecraftAccessToken, String oauthAccessToken,
|
||||
String oauthRefreshToken, long oauthExpire,
|
||||
HttpUserSession session) {
|
||||
public AuthManager.AuthReport toAuthReport() {
|
||||
return new AuthManager.AuthReport(minecraftAccessToken, oauthAccessToken, oauthRefreshToken, oauthExpire, session);
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateServerIdRequest {
|
||||
public String username;
|
||||
public UUID uuid;
|
||||
public String serverId;
|
||||
|
||||
public UpdateServerIdRequest(String username, UUID uuid, String serverId) {
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
this.serverId = serverId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CheckServerRequest {
|
||||
public String username;
|
||||
public String serverId;
|
||||
|
||||
public CheckServerRequest(String username, String serverId) {
|
||||
this.username = username;
|
||||
this.serverId = serverId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetAuthDetailsResponse {
|
||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details;
|
||||
}
|
||||
|
||||
public static class GetHardwareListResponse {
|
||||
public List<HttpUser> list;
|
||||
}
|
||||
|
||||
public static class JoinServerRequest {
|
||||
public String username;
|
||||
public String accessToken;
|
||||
public String serverId;
|
||||
|
||||
public JoinServerRequest(String username, String accessToken, String serverId) {
|
||||
this.username = username;
|
||||
this.accessToken = accessToken;
|
||||
this.serverId = serverId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AuthorizeRequest {
|
||||
public String login;
|
||||
public AuthResponse.AuthContext context;
|
||||
public AuthRequest.AuthPasswordInterface password;
|
||||
public boolean minecraftAccess;
|
||||
|
||||
public AuthorizeRequest() {
|
||||
}
|
||||
|
||||
public AuthorizeRequest(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) {
|
||||
this.login = login;
|
||||
this.context = context;
|
||||
this.password = password;
|
||||
this.minecraftAccess = minecraftAccess;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RefreshTokenRequest {
|
||||
public String refreshToken;
|
||||
public AuthResponse.AuthContext context;
|
||||
|
||||
public RefreshTokenRequest(String refreshToken, AuthResponse.AuthContext context) {
|
||||
this.refreshToken = refreshToken;
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
public record HardwareRequest(HttpUserHardware userHardware, byte[] key, HttpUserSession userSession) {
|
||||
|
||||
public HardwareRequest(HttpUserHardware userHardware) {
|
||||
this(userHardware, null, null);
|
||||
}
|
||||
|
||||
public HardwareRequest(HttpUserHardware userHardware, byte[] key) {
|
||||
this(userHardware, key, null);
|
||||
}
|
||||
|
||||
public HardwareRequest(HttpUserHardware userHardware, HttpUserSession userSession) {
|
||||
this(userHardware, null, userSession);
|
||||
}
|
||||
|
||||
public HardwareRequest(byte[] key) {
|
||||
this(null, key, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class HttpUserSession implements UserSession {
|
||||
private String id;
|
||||
private HttpUser user;
|
||||
private long expireIn;
|
||||
|
||||
public HttpUserSession() {
|
||||
}
|
||||
|
||||
public HttpUserSession(String id, HttpUser user, long expireIn) {
|
||||
this.id = id;
|
||||
this.user = user;
|
||||
this.expireIn = expireIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpireIn() {
|
||||
return expireIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpUserSession{" +
|
||||
"id='" + id + '\'' +
|
||||
", user=" + user +
|
||||
", expireIn=" + expireIn +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class HttpUserHardware implements UserHardware {
|
||||
private final HardwareReportRequest.HardwareInfo hardwareInfo;
|
||||
private final long id;
|
||||
private byte[] publicKey;
|
||||
private boolean banned;
|
||||
|
||||
public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, long id, boolean banned) {
|
||||
this.hardwareInfo = hardwareInfo;
|
||||
this.publicKey = publicKey;
|
||||
this.id = id;
|
||||
this.banned = banned;
|
||||
}
|
||||
|
||||
public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo) {
|
||||
this.hardwareInfo = hardwareInfo;
|
||||
this.id = Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
public HttpUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, boolean banned) {
|
||||
this.hardwareInfo = hardwareInfo;
|
||||
this.publicKey = publicKey;
|
||||
this.banned = banned;
|
||||
this.id = Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
public HttpUserHardware(long id) {
|
||||
this.id = id;
|
||||
this.hardwareInfo = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HardwareReportRequest.HardwareInfo getHardwareInfo() {
|
||||
return hardwareInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBanned() {
|
||||
return banned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpUserHardware{" +
|
||||
"hardwareInfo=" + hardwareInfo +
|
||||
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
|
||||
", id=" + id +
|
||||
", banned=" + banned +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public class HttpUser implements User, UserSupportTextures, UserSupportProperties, UserSupportHardware {
|
||||
private String username;
|
||||
private UUID uuid;
|
||||
private String serverId;
|
||||
private String accessToken;
|
||||
private ClientPermissions permissions;
|
||||
private Map<String, Texture> assets;
|
||||
private Map<String, String> properties;
|
||||
private long hwidId;
|
||||
private transient HttpUserHardware hardware;
|
||||
|
||||
public HttpUser() {
|
||||
}
|
||||
|
||||
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, long hwidId) {
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
this.serverId = serverId;
|
||||
this.accessToken = accessToken;
|
||||
this.permissions = permissions;
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak, long hwidId) {
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
this.serverId = serverId;
|
||||
this.accessToken = accessToken;
|
||||
this.permissions = permissions;
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Texture skin, Texture cloak, Map<String, String> properties, long hwidId) {
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
this.serverId = serverId;
|
||||
this.accessToken = accessToken;
|
||||
this.permissions = permissions;
|
||||
this.properties = properties;
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
public HttpUser(String username, UUID uuid, String serverId, String accessToken, ClientPermissions permissions, Map<String, Texture> assets, Map<String, String> properties, long hwidId) {
|
||||
this.username = username;
|
||||
this.uuid = uuid;
|
||||
this.serverId = serverId;
|
||||
this.accessToken = accessToken;
|
||||
this.permissions = permissions;
|
||||
this.assets = assets;
|
||||
this.properties = properties;
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientPermissions getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getSkinTexture() {
|
||||
return assets.get("SKIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture getCloakTexture() {
|
||||
return assets.get("CAPE");
|
||||
}
|
||||
|
||||
public Map<String, Texture> getAssets() {
|
||||
if (assets == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return assets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties() {
|
||||
if (properties == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpUser{" +
|
||||
"username='" + username + '\'' +
|
||||
", uuid=" + uuid +
|
||||
", serverId='" + serverId + '\'' +
|
||||
", accessToken='" + accessToken + '\'' +
|
||||
", permissions=" + permissions +
|
||||
", assets=" + getAssets() +
|
||||
", properties=" + properties +
|
||||
", hwidId=" + hwidId +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserHardware getHardware() {
|
||||
if (hardware != null) return hardware;
|
||||
HttpAuthCoreProvider.HttpUserHardware result = (HttpUserHardware) getHardwareInfoById(String.valueOf(hwidId));
|
||||
hardware = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -94,13 +94,6 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean updateServerID(User user, String serverID) {
|
||||
MemoryUser memoryUser = (MemoryUser) user;
|
||||
memoryUser.serverId = serverID;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) {
|
||||
synchronized (memory) {
|
||||
|
@ -116,7 +109,7 @@ public User checkServer(Client client, String username, String serverID) {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) {
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -158,16 +151,6 @@ public UUID getUUID() {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientPermissions getPermissions() {
|
||||
return permissions;
|
||||
|
@ -208,6 +191,11 @@ public User getUser() {
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMinecraftAccessToken() {
|
||||
return "IGNORED";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpireIn() {
|
||||
return expireIn;
|
||||
|
|
|
@ -67,7 +67,7 @@ public User checkServer(Client client, String username, String serverID) throws
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) {
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) {
|
||||
return false; // Authorization not supported
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -46,7 +47,12 @@ public void init(LaunchServer server) {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean updateServerID(User user, String serverID) {
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,6 @@ public interface User {
|
|||
|
||||
UUID getUUID();
|
||||
|
||||
String getServerId();
|
||||
|
||||
String getAccessToken();
|
||||
|
||||
ClientPermissions getPermissions();
|
||||
|
||||
default boolean isBanned() {
|
||||
|
|
|
@ -5,5 +5,7 @@ public interface UserSession {
|
|||
|
||||
User getUser();
|
||||
|
||||
String getMinecraftAccessToken();
|
||||
|
||||
long getExpireIn();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent;
|
||||
import pro.gravit.launchserver.auth.Feature;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Feature(GetAssetUploadUrlRequestEvent.FEATURE_NAME)
|
||||
public interface AuthSupportAssetUpload {
|
||||
String getAssetUploadUrl(String name, User user);
|
||||
|
||||
default AuthRequestEvent.OAuthRequestEvent getAssetUploadToken(String name, User user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default AssetUploadInfoRequestEvent getAssetUploadInfo(User user) {
|
||||
return new AssetUploadInfoRequestEvent(Set.of("SKIN", "CAPE"), AssetUploadInfoRequestEvent.SlimSupportConf.USER);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launchserver.auth.Feature;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.UserSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Feature("sessions")
|
||||
public interface AuthSupportGetSessionsFromUser extends AuthSupport {
|
||||
List<UserSession> getSessionsByUser(User user);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportBanInfo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public interface AuthSupportUserBan extends AuthSupport {
|
||||
UserSupportBanInfo.UserBanInfo banUser(User user, String reason, String moderator, LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
default UserSupportBanInfo.UserBanInfo banUser(User user) {
|
||||
return banUser(user, null, null, LocalDateTime.now(), null);
|
||||
}
|
||||
|
||||
void unbanUser(User user);
|
||||
|
||||
default UserSupportBanInfo fetchUserBanInfo(User user) {
|
||||
return (UserSupportBanInfo) user;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.user;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public interface UserSupportBanInfo {
|
||||
UserBanInfo getBanInfo();
|
||||
|
||||
interface UserBanInfo {
|
||||
String getId();
|
||||
|
||||
default String getReason() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getModerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default LocalDateTime getStartDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default LocalDateTime getEndDate() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package pro.gravit.launchserver.auth.mix;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
|
||||
public abstract class MixProvider implements AutoCloseable{
|
||||
public static final ProviderMap<MixProvider> providers = new ProviderMap<>("MixProvider");
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private static boolean registredProviders = false;
|
||||
|
||||
public static void registerProviders() {
|
||||
if (!registredProviders) {
|
||||
providers.register("uploadAsset", UploadAssetMixProvider.class);
|
||||
registredProviders = true;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void init(LaunchServer server, AuthCoreProvider core);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T isSupport(Class<T> clazz) {
|
||||
if (clazz.isAssignableFrom(getClass())) return (T) this;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void close();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package pro.gravit.launchserver.auth.mix;
|
||||
|
||||
import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class UploadAssetMixProvider extends MixProvider implements AuthSupportAssetUpload {
|
||||
public Map<String, String> urls;
|
||||
public AssetUploadInfoRequestEvent.SlimSupportConf slimSupportConf;
|
||||
|
||||
@Override
|
||||
public String getAssetUploadUrl(String name, User user) {
|
||||
return urls.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetUploadInfoRequestEvent getAssetUploadInfo(User user) {
|
||||
return new AssetUploadInfoRequestEvent(urls.keySet(), slimSupportConf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server, AuthCoreProvider core) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
|
@ -41,7 +42,7 @@ public boolean allowGetSecureLevelInfo(Client client) {
|
|||
@Override
|
||||
public void onHardwareReport(HardwareReportResponse response, Client client) {
|
||||
if (!enableHardwareFeature) {
|
||||
response.sendResult(new HardwareReportRequestEvent(null));
|
||||
response.sendResult(new HardwareReportRequestEvent());
|
||||
return;
|
||||
}
|
||||
if (!client.isAuth || client.trustLevel == null || client.trustLevel.publicKey == null) {
|
||||
|
@ -63,7 +64,7 @@ public void onHardwareReport(HardwareReportResponse response, Client client) {
|
|||
throw new SecurityException("Your hardware banned");
|
||||
}
|
||||
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
||||
response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, hardware)));
|
||||
response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, hardware), SECONDS.toMillis(server.config.netty.security.hardwareTokenExpire)));
|
||||
} else {
|
||||
logger.error("AuthCoreProvider not supported hardware");
|
||||
response.sendError("AuthCoreProvider not supported hardware");
|
||||
|
@ -78,22 +79,22 @@ public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
|
|||
if (authSupportHardware != null) {
|
||||
UserHardware hardware = authSupportHardware.getHardwareInfoByPublicKey(client.trustLevel.publicKey);
|
||||
if (hardware == null) //HWID not found?
|
||||
return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire));
|
||||
if (hardware.isBanned()) {
|
||||
throw new SecurityException("Your hardware banned");
|
||||
}
|
||||
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
||||
authSupportHardware.connectUserAndHardware(client.sessionObject, hardware);
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), createHardwareToken(client.username, hardware));
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire));
|
||||
} else {
|
||||
logger.warn("AuthCoreProvider not supported hardware. HardwareInfo not checked!");
|
||||
}
|
||||
}
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey), SECONDS.toMillis(server.config.netty.security.publicKeyTokenExpire));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onJoinServer(String serverID, String username, Client client) {
|
||||
public boolean onJoinServer(String serverID, String username, UUID uuid, Client client) {
|
||||
return !enableHardwareFeature || (client.trustLevel != null && client.trustLevel.hardwareInfo != null);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.protect;
|
||||
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
|
||||
public class NoProtectHandler extends ProtectHandler {
|
||||
|
@ -9,4 +10,8 @@ public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowJoinServer(Client client) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package pro.gravit.launchserver.auth.protect;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
|
||||
|
@ -19,6 +20,9 @@ public static void registerHandlers() {
|
|||
}
|
||||
|
||||
public abstract boolean allowGetAccessToken(AuthResponse.AuthContext context);
|
||||
public boolean allowJoinServer(Client client) {
|
||||
return client.isAuth && client.type == AuthResponse.ConnectTypes.CLIENT;
|
||||
}
|
||||
|
||||
public void init(LaunchServer server) {
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface JoinServerProtectHandler {
|
||||
default boolean onJoinServer(String serverID, String username, Client client) {
|
||||
default boolean onJoinServer(String serverID, String username, UUID uuid, Client client) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,22 +3,23 @@
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.HTTPRequest;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launchserver.HttpRequester;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class JsonTextureProvider extends TextureProvider {
|
||||
private static final Type MAP_TYPE = new TypeToken<Map<String, Texture>>() {
|
||||
private static final Type MAP_TYPE = new TypeToken<Map<String, JsonTexture>>() {
|
||||
}.getType();
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
private transient final HttpRequester requester = new HttpRequester();
|
||||
public String url;
|
||||
public String bearerToken;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
@ -40,24 +41,28 @@ public Texture getSkinTexture(UUID uuid, String username, String client) {
|
|||
@Override
|
||||
public Map<String, Texture> getAssets(UUID uuid, String username, String client) {
|
||||
try {
|
||||
var result = HTTPRequest.jsonRequest(null, "GET", new URL(RequestTextureProvider.getTextureURL(url, uuid, username, client)));
|
||||
|
||||
Map<String, Texture> map = Launcher.gsonManager.gson.fromJson(result, MAP_TYPE);
|
||||
if (map == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
if (map.get("skin") != null) { // Legacy script
|
||||
map.put("SKIN", map.get("skin"));
|
||||
map.remove("skin");
|
||||
}
|
||||
if (map.get("cloak") != null) {
|
||||
map.put("CAPE", map.get("cloak"));
|
||||
map.remove("cloak");
|
||||
}
|
||||
return map;
|
||||
Map<String, JsonTexture> map = requester.<Map<String, JsonTexture>>send(requester.get(RequestTextureProvider.getTextureURL(url, uuid, username, client), bearerToken), MAP_TYPE).getOrThrow();
|
||||
return JsonTexture.convertMap(map);
|
||||
} catch (IOException e) {
|
||||
logger.error("JsonTextureProvider", e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public record JsonTexture(String url, String digest, Map<String, String> metadata) {
|
||||
public Texture toTexture() {
|
||||
return new Texture(url, digest == null ? null : SecurityHelper.fromHex(digest), metadata);
|
||||
}
|
||||
|
||||
public static Map<String, Texture> convertMap(Map<String, JsonTexture> map) {
|
||||
if (map == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
Map<String, Texture> res = new HashMap<>();
|
||||
for(var e : map.entrySet()) {
|
||||
res.put(e.getKey(), e.getValue().toTexture());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
public class BinaryPipeline {
|
||||
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
||||
public final AtomicLong count = new AtomicLong(0);
|
||||
public final Path buildDir;
|
||||
public final String nameFormat;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
@ -72,11 +71,20 @@ public <T extends LauncherBuildTask> Optional<T> getTaskByClass(Class<T> taskCla
|
|||
return tasks.stream().filter(taskClass::isInstance).map(taskClass::cast).findFirst();
|
||||
}
|
||||
|
||||
public Optional<LauncherBuildTask> getTaskBefore(Predicate<LauncherBuildTask> pred) {
|
||||
LauncherBuildTask last = null;
|
||||
for(var e : tasks) {
|
||||
if(pred.test(e)) {
|
||||
return Optional.ofNullable(last);
|
||||
}
|
||||
last = e;
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void build(Path target, boolean deleteTempFiles) throws IOException {
|
||||
logger.info("Building launcher binary file");
|
||||
count.set(0); // set jar number
|
||||
Path thisPath = null;
|
||||
boolean isNeedDelete = false;
|
||||
long time_start = System.currentTimeMillis();
|
||||
long time_this = time_start;
|
||||
for (LauncherBuildTask task : tasks) {
|
||||
|
@ -86,19 +94,17 @@ public void build(Path target, boolean deleteTempFiles) throws IOException {
|
|||
long time_task_end = System.currentTimeMillis();
|
||||
long time_task = time_task_end - time_this;
|
||||
time_this = time_task_end;
|
||||
if (isNeedDelete && deleteTempFiles && oldPath != thisPath) Files.deleteIfExists(oldPath);
|
||||
isNeedDelete = task.allowDelete();
|
||||
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
||||
}
|
||||
long time_end = System.currentTimeMillis();
|
||||
if (isNeedDelete && deleteTempFiles) IOHelper.move(thisPath, target);
|
||||
if (deleteTempFiles) IOHelper.move(thisPath, target);
|
||||
else IOHelper.copy(thisPath, target);
|
||||
IOHelper.deleteDir(buildDir, false);
|
||||
logger.info("Build successful from {} millis", time_end - time_start);
|
||||
}
|
||||
|
||||
public String nextName(String taskName) {
|
||||
return nameFormat.formatted(taskName, count.getAndIncrement());
|
||||
return nameFormat.formatted(taskName);
|
||||
}
|
||||
|
||||
public Path nextPath(String taskName) {
|
||||
|
|
|
@ -45,6 +45,7 @@ public class BuildContext {
|
|||
public final MainBuildTask task;
|
||||
public final HashSet<String> fileList;
|
||||
public final HashSet<String> clientModules;
|
||||
public final HashSet<String> legacyClientModules;
|
||||
|
||||
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task) {
|
||||
this.output = output;
|
||||
|
@ -52,6 +53,7 @@ public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainB
|
|||
this.task = task;
|
||||
fileList = new HashSet<>(1024);
|
||||
clientModules = new HashSet<>();
|
||||
legacyClientModules = new HashSet<>();
|
||||
}
|
||||
|
||||
public void pushFile(String filename, InputStream inputStream) throws IOException {
|
||||
|
|
|
@ -7,7 +7,7 @@ public final class EXEL4JLauncherBinary extends LauncherBinary {
|
|||
|
||||
|
||||
public EXEL4JLauncherBinary(LaunchServer server) {
|
||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe");
|
||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
public class EXELauncherBinary extends LauncherBinary {
|
||||
|
||||
public EXELauncherBinary(LaunchServer server) {
|
||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe");
|
||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,7 +23,7 @@ public final class JARLauncherBinary extends LauncherBinary {
|
|||
public final Map<String, Path> files;
|
||||
|
||||
public JARLauncherBinary(LaunchServer server) throws IOException {
|
||||
super(server, resolve(server, ".jar"), "Launcher-%s-%d.jar");
|
||||
super(server, resolve(server, ".jar"), "Launcher-%s.jar");
|
||||
count = new AtomicLong(0);
|
||||
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
|
||||
buildDir = server.dir.resolve("build");
|
||||
|
|
|
@ -69,7 +69,6 @@ public SignerJar(ZipOutputStream out, Supplier<CMSSignedDataGenerator> gen, Stri
|
|||
*
|
||||
* @param filename name of the file to add (use forward slash as a path separator)
|
||||
* @param contents contents of the file
|
||||
* @throws IOException
|
||||
* @throws NullPointerException if any of the arguments is {@code null}
|
||||
*/
|
||||
public void addFileContents(String filename, byte[] contents) throws IOException {
|
||||
|
@ -82,7 +81,6 @@ public void addFileContents(String filename, byte[] contents) throws IOException
|
|||
*
|
||||
* @param filename name of the file to add (use forward slash as a path separator)
|
||||
* @param contents contents of the file
|
||||
* @throws IOException
|
||||
* @throws NullPointerException if any of the arguments is {@code null}
|
||||
*/
|
||||
public void addFileContents(String filename, InputStream contents) throws IOException {
|
||||
|
@ -95,7 +93,6 @@ public void addFileContents(String filename, InputStream contents) throws IOExce
|
|||
*
|
||||
* @param entry name of the file to add (use forward slash as a path separator)
|
||||
* @param contents contents of the file
|
||||
* @throws IOException
|
||||
* @throws NullPointerException if any of the arguments is {@code null}
|
||||
*/
|
||||
public void addFileContents(ZipEntry entry, byte[] contents) throws IOException {
|
||||
|
@ -108,7 +105,6 @@ public void addFileContents(ZipEntry entry, byte[] contents) throws IOException
|
|||
*
|
||||
* @param entry name of the file to add (use forward slash as a path separator)
|
||||
* @param contents contents of the file
|
||||
* @throws IOException
|
||||
* @throws NullPointerException if any of the arguments is {@code null}
|
||||
*/
|
||||
public void addFileContents(ZipEntry entry, InputStream contents) throws IOException {
|
||||
|
@ -134,7 +130,6 @@ public void addManifestAttribute(String name, String value) {
|
|||
* Closes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It closes the
|
||||
* underlying stream.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RuntimeException if the signing goes wrong
|
||||
*/
|
||||
@Override
|
||||
|
@ -148,7 +143,6 @@ public void close() throws IOException {
|
|||
* Finishes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It leaves the
|
||||
* underlying stream open.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RuntimeException if the signing goes wrong
|
||||
*/
|
||||
public void finish() throws IOException {
|
||||
|
@ -205,7 +199,6 @@ private byte[] signSigFile(byte[] sigContents) throws Exception {
|
|||
* Writes the manifest to the JAR. It also calculates the digests that are required to be placed in the the signature
|
||||
* file.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeManifest() throws IOException {
|
||||
zos.putNextEntry(IOHelper.newZipEntry(MANIFEST_FN));
|
||||
|
@ -268,7 +261,6 @@ private byte[] writeSigFile() throws IOException {
|
|||
/**
|
||||
* Signs the .SIG file and writes the signature (.RSA file) to the JAR.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RuntimeException if the signing failed
|
||||
*/
|
||||
private void writeSignature(byte[] sigFile) throws IOException {
|
||||
|
|
|
@ -74,9 +74,4 @@ public Path process(Path inputFile) throws IOException {
|
|||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,11 +68,6 @@ private boolean filter(String name) {
|
|||
return exclusions.stream().anyMatch(name::startsWith);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Path> getJars() {
|
||||
return jars;
|
||||
}
|
||||
|
|
|
@ -81,9 +81,4 @@ public Path process(Path inputFile) throws IOException {
|
|||
}
|
||||
return inputFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,9 +43,4 @@ public Path process(Path inputFile) throws IOException {
|
|||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,4 @@ public interface LauncherBuildTask {
|
|||
String getName();
|
||||
|
||||
Path process(Path inputFile) throws IOException;
|
||||
|
||||
boolean allowDelete();
|
||||
}
|
||||
|
|
|
@ -51,11 +51,12 @@ public String getName() {
|
|||
|
||||
@Override
|
||||
public Path process(Path inputJar) throws IOException {
|
||||
Path outputJar = server.launcherBinary.nextPath("main");
|
||||
Path outputJar = server.launcherBinary.nextPath(this);
|
||||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
|
||||
BuildContext context = new BuildContext(output, reader.getCp(), this);
|
||||
initProps();
|
||||
preBuildHook.hook(context);
|
||||
properties.put("launcher.legacymodules", context.legacyClientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
|
||||
properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
|
||||
postInitProps();
|
||||
reader.getCp().add(new JarFile(inputJar.toFile()));
|
||||
|
@ -160,11 +161,6 @@ public byte[] transformClass(byte[] bytes, String classname, BuildContext contex
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Transformer {
|
||||
byte[] transform(byte[] input, String classname, BuildContext context);
|
||||
|
|
|
@ -53,11 +53,6 @@ public Path process(Path inputFile) throws IOException {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void tryUnpack() throws IOException {
|
||||
logger.info("Unpacking launcher native guard list and runtime");
|
||||
UnpackHelper.unpackZipNoCheck("runtime.zip", server.launcherBinary.runtimeDir);
|
||||
|
|
|
@ -104,9 +104,4 @@ private void autoSign(Path inputFile, Path signedFile) throws IOException {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,11 +59,6 @@ public Path process(Path inputFile) throws IOException {
|
|||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Path setConfig() {
|
||||
Path path = server.launcherEXEBinary.nextPath(getName());
|
||||
Config config = new Config();
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
import me.tongfei.progressbar.ProgressBar;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
import me.tongfei.progressbar.ProgressBarStyle;
|
||||
import pro.gravit.launcher.AsyncDownloader;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.modern.Downloader;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.utils.Downloader;
|
||||
import pro.gravit.utils.command.CommandException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -45,9 +44,9 @@ protected boolean showApplyDialog(String text) throws IOException {
|
|||
return response.equals("y");
|
||||
}
|
||||
|
||||
protected Downloader downloadWithProgressBar(String taskName, List<AsyncDownloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
||||
protected Downloader downloadWithProgressBar(String taskName, List<Downloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
||||
long total = 0;
|
||||
for (AsyncDownloader.SizedFile file : list) {
|
||||
for (Downloader.SizedFile file : list) {
|
||||
total += file.size;
|
||||
}
|
||||
long totalFiles = list.size();
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
import com.google.gson.JsonObject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.AsyncDownloader;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.modern.Downloader;
|
||||
import pro.gravit.launchserver.HttpRequester;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.Downloader;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.Writer;
|
||||
|
@ -85,7 +84,7 @@ public void invoke(String... args) throws Exception {
|
|||
logger.info("Copy {} into {}", indexPath, targetPath);
|
||||
Files.copy(indexPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
List<AsyncDownloader.SizedFile> toDownload = new ArrayList<>(128);
|
||||
List<Downloader.SizedFile> toDownload = new ArrayList<>(128);
|
||||
for (var e : objects.entrySet()) {
|
||||
var value = e.getValue().getAsJsonObject();
|
||||
var hash = value.get("hash").getAsString();
|
||||
|
@ -101,7 +100,7 @@ public void invoke(String... args) throws Exception {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
toDownload.add(new AsyncDownloader.SizedFile(hash, path, size));
|
||||
toDownload.add(new Downloader.SizedFile(hash, path, size));
|
||||
}
|
||||
logger.info("Download {} files", toDownload.size());
|
||||
Downloader downloader = downloadWithProgressBar(dirName, toDownload, RESOURCES_DOWNLOAD_URL, assetDir);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class MakeProfileCommand extends Command {
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SecurityCheckCommand extends Command {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
@ -113,7 +112,7 @@ public void invoke(String... args) {
|
|||
List<X509Certificate> certChain = Arrays.stream(certChainPlain).map(e -> (X509Certificate) e).toList();
|
||||
X509Certificate cert = certChain.get(0);
|
||||
cert.checkValidity();
|
||||
if (certChain.size() <= 1) {
|
||||
if (certChain.size() == 1) {
|
||||
printCheckResult("sign", "certificate chain contains <2 element(recommend 2 and more)", false);
|
||||
bad = true;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
import proguard.ConfigurationParser;
|
||||
import proguard.ProGuard;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -26,6 +24,9 @@
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ProGuardComponent extends Component implements AutoCloseable, Reconfigurable {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
@ -36,6 +37,7 @@ public class ProGuardComponent extends Component implements AutoCloseable, Recon
|
|||
public transient ProguardConf proguardConf;
|
||||
private transient LaunchServer launchServer;
|
||||
private transient ProGuardBuildTask buildTask;
|
||||
private transient ProGuardMultiReleaseFixer fixerTask;
|
||||
|
||||
public static boolean checkFXJMods(Path path) {
|
||||
if (!IOHelper.exists(path.resolve("javafx.base.jmod")))
|
||||
|
@ -75,7 +77,9 @@ public void init(LaunchServer launchServer) {
|
|||
this.launchServer = launchServer;
|
||||
proguardConf = new ProguardConf(launchServer, this);
|
||||
this.buildTask = new ProGuardBuildTask(launchServer, proguardConf, this);
|
||||
this.fixerTask = new ProGuardMultiReleaseFixer(launchServer, this, "ProGuard.".concat(componentName));
|
||||
launchServer.launcherBinary.addAfter((v) -> v.getName().startsWith(modeAfter), buildTask);
|
||||
launchServer.launcherBinary.addAfter((v) -> v.getName().equals("ProGuard.".concat(componentName)), fixerTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +115,62 @@ public void invoke(String... args) throws Exception {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static class ProGuardMultiReleaseFixer implements LauncherBuildTask {
|
||||
private final LaunchServer server;
|
||||
private final ProGuardComponent component;
|
||||
private final String proguardTaskName;
|
||||
|
||||
public ProGuardMultiReleaseFixer(LaunchServer server, ProGuardComponent component, String proguardTaskName) {
|
||||
this.server = server;
|
||||
this.component = component;
|
||||
this.proguardTaskName = proguardTaskName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ProGuardMultiReleaseFixer.".concat(component.componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path process(Path inputFile) throws IOException {
|
||||
if (!component.enabled) {
|
||||
return inputFile;
|
||||
}
|
||||
LauncherBuildTask task = server.launcherBinary.getTaskBefore((x) -> proguardTaskName.equals(x.getName())).get();
|
||||
Path lastPath = server.launcherBinary.nextPath(task);
|
||||
if(Files.notExists(lastPath)) {
|
||||
logger.error("{} not exist. Multi-Release JAR fix not applied!", lastPath);
|
||||
return inputFile;
|
||||
}
|
||||
Path outputPath = server.launcherBinary.nextPath(this);
|
||||
try(ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outputPath.toFile()))) {
|
||||
try(ZipInputStream input = new ZipInputStream(new FileInputStream(inputFile.toFile()))) {
|
||||
ZipEntry entry = input.getNextEntry();
|
||||
while(entry != null) {
|
||||
ZipEntry newEntry = new ZipEntry(entry.getName());
|
||||
output.putNextEntry(newEntry);
|
||||
input.transferTo(output);
|
||||
entry = input.getNextEntry();
|
||||
}
|
||||
}
|
||||
try(ZipInputStream input = new ZipInputStream(new FileInputStream(lastPath.toFile()))) {
|
||||
ZipEntry entry = input.getNextEntry();
|
||||
while(entry != null) {
|
||||
if(!entry.getName().startsWith("META-INF/versions")) {
|
||||
entry = input.getNextEntry();
|
||||
continue;
|
||||
}
|
||||
ZipEntry newEntry = new ZipEntry(entry.getName());
|
||||
output.putNextEntry(newEntry);
|
||||
input.transferTo(output);
|
||||
entry = input.getNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProGuardBuildTask implements LauncherBuildTask {
|
||||
private final LaunchServer server;
|
||||
private final ProGuardComponent component;
|
||||
|
@ -157,11 +217,6 @@ public Path process(Path inputFile) throws IOException {
|
|||
IOHelper.copy(inputFile, outputJar);
|
||||
return outputJar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDelete() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProguardConf {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
public final class LaunchServerConfig {
|
||||
private final static List<String> oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/", "https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/");
|
||||
private final static List<String> oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/", "https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/", "https://mirror.gravitlauncher.com/5.4.x/");
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
public String projectName;
|
||||
public String[] mirrors;
|
||||
|
@ -49,7 +49,7 @@ public final class LaunchServerConfig {
|
|||
|
||||
public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||
LaunchServerConfig newConfig = new LaunchServerConfig();
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.4.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"};
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.5.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"};
|
||||
newConfig.launch4j = new LaunchServerConfig.ExeConf();
|
||||
newConfig.launch4j.enabled = false;
|
||||
newConfig.launch4j.copyright = "© GravitLauncher Team";
|
||||
|
@ -61,7 +61,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
|||
newConfig.launch4j.txtProductVersion = "%s, build %d";
|
||||
newConfig.launch4j.productName = "GravitLauncher";
|
||||
newConfig.launch4j.productVer = newConfig.launch4j.fileVer;
|
||||
newConfig.launch4j.maxVersion = "1.8.999";
|
||||
newConfig.launch4j.maxVersion = "99.0.0";
|
||||
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
||||
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
||||
newConfig.auth = new HashMap<>();
|
||||
|
@ -171,8 +171,8 @@ public void verify() {
|
|||
if (!updateMirror) {
|
||||
for (int i = 0; i < mirrors.length; ++i) {
|
||||
if (mirrors[i] != null && oldMirrorList.contains(mirrors[i])) {
|
||||
logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.4.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]);
|
||||
mirrors[i] = "https://mirror.gravitlauncher.com/5.4.x/";
|
||||
logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.5.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]);
|
||||
mirrors[i] = "https://mirror.gravitlauncher.com/5.5.x/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ public static class ExeConf {
|
|||
public boolean enabled;
|
||||
public boolean setMaxVersion;
|
||||
public String maxVersion;
|
||||
public String minVersion = "1.8.0";
|
||||
public String minVersion = "17.0.0";
|
||||
public String supportURL = null;
|
||||
public String downloadUrl = Launch4JTask.DOWNLOAD_URL;
|
||||
public String productName;
|
||||
|
@ -259,6 +259,7 @@ public static class JarSignerConf {
|
|||
public String metaInfKeyName = "SIGNUMO.RSA";
|
||||
public String metaInfSfName = "SIGNUMO.SF";
|
||||
public String signAlgo = "SHA256WITHRSA";
|
||||
public boolean checkCertificateExpired = true;
|
||||
}
|
||||
|
||||
public static class NettyUpdatesBind {
|
||||
|
|
|
@ -49,9 +49,7 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
} else if (version.compareTo(ClientProfileVersions.MINECRAFT_1_18) <= 0) { // 1.13 - 1.16.5
|
||||
jvmArgs.add("-XX:+UseG1GC");
|
||||
jvmArgs.add("-XX:+UnlockExperimentalVMOptions");
|
||||
} else { // 1.18+
|
||||
//jvmArgs.add("-XX:+UseShenandoahGC");
|
||||
//jvmArgs.add("-XX:+UnlockExperimentalVMOptions");
|
||||
} else {
|
||||
}
|
||||
// -----------
|
||||
Optional<MakeProfileOptionForge> forge = findOption(options, MakeProfileOptionForge.class);
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class SignHelper {
|
||||
|
@ -46,6 +48,24 @@ public static KeyStore getStore(Path file, String storepass, String algo) throws
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Instant getCertificateExpired(KeyStore keyStore, String keyAlias) throws KeyStoreException {
|
||||
List<Certificate> certChain = new ArrayList<>(Arrays.asList(keyStore.getCertificateChain(keyAlias)));
|
||||
Date date = null;
|
||||
for(var e : certChain) {
|
||||
if(e instanceof X509Certificate x509Certificate) {
|
||||
if(x509Certificate.getNotAfter() == null) {
|
||||
continue;
|
||||
}
|
||||
if(date == null || date.after(x509Certificate.getNotAfter())) {
|
||||
date = x509Certificate.getNotAfter();
|
||||
}
|
||||
}
|
||||
}
|
||||
return date == null ? null : date.toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the beast that can actually sign the data (for JKS, for other make it).
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherTrustManager;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.asm.InjectClassAcceptor;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
|
@ -50,7 +49,11 @@ public void init() {
|
|||
mainTask.preBuildHook.registerHook((buildContext) -> {
|
||||
for (ModuleEntity e : launcherModules) {
|
||||
if (e.propertyMap != null) buildContext.task.properties.putAll(e.propertyMap);
|
||||
buildContext.clientModules.add(e.moduleMainClass);
|
||||
if(e.modernModule) {
|
||||
buildContext.clientModules.add(e.moduleMainClass);
|
||||
} else {
|
||||
buildContext.legacyClientModules.add(e.moduleMainClass);
|
||||
}
|
||||
buildContext.readerClassPath.add(new JarFile(e.path.toFile()));
|
||||
}
|
||||
});
|
||||
|
@ -94,6 +97,7 @@ public static class ModuleEntity {
|
|||
public String moduleMainClass;
|
||||
public String moduleConfigClass;
|
||||
public String moduleConfigName;
|
||||
public boolean modernModule;
|
||||
public Map<String, Object> propertyMap;
|
||||
}
|
||||
|
||||
|
@ -104,7 +108,6 @@ private ModulesVisitor() {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.toFile().getName().endsWith(".jar"))
|
||||
try (JarFile f = new JarFile(file.toFile())) {
|
||||
|
@ -120,6 +123,8 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
|
|||
entity.path = file;
|
||||
entity.moduleMainClass = mainClass;
|
||||
entity.moduleConfigClass = attributes.getValue("Module-Config-Class");
|
||||
String requiredModernJava = attributes.getValue("Required-Modern-Java");
|
||||
entity.modernModule = Boolean.parseBoolean(requiredModernJava);
|
||||
if (entity.moduleConfigClass != null) {
|
||||
entity.moduleConfigName = attributes.getValue("Module-Config-Name");
|
||||
if (entity.moduleConfigName == null) {
|
||||
|
|
|
@ -115,7 +115,7 @@ public AuthReport auth(AuthResponse.AuthContext context, AuthRequest.AuthPasswor
|
|||
context.client.sessionObject = session;
|
||||
internalAuth(context.client, context.authType, context.pair, user.getUsername(), user.getUUID(), user.getPermissions(), true);
|
||||
if (context.authType == AuthResponse.ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) {
|
||||
return AuthReport.ofMinecraftAccessToken(user.getAccessToken(), session);
|
||||
return AuthReport.ofMinecraftAccessToken(session.getMinecraftAccessToken(), session);
|
||||
}
|
||||
return AuthReport.ofMinecraftAccessToken(null, session);
|
||||
}
|
||||
|
@ -166,9 +166,9 @@ public CheckServerReport checkServer(Client client, String username, String serv
|
|||
else return CheckServerReport.ofUser(user, getPlayerProfile(client.auth, user));
|
||||
}
|
||||
|
||||
public boolean joinServer(Client client, String username, String accessToken, String serverID) throws IOException {
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
|
||||
if (client.auth == null) return false;
|
||||
return client.auth.core.joinServer(client, username, accessToken, serverID);
|
||||
return client.auth.core.joinServer(client, username, uuid, accessToken, serverID);
|
||||
}
|
||||
|
||||
public PlayerProfile getPlayerProfile(Client client) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
|
@ -48,6 +49,7 @@ public void registerAdapters(GsonBuilder builder) {
|
|||
builder.registerTypeAdapter(GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails.class, new UniversalJsonAdapter<>(GetAvailabilityAuthRequest.providers));
|
||||
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
||||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||
}
|
||||
|
|
|
@ -3,20 +3,27 @@
|
|||
import com.google.gson.JsonElement;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.HTTPRequest;
|
||||
import pro.gravit.utils.HttpDownloader;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class MirrorManager {
|
||||
protected final ArrayList<Mirror> list = new ArrayList<>();
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
private transient final HttpClient client = HttpClient.newBuilder().build();
|
||||
private Mirror defaultMirror;
|
||||
|
||||
public void addMirror(String mirror) {
|
||||
|
@ -58,7 +65,7 @@ public boolean downloadZip(Mirror mirror, Path path, String mask, Object... args
|
|||
URL url = mirror.getURL(mask, args);
|
||||
logger.debug("Try download {}", url.toString());
|
||||
try {
|
||||
HttpDownloader.downloadZip(url, path);
|
||||
downloadZip(url, path);
|
||||
} catch (IOException e) {
|
||||
logger.error("Download {} failed({}: {})", url.toString(), e.getClass().getName(), e.getMessage());
|
||||
return false;
|
||||
|
@ -82,8 +89,12 @@ public JsonElement jsonRequest(Mirror mirror, JsonElement request, String method
|
|||
if (!mirror.enabled) return null;
|
||||
URL url = mirror.getURL(mask, args);
|
||||
try {
|
||||
return HTTPRequest.jsonRequest(request, method, url);
|
||||
} catch (IOException e) {
|
||||
var response = client.send(HttpRequest.newBuilder()
|
||||
.method(method, request == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(Launcher.gsonManager.gson.toJson(request)))
|
||||
.uri(url.toURI())
|
||||
.build(), HttpResponse.BodyHandlers.ofString());
|
||||
return Launcher.gsonManager.gson.fromJson(response.body(), JsonElement.class);
|
||||
} catch (IOException | URISyntaxException | InterruptedException e) {
|
||||
logger.error("JsonRequest {} failed({}: {})", url.toString(), e.getClass().getName(), e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
@ -101,6 +112,22 @@ public JsonElement jsonRequest(JsonElement request, String method, String mask,
|
|||
throw new IOException("Error jsonRequest. All mirrors return error");
|
||||
}
|
||||
|
||||
private void downloadZip(URL url, Path dir) throws IOException {
|
||||
try (ZipInputStream input = IOHelper.newZipInput(url)) {
|
||||
Files.createDirectory(dir);
|
||||
for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) {
|
||||
if (entry.isDirectory()) {
|
||||
Files.createDirectory(dir.resolve(IOHelper.toPath(entry.getName())));
|
||||
continue;
|
||||
}
|
||||
// Unpack entry
|
||||
String name = entry.getName();
|
||||
logger.debug("Downloading file: '{}'", name);
|
||||
IOHelper.transfer(input, dir.resolve(IOHelper.toPath(name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Mirror {
|
||||
final String baseUrl;
|
||||
boolean enabled;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
|
||||
import pro.gravit.launchserver.socket.response.auth.*;
|
||||
import pro.gravit.launchserver.socket.response.cabinet.AssetUploadInfoResponse;
|
||||
import pro.gravit.launchserver.socket.response.cabinet.GetAssetUploadInfoResponse;
|
||||
import pro.gravit.launchserver.socket.response.management.FeaturesResponse;
|
||||
import pro.gravit.launchserver.socket.response.management.GetPublicKeyResponse;
|
||||
import pro.gravit.launchserver.socket.response.profile.BatchProfileByUsername;
|
||||
|
@ -65,7 +67,6 @@ public static void registerResponses() {
|
|||
providers.register("updateList", UpdateListResponse.class);
|
||||
providers.register("setProfile", SetProfileResponse.class);
|
||||
providers.register("update", UpdateResponse.class);
|
||||
providers.register("restoreSession", RestoreSessionResponse.class);
|
||||
providers.register("batchProfileByUsername", BatchProfileByUsername.class);
|
||||
providers.register("profileByUsername", ProfileByUsername.class);
|
||||
providers.register("profileByUUID", ProfileByUUIDResponse.class);
|
||||
|
@ -82,6 +83,8 @@ public static void registerResponses() {
|
|||
providers.register("additionalData", AdditionalDataResponse.class);
|
||||
providers.register("clientProfileKey", FetchClientProfileKeyResponse.class);
|
||||
providers.register("getPublicKey", GetPublicKeyResponse.class);
|
||||
providers.register("getAssetUploadUrl", GetAssetUploadInfoResponse.class);
|
||||
providers.register("assetUploadInfo", AssetUploadInfoResponse.class);
|
||||
}
|
||||
|
||||
public static String getIPFromContext(ChannelHandlerContext ctx) {
|
||||
|
|
|
@ -20,14 +20,8 @@ public String getType() {
|
|||
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||
List<GetAvailabilityAuthRequestEvent.AuthAvailability> list = new ArrayList<>();
|
||||
for (AuthProviderPair pair : server.config.auth.values()) {
|
||||
var rca = pair.isSupport(AuthSupportRemoteClientAccess.class);
|
||||
if (rca != null) {
|
||||
list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName,
|
||||
pair.visible, pair.core.getDetails(client), rca.getClientApiUrl(), rca.getClientApiFeatures()));
|
||||
} else {
|
||||
list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.name, pair.displayName,
|
||||
pair.visible, pair.core.getDetails(client)));
|
||||
}
|
||||
list.add(new GetAvailabilityAuthRequestEvent.AuthAvailability(pair.core.getDetails(client), pair.name, pair.displayName,
|
||||
pair.visible, pair.getFeatures()));
|
||||
}
|
||||
sendResult(new GetAvailabilityAuthRequestEvent(list));
|
||||
}
|
||||
|
|
|
@ -10,11 +10,14 @@
|
|||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
import pro.gravit.utils.HookException;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class JoinServerResponse extends SimpleResponse {
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
public String serverID;
|
||||
public String accessToken;
|
||||
public String username;
|
||||
public UUID uuid;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
|
@ -23,11 +26,11 @@ public String getType() {
|
|||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||
if (!client.isAuth || client.type != AuthResponse.ConnectTypes.CLIENT) {
|
||||
if (!server.config.protectHandler.allowJoinServer(client)) {
|
||||
sendError("Permissions denied");
|
||||
return;
|
||||
}
|
||||
if (username == null || accessToken == null || serverID == null) {
|
||||
if ((username == null && uuid == null) || accessToken == null || serverID == null) {
|
||||
sendError("Invalid request");
|
||||
return;
|
||||
}
|
||||
|
@ -35,13 +38,13 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
try {
|
||||
server.authHookManager.joinServerHook.hook(this, client);
|
||||
if (server.config.protectHandler instanceof JoinServerProtectHandler joinServerProtectHandler) {
|
||||
success = joinServerProtectHandler.onJoinServer(serverID, username, client);
|
||||
success = joinServerProtectHandler.onJoinServer(serverID, username, uuid, client);
|
||||
if (!success) {
|
||||
sendResult(new JoinServerRequestEvent(false));
|
||||
return;
|
||||
}
|
||||
}
|
||||
success = server.authManager.joinServer(client, username, accessToken, serverID);
|
||||
success = server.authManager.joinServer(client, username, uuid, accessToken, serverID);
|
||||
if (success) {
|
||||
logger.debug("joinServer: {} accessToken: {} serverID: {}", username, accessToken, serverID);
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package pro.gravit.launchserver.socket.response.auth;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class RestoreSessionResponse extends SimpleResponse {
|
||||
@LauncherNetworkAPI
|
||||
public UUID session;
|
||||
public boolean needUserInfo;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "restoreSession";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||
sendError("Legacy session system removed");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package pro.gravit.launchserver.socket.response.cabinet;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
|
||||
public class AssetUploadInfoResponse extends SimpleResponse {
|
||||
@Override
|
||||
public String getType() {
|
||||
return "assetUploadInfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
||||
sendError("Access denied");
|
||||
return;
|
||||
}
|
||||
var support = client.auth.isSupport(AuthSupportAssetUpload.class);
|
||||
if(support == null) {
|
||||
sendError("Not supported");
|
||||
return;
|
||||
}
|
||||
sendResult(support.getAssetUploadInfo(client.getUser()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package pro.gravit.launchserver.socket.response.cabinet;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportAssetUpload;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
|
||||
public class GetAssetUploadInfoResponse extends SimpleResponse {
|
||||
public String name;
|
||||
@Override
|
||||
public String getType() {
|
||||
return "getAssetUploadUrl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
||||
sendError("Access denied");
|
||||
return;
|
||||
}
|
||||
var support = client.auth.isSupport(AuthSupportAssetUpload.class);
|
||||
if(support == null) {
|
||||
sendError("Not supported");
|
||||
return;
|
||||
}
|
||||
sendResult(new GetAssetUploadUrlRequestEvent(support.getAssetUploadUrl(name, client.getUser()), support.getAssetUploadToken(name, client.getUser())));
|
||||
}
|
||||
}
|
|
@ -50,9 +50,9 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
||||
if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) {
|
||||
client.checkSign = true;
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken()));
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
} else {
|
||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken()));
|
||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
}
|
||||
} else if (launcher_type == 2) //EXE
|
||||
{
|
||||
|
@ -60,9 +60,9 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
|||
if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
||||
if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) {
|
||||
client.checkSign = true;
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken()));
|
||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
} else {
|
||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken()));
|
||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||
}
|
||||
} else sendError("Request launcher type error");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="INFO" packages="pro.gravit.launchserver.config.log4j">
|
||||
<Configuration status="INFO">
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
-dontshrink
|
||||
-dontoptimize
|
||||
-ignorewarnings
|
||||
-target 8
|
||||
-forceprocessing
|
||||
|
||||
-repackageclasses 'pro.gravit.launcher'
|
||||
|
@ -17,7 +16,7 @@
|
|||
|
||||
-keeppackagenames com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.**, pro.gravit.utils.**, pro.gravit.launcher.request.**, pro.gravit.launcher.events.**, pro.gravit.launcher.profiles.**
|
||||
|
||||
-keep class com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.**, pro.gravit.utils.**, pro.gravit.launcher.request.**, pro.gravit.launcher.events.**, pro.gravit.launcher.profiles.** {
|
||||
-keep class com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.**, pro.gravit.utils.**, pro.gravit.launcher.request.**, pro.gravit.launcher.events.**, pro.gravit.launcher.profiles.**, pro.gravit.launcher.LauncherEngineWrapper {
|
||||
*;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.Feature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FeatureCollectionTest {
|
||||
public static class TestClass1 implements TextInterface1 {
|
||||
|
||||
}
|
||||
|
||||
@Feature("test")
|
||||
public interface TextInterface1 {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleTest() {
|
||||
var set = AuthProviderPair.getFeatures(TestClass1.class);
|
||||
Assertions.assertTrue(set.contains("test"));
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@
|
|||
version = "12"
|
||||
modules = ['javafx.controls', 'javafx.fxml']
|
||||
}
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
sourceCompatibility = '17'
|
||||
targetCompatibility = '17'
|
||||
|
||||
configurations {
|
||||
bundle
|
||||
|
@ -49,6 +49,9 @@
|
|||
|
||||
dependencies {
|
||||
pack project(':LauncherAPI')
|
||||
pack project(':LauncherModernCore')
|
||||
pack project(':LauncherClient')
|
||||
pack project(':LauncherStart')
|
||||
bundle group: 'com.github.oshi', name: 'oshi-core', version: rootProject['verOshiCore']
|
||||
pack group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty']
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
import pro.gravit.launcher.console.GetPublicKeyCommand;
|
||||
import pro.gravit.launcher.console.ModulesCommand;
|
||||
import pro.gravit.launcher.console.SignDataCommand;
|
||||
import pro.gravit.launcher.events.request.*;
|
||||
import pro.gravit.launcher.gui.NoRuntimeProvider;
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||
import pro.gravit.launcher.managers.ConsoleManager;
|
||||
import pro.gravit.launcher.modules.events.OfflineModeEvent;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
|
@ -20,11 +18,6 @@
|
|||
import pro.gravit.launcher.request.RequestException;
|
||||
import pro.gravit.launcher.request.RequestService;
|
||||
import pro.gravit.launcher.request.auth.*;
|
||||
import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails;
|
||||
import pro.gravit.launcher.request.management.FeaturesRequest;
|
||||
import pro.gravit.launcher.request.secure.GetSecureLevelInfoRequest;
|
||||
import pro.gravit.launcher.request.secure.SecurityReportRequest;
|
||||
import pro.gravit.launcher.request.update.LauncherRequest;
|
||||
import pro.gravit.launcher.request.websockets.OfflineRequestService;
|
||||
import pro.gravit.launcher.request.websockets.StdWebSocketService;
|
||||
import pro.gravit.launcher.utils.NativeJVMHalt;
|
||||
|
@ -32,31 +25,31 @@
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyPair;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class LauncherEngine {
|
||||
public static ClientLauncherProcess.ClientParams clientParams;
|
||||
public static ClientModuleManager modulesManager;
|
||||
public static ClientParams clientParams;
|
||||
public static RuntimeModuleManager modulesManager;
|
||||
public final boolean clientInstance;
|
||||
// Instance
|
||||
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public RuntimeProvider runtimeProvider;
|
||||
public ECPublicKey publicKey;
|
||||
public ECPrivateKey privateKey;
|
||||
public Class<? extends RuntimeProvider> basicRuntimeProvider;
|
||||
|
||||
private LauncherEngine(boolean clientInstance) {
|
||||
|
||||
private LauncherEngine(boolean clientInstance, Class<? extends RuntimeProvider> basicRuntimeProvider) {
|
||||
this.clientInstance = clientInstance;
|
||||
this.basicRuntimeProvider = basicRuntimeProvider;
|
||||
}
|
||||
|
||||
//JVMHelper.getCertificates
|
||||
|
@ -101,19 +94,32 @@ public static void exitLauncher(int code) {
|
|||
forceExit(code);
|
||||
}
|
||||
|
||||
public static boolean contains(String[] array, String value) {
|
||||
for(String s : array) {
|
||||
if(s.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
JVMHelper.checkStackTrace(LauncherEngine.class);
|
||||
JVMHelper.checkStackTrace(LauncherEngineWrapper.class);
|
||||
JVMHelper.verifySystemProperties(Launcher.class, true);
|
||||
EnvHelper.checkDangerousParams();
|
||||
//if(!LauncherAgent.isStarted()) throw new SecurityException("JavaAgent not set");
|
||||
verifyNoAgent();
|
||||
if(contains(args, "--log-output") && Launcher.getConfig().environment != LauncherConfig.LauncherEnvironment.PROD) {
|
||||
LogHelper.addOutput(Paths.get("Launcher.log"));
|
||||
}
|
||||
LogHelper.printVersion("Launcher");
|
||||
LogHelper.printLicense("Launcher");
|
||||
LauncherEngine.checkClass(LauncherEngineWrapper.class);
|
||||
LauncherEngine.checkClass(LauncherEngine.class);
|
||||
LauncherEngine.checkClass(LauncherAgent.class);
|
||||
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule());
|
||||
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
||||
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
||||
LauncherConfig.initModules(LauncherEngine.modulesManager);
|
||||
LauncherEngine.modulesManager.initModules(null);
|
||||
// Start Launcher
|
||||
|
@ -123,7 +129,7 @@ public static void main(String... args) throws Throwable {
|
|||
Launcher.getConfig(); // init config
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
new LauncherEngine(false).start(args);
|
||||
newInstance(false).start(args);
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
return;
|
||||
|
@ -133,12 +139,12 @@ public static void main(String... args) throws Throwable {
|
|||
LauncherEngine.exitLauncher(0);
|
||||
}
|
||||
|
||||
public static void initGson(ClientModuleManager modulesManager) {
|
||||
public static void initGson(RuntimeModuleManager modulesManager) {
|
||||
AuthRequest.registerProviders();
|
||||
GetAvailabilityAuthRequest.registerProviders();
|
||||
OptionalAction.registerProviders();
|
||||
OptionalTrigger.registerProviders();
|
||||
Launcher.gsonManager = new ClientGsonManager(modulesManager);
|
||||
Launcher.gsonManager = new RuntimeGsonManager(modulesManager);
|
||||
Launcher.gsonManager.initGson();
|
||||
}
|
||||
|
||||
|
@ -149,39 +155,18 @@ public static void verifyNoAgent() {
|
|||
|
||||
public static RequestService initOffline() {
|
||||
OfflineRequestService service = new OfflineRequestService();
|
||||
applyBasicOfflineProcessors(service);
|
||||
ClientLauncherMethods.applyBasicOfflineProcessors(service);
|
||||
OfflineModeEvent event = new OfflineModeEvent(service);
|
||||
modulesManager.invokeEvent(event);
|
||||
return event.service;
|
||||
}
|
||||
|
||||
public static void applyBasicOfflineProcessors(OfflineRequestService service) {
|
||||
service.registerRequestProcessor(LauncherRequest.class, (r) -> new LauncherRequestEvent(false, (String) null));
|
||||
service.registerRequestProcessor(CheckServerRequest.class, (r) -> {
|
||||
throw new RequestException("CheckServer disabled in offline mode");
|
||||
});
|
||||
service.registerRequestProcessor(GetAvailabilityAuthRequest.class, (r) -> {
|
||||
List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details = new ArrayList<>();
|
||||
details.add(new AuthLoginOnlyDetails());
|
||||
GetAvailabilityAuthRequestEvent.AuthAvailability authAvailability = new GetAvailabilityAuthRequestEvent.AuthAvailability("offline", "Offline Mode", true, details);
|
||||
List<GetAvailabilityAuthRequestEvent.AuthAvailability> list = new ArrayList<>(1);
|
||||
list.add(authAvailability);
|
||||
return new GetAvailabilityAuthRequestEvent(list);
|
||||
});
|
||||
service.registerRequestProcessor(JoinServerRequest.class, (r) -> new JoinServerRequestEvent(false));
|
||||
service.registerRequestProcessor(ExitRequest.class, (r) -> new ExitRequestEvent(ExitRequestEvent.ExitReason.CLIENT));
|
||||
service.registerRequestProcessor(SetProfileRequest.class, (r) -> new SetProfileRequestEvent(null));
|
||||
service.registerRequestProcessor(FeaturesRequest.class, (r) -> new FeaturesRequestEvent());
|
||||
service.registerRequestProcessor(GetSecureLevelInfoRequest.class, (r) -> new GetSecureLevelInfoRequestEvent(null, false));
|
||||
service.registerRequestProcessor(SecurityReportRequest.class, (r) -> new SecurityReportRequestEvent(SecurityReportRequestEvent.ReportAction.NONE));
|
||||
}
|
||||
|
||||
public static LauncherEngine clientInstance() {
|
||||
return new LauncherEngine(true);
|
||||
}
|
||||
|
||||
public static LauncherEngine newInstance(boolean clientInstance) {
|
||||
return new LauncherEngine(clientInstance);
|
||||
return new LauncherEngine(clientInstance, NoRuntimeProvider.class);
|
||||
}
|
||||
|
||||
public static LauncherEngine newInstance(boolean clientInstance, Class<? extends RuntimeProvider> basicRuntimeProvider) {
|
||||
return new LauncherEngine(clientInstance, basicRuntimeProvider);
|
||||
}
|
||||
|
||||
public ECPublicKey getClientPublicKey() {
|
||||
|
@ -219,7 +204,7 @@ public void start(String... args) throws Throwable {
|
|||
ClientPreGuiPhase event = new ClientPreGuiPhase(null);
|
||||
LauncherEngine.modulesManager.invokeEvent(event);
|
||||
runtimeProvider = event.runtimeProvider;
|
||||
if (runtimeProvider == null) runtimeProvider = new NoRuntimeProvider();
|
||||
if (runtimeProvider == null) runtimeProvider = basicRuntimeProvider.getConstructor().newInstance();
|
||||
runtimeProvider.init(clientInstance);
|
||||
//runtimeProvider.preLoad();
|
||||
if (!Request.isAvailable()) {
|
||||
|
@ -248,8 +233,9 @@ public void start(String... args) throws Throwable {
|
|||
}
|
||||
};
|
||||
}
|
||||
service.registerEventHandler(new BasicLauncherEventHandler());
|
||||
}
|
||||
Request.startAutoRefresh();
|
||||
Request.getRequestService().registerEventHandler(new BasicLauncherEventHandler());
|
||||
Objects.requireNonNull(args, "args");
|
||||
if (started.getAndSet(true))
|
||||
throw new IllegalStateException("Launcher has been already started");
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
@LauncherNetworkAPI
|
||||
public class LauncherEngineWrapper {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
LauncherEngine.main(args);
|
||||
}
|
||||
}
|
|
@ -10,33 +10,8 @@
|
|||
import java.util.Map;
|
||||
|
||||
public class NewLauncherSettings {
|
||||
@LauncherNetworkAPI
|
||||
public final transient List<HashedStoreEntry> lastHDirs = new ArrayList<>(16);
|
||||
@LauncherNetworkAPI
|
||||
public Map<String, UserSettings> userSettings = new HashMap<>();
|
||||
@LauncherNetworkAPI
|
||||
public List<String> features = new ArrayList<>();
|
||||
@LauncherNetworkAPI
|
||||
public String consoleUnlockKey;
|
||||
|
||||
public void putHDir(String name, Path path, HashedDir dir) {
|
||||
String fullPath = path.toAbsolutePath().toString();
|
||||
lastHDirs.removeIf((e) -> e.fullPath.equals(fullPath) && e.name.equals(name));
|
||||
HashedStoreEntry e = new HashedStoreEntry(dir, name, fullPath);
|
||||
e.needSave = true;
|
||||
lastHDirs.add(e);
|
||||
}
|
||||
|
||||
public static class HashedStoreEntry {
|
||||
public final HashedDir hdir;
|
||||
public final String name;
|
||||
public final String fullPath;
|
||||
public transient boolean needSave = false;
|
||||
|
||||
public HashedStoreEntry(HashedDir hdir, String name, String fullPath) {
|
||||
this.hdir = hdir;
|
||||
this.name = name;
|
||||
this.fullPath = fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,14 @@
|
|||
import pro.gravit.launcher.client.events.client.ClientProcessBuilderLaunchedEvent;
|
||||
import pro.gravit.launcher.client.events.client.ClientProcessBuilderParamsWrittedEvent;
|
||||
import pro.gravit.launcher.client.events.client.ClientProcessBuilderPreLaunchEvent;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.hasher.HashedDir;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.ClientProfileVersions;
|
||||
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||
import pro.gravit.launcher.profiles.optional.OptionalView;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalActionJvmArgs;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.*;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -238,120 +234,4 @@ public Process getProcess() {
|
|||
return process;
|
||||
}
|
||||
|
||||
public static class ClientParams {
|
||||
public String assetDir;
|
||||
|
||||
public String clientDir;
|
||||
|
||||
public String resourcePackDir;
|
||||
|
||||
public String nativesDir;
|
||||
|
||||
// Client params
|
||||
|
||||
public PlayerProfile playerProfile;
|
||||
|
||||
public ClientProfile profile;
|
||||
|
||||
public String accessToken;
|
||||
|
||||
//==Minecraft params==
|
||||
|
||||
public boolean autoEnter;
|
||||
|
||||
public boolean fullScreen;
|
||||
|
||||
public int ram;
|
||||
|
||||
public int width;
|
||||
|
||||
public int height;
|
||||
|
||||
public Set<OptionalAction> actions = new HashSet<>();
|
||||
|
||||
//========
|
||||
|
||||
public UUID session;
|
||||
|
||||
public AuthRequestEvent.OAuthRequestEvent oauth;
|
||||
|
||||
public String authId;
|
||||
|
||||
public long oauthExpiredTime;
|
||||
|
||||
public Map<String, String> extendedTokens;
|
||||
|
||||
public boolean offlineMode;
|
||||
|
||||
public transient HashedDir assetHDir;
|
||||
|
||||
public transient HashedDir clientHDir;
|
||||
|
||||
public transient HashedDir javaHDir;
|
||||
|
||||
public void addClientArgs(Collection<String> args) {
|
||||
if (profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_6_4) >= 0)
|
||||
addModernClientArgs(args);
|
||||
else
|
||||
addClientLegacyArgs(args);
|
||||
}
|
||||
|
||||
public void addClientLegacyArgs(Collection<String> args) {
|
||||
args.add(playerProfile.username);
|
||||
args.add(accessToken);
|
||||
|
||||
// Add args for tweaker
|
||||
Collections.addAll(args, "--version", profile.getVersion().toString());
|
||||
Collections.addAll(args, "--gameDir", clientDir);
|
||||
Collections.addAll(args, "--assetsDir", assetDir);
|
||||
}
|
||||
|
||||
private void addModernClientArgs(Collection<String> args) {
|
||||
|
||||
// Add version-dependent args
|
||||
ClientProfile.Version version = profile.getVersion();
|
||||
Collections.addAll(args, "--username", playerProfile.username);
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_2) >= 0) {
|
||||
Collections.addAll(args, "--uuid", Launcher.toHash(playerProfile.uuid));
|
||||
Collections.addAll(args, "--accessToken", accessToken);
|
||||
|
||||
// Add 1.7.10+ args (user properties, asset index)
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0) {
|
||||
// Add user properties
|
||||
Collections.addAll(args, "--userType", "mojang");
|
||||
Collections.addAll(args, "--userProperties", "{}");
|
||||
|
||||
// Add asset index
|
||||
Collections.addAll(args, "--assetIndex", profile.getAssetIndex());
|
||||
}
|
||||
} else
|
||||
Collections.addAll(args, "--session", accessToken);
|
||||
|
||||
// Add version and dirs args
|
||||
Collections.addAll(args, "--version", profile.getVersion().toString());
|
||||
Collections.addAll(args, "--gameDir", clientDir);
|
||||
Collections.addAll(args, "--assetsDir", assetDir);
|
||||
Collections.addAll(args, "--resourcePackDir", resourcePackDir);
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_9_4) >= 0)
|
||||
Collections.addAll(args, "--versionType", "Launcher v" + Version.getVersion().getVersionString());
|
||||
|
||||
// Add server args
|
||||
if (autoEnter) {
|
||||
Collections.addAll(args, "--server", profile.getServerAddress());
|
||||
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
|
||||
}
|
||||
for (OptionalAction a : actions) {
|
||||
if (a instanceof OptionalActionClientArgs) {
|
||||
args.addAll(((OptionalActionClientArgs) a).args);
|
||||
}
|
||||
}
|
||||
// Add window size args
|
||||
if (fullScreen)
|
||||
Collections.addAll(args, "--fullscreen", Boolean.toString(true));
|
||||
if (width > 0 && height > 0) {
|
||||
Collections.addAll(args, "--width", Integer.toString(width));
|
||||
Collections.addAll(args, "--height", Integer.toString(height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package pro.gravit.launcher.client;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import pro.gravit.launcher.managers.GsonManager;
|
||||
import pro.gravit.launcher.modules.events.PreGsonPhase;
|
||||
import pro.gravit.launcher.request.websockets.ClientWebSocketService;
|
||||
import pro.gravit.utils.UniversalJsonAdapter;
|
||||
|
||||
public class RuntimeGsonManager extends GsonManager {
|
||||
private final RuntimeModuleManager moduleManager;
|
||||
|
||||
public RuntimeGsonManager(RuntimeModuleManager moduleManager) {
|
||||
this.moduleManager = moduleManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdapters(GsonBuilder builder) {
|
||||
super.registerAdapters(builder);
|
||||
builder.registerTypeAdapter(UserSettings.class, new UniversalJsonAdapter<>(UserSettings.providers));
|
||||
ClientWebSocketService.appendTypeAdapters(builder);
|
||||
moduleManager.invokeEvent(new PreGsonPhase(builder));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package pro.gravit.launcher.client;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.utils.Version;
|
||||
|
||||
public class RuntimeLauncherCoreModule extends LauncherModule {
|
||||
public RuntimeLauncherCoreModule() {
|
||||
super(new LauncherModuleInfo("ClientLauncherCore", Version.getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LauncherInitContext initContext) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package pro.gravit.launcher.client.events.client;
|
||||
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.client.ClientLauncherProcess;
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
|
||||
public class ClientProcessInitPhase extends InitPhase {
|
||||
public final LauncherEngine clientInstance;
|
||||
public final ClientLauncherProcess.ClientParams params;
|
||||
|
||||
public ClientProcessInitPhase(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
|
||||
this.clientInstance = clientInstance;
|
||||
this.params = params;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package pro.gravit.launcher.client.events.client;
|
||||
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.client.ClientLauncherProcess;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class ClientProcessLaunchEvent extends LauncherModule.Event {
|
||||
public final LauncherEngine clientInstance;
|
||||
public final ClientLauncherProcess.ClientParams params;
|
||||
|
||||
public ClientProcessLaunchEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
|
||||
this.clientInstance = clientInstance;
|
||||
this.params = params;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package pro.gravit.launcher.client.events.client;
|
||||
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.client.ClientLauncherProcess;
|
||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||
|
||||
public class ClientProcessReadyEvent extends PostInitPhase {
|
||||
public final LauncherEngine clientInstance;
|
||||
public final ClientLauncherProcess.ClientParams params;
|
||||
|
||||
public ClientProcessReadyEvent(LauncherEngine clientInstance, ClientLauncherProcess.ClientParams params) {
|
||||
this.clientInstance = clientInstance;
|
||||
this.params = params;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package pro.gravit.launcher.debug;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.api.AuthService;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.events.request.ProfilesRequestEvent;
|
||||
import pro.gravit.launcher.gui.RuntimeProvider;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.update.ProfilesRequest;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ClientRuntimeProvider implements RuntimeProvider {
|
||||
@Override
|
||||
public void run(String[] args) {
|
||||
ArrayList<String> newArgs = new ArrayList<>(Arrays.asList(args));
|
||||
try {
|
||||
String username = System.getProperty("launcher.runtime.username", null);
|
||||
String uuid = System.getProperty("launcher.runtime.uuid", null);
|
||||
String login = System.getProperty("launcher.runtime.login", username);
|
||||
String password = System.getProperty("launcher.runtime.password", "Player");
|
||||
String authId = System.getProperty("launcher.runtime.auth.authid", "std");
|
||||
String accessToken = System.getProperty("launcher.runtime.auth.accesstoken", null);
|
||||
String refreshToken = System.getProperty("launcher.runtime.auth.refreshtoken", null);
|
||||
String minecraftAccessToken = System.getProperty("launcher.runtime.auth.minecraftaccesstoken", "DEBUG");
|
||||
long expire = Long.parseLong(System.getProperty("launcher.runtime.auth.expire", "0"));
|
||||
String profileUUID = System.getProperty("launcher.runtime.profileuuid", null);
|
||||
String mainClass = System.getProperty("launcher.runtime.mainclass", null);
|
||||
ClientPermissions permissions = new ClientPermissions();
|
||||
if(mainClass == null) {
|
||||
throw new NullPointerException("Add `-Dlauncher.runtime.mainclass=YOUR_MAIN_CLASS` to jvmArgs");
|
||||
}
|
||||
if(uuid == null) {
|
||||
if(accessToken != null) {
|
||||
Request.setOAuth(authId, new AuthRequestEvent.OAuthRequestEvent(accessToken, refreshToken, expire));
|
||||
Request.RequestRestoreReport report = Request.restore(true, false);
|
||||
permissions = report.userInfo.permissions;
|
||||
username = report.userInfo.playerProfile.username;
|
||||
uuid = report.userInfo.playerProfile.uuid.toString();
|
||||
if(report.userInfo.accessToken != null) {
|
||||
minecraftAccessToken = report.userInfo.accessToken;
|
||||
}
|
||||
} else {
|
||||
AuthRequest request = new AuthRequest(login, password, authId, AuthRequest.ConnectTypes.API);
|
||||
AuthRequestEvent event = request.request();
|
||||
Request.setOAuth(authId, event.oauth);
|
||||
if(event.accessToken != null) {
|
||||
minecraftAccessToken = event.accessToken;
|
||||
}
|
||||
username = event.playerProfile.username;
|
||||
uuid = event.playerProfile.uuid.toString();
|
||||
}
|
||||
}
|
||||
if(profileUUID != null) {
|
||||
UUID profileUuid = UUID.fromString(profileUUID);
|
||||
ProfilesRequest profiles = new ProfilesRequest();
|
||||
ProfilesRequestEvent event = profiles.request();
|
||||
for(ClientProfile profile : event.profiles) {
|
||||
if(profile.getUUID().equals(profileUuid)) {
|
||||
AuthService.profile = profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(username == null) {
|
||||
username = "Player";
|
||||
}
|
||||
if(uuid == null) {
|
||||
uuid = "a7899336-e61c-4e51-b480-0c815b18aed8";
|
||||
}
|
||||
replaceOrCreateArgument(newArgs, "--username", username);
|
||||
replaceOrCreateArgument(newArgs, "--uuid", uuid);
|
||||
replaceOrCreateArgument(newArgs, "--accessToken", minecraftAccessToken);
|
||||
AuthService.uuid = UUID.fromString(uuid);
|
||||
AuthService.username = username;
|
||||
AuthService.permissions = permissions;
|
||||
Class<?> mainClazz = Class.forName(mainClass);
|
||||
mainClazz.getMethod("main", String[].class).invoke(null, (Object) newArgs.toArray(new String[0]));
|
||||
} catch (Throwable e) {
|
||||
LogHelper.error(e);
|
||||
LauncherEngine.exitLauncher(-15);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceOrCreateArgument(ArrayList<String> args, String name, String value) {
|
||||
int index = args.indexOf(name);
|
||||
if(index < 0) {
|
||||
args.add(name);
|
||||
if(value != null) {
|
||||
args.add(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(value != null) {
|
||||
int valueIndex = index+1;
|
||||
args.set(valueIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean clientInstance) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package pro.gravit.launcher.debug;
|
||||
|
||||
import pro.gravit.launcher.ClientLauncherMethods;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.client.ClientLauncherCoreModule;
|
||||
import pro.gravit.launcher.client.ClientModuleManager;
|
||||
import pro.gravit.launcher.client.RuntimeLauncherCoreModule;
|
||||
import pro.gravit.launcher.client.RuntimeModuleManager;
|
||||
import pro.gravit.launcher.managers.ConsoleManager;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.events.OfflineModeEvent;
|
||||
|
@ -28,6 +29,7 @@ public class DebugMain {
|
|||
public static String projectName = System.getProperty("launcherdebug.projectname", "Minecraft");
|
||||
public static String unlockSecret = System.getProperty("launcherdebug.unlocksecret", "");
|
||||
public static boolean offlineMode = Boolean.getBoolean("launcherdebug.offlinemode");
|
||||
public static boolean disableAutoRefresh = Boolean.getBoolean("launcherdebug.disableautorefresh");
|
||||
public static String[] moduleClasses = System.getProperty("launcherdebug.modules", "").split(",");
|
||||
public static String[] moduleFiles = System.getProperty("launcherdebug.modulefiles", "").split(",");
|
||||
public static LauncherConfig.LauncherEnvironment environment = LauncherConfig.LauncherEnvironment.valueOf(System.getProperty("launcherdebug.env", "STD"));
|
||||
|
@ -42,8 +44,8 @@ public static void main(String[] args) throws Throwable {
|
|||
config.unlockSecret = unlockSecret;
|
||||
Launcher.setConfig(config);
|
||||
Launcher.applyLauncherEnv(environment);
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule());
|
||||
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
||||
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
||||
for (String moduleClassName : moduleClasses) {
|
||||
if (moduleClassName.isEmpty()) continue;
|
||||
LauncherEngine.modulesManager.loadModule(newModule(moduleClassName));
|
||||
|
@ -59,7 +61,7 @@ public static void main(String[] args) throws Throwable {
|
|||
RequestService service;
|
||||
if (offlineMode) {
|
||||
OfflineRequestService offlineRequestService = new OfflineRequestService();
|
||||
LauncherEngine.applyBasicOfflineProcessors(offlineRequestService);
|
||||
ClientLauncherMethods.applyBasicOfflineProcessors(offlineRequestService);
|
||||
OfflineModeEvent event = new OfflineModeEvent(offlineRequestService);
|
||||
LauncherEngine.modulesManager.invokeEvent(event);
|
||||
service = event.service;
|
||||
|
@ -67,9 +69,13 @@ public static void main(String[] args) throws Throwable {
|
|||
service = StdWebSocketService.initWebSockets(webSocketURL).get();
|
||||
}
|
||||
Request.setRequestService(service);
|
||||
if(!disableAutoRefresh) {
|
||||
Request.startAutoRefresh();
|
||||
}
|
||||
LogHelper.debug("Initialization LauncherEngine");
|
||||
LauncherEngine instance = LauncherEngine.newInstance(false);
|
||||
LauncherEngine instance = LauncherEngine.newInstance(false, ClientRuntimeProvider.class);
|
||||
instance.start(args);
|
||||
LauncherEngine.exitLauncher(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
public class NoRuntimeProvider implements RuntimeProvider {
|
||||
@Override
|
||||
public void run(String[] args) {
|
||||
JOptionPane.showMessageDialog(null, "GUI часть лаунчера не найдена.\nС 5.1.0 вам необходимо самостоятельно установить модуль, отвечающий за GUI. Рантайм на JS более не поддерживается");
|
||||
JOptionPane.showMessageDialog(null, "Модуль графического интерфейса лаунчера отсутствует");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,48 +44,4 @@ public void setConfig(NewLauncherSettings config) {
|
|||
public NewLauncherSettings getDefaultConfig() {
|
||||
return new NewLauncherSettings();
|
||||
}
|
||||
|
||||
public void loadHDirStore(Path storePath) throws IOException {
|
||||
Files.createDirectories(storePath);
|
||||
IOHelper.walk(storePath, new StoreFileVisitor(), false);
|
||||
}
|
||||
|
||||
public void saveHDirStore(Path storeProjectPath) throws IOException {
|
||||
Files.createDirectories(storeProjectPath);
|
||||
for (NewLauncherSettings.HashedStoreEntry e : settings.lastHDirs) {
|
||||
if (!e.needSave) continue;
|
||||
Path file = storeProjectPath.resolve(e.name.concat(".bin"));
|
||||
if (!Files.exists(file)) Files.createFile(file);
|
||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||
output.writeString(e.name, 128);
|
||||
output.writeString(e.fullPath, 1024);
|
||||
e.hdir.write(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadHDirStore() throws IOException {
|
||||
loadHDirStore(DirBridge.dirStore);
|
||||
}
|
||||
|
||||
public void saveHDirStore() throws IOException {
|
||||
saveHDirStore(DirBridge.dirProjectStore);
|
||||
}
|
||||
|
||||
public static class StoreFileVisitor extends SimpleFileVisitor<Path> {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||
String dirName = input.readString(128);
|
||||
String fullPath = input.readString(1024);
|
||||
HashedDir dir = new HashedDir(input);
|
||||
settings.lastHDirs.add(new NewLauncherSettings.HashedStoreEntry(dir, dirName, fullPath));
|
||||
} catch (IOException e) {
|
||||
LogHelper.error("Skip file %s exception: %s", file.toAbsolutePath().toString(), e.getMessage());
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package pro.gravit.launcher.utils;
|
||||
|
||||
import pro.gravit.launcher.AsyncDownloader;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.LauncherInject;
|
||||
import pro.gravit.launcher.request.update.LauncherRequest;
|
||||
|
@ -23,6 +22,8 @@
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static pro.gravit.launcher.modern.Downloader.makeSSLSocketFactory;
|
||||
|
||||
public class LauncherUpdater {
|
||||
@LauncherInject("launcher.certificatePinning")
|
||||
private static boolean isCertificatePinning;
|
||||
|
@ -49,7 +50,7 @@ public static Path prepareUpdate(URL url) throws Exception {
|
|||
if (isCertificatePinning) {
|
||||
HttpsURLConnection connection1 = (HttpsURLConnection) connection;
|
||||
try {
|
||||
connection1.setSSLSocketFactory(AsyncDownloader.makeSSLSocketFactory());
|
||||
connection1.setSSLSocketFactory(makeSSLSocketFactory());
|
||||
} catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -22,23 +20,9 @@ public final class Launcher {
|
|||
|
||||
// Authlib constants
|
||||
|
||||
public static final String SKIN_URL_PROPERTY = "skinURL";
|
||||
|
||||
public static final String SKIN_DIGEST_PROPERTY = "skinDigest";
|
||||
|
||||
public static final String SKIN_METADATA_PROPERTY = "skinMetadata";
|
||||
|
||||
public static final String CLOAK_URL_PROPERTY = "cloakURL";
|
||||
|
||||
public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest";
|
||||
|
||||
public static final String CLOAK_METADATA_PROPERTY = "cloakMetadata";
|
||||
|
||||
|
||||
// Used to determine from clientside is launched from launcher
|
||||
public static final AtomicBoolean LAUNCHED = new AtomicBoolean(false);
|
||||
public static final int PROTOCOL_MAGIC_LEGACY = 0x724724_00 + 24;
|
||||
public static final int PROTOCOL_MAGIC = 0xA205B064; // e = 2.718281828
|
||||
public static final String RUNTIME_DIR = "runtime";
|
||||
|
||||
// Constants
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import pro.gravit.launcher.serialize.HInput;
|
||||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.launcher.serialize.stream.StreamObject;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
@ -21,7 +22,7 @@
|
|||
public final class LauncherConfig extends StreamObject {
|
||||
@LauncherInject("launchercore.certificates")
|
||||
private static final List<byte[]> secureConfigCertificates = null;
|
||||
@LauncherInject("launcher.modules")
|
||||
@LauncherInject("launcher.legacymodules")
|
||||
private static final List<Class<?>> modulesClasses = null;
|
||||
private static final MethodType VOID_TYPE = MethodType.methodType(void.class);
|
||||
@LauncherInject("launcher.projectName")
|
||||
|
@ -51,6 +52,11 @@ public final class LauncherConfig extends StreamObject {
|
|||
@LauncherInject("runtimeconfig.buildNumber")
|
||||
public long buildNumber;
|
||||
|
||||
private static class ModernModulesClass {
|
||||
@LauncherInject("launcher.modules")
|
||||
private static final List<Class<?>> modulesClasses = null;
|
||||
}
|
||||
|
||||
|
||||
@LauncherInjectionConstructor
|
||||
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
|
||||
|
@ -114,6 +120,9 @@ public LauncherConfig(String address, Map<String, byte[]> runtime, String projec
|
|||
}
|
||||
|
||||
public static void initModules(LauncherModulesManager modulesManager) {
|
||||
if(JVMHelper.JVM_VERSION >= 17) {
|
||||
modulesClasses.addAll(ModernModulesClass.modulesClasses);
|
||||
}
|
||||
for (Class<?> clazz : modulesClasses)
|
||||
try {
|
||||
modulesManager.loadModule((LauncherModule) MethodHandles.publicLookup().findConstructor(clazz, VOID_TYPE).invokeWithArguments(Collections.emptyList()));
|
||||
|
|
|
@ -41,7 +41,13 @@ default String toJsonString() {
|
|||
default void loadConfig(Gson gson, Path configPath) throws IOException {
|
||||
if (generateConfigIfNotExists(configPath)) return;
|
||||
try (BufferedReader reader = IOHelper.newReader(configPath)) {
|
||||
setConfig(gson.fromJson(reader, getType()));
|
||||
T value = gson.fromJson(reader, getType());
|
||||
if(value == null) {
|
||||
LogHelper.warning("Config %s is null", configPath);
|
||||
resetConfig(configPath);
|
||||
return;
|
||||
}
|
||||
setConfig(value);
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
resetConfig(configPath);
|
||||
|
|
|
@ -4,4 +4,6 @@ public interface ExtendedTokenRequestEvent {
|
|||
String getExtendedTokenName();
|
||||
|
||||
String getExtendedToken();
|
||||
|
||||
long getExtendedTokenExpire();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class AssetUploadInfoRequestEvent extends RequestEvent {
|
||||
public Set<String> available;
|
||||
public SlimSupportConf slimSupportConf;
|
||||
|
||||
public AssetUploadInfoRequestEvent(Set<String> available, SlimSupportConf slimSupportConf) {
|
||||
this.available = available;
|
||||
this.slimSupportConf = slimSupportConf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "assetUploadInfo";
|
||||
}
|
||||
|
||||
public enum SlimSupportConf {
|
||||
UNSUPPORTED, USER, SERVER
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
public class GetAssetUploadUrlRequestEvent extends RequestEvent {
|
||||
public static final String FEATURE_NAME = "assetupload";
|
||||
public String url;
|
||||
public AuthRequestEvent.OAuthRequestEvent token;
|
||||
|
||||
public GetAssetUploadUrlRequestEvent() {
|
||||
}
|
||||
|
||||
public GetAssetUploadUrlRequestEvent(String url, AuthRequestEvent.OAuthRequestEvent token) {
|
||||
this.url = url;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "getAssetUploadUrl";
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
import pro.gravit.utils.TypeSerializeInterface;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class GetAvailabilityAuthRequestEvent extends RequestEvent {
|
||||
@LauncherNetworkAPI
|
||||
|
@ -49,24 +50,14 @@ public static class AuthAvailability {
|
|||
@LauncherNetworkAPI
|
||||
public boolean visible;
|
||||
@LauncherNetworkAPI
|
||||
public String apiUrl;
|
||||
@LauncherNetworkAPI
|
||||
public List<String> apiFeatures;
|
||||
public Set<String> features;
|
||||
|
||||
public AuthAvailability(String name, String displayName, boolean visible, List<AuthAvailabilityDetails> details) {
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.visible = visible;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public AuthAvailability(String name, String displayName, boolean visible, List<AuthAvailabilityDetails> details, String apiUrl, List<String> apiFeatures) {
|
||||
this.visible = visible;
|
||||
public AuthAvailability(List<AuthAvailabilityDetails> details, String name, String displayName, boolean visible, Set<String> features) {
|
||||
this.details = details;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.apiUrl = apiUrl;
|
||||
this.apiFeatures = apiFeatures;
|
||||
this.visible = visible;
|
||||
this.features = features;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,37 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.events.ExtendedTokenRequestEvent;
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
public class HardwareReportRequestEvent extends RequestEvent {
|
||||
public class HardwareReportRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent {
|
||||
public String extendedToken;
|
||||
public long expire;
|
||||
|
||||
public HardwareReportRequestEvent() {
|
||||
}
|
||||
|
||||
public HardwareReportRequestEvent(String extendedToken) {
|
||||
public HardwareReportRequestEvent(String extendedToken, long expire) {
|
||||
this.extendedToken = extendedToken;
|
||||
this.expire = expire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "hardwareReport";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedTokenName() {
|
||||
return "hardware";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedToken() {
|
||||
return extendedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExtendedTokenExpire() {
|
||||
return expire;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||
import pro.gravit.launcher.events.ExtendedTokenRequestEvent;
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class LauncherRequestEvent extends RequestEvent {
|
||||
public class LauncherRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent {
|
||||
public static final String LAUNCHER_EXTENDED_TOKEN_NAME = "launcher";
|
||||
@SuppressWarnings("unused")
|
||||
private static final UUID uuid = UUID.fromString("d54cc12a-4f59-4f23-9b10-f527fdd2e38f");
|
||||
|
@ -19,6 +20,7 @@ public class LauncherRequestEvent extends RequestEvent {
|
|||
@LauncherNetworkAPI
|
||||
public boolean needUpdate;
|
||||
public String launcherExtendedToken;
|
||||
public long launcherExtendedTokenExpire;
|
||||
|
||||
public LauncherRequestEvent(boolean needUpdate, String url) {
|
||||
this.needUpdate = needUpdate;
|
||||
|
@ -30,10 +32,11 @@ public LauncherRequestEvent(boolean b, byte[] digest) {
|
|||
this.digest = digest;
|
||||
}
|
||||
|
||||
public LauncherRequestEvent(boolean needUpdate, String url, String launcherExtendedToken) {
|
||||
public LauncherRequestEvent(boolean needUpdate, String url, String launcherExtendedToken, long expire) {
|
||||
this.url = url;
|
||||
this.needUpdate = needUpdate;
|
||||
this.launcherExtendedToken = launcherExtendedToken;
|
||||
this.launcherExtendedTokenExpire = expire;
|
||||
}
|
||||
|
||||
public LauncherRequestEvent(byte[] binary, byte[] digest) { //Legacy support constructor
|
||||
|
@ -45,4 +48,19 @@ public LauncherRequestEvent(byte[] binary, byte[] digest) { //Legacy support con
|
|||
public String getType() {
|
||||
return "launcher";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedTokenName() {
|
||||
return "launcher";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedToken() {
|
||||
return launcherExtendedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExtendedTokenExpire() {
|
||||
return launcherExtendedTokenExpire;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public enum ReportAction {
|
|||
LOGOUT,
|
||||
TOKEN_EXPIRED,
|
||||
EXIT,
|
||||
@Deprecated
|
||||
CRASH,
|
||||
OTHER
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package pro.gravit.launcher.events.request;
|
||||
|
||||
import pro.gravit.launcher.events.ExtendedTokenRequestEvent;
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
public class VerifySecureLevelKeyRequestEvent extends RequestEvent {
|
||||
public class VerifySecureLevelKeyRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent {
|
||||
public boolean needHardwareInfo;
|
||||
public boolean onlyStatisticInfo;
|
||||
public String extendedToken;
|
||||
public String hardwareExtendedToken;
|
||||
public long expire;
|
||||
|
||||
public VerifySecureLevelKeyRequestEvent() {
|
||||
}
|
||||
|
@ -15,21 +16,30 @@ public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo) {
|
|||
this.needHardwareInfo = needHardwareInfo;
|
||||
}
|
||||
|
||||
public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken) {
|
||||
public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken, long expire) {
|
||||
this.needHardwareInfo = needHardwareInfo;
|
||||
this.onlyStatisticInfo = onlyStatisticInfo;
|
||||
this.extendedToken = extendedToken;
|
||||
}
|
||||
|
||||
public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken, String hardwareExtendedToken) {
|
||||
this.needHardwareInfo = needHardwareInfo;
|
||||
this.onlyStatisticInfo = onlyStatisticInfo;
|
||||
this.extendedToken = extendedToken;
|
||||
this.hardwareExtendedToken = hardwareExtendedToken;
|
||||
this.expire = expire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "verifySecureLevelKey";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedTokenName() {
|
||||
return "publicKey";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtendedToken() {
|
||||
return extendedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExtendedTokenExpire() {
|
||||
return expire;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@ private ClientProfileVersions() {
|
|||
public static final ClientProfile.Version MINECRAFT_1_18 = ClientProfile.Version.of("1.18");
|
||||
public static final ClientProfile.Version MINECRAFT_1_19 = ClientProfile.Version.of("1.19");
|
||||
public static final ClientProfile.Version MINECRAFT_1_20 = ClientProfile.Version.of("1.20");
|
||||
public static final ClientProfile.Version MINECRAFT_1_20_2 = ClientProfile.Version.of("1.20.2");
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ public class OptionalFile {
|
|||
@LauncherNetworkAPI
|
||||
public boolean limited;
|
||||
|
||||
@LauncherNetworkAPI
|
||||
public String category;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.events.request.CurrentUserRequestEvent;
|
||||
import pro.gravit.launcher.events.request.RefreshTokenRequestEvent;
|
||||
import pro.gravit.launcher.events.request.RestoreRequestEvent;
|
||||
import pro.gravit.launcher.request.auth.RefreshTokenRequest;
|
||||
|
@ -11,32 +12,55 @@
|
|||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public abstract class Request<R extends WebSocketEvent> implements WebSocketRequest {
|
||||
private static final List<ExtendedTokenCallback> extendedTokenCallbacks = new ArrayList<>(4);
|
||||
private static final List<BiConsumer<String, AuthRequestEvent.OAuthRequestEvent>> oauthChangeHandlers = new ArrayList<>(4);
|
||||
@Deprecated
|
||||
public static StdWebSocketService service;
|
||||
private static RequestService requestService;
|
||||
private static AuthRequestEvent.OAuthRequestEvent oauth;
|
||||
private static Map<String, String> extendedTokens;
|
||||
private static String authId;
|
||||
private static long tokenExpiredTime;
|
||||
|
||||
private static volatile RequestService requestService;
|
||||
private static volatile AuthRequestEvent.OAuthRequestEvent oauth;
|
||||
private static volatile Map<String, ExtendedToken> extendedTokens;
|
||||
private static volatile String authId;
|
||||
private static volatile long tokenExpiredTime;
|
||||
private static volatile ScheduledExecutorService executorService;
|
||||
private static volatile boolean autoRefreshRunning;
|
||||
@LauncherNetworkAPI
|
||||
public final UUID requestUUID = UUID.randomUUID();
|
||||
private transient final AtomicBoolean started = new AtomicBoolean(false);
|
||||
|
||||
public static synchronized void startAutoRefresh() {
|
||||
if(!autoRefreshRunning) {
|
||||
if(executorService == null) {
|
||||
executorService = Executors.newSingleThreadScheduledExecutor((t) -> {
|
||||
Thread thread = new Thread(t);
|
||||
thread.setName("AutoRefresh thread");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
}
|
||||
executorService.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
restore(false, true);
|
||||
} catch (Exception e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}, 5, 5, TimeUnit.SECONDS);
|
||||
autoRefreshRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static RequestService getRequestService() {
|
||||
return requestService;
|
||||
}
|
||||
|
||||
public static void setRequestService(RequestService service) {
|
||||
requestService = service;
|
||||
if (service instanceof StdWebSocketService) {
|
||||
Request.service = (StdWebSocketService) service;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isAvailable() {
|
||||
|
@ -64,7 +88,7 @@ public static String getAuthId() {
|
|||
return authId;
|
||||
}
|
||||
|
||||
public static Map<String, String> getExtendedTokens() {
|
||||
public static Map<String, ExtendedToken> getExtendedTokens() {
|
||||
if (extendedTokens != null) {
|
||||
return Collections.unmodifiableMap(extendedTokens);
|
||||
} else {
|
||||
|
@ -72,22 +96,34 @@ public static Map<String, String> getExtendedTokens() {
|
|||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> getStringExtendedTokens() {
|
||||
if(extendedTokens != null) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for(Map.Entry<String, ExtendedToken> e : extendedTokens.entrySet()) {
|
||||
map.put(e.getKey(), e.getValue().token);
|
||||
}
|
||||
return map;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearExtendedTokens() {
|
||||
if (extendedTokens != null) {
|
||||
extendedTokens.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addExtendedToken(String name, String token) {
|
||||
public static void addExtendedToken(String name, ExtendedToken token) {
|
||||
if (extendedTokens == null) {
|
||||
extendedTokens = new HashMap<>();
|
||||
extendedTokens = new ConcurrentHashMap<>();
|
||||
}
|
||||
extendedTokens.put(name, token);
|
||||
}
|
||||
|
||||
public static void addAllExtendedToken(Map<String, String> map) {
|
||||
public static void addAllExtendedToken(Map<String, ExtendedToken> map) {
|
||||
if (extendedTokens == null) {
|
||||
extendedTokens = new HashMap<>();
|
||||
extendedTokens = new ConcurrentHashMap<>();
|
||||
}
|
||||
extendedTokens.putAll(map);
|
||||
}
|
||||
|
@ -117,11 +153,32 @@ public static String getRefreshToken() {
|
|||
}
|
||||
|
||||
public static void reconnect() throws Exception {
|
||||
service.open();
|
||||
|
||||
getRequestService().open();
|
||||
restore();
|
||||
}
|
||||
|
||||
public static RequestRestoreReport restore() throws Exception {
|
||||
return restore(false, false);
|
||||
}
|
||||
|
||||
private synchronized static Map<String, String> getExpiredExtendedTokens() {
|
||||
if(extendedTokens == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
Set<String> set = new HashSet<>();
|
||||
for(Map.Entry<String, ExtendedToken> e : extendedTokens.entrySet()) {
|
||||
if(e.getValue().expire != 0 && e.getValue().expire < System.currentTimeMillis()) {
|
||||
set.add(e.getKey());
|
||||
}
|
||||
}
|
||||
if(set.isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return makeNewTokens(set);
|
||||
}
|
||||
|
||||
public static synchronized RequestRestoreReport restore(boolean needUserInfo, boolean refreshOnly) throws Exception {
|
||||
boolean refreshed = false;
|
||||
RestoreRequest request;
|
||||
if (oauth != null) {
|
||||
|
@ -131,26 +188,18 @@ public static RequestRestoreReport restore() throws Exception {
|
|||
setOAuth(authId, event.oauth);
|
||||
refreshed = true;
|
||||
}
|
||||
request = new RestoreRequest(authId, oauth.accessToken, extendedTokens, false);
|
||||
request = new RestoreRequest(authId, oauth.accessToken, refreshOnly ? getExpiredExtendedTokens() : getStringExtendedTokens(), needUserInfo);
|
||||
} else {
|
||||
request = new RestoreRequest(authId, null, extendedTokens, false);
|
||||
request = new RestoreRequest(authId, null, refreshOnly ? getExpiredExtendedTokens() : getStringExtendedTokens(), false);
|
||||
}
|
||||
if(refreshOnly && (request.extended == null || request.extended.isEmpty())) {
|
||||
return new RequestRestoreReport(refreshed, null, null);
|
||||
}
|
||||
RestoreRequestEvent event = request.request();
|
||||
List<String> invalidTokens = null;
|
||||
if (event.invalidTokens != null && event.invalidTokens.size() > 0) {
|
||||
boolean needRequest = false;
|
||||
Map<String, String> tokens = new HashMap<>();
|
||||
for (ExtendedTokenCallback cb : extendedTokenCallbacks) {
|
||||
for (String tokenName : event.invalidTokens) {
|
||||
String newToken = cb.tryGetNewToken(tokenName);
|
||||
if (newToken != null) {
|
||||
needRequest = true;
|
||||
tokens.put(tokenName, newToken);
|
||||
addExtendedToken(tokenName, newToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needRequest) {
|
||||
Map<String, String> tokens = makeNewTokens(event.invalidTokens);
|
||||
if (!tokens.isEmpty()) {
|
||||
request = new RestoreRequest(authId, null, tokens, false);
|
||||
event = request.request();
|
||||
if (event.invalidTokens != null && event.invalidTokens.size() > 0) {
|
||||
|
@ -159,7 +208,21 @@ public static RequestRestoreReport restore() throws Exception {
|
|||
}
|
||||
invalidTokens = event.invalidTokens;
|
||||
}
|
||||
return new RequestRestoreReport(false, refreshed, invalidTokens);
|
||||
return new RequestRestoreReport(refreshed, invalidTokens, event.userInfo);
|
||||
}
|
||||
|
||||
private synchronized static Map<String, String> makeNewTokens(Collection<String> keys) {
|
||||
Map<String, String> tokens = new HashMap<>();
|
||||
for (ExtendedTokenCallback cb : extendedTokenCallbacks) {
|
||||
for (String tokenName : keys) {
|
||||
ExtendedToken newToken = cb.tryGetNewToken(tokenName);
|
||||
if (newToken != null) {
|
||||
tokens.put(tokenName, newToken.token);
|
||||
addExtendedToken(tokenName, newToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public static void requestError(String message) throws RequestException {
|
||||
|
@ -209,18 +272,29 @@ protected R requestDo(RequestService service) throws Exception {
|
|||
}
|
||||
|
||||
public interface ExtendedTokenCallback {
|
||||
String tryGetNewToken(String name);
|
||||
ExtendedToken tryGetNewToken(String name);
|
||||
}
|
||||
|
||||
public static class RequestRestoreReport {
|
||||
public final boolean legacySession;
|
||||
public final boolean refreshed;
|
||||
public final List<String> invalidExtendedTokens;
|
||||
public final CurrentUserRequestEvent.UserInfo userInfo;
|
||||
|
||||
public RequestRestoreReport(boolean legacySession, boolean refreshed, List<String> invalidExtendedTokens) {
|
||||
this.legacySession = legacySession;
|
||||
public RequestRestoreReport(boolean refreshed, List<String> invalidExtendedTokens, CurrentUserRequestEvent.UserInfo userInfo) {
|
||||
this.refreshed = refreshed;
|
||||
this.invalidExtendedTokens = invalidExtendedTokens;
|
||||
this.userInfo = userInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExtendedToken {
|
||||
public final String token;
|
||||
public final long expire;
|
||||
|
||||
public ExtendedToken(String token, long expire) {
|
||||
this.token = token;
|
||||
long time = System.currentTimeMillis();
|
||||
this.expire = expire < time/2 ? time+expire : expire;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
public interface RequestService {
|
||||
<T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException;
|
||||
void open() throws Exception;
|
||||
|
||||
void registerEventHandler(EventHandler handler);
|
||||
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public final class JoinServerRequest extends Request<JoinServerRequestEvent> implements WebSocketRequest {
|
||||
|
||||
// Instance
|
||||
@LauncherNetworkAPI
|
||||
public final String username;
|
||||
@LauncherNetworkAPI
|
||||
public final UUID uuid;
|
||||
@LauncherNetworkAPI
|
||||
public final String accessToken;
|
||||
@LauncherNetworkAPI
|
||||
public final String serverID;
|
||||
|
@ -19,10 +23,18 @@ public final class JoinServerRequest extends Request<JoinServerRequestEvent> imp
|
|||
|
||||
public JoinServerRequest(String username, String accessToken, String serverID) {
|
||||
this.username = username;
|
||||
this.uuid = null;
|
||||
this.accessToken = accessToken;
|
||||
this.serverID = VerifyHelper.verifyServerID(serverID);
|
||||
}
|
||||
|
||||
public JoinServerRequest(UUID uuid, String accessToken, String serverID) {
|
||||
this.username = null;
|
||||
this.uuid = uuid;
|
||||
this.accessToken = accessToken;
|
||||
this.serverID = serverID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "joinServer";
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package pro.gravit.launcher.request.cabinet;
|
||||
|
||||
import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
|
||||
public class AssetUploadInfoRequest extends Request<AssetUploadInfoRequestEvent> {
|
||||
@Override
|
||||
public String getType() {
|
||||
return "assetUploadInfo";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package pro.gravit.launcher.request.cabinet;
|
||||
|
||||
import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent;
|
||||
import pro.gravit.launcher.request.Request;
|
||||
|
||||
public class GetAssetUploadUrl extends Request<GetAssetUploadUrlRequestEvent> {
|
||||
public String name;
|
||||
|
||||
public GetAssetUploadUrl() {
|
||||
}
|
||||
|
||||
public GetAssetUploadUrl(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "getAssetUploadUrl";
|
||||
}
|
||||
}
|
|
@ -111,6 +111,8 @@ public void registerResults() {
|
|||
results.register("additionalData", AdditionalDataRequestEvent.class);
|
||||
results.register("clientProfileKey", FetchClientProfileKeyRequestEvent.class);
|
||||
results.register("getPublicKey", GetPublicKeyRequestEvent.class);
|
||||
results.register("getAssetUploadUrl", GetAssetUploadUrlRequestEvent.class);
|
||||
results.register("assetUploadInfo", AssetUploadInfoRequestEvent.class);
|
||||
resultsRegistered = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,11 @@ public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> reques
|
|||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEventHandler(EventHandler handler) {
|
||||
eventHandlers.add(handler);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue