Compare commits

...

5 Commits

Author SHA1 Message Date
Gravita 52c9196dcc [FIX] SQLCoreProvider 2024-04-25 03:05:13 +07:00
Gravita 095a5aef8b [FEATURE] Add mariadb connector 2024-04-25 02:09:17 +07:00
Gravita 765f1a9d8f [FEATURE] SQLCoreProvider 2024-04-25 02:06:44 +07:00
Gravita 9bd65c797b [REFACTOR] ClientProfileBuilder 2024-04-25 01:31:46 +07:00
XakepSDK 8908710ad6
[ANY] Add OpenID auth module (#709)
Co-authored-by: d3coder <admin@xakeps.dk>
2024-04-24 20:21:16 +07:00
27 changed files with 1163 additions and 240 deletions

View File

@ -83,7 +83,9 @@ dependencies {
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64'
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn']
bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn']
bundle group: 'com.h2database', name: 'h2', version: rootProject['verH2Conn']
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-slf4j2-impl', version: rootProject['verLog4j']

View File

@ -16,6 +16,10 @@ public final class AuthException extends IOException {
super(message);
}
public AuthException(String message, Throwable cause) {
super(message, cause);
}
public static AuthException need2FA() {
return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE);
}

View File

@ -0,0 +1,50 @@
package pro.gravit.launchserver.auth;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.function.Consumer;
public class HikariSQLSourceConfig implements SQLSourceConfig {
private transient HikariDataSource dataSource;
private String dsClass;
private Properties dsProps;
private String driverClass;
private String jdbcUrl;
private String username;
private String password;
public void init() {
if (dataSource != null) {
return;
}
HikariConfig config = new HikariConfig();
consumeIfNotNull(config::setDataSourceClassName, dsClass);
consumeIfNotNull(config::setDataSourceProperties, dsProps);
consumeIfNotNull(config::setDriverClassName, driverClass);
consumeIfNotNull(config::setJdbcUrl, jdbcUrl);
consumeIfNotNull(config::setUsername, username);
consumeIfNotNull(config::setPassword, password);
this.dataSource = new HikariDataSource(config);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public void close() {
dataSource.close();
}
private static <T> void consumeIfNotNull(Consumer<T> consumer, T val) {
if (val != null) {
consumer.accept(val);
}
}
}

View File

@ -21,6 +21,7 @@ import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetAllUs
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRegistration;
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportSudo;
import pro.gravit.launchserver.auth.core.openid.OpenIDAuthCoreProvider;
import pro.gravit.launchserver.manangers.AuthManager;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
@ -53,6 +54,8 @@ public abstract class AuthCoreProvider implements AutoCloseable, Reconfigurable
providers.register("postgresql", PostgresSQLCoreProvider.class);
providers.register("memory", MemoryAuthCoreProvider.class);
providers.register("merge", MergeAuthCoreProvider.class);
providers.register("openid", OpenIDAuthCoreProvider.class);
providers.register("sql", SQLCoreProvider.class);
registredProviders = true;
}
}

View File

@ -0,0 +1,27 @@
package pro.gravit.launchserver.auth.core;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
import pro.gravit.launchserver.auth.SQLSourceConfig;
public class SQLCoreProvider extends AbstractSQLCoreProvider {
public HikariSQLSourceConfig holder;
@Override
public void close() {
super.close();
holder.close();
}
@Override
public void init(LaunchServer server, AuthProviderPair pair) {
holder.init();
super.init(server, pair);
}
@Override
public SQLSourceConfig getSQLConfig() {
return holder;
}
}

View File

@ -0,0 +1,14 @@
package pro.gravit.launchserver.auth.core.openid;
import com.google.gson.annotations.SerializedName;
public record AccessTokenResponse(@SerializedName("access_token") String accessToken,
@SerializedName("expires_in") Long expiresIn,
@SerializedName("refresh_expires_in") Long refreshExpiresIn,
@SerializedName("refresh_token") String refreshToken,
@SerializedName("token_type") String tokenType,
@SerializedName("id_token") String idToken,
@SerializedName("not-before-policy") Integer notBeforePolicy,
@SerializedName("session_state") String sessionState,
@SerializedName("scope") String scope) {
}

View File

@ -0,0 +1,178 @@
package pro.gravit.launchserver.auth.core.openid;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import pro.gravit.launcher.base.ClientPermissions;
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
import pro.gravit.launcher.base.request.auth.AuthRequest;
import pro.gravit.launcher.base.request.auth.password.AuthCodePassword;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
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.manangers.AuthManager;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class OpenIDAuthCoreProvider extends AuthCoreProvider {
private transient SQLUserStore sqlUserStore;
private transient SQLServerSessionStore sqlSessionStore;
private transient OpenIDAuthenticator openIDAuthenticator;
private OpenIDConfig openIDConfig;
private HikariSQLSourceConfig sqlSourceConfig;
@Override
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
return openIDAuthenticator.getDetails();
}
@Override
public User getUserByUsername(String username) {
return sqlUserStore.getByUsername(username);
}
@Override
public User getUserByUUID(UUID uuid) {
return sqlUserStore.getUserByUUID(uuid);
}
@Override
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
return openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
}
@Override
public AuthManager.AuthReport refreshAccessToken(String oldRefreshToken, AuthResponse.AuthContext context) {
var tokens = openIDAuthenticator.refreshAccessToken(oldRefreshToken);
var accessToken = tokens.accessToken();
var refreshToken = tokens.refreshToken();
long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn());
UserSession session;
try {
session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
} catch (OAuthAccessTokenExpired e) {
throw new RuntimeException("invalid token", e);
}
return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken,
expiresIn, session);
}
@Override
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
if (password == null) {
throw AuthException.wrongPassword();
}
var authCodePassword = (AuthCodePassword) password;
var tokens = openIDAuthenticator.authorize(authCodePassword);
var accessToken = tokens.accessToken();
var refreshToken = tokens.refreshToken();
var user = openIDAuthenticator.createUserFromToken(accessToken);
long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn());
sqlUserStore.createOrUpdateUser(user);
UserSession session;
try {
session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
} catch (OAuthAccessTokenExpired e) {
throw new AuthException("invalid token", e);
}
if (minecraftAccess) {
var minecraftToken = generateMinecraftToken(user);
return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftToken, accessToken, refreshToken,
expiresIn, session);
} else {
return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken,
expiresIn, session);
}
}
private String generateMinecraftToken(User user) {
return Jwts.builder()
.issuer("LaunchServer")
.subject(user.getUUID().toString())
.claim("preferred_username", user.getUsername())
.expiration(Date.from(Instant.now().plus(24, ChronoUnit.HOURS)))
.signWith(server.keyAgreementManager.ecdsaPrivateKey)
.compact();
}
private User createUserFromMinecraftToken(String accessToken) throws AuthException {
try {
var parser = Jwts.parser()
.requireIssuer("LaunchServer")
.verifyWith(server.keyAgreementManager.ecdsaPublicKey)
.build();
var claims = parser.parseSignedClaims(accessToken);
var username = claims.getPayload().get("preferred_username", String.class);
var uuid = UUID.fromString(claims.getPayload().getSubject());
return new UserEntity(username, uuid, new ClientPermissions());
} catch (JwtException e) {
throw new AuthException("Bad minecraft token", e);
}
}
@Override
public void init(LaunchServer server, AuthProviderPair pair) {
super.init(server, pair);
this.sqlSourceConfig.init();
this.sqlUserStore = new SQLUserStore(sqlSourceConfig);
this.sqlUserStore.init();
this.sqlSessionStore = new SQLServerSessionStore(sqlSourceConfig);
this.sqlSessionStore.init();
this.openIDAuthenticator = new OpenIDAuthenticator(openIDConfig);
}
@Override
public User checkServer(Client client, String username, String serverID) throws IOException {
var savedServerId = sqlSessionStore.getServerIdByUsername(username);
if (!serverID.equals(savedServerId)) {
return null;
}
return sqlUserStore.getByUsername(username);
}
@Override
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
User user;
try {
user = createUserFromMinecraftToken(accessToken);
} catch (AuthException e) {
LogHelper.error(e);
return false;
}
if (!user.getUUID().equals(uuid)) {
return false;
}
sqlUserStore.createOrUpdateUser(user);
return sqlSessionStore.joinServer(user.getUUID(), user.getUsername(), serverID);
}
@Override
public void close() {
sqlSourceConfig.close();
}
}

View File

@ -0,0 +1,229 @@
package pro.gravit.launchserver.auth.core.openid;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Jwk;
import io.jsonwebtoken.security.JwkSet;
import io.jsonwebtoken.security.Jwks;
import pro.gravit.launcher.base.ClientPermissions;
import pro.gravit.launcher.base.Launcher;
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
import pro.gravit.launcher.base.request.auth.details.AuthWebViewDetails;
import pro.gravit.launcher.base.request.auth.password.AuthCodePassword;
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.launchserver.auth.core.UserSession;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.QueryHelper;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.Key;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
public class OpenIDAuthenticator {
private static final HttpClient CLIENT = HttpClient.newBuilder().build();
private final OpenIDConfig openIDConfig;
private final JwtParser jwtParser;
public OpenIDAuthenticator(OpenIDConfig openIDConfig) {
this.openIDConfig = openIDConfig;
var keyLocator = loadKeyLocator(openIDConfig);
this.jwtParser = Jwts.parser().keyLocator(keyLocator)
.build();
}
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails() {
var state = UUID.randomUUID().toString();
var uri = QueryBuilder.get(openIDConfig.authorizationEndpoint())
.addQuery("response_type", "code")
.addQuery("client_id", openIDConfig.clientId())
.addQuery("redirect_uri", openIDConfig.redirectUri())
.addQuery("scope", openIDConfig.scopes())
.addQuery("state", state)
.toUriString();
return List.of(new AuthWebViewDetails(uri, openIDConfig.redirectUri()));
}
public TokenResponse refreshAccessToken(String oldRefreshToken) {
var postBody = QueryBuilder.post()
.addQuery("grant_type", "refresh_token")
.addQuery("refresh_token", oldRefreshToken)
.addQuery("client_id", openIDConfig.clientId())
.addQuery("client_secret", openIDConfig.clientSecret())
.toString();
var accessTokenResponse = requestToken(postBody);
var accessToken = accessTokenResponse.accessToken();
var refreshToken = accessTokenResponse.refreshToken();
try {
readAndVerifyToken(accessToken);
} catch (AuthException e) {
throw new RuntimeException(e);
}
var accessTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.expiresIn(), 0L);
var refreshTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.refreshExpiresIn(), 0L);
return new TokenResponse(accessToken, accessTokenExpiresIn,
refreshToken, refreshTokenExpiresIn);
}
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws AuthCoreProvider.OAuthAccessTokenExpired {
Jws<Claims> token;
try {
token = readAndVerifyToken(accessToken);
} catch (AuthException e) {
throw new AuthCoreProvider.OAuthAccessTokenExpired("Can't read token", e);
}
var user = createUserFromToken(token);
long expiresIn = 0;
var expDate = token.getPayload().getExpiration();
if (expDate != null) {
expiresIn = expDate.toInstant().toEpochMilli();
}
return new OpenIDUserSession(user, accessToken, expiresIn);
}
public TokenResponse authorize(AuthCodePassword authCode) throws IOException {
var uri = URI.create(authCode.uri);
var queries = QueryHelper.splitUriQuery(uri);
String code = CommonHelper.multimapFirstOrNullValue("code", queries);
String error = CommonHelper.multimapFirstOrNullValue("error", queries);
String errorDescription = CommonHelper.multimapFirstOrNullValue("error_description", queries);
if (error != null && !error.isBlank()) {
throw new AuthException("Auth error. Error: %s, description: %s".formatted(error, errorDescription));
}
var postBody = QueryBuilder.post()
.addQuery("grant_type", "authorization_code")
.addQuery("code", code)
.addQuery("redirect_uri", openIDConfig.redirectUri())
.addQuery("client_id", openIDConfig.clientId())
.addQuery("client_secret", openIDConfig.clientSecret())
.toString();
var accessTokenResponse = requestToken(postBody);
var accessToken = accessTokenResponse.accessToken();
var refreshToken = accessTokenResponse.refreshToken();
readAndVerifyToken(accessToken);
var accessTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.expiresIn(), 0L);
var refreshTokenExpiresIn = Objects.requireNonNullElse(accessTokenResponse.refreshExpiresIn(), 0L);
return new TokenResponse(accessToken, accessTokenExpiresIn,
refreshToken, refreshTokenExpiresIn);
}
public User createUserFromToken(String accessToken) throws AuthException {
return createUserFromToken(readAndVerifyToken(accessToken));
}
private Jws<Claims> readAndVerifyToken(String accessToken) throws AuthException {
if (accessToken == null) {
throw new AuthException("Token is null");
}
try {
return jwtParser.parseSignedClaims(accessToken);
} catch (JwtException e) {
throw new AuthException("Bad token", e);
}
}
private User createUserFromToken(Jws<Claims> token) {
var username = token.getPayload().get(openIDConfig.extractorConfig().usernameClaim(), String.class);
var uuidStr = token.getPayload().get(openIDConfig.extractorConfig().uuidClaim(), String.class);
var uuid = UUID.fromString(uuidStr);
return new UserEntity(username, uuid, new ClientPermissions());
}
private AccessTokenResponse requestToken(String postBody) {
var request = HttpRequest.newBuilder()
.uri(openIDConfig.tokenUri())
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(postBody))
.build();
HttpResponse<String> resp;
try {
resp = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
return Launcher.gsonManager.gson.fromJson(resp.body(), AccessTokenResponse.class);
}
private static KeyLocator loadKeyLocator(OpenIDConfig openIDConfig) {
var request = HttpRequest.newBuilder(openIDConfig.jwksUri()).GET().build();
HttpResponse<String> response;
try {
response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
var jwks = Jwks.setParser().build().parse(response.body());
return new KeyLocator(jwks);
}
private static class KeyLocator extends LocatorAdapter<Key> {
private final Map<String, Key> keys;
public KeyLocator(JwkSet jwks) {
this.keys = jwks.getKeys().stream().collect(
Collectors.toMap(jwk -> String.valueOf(jwk.get("kid")), Jwk::toKey));
}
@Override
protected Key locate(JweHeader header) {
return super.locate(header);
}
@Override
protected Key locate(JwsHeader header) {
return keys.get(header.getKeyId());
}
@Override
protected Key doLocate(Header header) {
return super.doLocate(header);
}
}
record OpenIDUserSession(User user, String token, long expiresIn) implements UserSession {
@Override
public String getID() {
return user.getUsername();
}
@Override
public User getUser() {
return user;
}
@Override
public String getMinecraftAccessToken() {
return token;
}
@Override
public long getExpireIn() {
return expiresIn;
}
}
}

View File

@ -0,0 +1,9 @@
package pro.gravit.launchserver.auth.core.openid;
import java.net.URI;
public record OpenIDConfig(URI tokenUri, String authorizationEndpoint, String clientId, String clientSecret,
String redirectUri, URI jwksUri, String scopes, ClaimExtractorConfig extractorConfig) {
public record ClaimExtractorConfig(String usernameClaim, String uuidClaim) {}
}

View File

@ -0,0 +1,59 @@
package pro.gravit.launchserver.auth.core.openid;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* @author Xakep_SDK
*/
public class QueryBuilder {
private final String uri;
private final StringBuilder query = new StringBuilder();
public QueryBuilder(String uri) {
this.uri = uri;
}
public static QueryBuilder get(String uri) {
Objects.requireNonNull(uri, "uri");
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
}
return new QueryBuilder(uri);
}
public static QueryBuilder post() {
return new QueryBuilder(null);
}
public QueryBuilder addQuery(String key, String value) {
if (!query.isEmpty()) {
query.append('&');
}
query.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
.append('=')
.append(URLEncoder.encode(value, StandardCharsets.UTF_8));
return this;
}
public String toUriString() {
if (uri != null) {
if (query. isEmpty()) {
return uri;
}
return uri + '?' + query;
}
return toQueryString();
}
public String toQueryString() {
return query.toString();
}
@Override
public String toString() {
return toUriString();
}
}

View File

@ -0,0 +1,99 @@
package pro.gravit.launchserver.auth.core.openid;
import pro.gravit.launchserver.auth.SQLSourceConfig;
import pro.gravit.utils.helper.LogHelper;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.UUID;
public class SQLServerSessionStore implements ServerSessionStore {
private static final String CREATE_TABLE = """
create table if not exists `gravit_server_session` (
id int auto_increment,
uuid varchar(36),
username varchar(255),
server_id varchar(41),
primary key (id),
unique (uuid),
unique (username)
);
""";
private static final String DELETE_SERVER_ID = """
delete from `gravit_server_session` where uuid = ?
""";
private static final String INSERT_SERVER_ID = """
insert into `gravit_server_session` (uuid, username, server_id) values (?, ?, ?)
""";
private static final String SELECT_SERVER_ID_BY_USERNAME = """
select server_id from `gravit_server_session` where username = ?
""";
private final SQLSourceConfig sqlSourceConfig;
public SQLServerSessionStore(SQLSourceConfig sqlSourceConfig) {
this.sqlSourceConfig = sqlSourceConfig;
}
@Override
public boolean joinServer(UUID uuid, String username, String serverId) {
try (var connection = sqlSourceConfig.getConnection()) {
connection.setAutoCommit(false);
var savepoint = connection.setSavepoint();
try (var deleteServerIdStmt = connection.prepareStatement(DELETE_SERVER_ID);
var insertServerIdStmt = connection.prepareStatement(INSERT_SERVER_ID)) {
deleteServerIdStmt.setString(1, uuid.toString());
deleteServerIdStmt.execute();
insertServerIdStmt.setString(1, uuid.toString());
insertServerIdStmt.setString(2, username);
insertServerIdStmt.setString(3, serverId);
insertServerIdStmt.execute();
connection.commit();
return true;
} catch (Exception e) {
connection.rollback(savepoint);
throw e;
}
} catch (SQLException e) {
LogHelper.debug("Can't join server. Username: %s".formatted(username));
LogHelper.error(e);
}
return false;
}
@Override
public String getServerIdByUsername(String username) {
try (var connection = sqlSourceConfig.getConnection();
var selectServerId = connection.prepareStatement(SELECT_SERVER_ID_BY_USERNAME)) {
selectServerId.setString(1, username);
try (var rs = selectServerId.executeQuery()) {
if (!rs.next()) {
return null;
}
return rs.getString("server_id");
}
} catch (SQLException e) {
LogHelper.debug("Can't find server id by username. Username: %s".formatted(username));
LogHelper.error(e);
}
return null;
}
public void init() {
try (var connection = sqlSourceConfig.getConnection()) {
connection.setAutoCommit(false);
var savepoint = connection.setSavepoint();
try (var createTableStmt = connection.prepareStatement(CREATE_TABLE)) {
createTableStmt.execute();
connection.commit();
} catch (Exception e) {
connection.rollback(savepoint);
throw e;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,124 @@
package pro.gravit.launchserver.auth.core.openid;
import pro.gravit.launcher.base.ClientPermissions;
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
import pro.gravit.launchserver.auth.core.User;
import pro.gravit.utils.helper.LogHelper;
import java.sql.SQLException;
import java.util.UUID;
public class SQLUserStore implements UserStore {
private static final String CREATE_USER_TABLE = """
create table if not exists `gravit_user` (
id int auto_increment,
uuid varchar(36),
username varchar(255),
primary key (id),
unique (uuid),
unique (username)
)
""";
private static final String INSERT_USER = """
insert into `gravit_user` (uuid, username) values (?, ?)
""";
private static final String DELETE_USER_BY_NAME = """
delete `gravit_user` where username = ?
""";
private static final String SELECT_USER_BY_NAME = """
select uuid, username from `gravit_user` where username = ?
""";
private static final String SELECT_USER_BY_UUID = """
select uuid, username from `gravit_user` where uuid = ?
""";
private final HikariSQLSourceConfig sqlSourceConfig;
public SQLUserStore(HikariSQLSourceConfig sqlSourceConfig) {
this.sqlSourceConfig = sqlSourceConfig;
}
@Override
public User getByUsername(String username) {
try (var connection = sqlSourceConfig.getConnection();
var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_NAME)) {
selectUserStmt.setString(1, username);
try (var rs = selectUserStmt.executeQuery()) {
if (!rs.next()) {
LogHelper.debug("User not found, username: %s".formatted(username));
return null;
}
return new UserEntity(rs.getString("username"),
UUID.fromString(rs.getString("uuid")),
new ClientPermissions());
}
} catch (SQLException e) {
LogHelper.error(e);
}
return null;
}
@Override
public User getUserByUUID(UUID uuid) {
try (var connection = sqlSourceConfig.getConnection();
var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_UUID)) {
selectUserStmt.setString(1, uuid.toString());
try (var rs = selectUserStmt.executeQuery()) {
if (!rs.next()) {
LogHelper.debug("User not found, UUID: %s".formatted(uuid));
return null;
}
return new UserEntity(rs.getString("username"),
UUID.fromString(rs.getString("uuid")),
new ClientPermissions());
}
} catch (SQLException e) {
LogHelper.error(e);
}
return null;
}
@Override
public void createOrUpdateUser(User user) {
try (var connection = sqlSourceConfig.getConnection()) {
connection.setAutoCommit(false);
var savepoint = connection.setSavepoint();
try (var deleteUserStmt = connection.prepareStatement(DELETE_USER_BY_NAME);
var insertUserStmt = connection.prepareStatement(INSERT_USER)) {
deleteUserStmt.setString(1, user.getUsername());
deleteUserStmt.execute();
insertUserStmt.setString(1, user.getUUID().toString());
insertUserStmt.setString(2, user.getUsername());
insertUserStmt.execute();
connection.commit();
LogHelper.debug("User saved. UUID: %s, username: %s".formatted(user.getUUID(), user.getUsername()));
} catch (Exception e) {
connection.rollback(savepoint);
throw e;
}
} catch (SQLException e) {
LogHelper.debug("Failed to save user");
LogHelper.error(e);
throw new RuntimeException("Failed to save user", e);
}
}
public void init() {
try (var connection = sqlSourceConfig.getConnection()) {
connection.setAutoCommit(false);
var savepoint = connection.setSavepoint();
try (var createUserTableStmt = connection.prepareStatement(CREATE_USER_TABLE)) {
createUserTableStmt.execute();
connection.commit();
} catch (Exception e) {
connection.rollback(savepoint);
throw e;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,8 @@
package pro.gravit.launchserver.auth.core.openid;
import java.util.UUID;
public interface ServerSessionStore {
boolean joinServer(UUID uuid, String username, String serverId);
String getServerIdByUsername(String username);
}

View File

@ -0,0 +1,5 @@
package pro.gravit.launchserver.auth.core.openid;
public record TokenResponse(String accessToken, long accessTokenExpiresIn,
String refreshToken, long refreshTokenExpiresIn) {
}

View File

@ -0,0 +1,23 @@
package pro.gravit.launchserver.auth.core.openid;
import pro.gravit.launcher.base.ClientPermissions;
import pro.gravit.launchserver.auth.core.User;
import java.util.UUID;
record UserEntity(String username, UUID uuid, ClientPermissions permissions) implements User {
@Override
public String getUsername() {
return username;
}
@Override
public UUID getUUID() {
return uuid;
}
@Override
public ClientPermissions getPermissions() {
return permissions;
}
}

View File

@ -0,0 +1,13 @@
package pro.gravit.launchserver.auth.core.openid;
import pro.gravit.launchserver.auth.core.User;
import java.util.UUID;
public interface UserStore {
User getByUsername(String username);
User getUserByUUID(UUID uuid);
void createOrUpdateUser(User user);
}

View File

@ -5,6 +5,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.base.Launcher;
import pro.gravit.launcher.base.profiles.ClientProfile;
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
@ -61,9 +62,11 @@ public final class DownloadClientCommand extends Command {
try {
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
clientProfile.setTitle(dirName);
clientProfile.setDir(dirName);
clientProfile.setUUID(UUID.randomUUID());
var builder = new ClientProfileBuilder(clientProfile);
builder.setTitle(dirName);
builder.setDir(dirName);
builder.setUuid(UUID.randomUUID());
clientProfile = builder.createClientProfile();
if (clientProfile.getServers() != null) {
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
if (serverProfile != null) {

View File

@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launcher.base.Launcher;
import pro.gravit.launcher.base.profiles.ClientProfile;
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.IOHelper;
@ -44,8 +45,9 @@ public class CloneProfileCommand extends Command {
try(Reader reader = IOHelper.newReader(profilePath)) {
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
}
profile.setTitle(args[1]);
profile.setUUID(UUID.randomUUID());
var builder = new ClientProfileBuilder(profile);
builder.setTitle(args[1]);
builder.setUuid(UUID.randomUUID());
if(profile.getServers().size() == 1) {
profile.getServers().getFirst().name = args[1];
}
@ -61,7 +63,8 @@ public class CloneProfileCommand extends Command {
}
});
}
profile.setDir(args[1]);
builder.setDir(args[1]);
profile = builder.createClientProfile();
var targetPath = server.profilesDir.resolve(args[1].concat(".json"));
try(Writer writer = IOHelper.newWriter(targetPath)) {
Launcher.gsonManager.gson.toJson(profile, writer);

View File

@ -23,7 +23,6 @@ public class SaveProfilesCommand extends Command {
}
public static void saveProfile(ClientProfile profile, Path path) throws IOException {
if (profile.getUUID() == null) profile.setUUID(UUID.randomUUID());
if (profile.getServers().isEmpty()) {
ClientProfile.ServerProfile serverProfile = new ClientProfile.ServerProfile();
serverProfile.isDefault = true;

View File

@ -109,14 +109,14 @@ public class ClientLauncherProcess {
private void applyClientProfile() {
this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString());
Collections.addAll(this.jvmArgs, this.params.profile.getJvmArgs());
this.jvmArgs.addAll(this.params.profile.getJvmArgs());
for (OptionalAction a : this.params.actions) {
if (a instanceof OptionalActionJvmArgs) {
this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args);
}
}
this.systemEnv.put("JAVA_HOME", javaVersion.jvmDir.toString());
Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath());
this.systemClassPath.addAll(this.params.profile.getAlternativeClassPath());
if (params.ram > 0) {
this.jvmArgs.add("-Xmx" + params.ram + 'M');
}
@ -128,8 +128,6 @@ public class ClientLauncherProcess {
this.params.oauthExpiredTime = Request.getTokenExpiredTime();
this.params.extendedTokens = Request.getExtendedTokens();
}
this.jvmModules.addAll(this.params.profile.getModules());
this.jvmModulesPaths.addAll(this.params.profile.getModulePath());
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderCreateEvent(this));
}
@ -148,7 +146,6 @@ public class ClientLauncherProcess {
processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()));
} else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(new HashSet<>(), workDir, params.actions, params.profile)
.filter(x -> !params.profile.getModulePath().contains(workDir.relativize(x).toString()))
.map(Path::toString)
.toList());
}

View File

@ -41,8 +41,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherNetworkAPI
private List<String> updateExclusions;
@LauncherNetworkAPI
private List<String> updateShared;
@LauncherNetworkAPI
private List<String> updateVerify;
@LauncherNetworkAPI
private Set<OptionalFile> updateOptional;
@ -51,10 +49,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherNetworkAPI
private List<String> classPath;
@LauncherNetworkAPI
private List<String> modulePath = new ArrayList<>();
@LauncherNetworkAPI
private List<String> modules = new ArrayList<>();
@LauncherNetworkAPI
private List<String> altClassPath;
@LauncherNetworkAPI
private List<String> clientArgs;
@ -89,54 +83,37 @@ public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherNetworkAPI
private LaunchOptions.ModuleConf moduleConf;
public ClientProfile() {
update = new ArrayList<>();
updateExclusions = new ArrayList<>();
updateShared = new ArrayList<>();
updateVerify = new ArrayList<>();
updateOptional = new HashSet<>();
jvmArgs = new ArrayList<>();
classPath = new ArrayList<>();
modulePath = new ArrayList<>();
altClassPath = new ArrayList<>();
clientArgs = new ArrayList<>();
compatClasses = new ArrayList<>();
properties = new HashMap<>();
servers = new ArrayList<>(1);
classLoaderConfig = ClassLoaderConfig.LAUNCHER;
flags = new ArrayList<>();
}
public ClientProfile(List<String> update, List<String> updateExclusions, List<String> updateShared, List<String> updateVerify, Set<OptionalFile> updateOptional, List<String> jvmArgs, List<String> classPath, List<String> modulePath, List<String> modules, List<String> altClassPath, List<String> clientArgs, List<String> compatClasses, Map<String, String> properties, List<ServerProfile> servers, ClassLoaderConfig classLoaderConfig, List<CompatibilityFlags> flags, Version version, String assetIndex, String dir, String assetDir, int recommendJavaVersion, int minJavaVersion, int maxJavaVersion, ProfileDefaultSettings settings, int sortIndex, UUID uuid, String title, String info, String mainClass) {
public ClientProfile(String title, UUID uuid, Version version, String info, String dir, int sortIndex, String assetIndex, String assetDir, List<String> update, List<String> updateExclusions, List<String> updateVerify, Set<OptionalFile> updateOptional, List<String> jvmArgs, List<String> classPath, List<String> altClassPath, List<String> clientArgs, List<String> compatClasses, List<String> loadNatives, Map<String, String> properties, List<ServerProfile> servers, ClassLoaderConfig classLoaderConfig, List<CompatibilityFlags> flags, int recommendJavaVersion, int minJavaVersion, int maxJavaVersion, ProfileDefaultSettings settings, boolean limited, String mainClass, String mainModule, LaunchOptions.ModuleConf moduleConf) {
this.title = title;
this.uuid = uuid;
this.version = version;
this.info = info;
this.dir = dir;
this.sortIndex = sortIndex;
this.assetIndex = assetIndex;
this.assetDir = assetDir;
this.update = update;
this.updateExclusions = updateExclusions;
this.updateShared = updateShared;
this.updateVerify = updateVerify;
this.updateOptional = updateOptional;
this.jvmArgs = jvmArgs;
this.classPath = classPath;
this.modulePath = modulePath;
this.modules = modules;
this.altClassPath = altClassPath;
this.clientArgs = clientArgs;
this.compatClasses = compatClasses;
this.loadNatives = loadNatives;
this.properties = properties;
this.servers = servers;
this.classLoaderConfig = classLoaderConfig;
this.version = version;
this.assetIndex = assetIndex;
this.dir = dir;
this.assetDir = assetDir;
this.flags = flags;
this.recommendJavaVersion = recommendJavaVersion;
this.minJavaVersion = minJavaVersion;
this.maxJavaVersion = maxJavaVersion;
this.settings = settings;
this.sortIndex = sortIndex;
this.uuid = uuid;
this.title = title;
this.info = info;
this.limited = limited;
this.mainClass = mainClass;
this.flags = flags;
this.mainModule = mainModule;
this.moduleConf = moduleConf;
}
public ServerProfile getDefaultServerProfile() {
@ -159,34 +136,22 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0 ? ASSET_MATCHER : null;
}
public String[] getClassPath() {
return classPath.toArray(new String[0]);
public List<String> getClassPath() {
return Collections.unmodifiableList(classPath);
}
public List<String> getModulePath() {
return Collections.unmodifiableList(modulePath);
public List<String> getAlternativeClassPath() {
return Collections.unmodifiableList(altClassPath);
}
public List<String> getModules() {
return Collections.unmodifiableList(modules);
}
public String[] getAlternativeClassPath() {
return altClassPath.toArray(new String[0]);
}
public String[] getClientArgs() {
return clientArgs.toArray(new String[0]);
public List<String> getClientArgs() {
return Collections.unmodifiableList(clientArgs);
}
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
}
public String getAssetDir() {
return assetDir;
}
@ -195,24 +160,25 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return Collections.unmodifiableList(updateExclusions);
}
public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
public List<String> getUpdate() {
return Collections.unmodifiableList(update);
}
public List<String> getUpdateVerify() {
return Collections.unmodifiableList(updateVerify);
}
public FileNameMatcher getClientUpdateMatcher() {
String[] updateArray = update.toArray(new String[0]);
String[] verifyArray = updateVerify.toArray(new String[0]);
List<String> excludeList;
//if(excludeOptional)
//{
// excludeList = new ArrayList<>();
// excludeList.addAll(updateExclusions);
// excludeList.addAll(updateOptional);
//}
//else
excludeList = updateExclusions;
String[] exclusionsArray = excludeList.toArray(new String[0]);
return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
}
public String[] getJvmArgs() {
return jvmArgs.toArray(new String[0]);
public List<String> getJvmArgs() {
return Collections.unmodifiableList(jvmArgs);
}
public String getMainClass() {
@ -289,10 +255,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return null;
}
public Collection<String> getShared() {
return updateShared;
}
public int getServerPort() {
ServerProfile profile = getDefaultServerProfile();
return profile == null ? 25565 : profile.serverPort;
@ -306,26 +268,14 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Version getVersion() {
return version;
}
public void setVersion(Version version) {
this.version = version;
}
@Deprecated
public boolean isUpdateFastCheck() {
return true;
@ -340,10 +290,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return uuid;
}
public void setUUID(UUID uuid) {
this.uuid = uuid;
}
public boolean hasFlag(CompatibilityFlags flag) {
return flags.contains(flag);
}
@ -413,18 +359,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return properties.get(name);
}
public void putProperty(String name, String value) {
properties.put(name, value);
}
public boolean containsProperty(String name) {
return properties.containsKey(name);
}
public void clearProperties() {
properties.clear();
}
public Map<String, String> getProperties() {
return Collections.unmodifiableMap(properties);
}
@ -450,10 +384,6 @@ public final class ClientProfile implements Comparable<ClientProfile> {
return classLoaderConfig;
}
public void setClassLoaderConfig(ClassLoaderConfig classLoaderConfig) {
this.classLoaderConfig = classLoaderConfig;
}
public boolean isLimited() {
return limited;
}

View File

@ -1,136 +1,112 @@
package pro.gravit.launcher.base.profiles;
import pro.gravit.launcher.base.profiles.optional.OptionalFile;
import pro.gravit.utils.launch.LaunchOptions;
import java.util.*;
public class ClientProfileBuilder {
private List<String> update = new ArrayList<>();
private List<String> updateExclusions = new ArrayList<>();
private List<String> updateShared = new ArrayList<>();
private List<String> updateVerify = new ArrayList<>();
private Set<OptionalFile> updateOptional = new HashSet<>();
private List<String> jvmArgs = new ArrayList<>();
private List<String> classPath = new ArrayList<>();
private List<String> modulePath = new ArrayList<>();
private List<String> modules = new ArrayList<>();
private List<String> altClassPath = new ArrayList<>();
private List<String> clientArgs = new ArrayList<>();
private List<String> compatClasses = new ArrayList<>();
private Map<String, String> properties = new HashMap<>();
private List<ClientProfile.ServerProfile> servers = new ArrayList<>();
private ClientProfile.ClassLoaderConfig classLoaderConfig = ClientProfile.ClassLoaderConfig.LAUNCHER;
private List<ClientProfile.CompatibilityFlags> flags = new ArrayList<>();
private ClientProfile.Version version;
private String assetIndex;
private String dir;
private String assetDir;
private int recommendJavaVersion = 8;
private int minJavaVersion = 8;
private int maxJavaVersion = 999;
private ClientProfile.ProfileDefaultSettings settings = new ClientProfile.ProfileDefaultSettings();
private int sortIndex;
private UUID uuid;
private String title;
private UUID uuid;
private ClientProfile.Version version;
private String info;
private String dir;
private int sortIndex;
private String assetIndex;
private String assetDir;
private List<String> update;
private List<String> updateExclusions;
private List<String> updateVerify;
private Set<OptionalFile> updateOptional;
private List<String> jvmArgs;
private List<String> classPath;
private List<String> altClassPath;
private List<String> clientArgs;
private List<String> compatClasses;
private List<String> loadNatives;
private Map<String, String> properties;
private List<ClientProfile.ServerProfile> servers;
private ClientProfile.ClassLoaderConfig classLoaderConfig;
private List<ClientProfile.CompatibilityFlags> flags;
private int recommendJavaVersion;
private int minJavaVersion;
private int maxJavaVersion;
private ClientProfile.ProfileDefaultSettings settings;
private boolean limited;
private String mainClass;
private String mainModule;
private LaunchOptions.ModuleConf moduleConf;
public void setUpdate(List<String> update) {
this.update = update;
public ClientProfileBuilder() {
this.update = new ArrayList<>();
this.updateExclusions = new ArrayList<>();
this.updateVerify = new ArrayList<>();
this.updateOptional = new HashSet<>();
this.jvmArgs = new ArrayList<>();
this.classPath = new ArrayList<>();
this.altClassPath = new ArrayList<>();
this.clientArgs = new ArrayList<>();
this.compatClasses = new ArrayList<>();
this.loadNatives = new ArrayList<>();
this.properties = new HashMap<>();
this.servers = new ArrayList<>();
this.flags = new ArrayList<>();
}
public ClientProfileBuilder setUpdateExclusions(List<String> updateExclusions) {
this.updateExclusions = updateExclusions;
public ClientProfileBuilder(ClientProfile profile) {
this.title = profile.getTitle();
this.uuid = profile.getUUID();
this.version = profile.getVersion();
this.info = profile.getInfo();
this.dir = profile.getDir();
this.sortIndex = profile.getSortIndex();
this.assetIndex = profile.getAssetIndex();
this.assetDir = profile.getAssetDir();
this.update = new ArrayList<>(profile.getUpdate());
this.updateExclusions = new ArrayList<>(profile.getUpdateExclusions());
this.updateVerify = new ArrayList<>(profile.getUpdateVerify());
this.updateOptional = new HashSet<>(profile.getOptional());
this.jvmArgs = new ArrayList<>(profile.getJvmArgs());
this.classPath = new ArrayList<>(profile.getClassPath());
this.altClassPath = new ArrayList<>(profile.getAlternativeClassPath());
this.clientArgs = new ArrayList<>(profile.getClientArgs());
this.compatClasses = new ArrayList<>(profile.getCompatClasses());
this.loadNatives = new ArrayList<>(profile.getLoadNatives());
this.properties = new HashMap<>(profile.getProperties());
this.servers = new ArrayList<>(profile.getServers());
this.flags = new ArrayList<>(profile.getFlags());
this.recommendJavaVersion = profile.getRecommendJavaVersion();
this.minJavaVersion = profile.getMinJavaVersion();
this.maxJavaVersion = profile.getMaxJavaVersion();
this.settings = profile.getSettings();
this.limited = profile.isLimited();
this.mainClass = profile.getMainClass();
this.mainModule = profile.getMainModule();
this.moduleConf = profile.getModuleConf();
}
public ClientProfileBuilder setTitle(String title) {
this.title = title;
return this;
}
public ClientProfileBuilder setUpdateShared(List<String> updateShared) {
this.updateShared = updateShared;
public ClientProfileBuilder setUuid(UUID uuid) {
this.uuid = uuid;
return this;
}
public void setUpdateVerify(List<String> updateVerify) {
this.updateVerify = updateVerify;
}
public void setUpdateOptional(Set<OptionalFile> updateOptional) {
this.updateOptional = updateOptional;
}
public void setJvmArgs(List<String> jvmArgs) {
this.jvmArgs = jvmArgs;
}
public void setClassPath(List<String> classPath) {
this.classPath = classPath;
}
public void setAltClassPath(List<String> altClassPath) {
this.altClassPath = altClassPath;
}
public void setClientArgs(List<String> clientArgs) {
this.clientArgs = clientArgs;
}
public ClientProfileBuilder setCompatClasses(List<String> compatClasses) {
this.compatClasses = compatClasses;
return this;
}
public ClientProfileBuilder setProperties(Map<String, String> properties) {
this.properties = properties;
return this;
}
public void setServers(List<ClientProfile.ServerProfile> servers) {
this.servers = servers;
}
public void setClassLoaderConfig(ClientProfile.ClassLoaderConfig classLoaderConfig) {
this.classLoaderConfig = classLoaderConfig;
}
public void setVersion(ClientProfile.Version version) {
public ClientProfileBuilder setVersion(ClientProfile.Version version) {
this.version = version;
return this;
}
public void setAssetIndex(String assetIndex) {
this.assetIndex = assetIndex;
public ClientProfileBuilder setInfo(String info) {
this.info = info;
return this;
}
public void setDir(String dir) {
public ClientProfileBuilder setDir(String dir) {
this.dir = dir;
}
public void setAssetDir(String assetDir) {
this.assetDir = assetDir;
}
public void setRecommendJavaVersion(int recommendJavaVersion) {
this.recommendJavaVersion = recommendJavaVersion;
}
public ClientProfileBuilder setModulePath(List<String> modulePath) {
this.modulePath = modulePath;
return this;
}
public ClientProfileBuilder setModules(List<String> modules) {
this.modules = modules;
return this;
}
public void setMinJavaVersion(int minJavaVersion) {
this.minJavaVersion = minJavaVersion;
}
public void setMaxJavaVersion(int maxJavaVersion) {
this.maxJavaVersion = maxJavaVersion;
}
public ClientProfileBuilder setSettings(ClientProfile.ProfileDefaultSettings settings) {
this.settings = settings;
return this;
}
@ -139,20 +115,140 @@ public class ClientProfileBuilder {
return this;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
public ClientProfileBuilder setAssetIndex(String assetIndex) {
this.assetIndex = assetIndex;
return this;
}
public void setTitle(String title) {
this.title = title;
public ClientProfileBuilder setAssetDir(String assetDir) {
this.assetDir = assetDir;
return this;
}
public void setInfo(String info) {
this.info = info;
public ClientProfileBuilder setUpdate(List<String> update) {
this.update = update;
return this;
}
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
public ClientProfileBuilder update(String value) {
this.update.add(value);
return this;
}
public ClientProfileBuilder setUpdateExclusions(List<String> updateExclusions) {
this.updateExclusions = updateExclusions;
return this;
}
public ClientProfileBuilder updateExclusions(String value) {
this.updateExclusions.add(value);
return this;
}
public ClientProfileBuilder setUpdateVerify(List<String> updateVerify) {
this.updateVerify = updateVerify;
return this;
}
public ClientProfileBuilder updateVerify(String value) {
this.updateVerify.add(value);
return this;
}
public ClientProfileBuilder setUpdateOptional(Set<OptionalFile> updateOptional) {
this.updateOptional = updateOptional;
return this;
}
public ClientProfileBuilder updateOptional(OptionalFile value) {
this.updateOptional.add(value);
return this;
}
public ClientProfileBuilder setJvmArgs(List<String> jvmArgs) {
this.jvmArgs = jvmArgs;
return this;
}
public ClientProfileBuilder jvmArg(String value) {
this.jvmArgs.add(value);
return this;
}
public ClientProfileBuilder setClassPath(List<String> classPath) {
this.classPath = classPath;
return this;
}
public ClientProfileBuilder classPath(String value) {
this.classPath.add(value);
return this;
}
public ClientProfileBuilder setAltClassPath(List<String> altClassPath) {
this.altClassPath = altClassPath;
return this;
}
public ClientProfileBuilder altClassPath(String value) {
this.altClassPath.add(value);
return this;
}
public ClientProfileBuilder setClientArgs(List<String> clientArgs) {
this.clientArgs = clientArgs;
return this;
}
public ClientProfileBuilder clientArg(String value) {
this.clientArgs.add(value);
return this;
}
public ClientProfileBuilder setCompatClasses(List<String> compatClasses) {
this.compatClasses = compatClasses;
return this;
}
public ClientProfileBuilder compatClass(String value) {
this.compatClasses.add(value);
return this;
}
public ClientProfileBuilder setLoadNatives(List<String> loadNatives) {
this.loadNatives = loadNatives;
return this;
}
public ClientProfileBuilder loadNatives(String value) {
this.loadNatives.add(value);
return this;
}
public ClientProfileBuilder setProperties(Map<String, String> properties) {
this.properties = properties;
return this;
}
public ClientProfileBuilder property(String name, String value) {
this.properties.put(name, value);
return this;
}
public ClientProfileBuilder setServers(List<ClientProfile.ServerProfile> servers) {
this.servers = servers;
return this;
}
public ClientProfileBuilder server(ClientProfile.ServerProfile value) {
this.servers.add(value);
return this;
}
public ClientProfileBuilder setClassLoaderConfig(ClientProfile.ClassLoaderConfig classLoaderConfig) {
this.classLoaderConfig = classLoaderConfig;
return this;
}
public ClientProfileBuilder setFlags(List<ClientProfile.CompatibilityFlags> flags) {
@ -160,7 +256,52 @@ public class ClientProfileBuilder {
return this;
}
public ClientProfileBuilder flag(ClientProfile.CompatibilityFlags value) {
this.flags.add(value);
return this;
}
public ClientProfileBuilder setRecommendJavaVersion(int recommendJavaVersion) {
this.recommendJavaVersion = recommendJavaVersion;
return this;
}
public ClientProfileBuilder setMinJavaVersion(int minJavaVersion) {
this.minJavaVersion = minJavaVersion;
return this;
}
public ClientProfileBuilder setMaxJavaVersion(int maxJavaVersion) {
this.maxJavaVersion = maxJavaVersion;
return this;
}
public ClientProfileBuilder setSettings(ClientProfile.ProfileDefaultSettings settings) {
this.settings = settings;
return this;
}
public ClientProfileBuilder setLimited(boolean limited) {
this.limited = limited;
return this;
}
public ClientProfileBuilder setMainClass(String mainClass) {
this.mainClass = mainClass;
return this;
}
public ClientProfileBuilder setMainModule(String mainModule) {
this.mainModule = mainModule;
return this;
}
public ClientProfileBuilder setModuleConf(LaunchOptions.ModuleConf moduleConf) {
this.moduleConf = moduleConf;
return this;
}
public ClientProfile createClientProfile() {
return new ClientProfile(update, updateExclusions, updateShared, updateVerify, updateOptional, jvmArgs, classPath, modulePath, modules, altClassPath, clientArgs, compatClasses, properties, servers, classLoaderConfig, flags, version, assetIndex, dir, assetDir, recommendJavaVersion, minJavaVersion, maxJavaVersion, settings, sortIndex, uuid, title, info, mainClass);
return new ClientProfile(title, uuid, version, info, dir, sortIndex, assetIndex, assetDir, update, updateExclusions, updateVerify, updateOptional, jvmArgs, classPath, altClassPath, clientArgs, compatClasses, loadNatives, properties, servers, classLoaderConfig, flags, recommendJavaVersion, minJavaVersion, maxJavaVersion, settings, limited, mainClass, mainModule, moduleConf);
}
}

View File

@ -1,17 +1,19 @@
package pro.gravit.launcher.base.profiles.optional.actions;
import java.util.List;
public class OptionalActionClassPath extends OptionalAction {
public String[] args;
public List<String> args;
public boolean useAltClasspath = false;
public OptionalActionClassPath() {
}
public OptionalActionClassPath(String[] args) {
public OptionalActionClassPath(List<String> args) {
this.args = args;
}
public OptionalActionClassPath(String[] args, boolean useAltClasspath) {
public OptionalActionClassPath(List<String> args, boolean useAltClasspath) {
this.args = args;
this.useAltClasspath = useAltClasspath;
}

View File

@ -120,7 +120,6 @@ public class ClientLauncherEntryPoint {
LogHelper.debug("Verifying ClientLauncher sign and classpath");
Set<Path> ignoredPath = new HashSet<>();
List<Path> classpath = resolveClassPath(ignoredPath, clientDir, params.actions, params.profile)
.filter(x -> !profile.getModulePath().contains(clientDir.relativize(x).toString()))
.collect(Collectors.toCollection(ArrayList::new));
if(LogHelper.isDevEnabled()) {
for(var e : classpath) {
@ -253,11 +252,11 @@ public class ClientLauncherEntryPoint {
}
}
private static LinkedList<Path> resolveClassPathList(Set<Path> ignorePaths, Path clientDir, String... classPath) throws IOException {
private static LinkedList<Path> resolveClassPathList(Set<Path> ignorePaths, Path clientDir, List<String> classPath) throws IOException {
return resolveClassPathStream(ignorePaths, clientDir, classPath).collect(Collectors.toCollection(LinkedList::new));
}
private static Stream<Path> resolveClassPathStream(Set<Path> ignorePaths, Path clientDir, String... classPath) throws IOException {
private static Stream<Path> resolveClassPathStream(Set<Path> ignorePaths, Path clientDir, List<String> classPath) throws IOException {
Stream.Builder<Path> builder = Stream.builder();
for (String classPathEntry : classPath) {
Path path = clientDir.resolve(IOHelper.toPath(classPathEntry.replace(IOHelper.CROSS_SEPARATOR, IOHelper.PLATFORM_SEPARATOR)));
@ -301,7 +300,7 @@ public class ClientLauncherEntryPoint {
params.addClientLegacyArgs(args);
System.setProperty("minecraft.applet.TargetDirectory", params.clientDir);
}
Collections.addAll(args, profile.getClientArgs());
args.addAll(profile.getClientArgs());
for (OptionalAction action : params.actions) {
if (action instanceof OptionalActionClientArgs) {
args.addAll(((OptionalActionClientArgs) action).args);

View File

@ -6,9 +6,9 @@ public final class Version implements Comparable<Version> {
public static final int MAJOR = 5;
public static final int MINOR = 6;
public static final int PATCH = 1;
public static final int PATCH = 2;
public static final int BUILD = 1;
public static final Version.Type RELEASE = Type.STABLE;
public static final Version.Type RELEASE = Type.DEV;
public final int major;
public final int minor;
public final int patch;

View File

@ -5,7 +5,7 @@ plugins {
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
}
group = 'pro.gravit.launcher'
version = '5.6.1'
version = '5.6.2-SNAPSHOT'
apply from: 'props.gradle'

View File

@ -13,7 +13,9 @@ project.ext {
verSlf4j = '2.0.9'
verLog4j = '2.20.0'
verMySQLConn = '8.3.0'
verMariaDBConn = '3.3.3'
verPostgreSQLConn = '42.7.1'
verH2Conn = '2.2.224'
verProguard = '7.4.1'
verLaunch4j = '3.50'
}