[ANY] Небольшой рефактор.

Обнаружил isClient и IS_CLIENT, ещё пару подобных пережитков...
This commit is contained in:
Zaxar163 2021-07-21 19:43:47 +03:00
parent dfa2b042e4
commit eb9871123b
No known key found for this signature in database
GPG key ID: BC54673329B5017D
34 changed files with 454 additions and 438 deletions

View file

@ -278,11 +278,11 @@ public void invoke(String... args) throws Exception {
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
AuthProviderPair pair = config.getAuthProviderPair(args[0]);
if(pair == null) {
if (pair == null) {
logger.error("Pair not found");
return;
}
if(pair.isUseCore()){
if (pair.isUseCore()) {
pair.core.close();
} else {
pair.provider.close();
@ -293,7 +293,8 @@ public void invoke(String... args) throws Exception {
pair.core = new RejectAuthCoreProvider();
pair.core.init(instance);
}
};commands.put("resetauth", resetauth);
};
commands.put("resetauth", resetauth);
return commands;
}
@ -394,7 +395,7 @@ public void run() {
modulesManager.invokeEvent(new LaunchServerFullInitEvent(this));
logger.info("LaunchServer started");
} catch (Throwable e) {
logger.error("LaunchServer startup failed",e);
logger.error("LaunchServer startup failed", e);
JVMHelper.RUNTIME.exit(-1);
}
}

View file

@ -46,6 +46,29 @@ public AuthProviderPair(AuthCoreProvider core, AuthSocialProvider social, Textur
this.textureProvider = textureProvider;
}
public static Set<String> getFeatures(Class<?> clazz) {
Set<String> list = new HashSet<>();
getFeatures(clazz, list);
return list;
}
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());
}
}
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && superClass != Object.class) {
getFeatures(superClass, list);
}
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
getFeatures(i, list);
}
}
public final <T> T isSupport(Class<T> clazz) {
if (core == null) return null;
T result = null;
@ -118,29 +141,6 @@ public final void close() throws IOException {
}
}
public static Set<String> getFeatures(Class<?> clazz) {
Set<String> list = new HashSet<>();
getFeatures(clazz, list);
return list;
}
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());
}
}
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && superClass != Object.class) {
getFeatures(superClass, list);
}
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
getFeatures(i, list);
}
}
public final boolean isUseCore() {
return core != null;
}

View file

@ -24,6 +24,21 @@ public static void registerProviders() {
}
}
public abstract void init(LaunchServer server, AuthCoreProvider provider);
public abstract List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client);
public abstract SocialResult preAuth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException;
@SuppressWarnings("unchecked")
public <T> T isSupport(Class<T> clazz) {
if (clazz.isAssignableFrom(getClass())) return (T) this;
return null;
}
@Override
public abstract void close() throws IOException;
public static class SocialResult {
public String login;
public AuthRequest.AuthPasswordInterface password;
@ -43,19 +58,4 @@ public static SocialResult ofUser(User user) {
return new SocialResult(null, null, user);
}
}
public abstract void init(LaunchServer server, AuthCoreProvider provider);
public abstract List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client);
public abstract SocialResult preAuth(AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password) throws AuthException;
@SuppressWarnings("unchecked")
public <T> T isSupport(Class<T> clazz) {
if (clazz.isAssignableFrom(getClass())) return (T) this;
return null;
}
@Override
public abstract void close() throws IOException;
}

View file

@ -41,6 +41,140 @@ public class JsonCoreProvider extends AuthCoreProvider {
public PasswordVerifier passwordVerifier;
private transient HttpClient client;
public static <T, R> R jsonRequest(T request, String url, String bearerToken, Class<R> clazz, HttpClient client) {
HttpRequest.BodyPublisher publisher;
if (request != null) {
publisher = HttpRequest.BodyPublishers.ofString(request.toString());
} else {
publisher = HttpRequest.BodyPublishers.noBody();
}
try {
HttpRequest.Builder request1 = HttpRequest.newBuilder()
.method("POST", publisher)
.uri(new URI(url))
.header("Content-Type", "application/json; charset=UTF-8")
.header("Accept", "application/json")
.timeout(Duration.ofMillis(10000));
if (bearerToken != null) {
request1.header("Authentication", "Bearer ".concat(bearerToken));
}
HttpResponse<InputStream> response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream());
int statusCode = response.statusCode();
if (200 > statusCode || statusCode > 300) {
if (statusCode >= 500) {
logger.error("JsonCoreProvider: {} return {}", url, statusCode);
} else if (statusCode >= 300 && statusCode <= 400) {
logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown"));
} else if (statusCode == 403 || statusCode == 401) {
logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode);
}
return null;
}
try (Reader reader = new InputStreamReader(response.body())) {
return Launcher.gsonManager.gson.fromJson(reader, clazz);
}
} catch (Exception e) {
return null;
}
}
@Override
public User getUserByUsername(String username) {
return jsonRequest(new JsonGetUserByUsername(username), getUserByUsernameUrl, JsonUser.class);
}
@Override
public User getUserByLogin(String login) {
if (getUserByLoginUrl != null) {
return jsonRequest(new JsonGetUserByUsername(login), getUserByLoginUrl, JsonUser.class);
}
return super.getUserByLogin(login);
}
@Override
public User getUserByUUID(UUID uuid) {
return jsonRequest(new JsonGetUserByUUID(uuid), getUserByUUIDUrl, JsonUser.class);
}
@Override
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
if (getUserSessionByOAuthAccessTokenUrl == null) {
return null;
}
JsonGetUserSessionByOAuthTokenResponse response = jsonRequest(new JsonGetUserSessionByAccessToken(accessToken), getUserSessionByOAuthAccessTokenUrl, JsonGetUserSessionByOAuthTokenResponse.class);
if (response == null) return null;
if (!response.expired) throw new OAuthAccessTokenExpired();
return response.session;
}
@Override
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
if (getAuthDetailsUrl != null) {
JsonGetDetailsResponse response = jsonRequest(new JsonGetDetails(), getAuthDetailsUrl, JsonGetDetailsResponse.class);
if (response == null) return super.getDetails(client);
return response.details;
}
return super.getDetails(client);
}
@Override
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
JsonAuthReportResponse response = jsonRequest(new JsonRefreshToken(refreshToken, context.ip), this.refreshAccessTokenUrl, JsonAuthReportResponse.class);
return response == null ? null : response.toAuthReport();
}
@Override
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
}
@Override
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
JsonUser jsonUser = (JsonUser) user;
if (password instanceof AuthPlainPassword && jsonUser.password != null && passwordVerifier != null) {
if (passwordVerifier.check(((AuthPlainPassword) password).password, jsonUser.password)) {
return PasswordVerifyReport.OK;
} else {
return PasswordVerifyReport.FAILED;
}
}
if (user == null) {
return jsonRequest(new JsonPasswordVerify(null, null), verifyPasswordUrl, PasswordVerifyReport.class);
}
return jsonRequest(new JsonPasswordVerify(user.getUsername(), user.getUUID()), verifyPasswordUrl, PasswordVerifyReport.class);
}
@Override
public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
JsonAuthReportResponse response = jsonRequest(new JsonCreateOAuthSession(user == null ? null : user.getUsername(), user == null ? null : user.getUUID(), minecraftAccess), createOAuthSessionUrl, JsonAuthReportResponse.class);
if (response == null) return null;
if (response.error != null) throw new AuthException(response.error);
JsonUser user1 = (JsonUser) user;
user1.accessToken = response.minecraftAccessToken;
return response.toAuthReport();
}
@Override
public void init(LaunchServer server) {
client = HttpClient.newBuilder().build();
}
@Override
protected boolean updateServerID(User user, String serverID) throws IOException {
JsonSuccessResponse successResponse = jsonRequest(new JsonUpdateServerId(user.getUsername(), user.getUUID(), serverID), updateServerIdUrl, JsonSuccessResponse.class);
if (successResponse == null) return false;
return successResponse.success;
}
@Override
public void close() throws IOException {
}
public <T, R> R jsonRequest(T request, String url, Class<R> clazz) {
return jsonRequest(request, url, bearerToken, clazz, client);
}
public static class JsonGetUserByUsername {
public String username;
@ -142,99 +276,6 @@ public static class JsonGetDetailsResponse {
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> details;
}
@Override
public User getUserByUsername(String username) {
return jsonRequest(new JsonGetUserByUsername(username), getUserByUsernameUrl, JsonUser.class);
}
@Override
public User getUserByLogin(String login) {
if (getUserByLoginUrl != null) {
return jsonRequest(new JsonGetUserByUsername(login), getUserByLoginUrl, JsonUser.class);
}
return super.getUserByLogin(login);
}
@Override
public User getUserByUUID(UUID uuid) {
return jsonRequest(new JsonGetUserByUUID(uuid), getUserByUUIDUrl, JsonUser.class);
}
@Override
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
if (getUserSessionByOAuthAccessTokenUrl == null) {
return null;
}
JsonGetUserSessionByOAuthTokenResponse response = jsonRequest(new JsonGetUserSessionByAccessToken(accessToken), getUserSessionByOAuthAccessTokenUrl, JsonGetUserSessionByOAuthTokenResponse.class);
if (response == null) return null;
if (!response.expired) throw new OAuthAccessTokenExpired();
return response.session;
}
@Override
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
if (getAuthDetailsUrl != null) {
JsonGetDetailsResponse response = jsonRequest(new JsonGetDetails(), getAuthDetailsUrl, JsonGetDetailsResponse.class);
if (response == null) return super.getDetails(client);
return response.details;
}
return super.getDetails(client);
}
@Override
public AuthManager.AuthReport refreshAccessToken(String refreshToken, AuthResponse.AuthContext context) {
JsonAuthReportResponse response = jsonRequest(new JsonRefreshToken(refreshToken, context.ip), this.refreshAccessTokenUrl, JsonAuthReportResponse.class);
return response == null ? null : response.toAuthReport();
}
@Override
public void verifyAuth(AuthResponse.AuthContext context) throws AuthException {
}
@Override
public PasswordVerifyReport verifyPassword(User user, AuthRequest.AuthPasswordInterface password) {
JsonUser jsonUser = (JsonUser) user;
if (password instanceof AuthPlainPassword && jsonUser.password != null && passwordVerifier != null) {
if (passwordVerifier.check(((AuthPlainPassword) password).password, jsonUser.password)) {
return PasswordVerifyReport.OK;
} else {
return PasswordVerifyReport.FAILED;
}
}
if (user == null) {
return jsonRequest(new JsonPasswordVerify(null, null), verifyPasswordUrl, PasswordVerifyReport.class);
}
return jsonRequest(new JsonPasswordVerify(user.getUsername(), user.getUUID()), verifyPasswordUrl, PasswordVerifyReport.class);
}
@Override
public AuthManager.AuthReport createOAuthSession(User user, AuthResponse.AuthContext context, PasswordVerifyReport report, boolean minecraftAccess) throws IOException {
JsonAuthReportResponse response = jsonRequest(new JsonCreateOAuthSession(user == null ? null : user.getUsername(), user == null ? null : user.getUUID(), minecraftAccess), createOAuthSessionUrl, JsonAuthReportResponse.class);
if (response == null) return null;
if (response.error != null) throw new AuthException(response.error);
JsonUser user1 = (JsonUser) user;
user1.accessToken = response.minecraftAccessToken;
return response.toAuthReport();
}
@Override
public void init(LaunchServer server) {
client = HttpClient.newBuilder().build();
}
@Override
protected boolean updateServerID(User user, String serverID) throws IOException {
JsonSuccessResponse successResponse = jsonRequest(new JsonUpdateServerId(user.getUsername(), user.getUUID(), serverID), updateServerIdUrl, JsonSuccessResponse.class);
if (successResponse == null) return false;
return successResponse.success;
}
@Override
public void close() throws IOException {
}
public static class JsonUser implements User {
private String username;
private UUID uuid;
@ -319,45 +360,4 @@ public String toString() {
'}';
}
}
public <T, R> R jsonRequest(T request, String url, Class<R> clazz) {
return jsonRequest(request, url, bearerToken, clazz, client);
}
public static <T, R> R jsonRequest(T request, String url, String bearerToken, Class<R> clazz, HttpClient client) {
HttpRequest.BodyPublisher publisher;
if (request != null) {
publisher = HttpRequest.BodyPublishers.ofString(request.toString());
} else {
publisher = HttpRequest.BodyPublishers.noBody();
}
try {
HttpRequest.Builder request1 = HttpRequest.newBuilder()
.method("POST", publisher)
.uri(new URI(url))
.header("Content-Type", "application/json; charset=UTF-8")
.header("Accept", "application/json")
.timeout(Duration.ofMillis(10000));
if (bearerToken != null) {
request1.header("Authentication", "Bearer ".concat(bearerToken));
}
HttpResponse<InputStream> response = client.send(request1.build(), HttpResponse.BodyHandlers.ofInputStream());
int statusCode = response.statusCode();
if (200 > statusCode || statusCode > 300) {
if (statusCode >= 500) {
logger.error("JsonCoreProvider: {} return {}", url, statusCode);
} else if (statusCode >= 300 && statusCode <= 400) {
logger.error("JsonCoreProvider: {} return {}, try redirect to {}. Redirects not supported!", url, statusCode, response.headers().firstValue("Location").orElse("Unknown"));
} else if (statusCode == 403 || statusCode == 401) {
logger.error("JsonCoreProvider: {} return {}. Please set 'bearerToken'!", url, statusCode);
}
return null;
}
try (Reader reader = new InputStreamReader(response.body())) {
return Launcher.gsonManager.gson.fromJson(reader, clazz);
}
} catch (Exception e) {
return null;
}
}
}

View file

@ -41,6 +41,13 @@ public class MySQLCoreProvider extends AuthCoreProvider implements AuthSupportHa
public String tableHWID = "hwids";
public String tableHWIDLog = "hwidLog";
public PasswordVerifier passwordVerifier;
public double criticalCompareLevel = 1.0;
public String customQueryByUUIDSQL;
public String customQueryByUsernameSQL;
public String customQueryByLoginSQL;
public String customUpdateAuthSQL;
public String customUpdateServerIdSQL;
private transient String sqlFindHardwareByPublicKey;
private transient String sqlFindHardwareByData;
private transient String sqlFindHardwareById;
@ -50,10 +57,6 @@ public class MySQLCoreProvider extends AuthCoreProvider implements AuthSupportHa
private transient String sqlUpdateHardwareBanned;
private transient String sqlUpdateUsers;
private transient String sqlUsersByHwidId;
public PasswordVerifier passwordVerifier;
public double criticalCompareLevel = 1.0;
// Prepared SQL queries
private transient String queryByUUIDSQL;
private transient String queryByUsernameSQL;
@ -61,12 +64,6 @@ public class MySQLCoreProvider extends AuthCoreProvider implements AuthSupportHa
private transient String updateAuthSQL;
private transient String updateServerIDSQL;
public String customQueryByUUIDSQL;
public String customQueryByUsernameSQL;
public String customQueryByLoginSQL;
public String customUpdateAuthSQL;
public String customUpdateServerIdSQL;
@Override
public User getUserByUsername(String username) {
try {
@ -154,16 +151,20 @@ public void init(LaunchServer server) {
updateServerIDSQL = customUpdateServerIdSQL != null ? customUpdateServerIdSQL : String.format("UPDATE %s SET %s=? WHERE %s=? LIMIT 1",
table, serverIDColumn, uuidColumn);
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
if(sqlFindHardwareByPublicKey == null) sqlFindHardwareByPublicKey = String.format("SELECT %s FROM %s WHERE `publicKey` = ?", hardwareInfoCols, tableHWID);
if(sqlFindHardwareById == null) sqlFindHardwareById = String.format("SELECT %s FROM %s WHERE `id` = ?", hardwareInfoCols, tableHWID);
if(sqlUsersByHwidId == null) sqlUsersByHwidId = String.format("SELECT %s FROM %s WHERE `%s` = ?", userInfoCols, table, hardwareIdColumn);
if (sqlFindHardwareByPublicKey == null)
sqlFindHardwareByPublicKey = String.format("SELECT %s FROM %s WHERE `publicKey` = ?", hardwareInfoCols, tableHWID);
if (sqlFindHardwareById == null)
sqlFindHardwareById = String.format("SELECT %s FROM %s WHERE `id` = ?", hardwareInfoCols, tableHWID);
if (sqlUsersByHwidId == null)
sqlUsersByHwidId = String.format("SELECT %s FROM %s WHERE `%s` = ?", userInfoCols, table, hardwareIdColumn);
if (sqlFindHardwareByData == null)
sqlFindHardwareByData = String.format("SELECT %s FROM %s", hardwareInfoCols, tableHWID);
if (sqlCreateHardware == null)
sqlCreateHardware = String.format("INSERT INTO `%s` (`publickey`, `hwDiskId`, `baseboardSerialNumber`, `displayId`, `bitness`, `totalMemory`, `logicalProcessors`, `physicalProcessors`, `processorMaxFreq`, `graphicCard`, `battery`, `banned`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0')", tableHWID);
if (sqlCreateHWIDLog == null)
sqlCreateHWIDLog = String.format("INSERT INTO %s (`hwidId`, `newPublicKey`) VALUES (?, ?)", tableHWIDLog);
if(sqlUpdateHardwarePublicKey == null) sqlUpdateHardwarePublicKey = String.format("UPDATE %s SET `publicKey` = ? WHERE `id` = ?", tableHWID);
if (sqlUpdateHardwarePublicKey == null)
sqlUpdateHardwarePublicKey = String.format("UPDATE %s SET `publicKey` = ? WHERE `id` = ?", tableHWID);
sqlUpdateHardwareBanned = String.format("UPDATE %s SET `banned` = ? WHERE `id` = ?", tableHWID);
sqlUpdateUsers = String.format("UPDATE %s SET `%s` = ? WHERE `%s` = ?", table, hardwareIdColumn, uuidColumn);
}
@ -405,6 +406,50 @@ public void unbanHardware(UserHardware hardware) {
}
}
public static class MySQLUserHardware implements UserHardware {
private final HardwareReportRequest.HardwareInfo hardwareInfo;
private final long id;
private byte[] publicKey;
private boolean banned;
public MySQLUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, long id, boolean banned) {
this.hardwareInfo = hardwareInfo;
this.publicKey = publicKey;
this.id = id;
this.banned = banned;
}
@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 "MySQLUserHardware{" +
"hardwareInfo=" + hardwareInfo +
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
", id=" + id +
", banned=" + banned +
'}';
}
}
public class MySQLUser implements User, UserSupportHardware {
protected UUID uuid;
protected String username;
@ -468,48 +513,4 @@ public String toString() {
'}';
}
}
public static class MySQLUserHardware implements UserHardware {
private final HardwareReportRequest.HardwareInfo hardwareInfo;
private byte[] publicKey;
private final long id;
private boolean banned;
public MySQLUserHardware(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, long id, boolean banned) {
this.hardwareInfo = hardwareInfo;
this.publicKey = publicKey;
this.id = id;
this.banned = banned;
}
@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 "MySQLUserHardware{" +
"hardwareInfo=" + hardwareInfo +
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
", id=" + id +
", banned=" + banned +
'}';
}
}
}

View file

@ -3,6 +3,8 @@
import java.time.LocalDateTime;
public interface UserSupportBanInfo {
UserBanInfo getBanInfo();
interface UserBanInfo {
String getId();
@ -22,6 +24,4 @@ default LocalDateTime getEndDate() {
return null;
}
}
UserBanInfo getBanInfo();
}

View file

@ -2,9 +2,9 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@ -15,7 +15,7 @@ public class DigestPasswordVerifier extends PasswordVerifier {
private byte[] digest(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(algo);
return digest.digest(text.getBytes(StandardCharsets.UTF_8));
return digest.digest(IOHelper.encode(text));
}
@Override

View file

@ -2,9 +2,9 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@ -16,8 +16,8 @@ public class DoubleDigestPasswordVerifier extends PasswordVerifier {
private byte[] digest(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(algo);
byte[] firstDigest = digest.digest(text.getBytes(StandardCharsets.UTF_8));
return toHexMode ? digest.digest(SecurityHelper.toHex(firstDigest).getBytes(StandardCharsets.UTF_8)) : digest.digest(firstDigest);
byte[] firstDigest = digest.digest(IOHelper.encode(text));
return toHexMode ? digest.digest(IOHelper.encode(SecurityHelper.toHex(firstDigest))) : digest.digest(firstDigest);
}
@Override

View file

@ -5,9 +5,18 @@
import java.net.http.HttpClient;
public class JsonPasswordVerifier extends PasswordVerifier {
private transient final HttpClient client = HttpClient.newBuilder().build();
public String url;
public String bearerToken;
private transient final HttpClient client = HttpClient.newBuilder().build();
@Override
public boolean check(String encryptedPassword, String password) {
JsonPasswordResponse response = JsonCoreProvider.jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client);
if (response != null) {
return response.success;
}
return false;
}
public static class JsonPasswordRequest {
public String encryptedPassword;
@ -22,13 +31,4 @@ public JsonPasswordRequest(String encryptedPassword, String password) {
public static class JsonPasswordResponse {
public boolean success;
}
@Override
public boolean check(String encryptedPassword, String password) {
JsonPasswordResponse response = JsonCoreProvider.jsonRequest(new JsonPasswordRequest(encryptedPassword, password), url, bearerToken, JsonPasswordResponse.class, client);
if (response != null) {
return response.success;
}
return false;
}
}

View file

@ -14,6 +14,7 @@
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -37,7 +38,6 @@
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static pro.gravit.utils.helper.IOHelper.UNICODE_CHARSET;
import static pro.gravit.utils.helper.IOHelper.newZipEntry;
public class BuildContext {
@ -72,8 +72,14 @@ public void pushFile(String filename, StreamObject object) throws IOException {
}
public void pushFile(String filename, Object object, Type type) throws IOException {
String bytes = Launcher.gsonManager.gson.toJson(object, type);
pushBytes(filename, bytes.getBytes(UNICODE_CHARSET));
ZipEntry zip = IOHelper.newZipEntry(filename);
output.putNextEntry(zip);
try (BufferedWriter w = IOHelper.newWriter(IOHelper.nonClosing(output))) {
Launcher.gsonManager.gson.toJson(object, type);
}
output.closeEntry();
fileList.add(filename);
pushBytes(filename, IOHelper.encode(Launcher.gsonManager.gson.toJson(object, type)));
}
public void pushDir(Path dir, String targetDir, Map<String, byte[]> hashMap, boolean hidden) throws IOException {
@ -211,7 +217,7 @@ private EncryptedRuntimeDirVisitor(ZipOutputStream output, String aesKey, Map<St
byte[] key = SecurityHelper.fromHex(aesKey);
byte[] compatKey = SecurityHelper.getAESKey(key);
sKeySpec = new SecretKeySpec(compatKey, "AES/CBC/PKCS5Padding");
iKeySpec = new IvParameterSpec("8u3d90ikr7o67lsq".getBytes());
iKeySpec = new IvParameterSpec(IOHelper.encode("8u3d90ikr7o67lsq"));
} catch (Exception e) {
throw new RuntimeException(e);
}

View file

@ -35,7 +35,8 @@ public void invoke(String... args) throws Exception {
if (args.length > 2) pair = server.config.getAuthProviderPair(args[2]);
else pair = server.config.getAuthProviderPair();
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[1]));
if(pair.isUseCore()) throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
if (pair.isUseCore())
throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
String login = args[0];
String password = args[1];

View file

@ -34,7 +34,8 @@ public void invoke(String... args) throws CommandException, IOException {
if (args.length > 1) pair = server.config.getAuthProviderPair(args[1]);
else pair = server.config.getAuthProviderPair();
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[1]));
if(pair.isUseCore()) throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
if (pair.isUseCore())
throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
UUID uuid = parseUUID(args[0]);
// Get UUID by username

View file

@ -34,7 +34,8 @@ public void invoke(String... args) throws CommandException, IOException {
if (args.length > 1) pair = server.config.getAuthProviderPair(args[1]);
else pair = server.config.getAuthProviderPair();
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[1]));
if(pair.isUseCore()) throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
if (pair.isUseCore())
throw new UnsupportedOperationException(String.format("Please use `config auth.%s.core COMMAND ARGS`", pair.name));
String username = parseUsername(args[0]);
// Get UUID by username

View file

@ -78,7 +78,7 @@ public void invoke(String... args) {
} else {
printCheckResult(String.format("auth.%s.handler", name), "", true);
}
if(!pair.isUseCore()) {
if (!pair.isUseCore()) {
printCheckResult(String.format("auth.%s", name), "AuthProvider/AuthHandler may be removed in future release", null);
}
});

View file

@ -16,11 +16,11 @@
import java.util.Map;
public class WhitelistComponent extends Component implements AutoCloseable, Reconfigurable {
private transient LaunchServer server;
private transient final Logger logger = LogManager.getLogger();
public String message = "auth.message.techwork";
public boolean enabled = true;
public List<String> whitelist = new ArrayList<>();
private transient LaunchServer server;
@Override
public void init(LaunchServer launchServer) {

View file

@ -182,6 +182,14 @@ public static MakeProfileOption[] getMakeProfileOptionsFromDir(Path dir, ClientP
return options.toArray(new MakeProfileOption[0]);
}
private static Path findFirstDir(Path path) throws IOException {
return Files.list(path).findFirst().orElse(null);
}
private static Path findFirstMavenFile(Path path) throws IOException {
return Files.list(Files.list(path).findFirst().orElseThrow()).filter(e -> e.getFileName().toString().endsWith(".jar")).findFirst().orElseThrow();
}
public interface MakeProfileOption {
}
@ -192,11 +200,6 @@ public static class MakeProfileOptionForge implements MakeProfileOption {
public String minecraftVersion;
public String mcpVersion;
public List<String> makeClientArgs() {
if (launchTarget == null) return List.of();
return List.of("--launchTarget", launchTarget, "--fml.forgeVersion", forgeVersion, "--fml.mcVersion", minecraftVersion, "--fml.forgeGroup", forgeGroup, "--fml.mcpVersion", mcpVersion);
}
public MakeProfileOptionForge() {
}
@ -230,14 +233,11 @@ public MakeProfileOptionForge(Path clientDir) throws IOException {
String[] minecraftFullVersion = minecraftPath.getFileName().toString().split("-");
mcpVersion = minecraftFullVersion[1];
}
}
private static Path findFirstDir(Path path) throws IOException {
return Files.list(path).findFirst().orElse(null);
public List<String> makeClientArgs() {
if (launchTarget == null) return List.of();
return List.of("--launchTarget", launchTarget, "--fml.forgeVersion", forgeVersion, "--fml.mcVersion", minecraftVersion, "--fml.forgeGroup", forgeGroup, "--fml.mcpVersion", mcpVersion);
}
private static Path findFirstMavenFile(Path path) throws IOException {
return Files.list(Files.list(path).findFirst().orElseThrow()).filter(e -> e.getFileName().toString().endsWith(".jar")).findFirst().orElseThrow();
}
public static class MakeProfileOptionLaunchWrapper implements MakeProfileOption {
@ -248,11 +248,6 @@ public static class MakeProfileOptionFabric implements MakeProfileOption {
public String jimfsPath;
public String guavaPath;
public List<String> getAltClassPath() {
if (jimfsPath == null || guavaPath == null) return List.of();
return List.of(jimfsPath, guavaPath);
}
public MakeProfileOptionFabric() {
}
@ -267,6 +262,11 @@ public MakeProfileOptionFabric(Path clientDir) throws IOException {
guavaPath = clientDir.relativize(findFirstMavenFile(clientDir.resolve("libraries/com/google/guava/guava/"))).toString();
}
}
public List<String> getAltClassPath() {
if (jimfsPath == null || guavaPath == null) return List.of();
return List.of(jimfsPath, guavaPath);
}
}
public static class MakeProfileOptionLiteLoader implements MakeProfileOption {

View file

@ -210,26 +210,6 @@ public void internalAuth(Client client, AuthResponse.ConnectTypes authType, Auth
}
}
public static class CheckServerReport {
public UUID uuid;
public User user;
public PlayerProfile playerProfile;
public CheckServerReport(UUID uuid, User user, PlayerProfile playerProfile) {
this.uuid = uuid;
this.user = user;
this.playerProfile = playerProfile;
}
public static CheckServerReport ofUser(User user, PlayerProfile playerProfile) {
return new CheckServerReport(user.getUUID(), user, playerProfile);
}
public static CheckServerReport ofUUID(UUID uuid, PlayerProfile playerProfile) {
return new CheckServerReport(uuid, null, playerProfile);
}
}
public CheckServerReport checkServer(Client client, String username, String serverID) throws IOException {
if (client.auth == null) return null;
if (client.auth.isUseCore()) {
@ -397,6 +377,26 @@ private AuthRequest.AuthPasswordInterface tryDecryptPasswordPlain(AuthRequest.Au
return password;
}
public static class CheckServerReport {
public UUID uuid;
public User user;
public PlayerProfile playerProfile;
public CheckServerReport(UUID uuid, User user, PlayerProfile playerProfile) {
this.uuid = uuid;
this.user = user;
this.playerProfile = playerProfile;
}
public static CheckServerReport ofUser(User user, PlayerProfile playerProfile) {
return new CheckServerReport(user.getUUID(), user, playerProfile);
}
public static CheckServerReport ofUUID(UUID uuid, PlayerProfile playerProfile) {
return new CheckServerReport(uuid, null, playerProfile);
}
}
public static class AuthReport {
public final String minecraftAccessToken;
public final String oauthAccessToken;

View file

@ -6,8 +6,8 @@
import pro.gravit.launchserver.auth.RequiredDAO;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.utils.HookSet;
import pro.gravit.utils.helper.IOHelper;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
@ -46,11 +46,11 @@ public void clear() {
}
private byte[] compressClient(Client client) {
return Launcher.gsonManager.gson.toJson(client).getBytes(StandardCharsets.UTF_8); //Compress using later
return IOHelper.encode(Launcher.gsonManager.gson.toJson(client)); //Compress using later
}
private Client decompressClient(byte[] client) {
return Launcher.gsonManager.gson.fromJson(new String(client, StandardCharsets.UTF_8), Client.class); //Compress using later
return Launcher.gsonManager.gson.fromJson(IOHelper.decode(client), Client.class); //Compress using later
}
@SuppressWarnings("deprecation")

View file

@ -19,8 +19,8 @@
public class UpdatesManager {
private final LaunchServer server;
private final Logger logger = LogManager.getLogger();
private volatile Map<String, HashedDir> updatesDirMap;
private final Path cacheFile;
private volatile Map<String, HashedDir> updatesDirMap;
public UpdatesManager(LaunchServer server) {
this.server = server;

View file

@ -9,6 +9,7 @@
import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.socket.NettyConnectContext;
import pro.gravit.utils.helper.IOHelper;
import java.net.URLDecoder;
import java.nio.charset.Charset;
@ -21,6 +22,12 @@
public class NettyWebAPIHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private static final TreeSet<SeverletPathPair> severletList = new TreeSet<>(Comparator.comparingInt((e) -> -e.key.length()));
private static final DefaultFullHttpResponse ERROR_500 = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR, Unpooled.wrappedBuffer(IOHelper.encode("Internal Server Error 500")));
static {
ERROR_500.retain();
}
private final NettyConnectContext context;
private transient final Logger logger = LogManager.getLogger();
@ -54,7 +61,7 @@ protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) thro
pair.callback.handle(ctx, msg, context);
} catch (Throwable e) {
logger.error("WebAPI Error", e);
ctx.writeAndFlush(new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR, Unpooled.wrappedBuffer("Internal Server Error 500".getBytes())), ctx.voidPromise());
ctx.writeAndFlush(ERROR_500, ctx.voidPromise());
}
isNext = false;
break;
@ -92,11 +99,11 @@ default Map<String, String> getParamsFromUri(String uri) {
}
default FullHttpResponse simpleResponse(HttpResponseStatus status, String body) {
return new DefaultFullHttpResponse(HTTP_1_1, status, body != null ? Unpooled.wrappedBuffer(body.getBytes()) : Unpooled.buffer());
return new DefaultFullHttpResponse(HTTP_1_1, status, body != null ? Unpooled.wrappedBuffer(IOHelper.encode(body)) : Unpooled.buffer());
}
default FullHttpResponse simpleJsonResponse(HttpResponseStatus status, Object body) {
DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, status, body != null ? Unpooled.wrappedBuffer(Launcher.gsonManager.gson.toJson(body).getBytes()) : Unpooled.buffer());
DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, status, body != null ? Unpooled.wrappedBuffer(IOHelper.encode(Launcher.gsonManager.gson.toJson(body))) : Unpooled.buffer());
httpResponse.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON);
return httpResponse;
}

View file

@ -17,16 +17,14 @@ public <T extends WebSocketEvent> boolean eventHandle(T event) {
SecurityReportRequestEvent event1 = (SecurityReportRequestEvent) event;
if (event1.action == SecurityReportRequestEvent.ReportAction.CRASH) {
LauncherEngine.exitLauncher(80);
}
else if(event1.action == SecurityReportRequestEvent.ReportAction.TOKEN_EXPIRED) {
} else if (event1.action == SecurityReportRequestEvent.ReportAction.TOKEN_EXPIRED) {
try {
Request.restore();
} catch (Exception e) {
LogHelper.error(e);
}
}
}
else if (event instanceof ExtendedTokenRequestEvent) {
} else if (event instanceof ExtendedTokenRequestEvent) {
ExtendedTokenRequestEvent event1 = (ExtendedTokenRequestEvent) event;
String token = event1.getExtendedToken();
if (token != null) {

View file

@ -1,19 +0,0 @@
package pro.gravit.launcher;
import javafx.application.Application;
import java.util.concurrent.atomic.AtomicReference;
@Deprecated
public abstract class JSApplication extends Application {
private static final AtomicReference<JSApplication> INSTANCE = new AtomicReference<>();
public JSApplication() {
INSTANCE.set(this);
}
public static JSApplication getInstance() {
return INSTANCE.get();
}
}

View file

@ -38,7 +38,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
public class LauncherEngine {
public static final AtomicBoolean IS_CLIENT = new AtomicBoolean(false);
public static ClientLauncherProcess.ClientParams clientParams;
public static LauncherGuardInterface guard;
public static ClientModuleManager modulesManager;
@ -133,14 +132,6 @@ public static void verifyNoAgent() {
throw new SecurityException("JavaAgent found");
}
public ECPublicKey getClientPublicKey() {
return publicKey;
}
public byte[] sign(byte[] bytes) {
return SecurityHelper.sign(bytes, privateKey);
}
public static LauncherGuardInterface tryGetStdGuard() {
switch (Launcher.getConfig().guardType) {
case "no":
@ -159,6 +150,14 @@ public static LauncherEngine newInstance(boolean clientInstance) {
return new LauncherEngine(clientInstance);
}
public ECPublicKey getClientPublicKey() {
return publicKey;
}
public byte[] sign(byte[] bytes) {
return SecurityHelper.sign(bytes, privateKey);
}
public void readKeys() throws IOException, InvalidKeySpecException {
if (privateKey != null || publicKey != null) return;
Path dir = DirBridge.dir;

View file

@ -12,20 +12,6 @@ private DialogService() {
throw new UnsupportedOperationException();
}
public interface DialogServiceImplementation {
void showDialog(String header, String text, Runnable onApplyCallback, Runnable onCloseCallback);
void showApplyDialog(String header, String text, Runnable onApplyCallback, Runnable onDenyCallback);
void showApplyDialog(String header, String text, Runnable onApplyCallback, Runnable onDenyCallback, Runnable onCloseCallback);
void showTextDialog(String header, Consumer<String> onApplyCallback, Runnable onCloseCallback);
}
public interface DialogServiceNotificationImplementation {
void createNotification(NotificationEvent.NotificationType type, String head, String message);
}
public static void setDialogImpl(DialogServiceImplementation impl) {
DialogService.dialogImpl = impl;
}
@ -74,4 +60,18 @@ public static void showTextDialog(String header, Consumer<String> onApplyCallbac
checkIfAvailable();
dialogImpl.showTextDialog(header, onApplyCallback, onCloseCallback);
}
public interface DialogServiceImplementation {
void showDialog(String header, String text, Runnable onApplyCallback, Runnable onCloseCallback);
void showApplyDialog(String header, String text, Runnable onApplyCallback, Runnable onDenyCallback);
void showApplyDialog(String header, String text, Runnable onApplyCallback, Runnable onDenyCallback, Runnable onCloseCallback);
void showTextDialog(String header, Consumer<String> onApplyCallback, Runnable onCloseCallback);
}
public interface DialogServiceNotificationImplementation {
void createNotification(NotificationEvent.NotificationType type, String head, String message);
}
}

View file

@ -49,7 +49,7 @@ private static ClientLauncherProcess.ClientParams readParams(SocketAddress addre
socket.connect(address);
try (HInput input = new HInput(socket.getInputStream())) {
byte[] serialized = input.readByteArray(0);
ClientLauncherProcess.ClientParams params = Launcher.gsonManager.gson.fromJson(new String(serialized, IOHelper.UNICODE_CHARSET), ClientLauncherProcess.ClientParams.class);
ClientLauncherProcess.ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientLauncherProcess.ClientParams.class);
params.clientHDir = new HashedDir(input);
params.assetHDir = new HashedDir(input);
boolean isNeedReadJavaDir = input.readBoolean();
@ -61,7 +61,6 @@ private static ClientLauncherProcess.ClientParams readParams(SocketAddress addre
}
public static void main(String[] args) throws Throwable {
LauncherEngine.IS_CLIENT.set(true);
LauncherEngine engine = LauncherEngine.clientInstance();
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
EnvHelper.checkDangerousParams();

View file

@ -221,7 +221,7 @@ public void runWriteParams(SocketAddress address) throws IOException {
}
Socket socket = serverSocket.accept();
try (HOutput output = new HOutput(socket.getOutputStream())) {
byte[] serializedMainParams = Launcher.gsonManager.gson.toJson(params).getBytes(IOHelper.UNICODE_CHARSET);
byte[] serializedMainParams = IOHelper.encode(Launcher.gsonManager.gson.toJson(params));
output.writeByteArray(serializedMainParams, 0);
params.clientHDir.write(output);
params.assetHDir.write(output);

View file

@ -14,6 +14,7 @@ public abstract class LauncherModule {
protected InitStatus initStatus = InitStatus.CREATED;
private LauncherModulesContext context;
private LauncherTrustManager.CheckClassResult checkResult;
protected LauncherModule() {
moduleInfo = new LauncherModuleInfo("UnknownModule");
}

View file

@ -6,6 +6,8 @@
public abstract class OptionalTrigger {
public static ProviderMap<OptionalTrigger> providers = new ProviderMap<>("OptionalTriggers");
private static boolean isRegisteredProviders = false;
public boolean required;
public boolean inverted;
public static void registerProviders() {
if (!isRegisteredProviders) {
@ -15,9 +17,6 @@ public static void registerProviders() {
}
}
public boolean required;
public boolean inverted;
protected abstract boolean isTriggered(OptionalFile optional, OptionalTriggerContext context);
public boolean check(OptionalFile optional, OptionalTriggerContext context) {

View file

@ -17,14 +17,14 @@
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);
public static StdWebSocketService service;
private static UUID session = UUID.randomUUID();
private static AuthRequestEvent.OAuthRequestEvent oauth;
private static Map<String, String> extendedTokens;
private static String authId;
private static long tokenExpiredTime;
private static final List<ExtendedTokenCallback> extendedTokenCallbacks = new ArrayList<>(4);
private static final List<BiConsumer<String, AuthRequestEvent.OAuthRequestEvent>> oauthChangeHandlers = new ArrayList<>(4);
@LauncherNetworkAPI
public final UUID requestUUID = UUID.randomUUID();
private transient final AtomicBoolean started = new AtomicBoolean(false);

View file

@ -42,6 +42,20 @@ public AsyncDownloader() {
callback = IGNORE;
}
public static SSLSocketFactory makeSSLSocketFactory() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException {
if (sslSocketFactory != null) return sslSocketFactory;
SSLContext sslContext = makeSSLContext();
sslSocketFactory = sslContext.getSocketFactory();
return sslSocketFactory;
}
public static SSLContext makeSSLContext() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException {
if (sslContext != null) return sslContext;
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, CertificatePinningTrustManager.getTrustManager().getTrustManagers(), new SecureRandom());
return sslContext;
}
public void downloadFile(URL url, Path target, long size) throws IOException {
if (isClosed) throw new IOException("Download interrupted");
URLConnection connection = url.openConnection();
@ -73,20 +87,6 @@ public void downloadFile(URL url, Path target) throws IOException {
}
}
public static SSLSocketFactory makeSSLSocketFactory() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException {
if (sslSocketFactory != null) return sslSocketFactory;
SSLContext sslContext = makeSSLContext();
sslSocketFactory = sslContext.getSocketFactory();
return sslSocketFactory;
}
public static SSLContext makeSSLContext() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, KeyManagementException {
if (sslContext != null) return sslContext;
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, CertificatePinningTrustManager.getTrustManager().getTrustManagers(), new SecureRandom());
return sslContext;
}
public void downloadListInOneThread(List<SizedFile> files, String baseURL, Path targetDir) throws URISyntaxException, IOException {
URI baseUri = new URI(baseURL);
String scheme = baseUri.getScheme();

View file

@ -10,32 +10,13 @@
import java.util.concurrent.Executors;
public class Downloader {
public interface DownloadCallback {
void apply(long fullDiff);
void onComplete(Path path);
}
private final CompletableFuture<Void> future;
private final AsyncDownloader asyncDownloader;
private Downloader(CompletableFuture<Void> future, AsyncDownloader downloader) {
this.future = future;
this.asyncDownloader = downloader;
}
public CompletableFuture<Void> getFuture() {
return future;
}
public void cancel() {
this.asyncDownloader.isClosed = true;
}
public boolean isCanceled() {
return this.asyncDownloader.isClosed;
}
public static Downloader downloadList(List<AsyncDownloader.SizedFile> files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception {
final boolean closeExecutor;
LogHelper.info("Download with legacy mode");
@ -60,4 +41,22 @@ public static Downloader downloadList(List<AsyncDownloader.SizedFile> files, Str
}
}), asyncDownloader);
}
public CompletableFuture<Void> getFuture() {
return future;
}
public void cancel() {
this.asyncDownloader.isClosed = true;
}
public boolean isCanceled() {
return this.asyncDownloader.isClosed;
}
public interface DownloadCallback {
void apply(long fullDiff);
void onComplete(Path path);
}
}

View file

@ -589,6 +589,29 @@ public static void write(Path file, byte[] bytes) throws IOException {
Files.write(file, bytes, WRITE_OPTIONS);
}
public static InputStream nonClosing(InputStream in) {
return new FilterInputStream(in) {
@Override
public void close() {
// ignore
}
};
}
public static OutputStream nonClosing(OutputStream out) {
return new FilterOutputStream(out) {
@Override
public void write(byte[] b, int offset, int len) throws IOException {
super.out.write(b, offset, len);
}
@Override
public void close() {
// ignore
}
};
}
private static class MoveFileVisitor implements FileVisitor<Path> {
private final Path from, to;

View file

@ -26,41 +26,15 @@ public class Downloader {
private static boolean isCertificatePinning;
@LauncherInject("launcher.noHttp2")
private static boolean isNoHttp2;
public interface DownloadCallback {
void apply(long fullDiff);
void onComplete(Path path);
}
protected final HttpClient client;
protected final ExecutorService executor;
protected CompletableFuture<Void> future;
protected final LinkedList<DownloadTask> tasks = new LinkedList<>();
protected CompletableFuture<Void> future;
protected Downloader(HttpClient client, ExecutorService executor) {
this.client = client;
this.executor = executor;
}
public void cancel() {
for (DownloadTask task : tasks) {
if (!task.isCompleted()) {
task.cancel();
}
}
tasks.clear();
executor.shutdownNow();
}
public boolean isCanceled() {
return executor.isTerminated();
}
public CompletableFuture<Void> getFuture() {
return future;
}
public static Downloader downloadList(List<AsyncDownloader.SizedFile> files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception {
boolean closeExecutor = false;
LogHelper.info("Download with Java 11+ HttpClient");
@ -96,8 +70,22 @@ public static Downloader newDownloader(ExecutorService executor) {
return new Downloader(client, executor);
}
private static class ConsumerObject {
Consumer<HttpResponse<Path>> next = null;
public void cancel() {
for (DownloadTask task : tasks) {
if (!task.isCompleted()) {
task.cancel();
}
}
tasks.clear();
executor.shutdownNow();
}
public boolean isCanceled() {
return executor.isTerminated();
}
public CompletableFuture<Void> getFuture() {
return future;
}
public CompletableFuture<Void> downloadFiles(List<AsyncDownloader.SizedFile> files, String baseURL, Path targetDir, DownloadCallback callback, ExecutorService executor, int threads) throws Exception {
@ -136,24 +124,6 @@ public CompletableFuture<Void> downloadFiles(List<AsyncDownloader.SizedFile> fil
return future;
}
public static class DownloadTask {
public final ProgressTrackingBodyHandler<Path> bodyHandler;
public final CompletableFuture<HttpResponse<Path>> completableFuture;
public DownloadTask(ProgressTrackingBodyHandler<Path> bodyHandler, CompletableFuture<HttpResponse<Path>> completableFuture) {
this.bodyHandler = bodyHandler;
this.completableFuture = completableFuture;
}
public boolean isCompleted() {
return completableFuture.isDone() | completableFuture.isCompletedExceptionally();
}
public void cancel() {
bodyHandler.cancel();
}
}
protected DownloadTask sendAsync(AsyncDownloader.SizedFile file, URI baseUri, Path targetDir, DownloadCallback callback) throws Exception {
IOHelper.createParentDirs(targetDir.resolve(file.filePath));
ProgressTrackingBodyHandler<Path> bodyHandler = makeBodyHandler(targetDir.resolve(file.filePath), callback);
@ -187,6 +157,34 @@ protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadC
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE), callback);
}
public interface DownloadCallback {
void apply(long fullDiff);
void onComplete(Path path);
}
private static class ConsumerObject {
Consumer<HttpResponse<Path>> next = null;
}
public static class DownloadTask {
public final ProgressTrackingBodyHandler<Path> bodyHandler;
public final CompletableFuture<HttpResponse<Path>> completableFuture;
public DownloadTask(ProgressTrackingBodyHandler<Path> bodyHandler, CompletableFuture<HttpResponse<Path>> completableFuture) {
this.bodyHandler = bodyHandler;
this.completableFuture = completableFuture;
}
public boolean isCompleted() {
return completableFuture.isDone() | completableFuture.isCompletedExceptionally();
}
public void cancel() {
bodyHandler.cancel();
}
}
public static class ProgressTrackingBodyHandler<T> implements HttpResponse.BodyHandler<T> {
private final HttpResponse.BodyHandler<T> delegate;
private final DownloadCallback callback;

View file

@ -1,4 +1,5 @@
# Modification of the launcher sashok724's v3 from Gravit [![Build Status](https://travis-ci.com/GravitLauncher/Launcher.svg?branch=master)](https://travis-ci.com/GravitLauncher/Launcher)
* [Discord channel](https://discord.gg/b9QG4ygY75)
* [See license](LICENSE)