[FIX] Bug fixes

This commit is contained in:
Gravita 2021-05-23 21:11:27 +07:00
parent b7a7156408
commit 2c41b510ad
17 changed files with 186 additions and 35 deletions

View file

@ -86,6 +86,9 @@ pack project(':LauncherAPI')
bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard']
bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j']
bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: rootProject['verLog4j']
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']
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
hikari 'io.micrometer:micrometer-core:1.5.10'

View file

@ -20,6 +20,7 @@
import pro.gravit.launchserver.modules.events.*;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.CommandHandler;
import pro.gravit.utils.command.SubCommand;
@ -171,6 +172,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
pingServerManager = new PingServerManager(this);
featuresManager = new FeaturesManager(this);
authManager = new AuthManager(this);
RestoreResponse.registerProviders(this);
//Generate or set new Certificate API
certificateManager.orgName = config.projectName;
config.init(ReloadType.FULL);

View file

@ -45,6 +45,7 @@ public void invoke(String... args) {
else {
logger.info("Client name {} | ip {} | connectUUID {}", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID());
logger.info("userUUID: {} | session {}", client.uuid == null ? "null" : client.uuid.toString(), client.session == null ? "null" : client.session);
logger.info("OAuth {} | session {}", client.useOAuth, client.sessionObject == null ? "null" : client.sessionObject);
logger.info("Data: checkSign {} | auth_id {}", client.checkSign ? "true" : "false",
client.auth_id);
if (client.trustLevel != null) {

View file

@ -166,7 +166,7 @@ void process(ChannelHandlerContext ctx, WebSocketServerResponse response, Client
try {
response.execute(ctx, client);
} catch (Exception e) {
logger.error(e);
logger.error("WebSocket request processing failed", e);
RequestEvent event;
if (server.config.netty.sendExceptionEnabled) {
event = new ExceptionEvent(e);

View file

@ -25,13 +25,13 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
}
AuthProviderPair pair;
if(!client.isAuth) {
if(authId == null || !client.useOAuth) {
if(authId == null) {
pair = server.config.getAuthProviderPair();
} else {
pair = client.auth;
pair = server.config.getAuthProviderPair(authId);
}
} else {
pair = server.config.getAuthProviderPair(authId);
pair = client.auth;
}
if(pair == null || !pair.isUseCore()) {
sendError("Invalid request");

View file

@ -2,23 +2,35 @@
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.AuthRequestEvent;
import pro.gravit.launcher.events.request.LauncherRequestEvent;
import pro.gravit.launcher.events.request.RestoreRequestEvent;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.launchserver.auth.core.UserSession;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.socket.response.update.LauncherResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RestoreResponse extends SimpleResponse {
@FunctionalInterface
public interface ExtendedTokenProvider {
void accept(Client client, AuthProviderPair pair, String extendedToken);
boolean accept(Client client, AuthProviderPair pair, String extendedToken);
}
public static Map<String, ExtendedTokenProvider> providers = new HashMap<>();
private static boolean registeredProviders = false;
public static void registerProviders(LaunchServer server) {
if(!registeredProviders) {
providers.put(LauncherRequestEvent.LAUNCHER_EXTENDED_TOKEN_NAME, new LauncherResponse.LauncherTokenVerifier(server));
registeredProviders = true;
}
}
public String authId;
public String accessToken;
public Map<String, String> extended;
@ -37,16 +49,16 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
}
AuthProviderPair pair;
if(!client.isAuth) {
if(authId == null || !client.useOAuth) {
if(authId == null) {
pair = server.config.getAuthProviderPair();
} else {
pair = client.auth;
pair = server.config.getAuthProviderPair(authId);
}
} else {
pair = server.config.getAuthProviderPair(authId);
pair = client.auth;
}
if(pair == null || !pair.isUseCore()) {
sendError("Invalid request");
sendError("Invalid authId");
return;
}
if(accessToken != null) {
@ -66,17 +78,20 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
client.sessionObject = session;
server.authManager.internalAuth(client, client.type == null ? AuthResponse.ConnectTypes.API : client.type, pair, user.getUsername(), user.getUUID(), user.getPermissions(), true);
}
List<String> invalidTokens = new ArrayList<>(4);
if(extended != null) {
extended.forEach((k,v) -> {
ExtendedTokenProvider provider = providers.get(k);
if(provider == null) return;
provider.accept(client, pair, v);
if(!provider.accept(client, pair, v)) {
invalidTokens.add(k);
}
});
}
if(needUserInfo && client.isAuth) {
sendResult(new RestoreRequestEvent(CurrentUserResponse.collectUserInfoFromClient(client)));
sendResult(new RestoreRequestEvent(CurrentUserResponse.collectUserInfoFromClient(client), invalidTokens));
} else {
sendResult(new RestoreRequestEvent());
sendResult(new RestoreRequestEvent(invalidTokens));
}
}
}

View file

@ -4,6 +4,7 @@
import pro.gravit.launcher.events.request.BatchProfileByUsernameRequestEvent;
import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
@ -31,7 +32,13 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
if (pair == null) {
pair = server.config.getAuthProviderPair();
}
uuid = pair.handler.usernameToUUID(list[i].username);
if(pair.isUseCore()) {
User user = pair.core.getUserByUsername(list[i].username);
if(user == null) uuid = null;
else uuid = user.getUUID();
} else {
uuid = pair.handler.usernameToUUID(list[i].username);
}
result.playerProfiles[i] = ProfileByUUIDResponse.getProfile(uuid, list[i].username, list[i].client, pair.textureProvider);
}
sendResult(result);

View file

@ -5,6 +5,7 @@
import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launcher.profiles.Texture;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
@ -55,10 +56,19 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
sendError("ProfileByUUIDResponse: AuthProviderPair is null");
return;
}
username = pair.handler.uuidToUsername(uuid);
if (username == null) {
sendError(String.format("ProfileByUUIDResponse: User with uuid %s not found or AuthProvider#uuidToUsername returned null", uuid));
return;
if(pair.isUseCore()) {
User user = pair.core.getUserByUUID(uuid);
if(user == null) {
sendError("User not found");
return;
}
else username = user.getUsername();
} else {
username = pair.handler.uuidToUsername(uuid);
if (username == null) {
sendError(String.format("ProfileByUUIDResponse: User with uuid %s not found or AuthProvider#uuidToUsername returned null", uuid));
return;
}
}
sendResult(new ProfileByUUIDRequestEvent(getProfile(uuid, username, this.client, pair.textureProvider)));
}

View file

@ -3,6 +3,7 @@
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
@ -22,7 +23,13 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
UUID uuid;
AuthProviderPair pair = client.auth;
if (pair == null) pair = server.config.getAuthProviderPair();
uuid = pair.handler.usernameToUUID(username);
if(pair.isUseCore()) {
User user = pair.core.getUserByUsername(username);
if(user == null) uuid = null;
else uuid = user.getUUID();
} else {
uuid = pair.handler.usernameToUUID(username);
}
if (uuid == null) {
sendError("User not found");
return;

View file

@ -1,14 +1,24 @@
package pro.gravit.launchserver.socket.response.update;
import io.jsonwebtoken.*;
import io.netty.channel.ChannelHandlerContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.events.request.LauncherRequestEvent;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
import pro.gravit.utils.Version;
import pro.gravit.utils.helper.SecurityHelper;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
public class LauncherResponse extends SimpleResponse {
public Version version;
@ -38,9 +48,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));
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken()));
} else {
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL));
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken()));
}
} else if (launcher_type == 2) //EXE
{
@ -48,13 +58,50 @@ 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));
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken()));
} else {
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken()));
}
} else sendError("Request launcher type error");
}
public String createLauncherExtendedToken() {
return Jwts.builder()
.setIssuer("LaunchServer")
.claim("checkSign", true)
.setExpiration(Date.from(LocalDateTime.now().plusHours(8).toInstant(ZoneOffset.UTC)))
.signWith(server.keyAgreementManager.ecdsaPrivateKey, SignatureAlgorithm.ES256)
.compact();
}
public static class LauncherTokenVerifier implements RestoreResponse.ExtendedTokenProvider {
private final LaunchServer server;
private final JwtParser parser;
private final Logger logger = LogManager.getLogger();
public LauncherTokenVerifier(LaunchServer server) {
this.server = server;
parser = Jwts.parserBuilder()
.setSigningKey(server.keyAgreementManager.ecdsaPublicKey)
.requireIssuer("LaunchServer")
.build();
}
@Override
public boolean accept(Client client, AuthProviderPair pair, String extendedToken) {
try {
var jwt = parser.parseClaimsJws(extendedToken);
client.checkSign = jwt.getBody().get("checkSign", Boolean.class);
client.type = AuthResponse.ConnectTypes.CLIENT;
return true;
} catch (Exception e) {
logger.error("JWT check failed", e);
return false;
}
}
}
private boolean checkSecure(String hash, String salt) {
if (hash == null || salt == null) return false;
byte[] normal_hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,

View file

@ -91,9 +91,8 @@ public static void main(String[] args) throws Throwable {
Launcher.profile = profile;
AuthService.profile = profile;
LauncherEngine.clientParams = params;
if(params.session != null) {
Request.setSession(params.session);
} else if(params.oauth != null) {
if(params.oauth != null) {
LogHelper.info("Using OAuth");
if(params.oauthExpiredTime != 0) {
Request.setOAuth(params.authId, params.oauth, params.oauthExpiredTime);
} else {
@ -102,6 +101,9 @@ public static void main(String[] args) throws Throwable {
if(params.extendedTokens != null) {
Request.addAllExtendedToken(params.extendedTokens);
}
} else if(params.session != null) {
LogHelper.info("Using Sessions");
Request.setSession(params.session);
}
checkJVMBitsAndVersion(params.profile.getMinJavaVersion(), params.profile.getRecommendJavaVersion(), params.profile.getMaxJavaVersion(), params.profile.isWarnMissJavaVersion());
LauncherEngine.modulesManager.invokeEvent(new ClientProcessInitPhase(engine, params));

View file

@ -90,6 +90,9 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path r
javaVersion = ClientLauncherWrapper.JavaVersion.getByPath(javaDir);
} catch (IOException e) {
LogHelper.error(e);
javaVersion = null;
}
if(javaVersion == null) {
javaVersion = ClientLauncherWrapper.JavaVersion.getCurrentJavaVersion();
}
this.bits = JVMHelper.JVM_BITS;
@ -120,6 +123,7 @@ private void applyClientProfile() {
if(this.params.oauth == null) {
this.params.session = Request.getSession();
} else {
this.params.authId = Request.getAuthId();
this.params.oauthExpiredTime = Request.getTokenExpiredTime();
this.params.extendedTokens = Request.getExtendedTokens();
}

View file

@ -9,6 +9,7 @@
public class LauncherRequestEvent extends RequestEvent {
@SuppressWarnings("unused")
private static final UUID uuid = UUID.fromString("d54cc12a-4f59-4f23-9b10-f527fdd2e38f");
public static final String LAUNCHER_EXTENDED_TOKEN_NAME = "launcher";
@LauncherNetworkAPI
public String url;
@LauncherNetworkAPI
@ -17,6 +18,7 @@ public class LauncherRequestEvent extends RequestEvent {
public byte[] binary;
@LauncherNetworkAPI
public boolean needUpdate;
public String launcherExtendedToken;
public LauncherRequestEvent(boolean needUpdate, String url) {
this.needUpdate = needUpdate;
@ -28,6 +30,12 @@ public LauncherRequestEvent(boolean b, byte[] digest) {
this.digest = digest;
}
public LauncherRequestEvent(boolean needUpdate, String url, String launcherExtendedToken) {
this.url = url;
this.needUpdate = needUpdate;
this.launcherExtendedToken = launcherExtendedToken;
}
public LauncherRequestEvent(byte[] binary, byte[] digest) { //Legacy support constructor
this.binary = binary;
this.digest = digest;

View file

@ -2,8 +2,11 @@
import pro.gravit.launcher.events.RequestEvent;
import java.util.List;
public class RestoreRequestEvent extends RequestEvent {
public CurrentUserRequestEvent.UserInfo userInfo;
public List<String> invalidTokens;
public RestoreRequestEvent() {
}
@ -12,6 +15,15 @@ public RestoreRequestEvent(CurrentUserRequestEvent.UserInfo userInfo) {
this.userInfo = userInfo;
}
public RestoreRequestEvent(CurrentUserRequestEvent.UserInfo userInfo, List<String> invalidTokens) {
this.userInfo = userInfo;
this.invalidTokens = invalidTokens;
}
public RestoreRequestEvent(List<String> invalidTokens) {
this.invalidTokens = invalidTokens;
}
@Override
public String getType() {
return "restore";

View file

@ -10,12 +10,12 @@
import pro.gravit.launcher.request.auth.RestoreSessionRequest;
import pro.gravit.launcher.request.websockets.StdWebSocketService;
import pro.gravit.launcher.request.websockets.WebSocketRequest;
import pro.gravit.utils.helper.LogHelper;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
public abstract class Request<R extends WebSocketEvent> implements WebSocketRequest {
public static StdWebSocketService service;
@ -24,6 +24,10 @@ public abstract class Request<R extends WebSocketEvent> implements WebSocketRequ
private static Map<String, String> extendedTokens;
private static String authId;
private static long tokenExpiredTime;
private static List<ExtendedTokenCallback> extendedTokenCallbacks = new ArrayList<>(4);
public interface ExtendedTokenCallback {
String tryGetNewToken(String name);
}
@LauncherNetworkAPI
public final UUID requestUUID = UUID.randomUUID();
private transient final AtomicBoolean started = new AtomicBoolean(false);
@ -46,10 +50,18 @@ public static void setOAuth(String authId, AuthRequestEvent.OAuthRequestEvent ev
}
}
public void addExtendedTokenCallback(ExtendedTokenCallback cb) {
extendedTokenCallbacks.add(cb);
}
public static AuthRequestEvent.OAuthRequestEvent getOAuth() {
return oauth;
}
public static String getAuthId() {
return authId;
}
public static Map<String, String> getExtendedTokens() {
if(extendedTokens != null) {
return Collections.unmodifiableMap(extendedTokens);
@ -108,17 +120,37 @@ public static void reconnect() throws Exception {
}
public static void restore() throws Exception {
if(session != null) {
RestoreSessionRequest request = new RestoreSessionRequest(session);
request.request();
}
else if(oauth != null) {
if(oauth != null) {
if(isTokenExpired() || oauth.accessToken == null) {
RefreshTokenRequest request = new RefreshTokenRequest(authId, oauth.refreshToken);
RefreshTokenRequestEvent event = request.request();
setOAuth(authId, event.oauth);
}
RestoreRequest request = new RestoreRequest(authId, oauth.accessToken, extendedTokens, false);
RestoreRequestEvent event = request.request();
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) {
request = new RestoreRequest(authId, null, tokens, false);
event = request.request();
if(event.invalidTokens != null && event.invalidTokens.size() > 0) {
LogHelper.warning("Tokens %s not restored", String.join(",", event.invalidTokens));
}
}
}
} else if(session != null) {
RestoreSessionRequest request = new RestoreSessionRequest(session);
request.request();
}
}

@ -1 +1 @@
Subproject commit 7efafab83a169da634a28b9f0aadb14f512c8f58
Subproject commit d7d34954f68deb77a1d7d0b170008e6573d3475f

View file

@ -6,6 +6,7 @@
verGuavaC = '30.1-jre'
verJansi = '2.3.2'
verJline = '3.19.0'
verJwt = '0.11.2'
verBcprov = '1.68'
verGson = '2.8.6'
verBcpkix = '1.68'