mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-04-23 16:33:04 +03:00
Compare commits
No commits in common. "master" and "vv5.6.1" have entirely different histories.
105 changed files with 784 additions and 2628 deletions
12
.github/workflows/push.yml
vendored
12
.github/workflows/push.yml
vendored
|
@ -6,28 +6,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Cache Gradle
|
- name: Cache Gradle
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v1
|
||||||
with:
|
with:
|
||||||
path: ~/.gradle/caches
|
path: ~/.gradle/caches
|
||||||
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
|
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 21
|
||||||
distribution: temurin
|
|
||||||
|
|
||||||
- name: Grant execute permission for gradlew
|
- name: Grant execute permission for gradlew
|
||||||
run: chmod +x gradlew
|
run: chmod +x gradlew
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
|
||||||
- name: Generate and submit dependency graph
|
- name: Generate and submit dependency graph
|
||||||
uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
||||||
|
|
||||||
|
@ -44,7 +42,7 @@ jobs:
|
||||||
cp modules/*_lmodule/build/libs/*.jar artifacts/modules || true
|
cp modules/*_lmodule/build/libs/*.jar artifacts/modules || true
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: Launcher
|
name: Launcher
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
@ -65,7 +63,7 @@ jobs:
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
if: startsWith(github.event.ref, 'refs/tags')
|
if: startsWith(github.event.ref, 'refs/tags')
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
@ -13,24 +13,20 @@
|
||||||
maven {
|
maven {
|
||||||
url "https://jitpack.io/"
|
url "https://jitpack.io/"
|
||||||
}
|
}
|
||||||
maven {
|
|
||||||
url 'https://maven.gravit-support.ru/repository/jitpack'
|
|
||||||
credentials {
|
|
||||||
username = 'gravitlauncher'
|
|
||||||
password = 'gravitlauncher'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = '21'
|
sourceCompatibility = '21'
|
||||||
targetCompatibility = '21'
|
targetCompatibility = '21'
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
compileOnlyA
|
||||||
bundleOnly
|
bundleOnly
|
||||||
bundle
|
bundle
|
||||||
|
hikari
|
||||||
pack
|
pack
|
||||||
|
launch4j
|
||||||
bundleOnly.extendsFrom bundle
|
bundleOnly.extendsFrom bundle
|
||||||
api.extendsFrom bundle, pack
|
api.extendsFrom bundle, hikari, pack, launch4j
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
@ -65,6 +61,7 @@
|
||||||
dependsOn jar
|
dependsOn jar
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
|
"Premain-Class": mainAgentName,
|
||||||
"Automatic-Module-Name": "launchserver"
|
"Automatic-Module-Name": "launchserver"
|
||||||
)
|
)
|
||||||
from sourceSets.main.output
|
from sourceSets.main.output
|
||||||
|
@ -73,60 +70,68 @@
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
pack project(':LauncherAPI')
|
pack project(':LauncherAPI')
|
||||||
bundle group: 'me.tongfei', name: 'progressbar', version: '0.10.1'
|
bundle group: 'me.tongfei', name: 'progressbar', version: '0.9.2'
|
||||||
|
bundle group: 'com.github.Marcono1234', name: 'gson-record-type-adapter-factory', version: 'v0.2.0'
|
||||||
bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
||||||
bundle group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
bundle group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
||||||
bundle group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
bundle group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
||||||
bundle group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
bundle group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
||||||
bundle group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: rootProject['verBcpkix']
|
bundle group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: rootProject['verBcpkix']
|
||||||
bundle group: 'org.bouncycastle', name: 'bcpkix-jdk18on', version: rootProject['verBcpkix']
|
|
||||||
bundle group: 'org.ow2.asm', name: 'asm-commons', version: rootProject['verAsm']
|
bundle group: 'org.ow2.asm', name: 'asm-commons', version: rootProject['verAsm']
|
||||||
bundle group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty']
|
bundle group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty']
|
||||||
bundle group: 'io.netty', name: 'netty-transport-classes-epoll', version: rootProject['verNetty']
|
bundle group: 'io.netty', name: 'netty-transport-classes-epoll', version: rootProject['verNetty']
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64'
|
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64'
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-aarch_64'
|
|
||||||
bundle group: 'io.netty', name: 'netty-transport-classes-io_uring', version: rootProject['verNetty']
|
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-io_uring', version: rootProject['verNetty'], classifier: 'linux-x86_64'
|
|
||||||
bundle group: 'io.netty', name: 'netty-transport-native-io_uring', version: rootProject['verNetty'], classifier: 'linux-aarch_64'
|
|
||||||
// Netty
|
|
||||||
bundle 'org.jboss.marshalling:jboss-marshalling:1.4.11.Final'
|
|
||||||
bundle 'com.google.protobuf.nano:protobuf-javanano:3.1.0'
|
|
||||||
//
|
|
||||||
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
bundle group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||||
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
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: '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: '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-core', version: rootProject['verLog4j']
|
||||||
bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: rootProject['verLog4j']
|
bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: rootProject['verLog4j']
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt']
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
|
||||||
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
|
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
|
||||||
bundle group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
|
||||||
annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'])
|
annotationProcessor(group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'])
|
||||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||||
|
|
||||||
bundle 'io.micrometer:micrometer-core:1.14.4'
|
hikari 'io.micrometer:micrometer-core:1.8.4'
|
||||||
bundle('com.zaxxer:HikariCP:6.2.1') {
|
hikari('com.zaxxer:HikariCP:5.0.1') {
|
||||||
exclude group: 'javassist'
|
exclude group: 'javassist'
|
||||||
exclude group: 'io.micrometer'
|
exclude group: 'io.micrometer'
|
||||||
exclude group: 'org.slf4j'
|
exclude group: 'org.slf4j'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOnlyA group: 'com.google.guava', name: 'guava', version: rootProject['verGuavaC']
|
||||||
|
// Do not update (laggy deps).
|
||||||
|
compileOnlyA 'log4j:log4j:1.2.17'
|
||||||
|
compileOnlyA 'org.apache.logging.log4j:log4j-core:2.14.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('hikari', Copy) {
|
||||||
|
duplicatesStrategy = 'EXCLUDE'
|
||||||
|
into "$buildDir/libs/libraries/hikaricp"
|
||||||
|
from configurations.hikari
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('dumpLibs', Copy) {
|
tasks.register('dumpLibs', Copy) {
|
||||||
duplicatesStrategy = 'EXCLUDE'
|
duplicatesStrategy = 'EXCLUDE'
|
||||||
|
dependsOn tasks.hikari
|
||||||
into "$buildDir/libs/libraries"
|
into "$buildDir/libs/libraries"
|
||||||
from configurations.bundleOnly
|
from configurations.bundleOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('dumpCompileOnlyLibs', Copy) {
|
||||||
|
duplicatesStrategy = 'EXCLUDE'
|
||||||
|
into "$buildDir/libs/launcher-libraries-compile"
|
||||||
|
from configurations.compileOnlyA
|
||||||
|
}
|
||||||
|
|
||||||
tasks.register('bundle', Zip) {
|
tasks.register('bundle', Zip) {
|
||||||
duplicatesStrategy = 'EXCLUDE'
|
duplicatesStrategy = 'EXCLUDE'
|
||||||
dependsOn parent.childProjects.Launcher.tasks.build, tasks.dumpLibs, tasks.jar
|
dependsOn parent.childProjects.Launcher.tasks.build, tasks.dumpLibs, tasks.dumpCompileOnlyLibs, tasks.jar
|
||||||
archiveFileName = 'LaunchServer.zip'
|
archiveFileName = 'LaunchServer.zip'
|
||||||
destinationDirectory = file("$buildDir")
|
destinationDirectory = file("$buildDir")
|
||||||
from(tasks.dumpLibs.destinationDir) { into 'libraries' }
|
from(tasks.dumpLibs.destinationDir) { into 'libraries' }
|
||||||
|
from(tasks.dumpCompileOnlyLibs.destinationDir) { into 'launcher-libraries-compile' }
|
||||||
from(tasks.jar)
|
from(tasks.jar)
|
||||||
from(parent.childProjects.Launcher.tasks.dumpLibs) { into 'launcher-libraries' }
|
from(parent.childProjects.Launcher.tasks.dumpLibs) { into 'launcher-libraries' }
|
||||||
}
|
}
|
||||||
|
@ -137,7 +142,7 @@ pack project(':LauncherAPI')
|
||||||
from parent.childProjects.Launcher.tasks.dumpLibs
|
from parent.childProjects.Launcher.tasks.dumpLibs
|
||||||
}
|
}
|
||||||
|
|
||||||
assemble.dependsOn tasks.dumpLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar
|
assemble.dependsOn tasks.dumpLibs, tasks.dumpCompileOnlyLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar
|
||||||
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.base.Launcher;
|
||||||
import pro.gravit.launcher.base.events.RequestEvent;
|
import pro.gravit.launcher.base.events.RequestEvent;
|
||||||
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
|
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
|
||||||
import pro.gravit.launcher.base.modules.events.ClosePhase;
|
import pro.gravit.launcher.base.modules.events.ClosePhase;
|
||||||
|
@ -20,18 +21,21 @@
|
||||||
import pro.gravit.launchserver.modules.events.*;
|
import pro.gravit.launchserver.modules.events.*;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.SocketCommandServer;
|
|
||||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||||
|
import pro.gravit.launchserver.socket.response.auth.ProfilesResponse;
|
||||||
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
||||||
import pro.gravit.utils.command.Command;
|
import pro.gravit.utils.command.Command;
|
||||||
import pro.gravit.utils.command.CommandHandler;
|
import pro.gravit.utils.command.CommandHandler;
|
||||||
import pro.gravit.utils.command.SubCommand;
|
import pro.gravit.utils.command.SubCommand;
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
import pro.gravit.utils.helper.CommonHelper;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
@ -66,7 +70,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
/**
|
/**
|
||||||
* The path to the folder with updates/webroot
|
* The path to the folder with updates/webroot
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public final Path updatesDir;
|
public final Path updatesDir;
|
||||||
|
|
||||||
// Constant paths
|
// Constant paths
|
||||||
|
@ -77,11 +80,8 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
/**
|
/**
|
||||||
* The path to the folder with profiles
|
* The path to the folder with profiles
|
||||||
*/
|
*/
|
||||||
|
public final Path profilesDir;
|
||||||
public final Path tmpDir;
|
public final Path tmpDir;
|
||||||
public final Path modulesDir;
|
|
||||||
public final Path launcherModulesDir;
|
|
||||||
public final Path librariesDir;
|
|
||||||
public final Path controlFile;
|
|
||||||
/**
|
/**
|
||||||
* This object contains runtime configuration
|
* This object contains runtime configuration
|
||||||
*/
|
*/
|
||||||
|
@ -110,13 +110,14 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
// Server
|
// Server
|
||||||
public final CommandHandler commandHandler;
|
public final CommandHandler commandHandler;
|
||||||
public final NettyServerSocketHandler nettyServerSocketHandler;
|
public final NettyServerSocketHandler nettyServerSocketHandler;
|
||||||
public final SocketCommandServer socketCommandServer;
|
|
||||||
public final ScheduledExecutorService service;
|
public final ScheduledExecutorService service;
|
||||||
public final AtomicBoolean started = new AtomicBoolean(false);
|
public final AtomicBoolean started = new AtomicBoolean(false);
|
||||||
public final LauncherModuleLoader launcherModuleLoader;
|
public final LauncherModuleLoader launcherModuleLoader;
|
||||||
private final Logger logger = LogManager.getLogger();
|
private final Logger logger = LogManager.getLogger();
|
||||||
public final int shardId;
|
public final int shardId;
|
||||||
public LaunchServerConfig config;
|
public LaunchServerConfig config;
|
||||||
|
// Updates and profiles
|
||||||
|
private volatile Set<ClientProfile> profilesList;
|
||||||
|
|
||||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException {
|
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException {
|
||||||
this.dir = directories.dir;
|
this.dir = directories.dir;
|
||||||
|
@ -125,6 +126,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.launchServerConfigManager = launchServerConfigManager;
|
this.launchServerConfigManager = launchServerConfigManager;
|
||||||
this.modulesManager = modulesManager;
|
this.modulesManager = modulesManager;
|
||||||
|
this.profilesDir = directories.profilesDir;
|
||||||
this.updatesDir = directories.updatesDir;
|
this.updatesDir = directories.updatesDir;
|
||||||
this.keyAgreementManager = keyAgreementManager;
|
this.keyAgreementManager = keyAgreementManager;
|
||||||
this.commandHandler = commandHandler;
|
this.commandHandler = commandHandler;
|
||||||
|
@ -134,10 +136,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
launcherLibraries = directories.launcherLibrariesDir;
|
launcherLibraries = directories.launcherLibrariesDir;
|
||||||
launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
|
launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
|
||||||
launcherPack = directories.launcherPackDir;
|
launcherPack = directories.launcherPackDir;
|
||||||
modulesDir = directories.modules;
|
|
||||||
launcherModulesDir = directories.launcherModules;
|
|
||||||
librariesDir = directories.librariesDir;
|
|
||||||
controlFile = directories.controlFile;
|
|
||||||
this.shardId = shardId;
|
this.shardId = shardId;
|
||||||
if(!Files.isDirectory(launcherPack)) {
|
if(!Files.isDirectory(launcherPack)) {
|
||||||
Files.createDirectories(launcherPack);
|
Files.createDirectories(launcherPack);
|
||||||
|
@ -189,7 +187,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
}
|
}
|
||||||
launcherModuleLoader.init();
|
launcherModuleLoader.init();
|
||||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||||
socketCommandServer = new SocketCommandServer(commandHandler, controlFile);
|
|
||||||
if(config.sign.checkCertificateExpired) {
|
if(config.sign.checkCertificateExpired) {
|
||||||
checkCertificateExpired();
|
checkCertificateExpired();
|
||||||
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
||||||
|
@ -323,14 +320,12 @@ public void close() throws Exception {
|
||||||
logger.info("LaunchServer stopped");
|
logger.info("LaunchServer stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
public Set<ClientProfile> getProfiles() {
|
||||||
return config.profileProvider.getProfiles();
|
return profilesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void setProfiles(Set<ClientProfile> profilesList) {
|
public void setProfiles(Set<ClientProfile> profilesList) {
|
||||||
throw new UnsupportedOperationException();
|
this.profilesList = Collections.unmodifiableSet(profilesList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rebindNettyServerSocket() {
|
public void rebindNettyServerSocket() {
|
||||||
|
@ -353,17 +348,17 @@ public void run() {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||||
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
|
||||||
// Sync updates dir
|
// Sync updates dir
|
||||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
||||||
try {
|
try {
|
||||||
|
if (!IOHelper.isDir(updatesDir))
|
||||||
|
Files.createDirectory(updatesDir);
|
||||||
|
updatesManager.readUpdatesDir();
|
||||||
|
|
||||||
// Sync profiles dir
|
// Sync profiles dir
|
||||||
|
if (!IOHelper.isDir(profilesDir))
|
||||||
|
Files.createDirectory(profilesDir);
|
||||||
syncProfilesDir();
|
syncProfilesDir();
|
||||||
|
|
||||||
// Sync updates dir
|
|
||||||
config.updatesProvider.syncInitially();
|
|
||||||
|
|
||||||
|
|
||||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Updates/Profiles not synced", e);
|
logger.error("Updates/Profiles not synced", e);
|
||||||
|
@ -398,7 +393,12 @@ public void syncLauncherBinaries() throws IOException {
|
||||||
|
|
||||||
public void syncProfilesDir() throws IOException {
|
public void syncProfilesDir() throws IOException {
|
||||||
logger.info("Syncing profiles dir");
|
logger.info("Syncing profiles dir");
|
||||||
config.profileProvider.sync();
|
List<ClientProfile> newProfies = new LinkedList<>();
|
||||||
|
IOHelper.walk(profilesDir, new ProfilesFileVisitor(newProfies), false);
|
||||||
|
|
||||||
|
// Sort and set new profiles
|
||||||
|
newProfies.sort(Comparator.comparing(a -> a));
|
||||||
|
profilesList = Set.copyOf(newProfies);
|
||||||
if (config.netty.sendProfileUpdatesEvent) {
|
if (config.netty.sendProfileUpdatesEvent) {
|
||||||
sendUpdateProfilesEvent();
|
sendUpdateProfilesEvent();
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ private void sendUpdateProfilesEvent() {
|
||||||
if (client == null || !client.isAuth) {
|
if (client == null || !client.isAuth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ProfilesRequestEvent event = new ProfilesRequestEvent(config.profileProvider.getProfiles(client));
|
ProfilesRequestEvent event = new ProfilesRequestEvent(ProfilesResponse.getListVisibleProfiles(this, client));
|
||||||
event.requestUUID = RequestEvent.eventUUID;
|
event.requestUUID = RequestEvent.eventUUID;
|
||||||
handler.service.sendObject(ch, event);
|
handler.service.sendObject(ch, event);
|
||||||
});
|
});
|
||||||
|
@ -459,12 +459,38 @@ public interface LaunchServerConfigManager {
|
||||||
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
|
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
||||||
|
private final Collection<ClientProfile> result;
|
||||||
|
private final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
|
private ProfilesFileVisitor(Collection<ClientProfile> result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
||||||
|
|
||||||
|
// Read profile
|
||||||
|
ClientProfile profile;
|
||||||
|
try (BufferedReader reader = IOHelper.newReader(file)) {
|
||||||
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
profile.verify();
|
||||||
|
profile.setProfileFilePath(file);
|
||||||
|
|
||||||
|
// Add SIGNED profile to result list
|
||||||
|
result.add(profile);
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class LaunchServerDirectories {
|
public static class LaunchServerDirectories {
|
||||||
public static final String UPDATES_NAME = "updates",
|
public static final String UPDATES_NAME = "updates", PROFILES_NAME = "profiles",
|
||||||
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
|
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
|
||||||
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", LIBRARIES = "libraries", CONTROL_FILE = "control-file";
|
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys";
|
||||||
public Path updatesDir;
|
public Path updatesDir;
|
||||||
public Path librariesDir;
|
public Path profilesDir;
|
||||||
public Path launcherLibrariesDir;
|
public Path launcherLibrariesDir;
|
||||||
public Path launcherLibrariesCompileDir;
|
public Path launcherLibrariesCompileDir;
|
||||||
public Path launcherPackDir;
|
public Path launcherPackDir;
|
||||||
|
@ -472,23 +498,17 @@ public static class LaunchServerDirectories {
|
||||||
public Path dir;
|
public Path dir;
|
||||||
public Path trustStore;
|
public Path trustStore;
|
||||||
public Path tmpDir;
|
public Path tmpDir;
|
||||||
public Path modules;
|
|
||||||
public Path launcherModules;
|
|
||||||
public Path controlFile;
|
|
||||||
|
|
||||||
public void collect() {
|
public void collect() {
|
||||||
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
||||||
|
if (profilesDir == null) profilesDir = getPath(PROFILES_NAME);
|
||||||
if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME);
|
if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME);
|
||||||
if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME);
|
if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME);
|
||||||
if (launcherLibrariesCompileDir == null)
|
if (launcherLibrariesCompileDir == null)
|
||||||
launcherLibrariesCompileDir = getPath(LAUNCHERLIBRARIESCOMPILE_NAME);
|
launcherLibrariesCompileDir = getPath(LAUNCHERLIBRARIESCOMPILE_NAME);
|
||||||
if (launcherPackDir == null)
|
if(launcherPackDir == null)
|
||||||
launcherPackDir = getPath(LAUNCHERPACK_NAME);
|
launcherPackDir = getPath(LAUNCHERPACK_NAME);
|
||||||
if (keyDirectory == null) keyDirectory = getPath(KEY_NAME);
|
if (keyDirectory == null) keyDirectory = getPath(KEY_NAME);
|
||||||
if (modules == null) modules = getPath(MODULES);
|
|
||||||
if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES);
|
|
||||||
if (librariesDir == null) librariesDir = getPath(LIBRARIES);
|
|
||||||
if (controlFile == null) controlFile = getPath(CONTROL_FILE);
|
|
||||||
if (tmpDir == null)
|
if (tmpDir == null)
|
||||||
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,8 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
|
@ -53,16 +51,13 @@ public static void main(String[] args) throws Exception {
|
||||||
try {
|
try {
|
||||||
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
LogHelper.error("Library BouncyCastle not found! Is directory 'libraries' empty?");
|
LogHelper.error("Library BouncyCastle not found! Is directory 'libraries' empty?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
|
||||||
directories.dir = dir;
|
|
||||||
directories.collect();
|
|
||||||
CertificateManager certificateManager = new CertificateManager();
|
CertificateManager certificateManager = new CertificateManager();
|
||||||
try {
|
try {
|
||||||
certificateManager.readTrustStore(directories.trustStore);
|
certificateManager.readTrustStore(dir.resolve("truststore"));
|
||||||
} catch (CertificateException e) {
|
} catch (CertificateException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +78,7 @@ public static void main(String[] args) throws Exception {
|
||||||
LaunchServerRuntimeConfig runtimeConfig;
|
LaunchServerRuntimeConfig runtimeConfig;
|
||||||
LaunchServerConfig config;
|
LaunchServerConfig config;
|
||||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(directories.modules, dir.resolve("config"), certificateManager.trustManager);
|
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
|
||||||
modulesManager.autoload();
|
modulesManager.autoload();
|
||||||
modulesManager.initModules(null);
|
modulesManager.initModules(null);
|
||||||
registerAll();
|
registerAll();
|
||||||
|
@ -128,6 +123,8 @@ public static void main(String[] args) throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
||||||
|
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||||
|
directories.dir = dir;
|
||||||
LaunchServer server = new LaunchServerBuilder()
|
LaunchServer server = new LaunchServerBuilder()
|
||||||
.setDirectories(directories)
|
.setDirectories(directories)
|
||||||
.setEnv(env)
|
.setEnv(env)
|
||||||
|
@ -138,24 +135,7 @@ public static void main(String[] args) throws Exception {
|
||||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||||
.setCertificateManager(certificateManager)
|
.setCertificateManager(certificateManager)
|
||||||
.build();
|
.build();
|
||||||
List<String> allArgs = List.of(args);
|
if (!prepareMode) {
|
||||||
boolean isPrepareMode = prepareMode || allArgs.contains("--prepare");
|
|
||||||
boolean isRunCommand = false;
|
|
||||||
String runCommand = null;
|
|
||||||
for(var e : allArgs) {
|
|
||||||
if(e.equals("--run")) {
|
|
||||||
isRunCommand = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(isRunCommand) {
|
|
||||||
runCommand = e;
|
|
||||||
isRunCommand = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(runCommand != null) {
|
|
||||||
localCommandHandler.eval(runCommand, false);
|
|
||||||
}
|
|
||||||
if (!isPrepareMode) {
|
|
||||||
server.run();
|
server.run();
|
||||||
} else {
|
} else {
|
||||||
server.close();
|
server.close();
|
||||||
|
@ -179,8 +159,6 @@ public static void registerAll() {
|
||||||
OptionalAction.registerProviders();
|
OptionalAction.registerProviders();
|
||||||
OptionalTrigger.registerProviders();
|
OptionalTrigger.registerProviders();
|
||||||
MixProvider.registerProviders();
|
MixProvider.registerProviders();
|
||||||
ProfileProvider.registerProviders();
|
|
||||||
UpdatesProvider.registerProviders();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printExperimentalBranch() {
|
private static void printExperimentalBranch() {
|
||||||
|
@ -223,7 +201,7 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
||||||
address = System.getProperty("launchserver.address", null);
|
address = System.getProperty("launchserver.address", null);
|
||||||
}
|
}
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
System.out.println("External launchServer address:port (default: localhost:9274): ");
|
System.out.println("LaunchServer address(default: localhost): ");
|
||||||
address = commandHandler.readLine();
|
address = commandHandler.readLine();
|
||||||
}
|
}
|
||||||
String projectName = System.getenv("PROJECTNAME");
|
String projectName = System.getenv("PROJECTNAME");
|
||||||
|
@ -237,29 +215,18 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
||||||
newConfig.setProjectName(projectName);
|
newConfig.setProjectName(projectName);
|
||||||
}
|
}
|
||||||
if (address == null || address.isEmpty()) {
|
if (address == null || address.isEmpty()) {
|
||||||
logger.error("Address null. Using localhost:9274");
|
logger.error("Address null. Using localhost");
|
||||||
address = "localhost:9274";
|
address = "localhost";
|
||||||
}
|
}
|
||||||
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
||||||
logger.error("ProjectName null. Using MineCraft");
|
logger.error("ProjectName null. Using MineCraft");
|
||||||
newConfig.projectName = "MineCraft";
|
newConfig.projectName = "MineCraft";
|
||||||
}
|
}
|
||||||
int port = 9274;
|
|
||||||
if(address.contains(":")) {
|
newConfig.netty.address = "ws://" + address + ":9274/api";
|
||||||
String portString = address.substring(address.indexOf(':')+1);
|
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
||||||
try {
|
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
||||||
port = Integer.parseInt(portString);
|
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
logger.warn("Unknown port {}, using 9274", portString);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("Address {} doesn't contains port (you want to use nginx?)", address);
|
|
||||||
}
|
|
||||||
newConfig.netty.address = "ws://" + address + "/api";
|
|
||||||
newConfig.netty.downloadURL = "http://" + address + "/%dirname%/";
|
|
||||||
newConfig.netty.launcherURL = "http://" + address + "/Launcher.jar";
|
|
||||||
newConfig.netty.launcherEXEURL = "http://" + address + "/Launcher.exe";
|
|
||||||
newConfig.netty.binds[0].port = port;
|
|
||||||
|
|
||||||
// Write LaunchServer config
|
// Write LaunchServer config
|
||||||
logger.info("Writing LaunchServer config file");
|
logger.info("Writing LaunchServer config file");
|
||||||
|
|
|
@ -18,10 +18,8 @@
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
private static final List<String> classpathOnly = List.of("proguard", "jline", "progressbar", "kotlin");
|
private static final List<String> classpathOnly = List.of("proguard", "jline", "kotlin", "epoll");
|
||||||
private static final String LOG4J_PROPERTY = "log4j2.configurationFile";
|
private static final String LOG4J_PROPERTY = "log4j2.configurationFile";
|
||||||
private static final String DEBUG_PROPERTY = "launchserver.main.debug";
|
|
||||||
private static final String LIBRARIES_PROPERTY = "launchserver.dir.libraries";
|
|
||||||
private static boolean isClasspathOnly(Path path) {
|
private static boolean isClasspathOnly(Path path) {
|
||||||
var fileName = path.getFileName().toString();
|
var fileName = path.getFileName().toString();
|
||||||
for(var e : classpathOnly) {
|
for(var e : classpathOnly) {
|
||||||
|
@ -57,9 +55,8 @@ public static void main(String[] args) throws Throwable {
|
||||||
ModuleLaunch launch = new ModuleLaunch();
|
ModuleLaunch launch = new ModuleLaunch();
|
||||||
LaunchOptions options = new LaunchOptions();
|
LaunchOptions options = new LaunchOptions();
|
||||||
options.moduleConf = new LaunchOptions.ModuleConf();
|
options.moduleConf = new LaunchOptions.ModuleConf();
|
||||||
Path librariesPath = Path.of(System.getProperty(LIBRARIES_PROPERTY, "libraries"));
|
|
||||||
List<Path> libraries;
|
List<Path> libraries;
|
||||||
try(Stream<Path> files = Files.walk(librariesPath, FileVisitOption.FOLLOW_LINKS)) {
|
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
|
||||||
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
|
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
|
||||||
}
|
}
|
||||||
List<Path> classpath = new ArrayList<>();
|
List<Path> classpath = new ArrayList<>();
|
||||||
|
@ -81,14 +78,6 @@ public static void main(String[] args) throws Throwable {
|
||||||
ModuleLayer.Controller controller = (ModuleLayer.Controller) control.getJava9ModuleController();
|
ModuleLayer.Controller controller = (ModuleLayer.Controller) control.getJava9ModuleController();
|
||||||
LaunchServerControlHolder.setControl(control);
|
LaunchServerControlHolder.setControl(control);
|
||||||
LaunchServerControlHolder.setController(controller);
|
LaunchServerControlHolder.setController(controller);
|
||||||
if(Boolean.getBoolean(DEBUG_PROPERTY)) {
|
|
||||||
for(var e : controller.layer().modules()) {
|
|
||||||
System.out.printf("Module %s\n", e.getName());
|
|
||||||
for(var p : e.getPackages()) {
|
|
||||||
System.out.printf("Package %s\n", p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
launch.launch("pro.gravit.launchserver.LaunchServerStarter", null, Arrays.asList(args));
|
launch.launch("pro.gravit.launchserver.LaunchServerStarter", null, Arrays.asList(args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@ public AuthException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthException need2FA() {
|
public static AuthException need2FA() {
|
||||||
return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE);
|
return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
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 volatile HikariDataSource dataSource;
|
|
||||||
private String dsClass;
|
|
||||||
private Properties dsProps;
|
|
||||||
private String driverClass;
|
|
||||||
private String jdbcUrl;
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private boolean initializeAtStart;
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
if(initializeAtStart) {
|
|
||||||
initializeConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeConnection() {
|
|
||||||
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 {
|
|
||||||
if(dataSource == null && !initializeAtStart) {
|
|
||||||
synchronized (this) {
|
|
||||||
initializeConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -174,7 +174,7 @@ public AuthManager.AuthReport sudo(User user, boolean shadow) throws IOException
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User checkServer(Client client, String username, String serverID) {
|
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||||
SQLUser user = (SQLUser) getUserByUsername(username);
|
SQLUser user = (SQLUser) getUserByUsername(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -276,7 +276,7 @@ public void close() {
|
||||||
|
|
||||||
protected SQLUser constructUser(ResultSet set) throws SQLException {
|
protected SQLUser constructUser(ResultSet set) throws SQLException {
|
||||||
return set.next() ? new SQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
return set.next() ? new SQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn)) : null;
|
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), requestPermissions(set.getString(uuidColumn))) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientPermissions requestPermissions (String uuid) throws SQLException
|
public ClientPermissions requestPermissions (String uuid) throws SQLException
|
||||||
|
@ -286,19 +286,14 @@ public ClientPermissions requestPermissions (String uuid) throws SQLException
|
||||||
}
|
}
|
||||||
|
|
||||||
private SQLUser queryUser(String sql, String value) throws SQLException {
|
private SQLUser queryUser(String sql, String value) throws SQLException {
|
||||||
SQLUser user;
|
|
||||||
try (Connection c = getSQLConfig().getConnection()) {
|
try (Connection c = getSQLConfig().getConnection()) {
|
||||||
PreparedStatement s = c.prepareStatement(sql);
|
PreparedStatement s = c.prepareStatement(sql);
|
||||||
s.setString(1, value);
|
s.setString(1, value);
|
||||||
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
try (ResultSet set = s.executeQuery()) {
|
try (ResultSet set = s.executeQuery()) {
|
||||||
user = constructUser(set);
|
return constructUser(set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(user != null) {
|
|
||||||
user.permissions = requestPermissions(user.uuid.toString());
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> queryPermissions(String sql, String value) throws SQLException {
|
private List<String> queryPermissions(String sql, String value) throws SQLException {
|
||||||
|
@ -345,14 +340,15 @@ public static class SQLUser implements User {
|
||||||
protected String accessToken;
|
protected String accessToken;
|
||||||
protected String serverId;
|
protected String serverId;
|
||||||
protected final String password;
|
protected final String password;
|
||||||
protected ClientPermissions permissions;
|
protected final ClientPermissions permissions;
|
||||||
|
|
||||||
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password) {
|
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
this.serverId = serverId;
|
this.serverId = serverId;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
this.permissions = permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
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.AuthSupportRegistration;
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportSudo;
|
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.manangers.AuthManager;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
@ -54,8 +53,6 @@ public static void registerProviders() {
|
||||||
providers.register("postgresql", PostgresSQLCoreProvider.class);
|
providers.register("postgresql", PostgresSQLCoreProvider.class);
|
||||||
providers.register("memory", MemoryAuthCoreProvider.class);
|
providers.register("memory", MemoryAuthCoreProvider.class);
|
||||||
providers.register("merge", MergeAuthCoreProvider.class);
|
providers.register("merge", MergeAuthCoreProvider.class);
|
||||||
providers.register("openid", OpenIDAuthCoreProvider.class);
|
|
||||||
providers.register("sql", SQLCoreProvider.class);
|
|
||||||
registredProviders = true;
|
registredProviders = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.ClientPermissions;
|
||||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
|
@ -43,7 +44,6 @@ public SQLSourceConfig getSQLConfig() {
|
||||||
@Override
|
@Override
|
||||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||||
super.init(server, pair);
|
super.init(server, pair);
|
||||||
logger.warn("Method 'mysql' deprecated and may be removed in future release. Please use new 'sql' method: https://gravitlauncher.com/auth");
|
|
||||||
String userInfoCols = makeUserCols();
|
String userInfoCols = makeUserCols();
|
||||||
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
||||||
if (sqlFindHardwareByPublicKey == null)
|
if (sqlFindHardwareByPublicKey == null)
|
||||||
|
@ -72,7 +72,7 @@ protected String makeUserCols() {
|
||||||
@Override
|
@Override
|
||||||
protected MySQLUser constructUser(ResultSet set) throws SQLException {
|
protected MySQLUser constructUser(ResultSet set) throws SQLException {
|
||||||
return set.next() ? new MySQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
return set.next() ? new MySQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), set.getLong(hardwareIdColumn)) : null;
|
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), requestPermissions(set.getString(uuidColumn)), set.getLong(hardwareIdColumn)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MySQLUserHardware fetchHardwareInfo(ResultSet set) throws SQLException, IOException {
|
private MySQLUserHardware fetchHardwareInfo(ResultSet set) throws SQLException, IOException {
|
||||||
|
@ -336,8 +336,8 @@ public String toString() {
|
||||||
public static class MySQLUser extends SQLUser {
|
public static class MySQLUser extends SQLUser {
|
||||||
protected long hwidId;
|
protected long hwidId;
|
||||||
|
|
||||||
public MySQLUser(UUID uuid, String username, String accessToken, String serverId, String password, long hwidId) {
|
public MySQLUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions, long hwidId) {
|
||||||
super(uuid, username, accessToken, serverId, password);
|
super(uuid, username, accessToken, serverId, password, permissions);
|
||||||
this.hwidId = hwidId;
|
this.hwidId = hwidId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
package pro.gravit.launchserver.auth.core;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
|
||||||
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
|
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
|
||||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||||
|
|
||||||
|
@ -12,10 +10,4 @@ public class PostgresSQLCoreProvider extends AbstractSQLCoreProvider {
|
||||||
public SQLSourceConfig getSQLConfig() {
|
public SQLSourceConfig getSQLConfig() {
|
||||||
return postgresSQLHolder;
|
return postgresSQLHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
|
||||||
super.init(server, pair);
|
|
||||||
logger.warn("Method 'postgresql' deprecated and may be removed in future release. Please use new 'sql' method: https://gravitlauncher.com/auth");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,12 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User checkServer(Client client, String username, String serverID) {
|
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) {
|
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,391 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.core;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
|
||||||
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
|
|
||||||
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
|
||||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportExtendedCheckServer;
|
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
|
||||||
import pro.gravit.launchserver.auth.core.interfaces.session.UserSessionSupportHardware;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class SQLCoreProvider extends AbstractSQLCoreProvider implements AuthSupportHardware, AuthSupportExtendedCheckServer {
|
|
||||||
public HikariSQLSourceConfig holder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
super.close();
|
|
||||||
holder.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SQLSourceConfig getSQLConfig() {
|
|
||||||
return holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String hardwareIdColumn;
|
|
||||||
public String tableHWID = "hwids";
|
|
||||||
public String tableHWIDLog = "hwidLog";
|
|
||||||
public double criticalCompareLevel = 1.0;
|
|
||||||
private transient String sqlFindHardwareByPublicKey;
|
|
||||||
private transient String sqlFindHardwareByData;
|
|
||||||
private transient String sqlFindHardwareById;
|
|
||||||
private transient String sqlCreateHardware;
|
|
||||||
private transient String sqlCreateHWIDLog;
|
|
||||||
private transient String sqlUpdateHardwarePublicKey;
|
|
||||||
private transient String sqlUpdateHardwareBanned;
|
|
||||||
private transient String sqlUpdateUsers;
|
|
||||||
private transient String sqlUsersByHwidId;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
|
||||||
holder.init();
|
|
||||||
super.init(server, pair);
|
|
||||||
String userInfoCols = makeUserCols();
|
|
||||||
String hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
|
||||||
if (sqlFindHardwareByPublicKey == null)
|
|
||||||
sqlFindHardwareByPublicKey = "SELECT %s FROM %s WHERE publicKey = ?".formatted(hardwareInfoCols, tableHWID);
|
|
||||||
if (sqlFindHardwareById == null)
|
|
||||||
sqlFindHardwareById = "SELECT %s FROM %s WHERE id = ?".formatted(hardwareInfoCols, tableHWID);
|
|
||||||
if (sqlUsersByHwidId == null)
|
|
||||||
sqlUsersByHwidId = "SELECT %s FROM %s WHERE %s = ?".formatted(userInfoCols, table, hardwareIdColumn);
|
|
||||||
if (sqlFindHardwareByData == null)
|
|
||||||
sqlFindHardwareByData = "SELECT %s FROM %s".formatted(hardwareInfoCols, tableHWID);
|
|
||||||
if (sqlCreateHardware == null)
|
|
||||||
sqlCreateHardware = "INSERT INTO %s (publickey, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, graphicCard, battery, banned) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0')".formatted(tableHWID);
|
|
||||||
if (sqlCreateHWIDLog == null)
|
|
||||||
sqlCreateHWIDLog = "INSERT INTO %s (hwidId, newPublicKey) VALUES (?, ?)".formatted(tableHWIDLog);
|
|
||||||
if (sqlUpdateHardwarePublicKey == null)
|
|
||||||
sqlUpdateHardwarePublicKey = "UPDATE %s SET publicKey = ? WHERE id = ?".formatted(tableHWID);
|
|
||||||
sqlUpdateHardwareBanned = "UPDATE %s SET banned = ? WHERE id = ?".formatted(tableHWID);
|
|
||||||
sqlUpdateUsers = "UPDATE %s SET %s = ? WHERE %s = ?".formatted(table, hardwareIdColumn, uuidColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String makeUserCols() {
|
|
||||||
return super.makeUserCols().concat(", ").concat(hardwareIdColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SQLUser constructUser(ResultSet set) throws SQLException {
|
|
||||||
return set.next() ? new SQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
|
||||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), set.getLong(hardwareIdColumn)) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SQLUserHardware fetchHardwareInfo(ResultSet set) throws SQLException {
|
|
||||||
HardwareReportRequest.HardwareInfo hardwareInfo = new HardwareReportRequest.HardwareInfo();
|
|
||||||
hardwareInfo.hwDiskId = set.getString("hwDiskId");
|
|
||||||
hardwareInfo.baseboardSerialNumber = set.getString("baseboardSerialNumber");
|
|
||||||
byte[] displayId = set.getBytes("displayId");
|
|
||||||
hardwareInfo.displayId = displayId == null ? null : displayId;
|
|
||||||
hardwareInfo.bitness = set.getInt("bitness");
|
|
||||||
hardwareInfo.totalMemory = set.getLong("totalMemory");
|
|
||||||
hardwareInfo.logicalProcessors = set.getInt("logicalProcessors");
|
|
||||||
hardwareInfo.physicalProcessors = set.getInt("physicalProcessors");
|
|
||||||
hardwareInfo.processorMaxFreq = set.getLong("processorMaxFreq");
|
|
||||||
hardwareInfo.battery = set.getBoolean("battery");
|
|
||||||
hardwareInfo.graphicCard = set.getString("graphicCard");
|
|
||||||
byte[] publicKey = set.getBytes("publicKey");
|
|
||||||
long id = set.getLong("id");
|
|
||||||
boolean banned = set.getBoolean("banned");
|
|
||||||
return new SQLUserHardware(hardwareInfo, publicKey, id, banned);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setUserHardwareId(Connection connection, UUID uuid, long hwidId) throws SQLException {
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlUpdateUsers);
|
|
||||||
s.setLong(1, hwidId);
|
|
||||||
s.setString(2, uuid.toString());
|
|
||||||
s.executeUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserHardware getHardwareInfoByPublicKey(byte[] publicKey) {
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByPublicKey);
|
|
||||||
s.setBytes(1, publicKey);
|
|
||||||
try (ResultSet set = s.executeQuery()) {
|
|
||||||
if (set.next()) {
|
|
||||||
connection.commit();
|
|
||||||
return fetchHardwareInfo(set);
|
|
||||||
} else {
|
|
||||||
connection.commit();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException throwables) {
|
|
||||||
logger.error("SQL Error", throwables);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info) {
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareByData);
|
|
||||||
try (ResultSet set = s.executeQuery()) {
|
|
||||||
while (set.next()) {
|
|
||||||
SQLUserHardware hw = fetchHardwareInfo(set);
|
|
||||||
AuthSupportHardware.HardwareInfoCompareResult result = compareHardwareInfo(hw.getHardwareInfo(), info);
|
|
||||||
if (result.compareLevel > criticalCompareLevel) {
|
|
||||||
connection.commit();
|
|
||||||
return hw;
|
|
||||||
} else {
|
|
||||||
connection.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException throwables) {
|
|
||||||
logger.error("SQL Error", throwables);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserHardware getHardwareInfoById(String id) {
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlFindHardwareById);
|
|
||||||
s.setLong(1, Long.parseLong(id));
|
|
||||||
try (ResultSet set = s.executeQuery()) {
|
|
||||||
if (set.next()) {
|
|
||||||
connection.commit();
|
|
||||||
return fetchHardwareInfo(set);
|
|
||||||
} else {
|
|
||||||
connection.commit();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException throwables) {
|
|
||||||
logger.error("SQL Error", throwables);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey) {
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlCreateHardware, Statement.RETURN_GENERATED_KEYS);
|
|
||||||
s.setBytes(1, publicKey);
|
|
||||||
s.setString(2, hardwareInfo.hwDiskId);
|
|
||||||
s.setString(3, hardwareInfo.baseboardSerialNumber);
|
|
||||||
s.setBytes(4, hardwareInfo.displayId == null ? null : hardwareInfo.displayId);
|
|
||||||
s.setInt(5, hardwareInfo.bitness);
|
|
||||||
s.setLong(6, hardwareInfo.totalMemory);
|
|
||||||
s.setInt(7, hardwareInfo.logicalProcessors);
|
|
||||||
s.setInt(8, hardwareInfo.physicalProcessors);
|
|
||||||
s.setLong(9, hardwareInfo.processorMaxFreq);
|
|
||||||
s.setString(10, hardwareInfo.graphicCard);
|
|
||||||
s.setBoolean(11, hardwareInfo.battery);
|
|
||||||
s.executeUpdate();
|
|
||||||
try (ResultSet generatedKeys = s.getGeneratedKeys()) {
|
|
||||||
if (generatedKeys.next()) {
|
|
||||||
//writeHwidLog(connection, generatedKeys.getLong(1), publicKey);
|
|
||||||
long id = generatedKeys.getLong(1);
|
|
||||||
connection.commit();
|
|
||||||
return new SQLUserHardware(hardwareInfo, publicKey, id, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
connection.commit();
|
|
||||||
return null;
|
|
||||||
} catch (SQLException throwables) {
|
|
||||||
logger.error("SQL Error", throwables);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectUserAndHardware(UserSession userSession, UserHardware hardware) {
|
|
||||||
AbstractSQLCoreProvider.SQLUserSession SQLUserSession = (AbstractSQLCoreProvider.SQLUserSession) userSession;
|
|
||||||
SQLUser SQLUser = (SQLUser) SQLUserSession.getUser();
|
|
||||||
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
|
||||||
if (SQLUser.hwidId == SQLUserHardware.id) return;
|
|
||||||
SQLUser.hwidId = SQLUserHardware.id;
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
setUserHardwareId(connection, SQLUser.getUUID(), SQLUserHardware.id);
|
|
||||||
} catch (SQLException throwables) {
|
|
||||||
logger.error("SQL Error", throwables);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey) {
|
|
||||||
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
|
||||||
SQLUserHardware.publicKey = publicKey;
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
connection.setAutoCommit(false);
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwarePublicKey);
|
|
||||||
s.setBytes(1, publicKey);
|
|
||||||
s.setLong(2, SQLUserHardware.id);
|
|
||||||
s.executeUpdate();
|
|
||||||
connection.commit();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("SQL error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterable<User> getUsersByHardwareInfo(UserHardware hardware) {
|
|
||||||
List<User> users = new LinkedList<>();
|
|
||||||
try (Connection c = holder.getConnection()) {
|
|
||||||
c.setAutoCommit(false);
|
|
||||||
PreparedStatement s = c.prepareStatement(sqlUsersByHwidId);
|
|
||||||
s.setLong(1, Long.parseLong(hardware.getId()));
|
|
||||||
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
|
||||||
try (ResultSet set = s.executeQuery()) {
|
|
||||||
while (!set.isLast()) {
|
|
||||||
users.add(constructUser(set));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.commit();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("SQL error", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void banHardware(UserHardware hardware) {
|
|
||||||
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
|
||||||
SQLUserHardware.banned = true;
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
|
||||||
s.setBoolean(1, true);
|
|
||||||
s.setLong(2, SQLUserHardware.id);
|
|
||||||
s.executeUpdate();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("SQL Error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unbanHardware(UserHardware hardware) {
|
|
||||||
SQLUserHardware SQLUserHardware = (SQLUserHardware) hardware;
|
|
||||||
SQLUserHardware.banned = false;
|
|
||||||
try (Connection connection = holder.getConnection()) {
|
|
||||||
PreparedStatement s = connection.prepareStatement(sqlUpdateHardwareBanned);
|
|
||||||
s.setBoolean(1, false);
|
|
||||||
s.setLong(2, SQLUserHardware.id);
|
|
||||||
s.executeUpdate();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.error("SQL error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AbstractSQLCoreProvider.SQLUserSession createSession(AbstractSQLCoreProvider.SQLUser user) {
|
|
||||||
return new SQLUserSession(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserSession extendedCheckServer(Client client, String username, String serverID) {
|
|
||||||
AbstractSQLCoreProvider.SQLUser user = (AbstractSQLCoreProvider.SQLUser) getUserByUsername(username);
|
|
||||||
if (user == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (user.getUsername().equals(username) && user.getServerId().equals(serverID)) {
|
|
||||||
return createSession(user);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SQLUserSession extends AbstractSQLCoreProvider.SQLUserSession implements UserSessionSupportHardware {
|
|
||||||
private transient SQLUser SQLUser;
|
|
||||||
protected transient SQLUserHardware hardware;
|
|
||||||
|
|
||||||
public SQLUserSession(AbstractSQLCoreProvider.SQLUser user) {
|
|
||||||
super(user);
|
|
||||||
SQLUser = (SQLUser) user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHardwareId() {
|
|
||||||
return SQLUser.hwidId == 0 ? null : String.valueOf(SQLUser.hwidId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserHardware getHardware() {
|
|
||||||
if(hardware == null) {
|
|
||||||
hardware = (SQLUserHardware) getHardwareInfoById(String.valueOf(SQLUser.hwidId));
|
|
||||||
}
|
|
||||||
return hardware;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SQLUserHardware implements UserHardware {
|
|
||||||
private final HardwareReportRequest.HardwareInfo hardwareInfo;
|
|
||||||
private final long id;
|
|
||||||
private byte[] publicKey;
|
|
||||||
private boolean banned;
|
|
||||||
|
|
||||||
public SQLUserHardware(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 "SQLUserHardware{" +
|
|
||||||
"hardwareInfo=" + hardwareInfo +
|
|
||||||
", publicKey=" + (publicKey == null ? null : new String(Base64.getEncoder().encode(publicKey))) +
|
|
||||||
", id=" + id +
|
|
||||||
", banned=" + banned +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SQLUser extends AbstractSQLCoreProvider.SQLUser {
|
|
||||||
protected long hwidId;
|
|
||||||
|
|
||||||
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password, long hwidId) {
|
|
||||||
super(uuid, username, accessToken, serverId, password);
|
|
||||||
this.hwidId = hwidId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SQLUser{" +
|
|
||||||
"uuid=" + uuid +
|
|
||||||
", username='" + username + '\'' +
|
|
||||||
", permissions=" + permissions +
|
|
||||||
", hwidId=" + hwidId +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,5 +6,5 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface AuthSupportExtendedCheckServer {
|
public interface AuthSupportExtendedCheckServer {
|
||||||
UserSession extendedCheckServer(Client client, String username, String serverID);
|
UserSession extendedCheckServer(Client client, String username, String serverID) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
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) {
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
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)
|
|
||||||
.requireIssuer(openIDConfig.issuer())
|
|
||||||
.require("azp", openIDConfig.clientId())
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
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, String issuer,
|
|
||||||
ClaimExtractorConfig extractorConfig) {
|
|
||||||
|
|
||||||
public record ClaimExtractorConfig(String usernameClaim, String uuidClaim) {}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.core.openid;
|
|
||||||
|
|
||||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.core.openid;
|
|
||||||
|
|
||||||
public record TokenResponse(String accessToken, long accessTokenExpiresIn,
|
|
||||||
String refreshToken, long refreshTokenExpiresIn) {
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
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.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class LocalProfileProvider extends ProfileProvider {
|
|
||||||
public String profilesDir = "profiles";
|
|
||||||
private transient volatile Map<Path, ClientProfile> profilesMap;
|
|
||||||
private transient volatile Set<ClientProfile> profilesList; // Cache
|
|
||||||
@Override
|
|
||||||
public void sync() throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
if (!IOHelper.isDir(profilesDirPath))
|
|
||||||
Files.createDirectory(profilesDirPath);
|
|
||||||
Map<Path, ClientProfile> newProfiles = new HashMap<>();
|
|
||||||
IOHelper.walk(profilesDirPath, new ProfilesFileVisitor(newProfiles), false);
|
|
||||||
Set<ClientProfile> newProfilesList = new HashSet<>(newProfiles.values());
|
|
||||||
profilesMap = newProfiles;
|
|
||||||
profilesList = newProfilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
|
||||||
return profilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addProfile(ClientProfile profile) throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
ClientProfile oldProfile;
|
|
||||||
Path target = null;
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
target = e.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(target == null) {
|
|
||||||
target = profilesDirPath.resolve(profile.getTitle()+".json");
|
|
||||||
oldProfile = profilesMap.get(target);
|
|
||||||
if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) {
|
|
||||||
throw new FileAlreadyExistsException(target.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try (BufferedWriter writer = IOHelper.newWriter(target)) {
|
|
||||||
Launcher.gsonManager.configGson.toJson(profile, writer);
|
|
||||||
}
|
|
||||||
addProfile(target, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteProfile(ClientProfile profile) throws IOException {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
Files.deleteIfExists(e.getKey());
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addProfile(Path path, ClientProfile profile) {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profilesMap.put(path, profile);
|
|
||||||
profilesList.add(profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
|
||||||
private final Map<Path, ClientProfile> result;
|
|
||||||
private final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
private ProfilesFileVisitor(Map<Path, ClientProfile> result) {
|
|
||||||
this.result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
|
||||||
|
|
||||||
// Read profile
|
|
||||||
ClientProfile profile;
|
|
||||||
try (BufferedReader reader = IOHelper.newReader(file)) {
|
|
||||||
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
|
||||||
}
|
|
||||||
profile.verify();
|
|
||||||
|
|
||||||
// Add SIGNED profile to result list
|
|
||||||
result.put(file.toAbsolutePath(), profile);
|
|
||||||
return super.visitFile(file, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.utils.ProviderMap;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class ProfileProvider {
|
|
||||||
public static final ProviderMap<ProfileProvider> providers = new ProviderMap<>("ProfileProvider");
|
|
||||||
private static boolean registredProviders = false;
|
|
||||||
protected transient LaunchServer server;
|
|
||||||
|
|
||||||
public static void registerProviders() {
|
|
||||||
if (!registredProviders) {
|
|
||||||
providers.register("local", LocalProfileProvider.class);
|
|
||||||
registredProviders = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void sync() throws IOException;
|
|
||||||
|
|
||||||
public abstract Set<ClientProfile> getProfiles();
|
|
||||||
|
|
||||||
public abstract void addProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public abstract void deleteProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(UUID uuid) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getUUID().equals(uuid)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(String title) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getTitle().equals(title)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ClientProfile> getProfiles(Client client) {
|
|
||||||
List<ClientProfile> profileList;
|
|
||||||
Set<ClientProfile> serverProfiles = getProfiles();
|
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) {
|
|
||||||
profileList = new ArrayList<>(4);
|
|
||||||
for (ClientProfile profile : serverProfiles) {
|
|
||||||
if (protectHandler.canGetProfile(profile, client)) {
|
|
||||||
profileList.add(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
profileList = List.copyOf(serverProfiles);
|
|
||||||
}
|
|
||||||
return profileList;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.updates;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launcher.core.serialize.HInput;
|
|
||||||
import pro.gravit.launcher.core.serialize.HOutput;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.DirectoryStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class LocalUpdatesProvider extends UpdatesProvider {
|
|
||||||
private final transient Logger logger = LogManager.getLogger();
|
|
||||||
public String cacheFile = ".updates-cache";
|
|
||||||
public String updatesDir = "updates";
|
|
||||||
public boolean cacheUpdates = true;
|
|
||||||
private volatile transient Map<String, HashedDir> updatesDirMap;
|
|
||||||
|
|
||||||
private void writeCache(Path file) throws IOException {
|
|
||||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
|
||||||
output.writeLength(updatesDirMap.size(), 0);
|
|
||||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
|
||||||
output.writeString(entry.getKey(), 0);
|
|
||||||
entry.getValue().write(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readCache(Path file) throws IOException {
|
|
||||||
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
|
||||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
|
||||||
int size = input.readLength(0);
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
String name = input.readString(0);
|
|
||||||
HashedDir dir = new HashedDir(input);
|
|
||||||
updatesDirMap.put(name, dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
|
||||||
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readUpdatesFromCache() throws IOException {
|
|
||||||
readCache(Path.of(cacheFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readUpdatesDir() throws IOException {
|
|
||||||
var cacheFilePath = Path.of(cacheFile);
|
|
||||||
if (cacheUpdates) {
|
|
||||||
if (Files.exists(cacheFilePath)) {
|
|
||||||
try {
|
|
||||||
readCache(cacheFilePath);
|
|
||||||
return;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Read updates cache failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sync(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
super.init(server);
|
|
||||||
try {
|
|
||||||
if (!IOHelper.isDir(Path.of(updatesDir)))
|
|
||||||
Files.createDirectory(Path.of(updatesDir));
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("Updates not synced", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void syncInitially() throws IOException {
|
|
||||||
readUpdatesDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sync(Collection<String> dirs) throws IOException {
|
|
||||||
logger.info("Syncing updates dir");
|
|
||||||
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
|
||||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(Path.of(updatesDir))) {
|
|
||||||
for (final Path updateDir : dirStream) {
|
|
||||||
if (Files.isHidden(updateDir))
|
|
||||||
continue; // Skip hidden
|
|
||||||
|
|
||||||
// Resolve name and verify is dir
|
|
||||||
String name = IOHelper.getFileName(updateDir);
|
|
||||||
if (!IOHelper.isDir(updateDir)) {
|
|
||||||
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
|
||||||
logger.warn("Not update dir: '{}'", name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add from previous map (it's guaranteed to be non-null)
|
|
||||||
if (dirs != null && !dirs.contains(name)) {
|
|
||||||
HashedDir hdir = updatesDirMap.get(name);
|
|
||||||
if (hdir != null) {
|
|
||||||
newUpdatesDirMap.put(name, hdir);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync and sign update dir
|
|
||||||
logger.info("Syncing '{}' update dir", name);
|
|
||||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
|
||||||
newUpdatesDirMap.put(name, updateHDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
|
||||||
if (cacheUpdates) {
|
|
||||||
try {
|
|
||||||
writeCache(Path.of(cacheFile));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Write updates cache failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HashedDir getUpdatesDir(String updateName) {
|
|
||||||
return updatesDirMap.get(updateName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path resolveUpdateName(String updateName) {
|
|
||||||
if(updateName == null) {
|
|
||||||
return Path.of(updatesDir);
|
|
||||||
}
|
|
||||||
return Path.of(updatesDir).resolve(updateName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
for(var e : files.entrySet()) {
|
|
||||||
var target = path.resolve(e.getKey());
|
|
||||||
var source = e.getValue();
|
|
||||||
IOHelper.createParentDirs(target);
|
|
||||||
if(deleteAfterUpload) {
|
|
||||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
} else {
|
|
||||||
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Path> download(String updateName, List<String> files) {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
Map<String, Path> map = new HashMap<>();
|
|
||||||
for(var e : files) {
|
|
||||||
map.put(e, path.resolve(e));
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String updateName, List<String> files) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
for(var e : files) {
|
|
||||||
var target = path.resolve(e);
|
|
||||||
Files.delete(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String updateName) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
IOHelper.deleteDir(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(String updateName) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
Files.createDirectories(path);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.updates;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.utils.ProviderMap;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class UpdatesProvider {
|
|
||||||
public static final ProviderMap<UpdatesProvider> providers = new ProviderMap<>("UpdatesProvider");
|
|
||||||
private static boolean registredProviders = false;
|
|
||||||
protected transient LaunchServer server;
|
|
||||||
|
|
||||||
public static void registerProviders() {
|
|
||||||
if (!registredProviders) {
|
|
||||||
providers.register("local", LocalUpdatesProvider.class);
|
|
||||||
registredProviders = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sync() throws IOException {
|
|
||||||
sync(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void syncInitially() throws IOException;
|
|
||||||
|
|
||||||
public abstract void sync(Collection<String> updateNames) throws IOException;
|
|
||||||
|
|
||||||
public abstract HashedDir getUpdatesDir(String updateName);
|
|
||||||
|
|
||||||
public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException;
|
|
||||||
|
|
||||||
public abstract Map<String, Path> download(String updateName, List<String> files);
|
|
||||||
|
|
||||||
public abstract void delete(String updateName, List<String> files) throws IOException;
|
|
||||||
|
|
||||||
public abstract void delete(String updateName) throws IOException;
|
|
||||||
|
|
||||||
public abstract void create(String updateName) throws IOException;
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,9 @@
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
import pro.gravit.utils.helper.CommonHelper;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -12,11 +14,11 @@
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public abstract class BinaryPipeline {
|
public class BinaryPipeline {
|
||||||
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
||||||
public final Path buildDir;
|
public final Path buildDir;
|
||||||
public final String nameFormat;
|
public final String nameFormat;
|
||||||
protected transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
public BinaryPipeline(Path buildDir, String nameFormat) {
|
public BinaryPipeline(Path buildDir, String nameFormat) {
|
||||||
this.buildDir = buildDir;
|
this.buildDir = buildDir;
|
||||||
|
@ -78,6 +80,27 @@ public Optional<LauncherBuildTask> getTaskBefore(Predicate<LauncherBuildTask> pr
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void build(Path target, boolean deleteTempFiles) throws IOException {
|
||||||
|
logger.info("Building launcher binary file");
|
||||||
|
Path thisPath = null;
|
||||||
|
long time_start = System.currentTimeMillis();
|
||||||
|
long time_this = time_start;
|
||||||
|
for (LauncherBuildTask task : tasks) {
|
||||||
|
logger.info("Task {}", task.getName());
|
||||||
|
Path oldPath = thisPath;
|
||||||
|
thisPath = task.process(oldPath);
|
||||||
|
long time_task_end = System.currentTimeMillis();
|
||||||
|
long time_task = time_task_end - time_this;
|
||||||
|
time_this = time_task_end;
|
||||||
|
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
||||||
|
}
|
||||||
|
long time_end = System.currentTimeMillis();
|
||||||
|
if (deleteTempFiles) IOHelper.move(thisPath, target);
|
||||||
|
else IOHelper.copy(thisPath, target);
|
||||||
|
IOHelper.deleteDir(buildDir, false);
|
||||||
|
logger.info("Build successful from {} millis", time_end - time_start);
|
||||||
|
}
|
||||||
|
|
||||||
public String nextName(String taskName) {
|
public String nextName(String taskName) {
|
||||||
return nameFormat.formatted(taskName);
|
return nameFormat.formatted(taskName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package pro.gravit.launchserver.binary;
|
package pro.gravit.launchserver.binary;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class LauncherBinary extends BinaryPipeline {
|
public abstract class LauncherBinary extends BinaryPipeline {
|
||||||
public final LaunchServer server;
|
public final LaunchServer server;
|
||||||
|
@ -22,27 +19,11 @@ protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path resolve(LaunchServer server, String ext) {
|
public static Path resolve(LaunchServer server, String ext) {
|
||||||
return Path.of(server.config.binaryName + ext);
|
return server.config.copyBinaries ? server.updatesDir.resolve(server.config.binaryName + ext) : server.dir.resolve(server.config.binaryName + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void build() throws IOException {
|
public void build() throws IOException {
|
||||||
logger.info("Building launcher binary file");
|
build(syncBinaryFile, server.config.launcher.deleteTempFiles);
|
||||||
Path thisPath = null;
|
|
||||||
long time_start = System.currentTimeMillis();
|
|
||||||
long time_this = time_start;
|
|
||||||
for (LauncherBuildTask task : tasks) {
|
|
||||||
logger.info("Task {}", task.getName());
|
|
||||||
Path oldPath = thisPath;
|
|
||||||
thisPath = task.process(oldPath);
|
|
||||||
long time_task_end = System.currentTimeMillis();
|
|
||||||
long time_task = time_task_end - time_this;
|
|
||||||
time_this = time_task_end;
|
|
||||||
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
|
||||||
}
|
|
||||||
long time_end = System.currentTimeMillis();
|
|
||||||
server.config.updatesProvider.upload(null, Map.of(syncBinaryFile.toString(), thisPath), true);
|
|
||||||
IOHelper.deleteDir(buildDir, false);
|
|
||||||
logger.info("Build successful from {} millis", time_end - time_start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean exists() {
|
public final boolean exists() {
|
||||||
|
@ -56,14 +37,10 @@ public final byte[] getDigest() {
|
||||||
public void init() {
|
public void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean sync() {
|
public final boolean sync() throws IOException {
|
||||||
try {
|
boolean exists = exists();
|
||||||
var target = syncBinaryFile.toString();
|
digest = exists ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(syncBinaryFile)) : null;
|
||||||
var path = server.config.updatesProvider.download(null, List.of(target)).get(target);
|
|
||||||
digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(path));
|
return exists;
|
||||||
return true;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
import pro.gravit.utils.helper.UnpackHelper;
|
import pro.gravit.utils.helper.UnpackHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -34,10 +37,8 @@ public Path process(Path inputFile) throws IOException {
|
||||||
server.launcherBinary.addonLibs.clear();
|
server.launcherBinary.addonLibs.clear();
|
||||||
server.launcherBinary.files.clear();
|
server.launcherBinary.files.clear();
|
||||||
IOHelper.walk(server.launcherLibraries, new ListFileVisitor(server.launcherBinary.coreLibs), false);
|
IOHelper.walk(server.launcherLibraries, new ListFileVisitor(server.launcherBinary.coreLibs), false);
|
||||||
if(Files.isDirectory(server.launcherLibrariesCompile)) {
|
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
||||||
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
try(Stream<Path> stream = Files.walk(server.launcherPack).filter((e) -> {
|
||||||
}
|
|
||||||
try(Stream<Path> stream = Files.walk(server.launcherPack, FileVisitOption.FOLLOW_LINKS).filter((e) -> {
|
|
||||||
try {
|
try {
|
||||||
return !Files.isDirectory(e) && !Files.isHidden(e);
|
return !Files.isDirectory(e) && !Files.isHidden(e);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
|
|
@ -32,7 +32,6 @@ public void invoke(String... args) throws Exception {
|
||||||
boolean value = Boolean.parseBoolean(args[0]);
|
boolean value = Boolean.parseBoolean(args[0]);
|
||||||
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
|
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
|
||||||
Configuration config = ctx.getConfiguration();
|
Configuration config = ctx.getConfiguration();
|
||||||
config.getWatchManager().setIntervalSeconds(-1);
|
|
||||||
LoggerConfig loggerConfig = config.getLoggerConfig("pro.gravit");
|
LoggerConfig loggerConfig = config.getLoggerConfig("pro.gravit");
|
||||||
loggerConfig.setLevel(value ? Level.TRACE : Level.DEBUG);
|
loggerConfig.setLevel(value ? Level.TRACE : Level.DEBUG);
|
||||||
ctx.updateLoggers();
|
ctx.updateLoggers();
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launcher.base.Launcher;
|
import pro.gravit.launcher.base.Launcher;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
@ -13,6 +12,7 @@
|
||||||
import pro.gravit.utils.command.CommandException;
|
import pro.gravit.utils.command.CommandException;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -61,11 +61,9 @@ public void invoke(String... args) throws IOException, CommandException {
|
||||||
try {
|
try {
|
||||||
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
|
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
|
||||||
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
|
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
|
||||||
var builder = new ClientProfileBuilder(clientProfile);
|
clientProfile.setTitle(dirName);
|
||||||
builder.setTitle(dirName);
|
clientProfile.setDir(dirName);
|
||||||
builder.setDir(dirName);
|
clientProfile.setUUID(UUID.randomUUID());
|
||||||
builder.setUuid(UUID.randomUUID());
|
|
||||||
clientProfile = builder.createClientProfile();
|
|
||||||
if (clientProfile.getServers() != null) {
|
if (clientProfile.getServers() != null) {
|
||||||
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
|
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
|
||||||
if (serverProfile != null) {
|
if (serverProfile != null) {
|
||||||
|
@ -96,7 +94,10 @@ public void invoke(String... args) throws IOException, CommandException {
|
||||||
isMirrorClientDownload = true;
|
isMirrorClientDownload = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.config.profileProvider.addProfile(clientProfile);
|
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
|
||||||
|
dirName, "json"))) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(clientProfile, writer);
|
||||||
|
}
|
||||||
|
|
||||||
// Finished
|
// Finished
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
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.ClientProfile;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -23,7 +25,7 @@ public CloneProfileCommand(LaunchServer server) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArgsDescription() {
|
public String getArgsDescription() {
|
||||||
return "[profile title/uuid] [new profile title]";
|
return "[profile file name] [new profile title]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,16 +36,16 @@ public String getUsageDescription() {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 2);
|
verifyArgs(args, 2);
|
||||||
ClientProfile profile;
|
var profilePath = server.profilesDir.resolve(args[0].concat(".json"));
|
||||||
try {
|
if(!Files.exists(profilePath)) {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
logger.error("File {} not found", profilePath);
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
|
||||||
}
|
}
|
||||||
var builder = new ClientProfileBuilder(profile);
|
ClientProfile profile;
|
||||||
builder.setTitle(args[1]);
|
try(Reader reader = IOHelper.newReader(profilePath)) {
|
||||||
builder.setUuid(UUID.randomUUID());
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
profile.setTitle(args[1]);
|
||||||
|
profile.setUUID(UUID.randomUUID());
|
||||||
if(profile.getServers().size() == 1) {
|
if(profile.getServers().size() == 1) {
|
||||||
profile.getServers().getFirst().name = args[1];
|
profile.getServers().getFirst().name = args[1];
|
||||||
}
|
}
|
||||||
|
@ -59,9 +61,11 @@ public void invoke(String... args) throws Exception {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
builder.setDir(args[1]);
|
profile.setDir(args[1]);
|
||||||
profile = builder.createClientProfile();
|
var targetPath = server.profilesDir.resolve(args[1].concat(".json"));
|
||||||
server.config.profileProvider.addProfile(profile);
|
try(Writer writer = IOHelper.newWriter(targetPath)) {
|
||||||
|
Launcher.gsonManager.gson.toJson(profile, writer);
|
||||||
|
}
|
||||||
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
server.syncUpdatesDir(List.of(args[1]));
|
server.syncUpdatesDir(List.of(args[1]));
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
public class DeleteProfileCommand extends Command {
|
public class DeleteProfileCommand extends Command {
|
||||||
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
||||||
|
@ -27,24 +28,29 @@ public String getUsageDescription() {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 1);
|
verifyArgs(args, 1);
|
||||||
ClientProfile profile;
|
ClientProfile profile = null;
|
||||||
try {
|
for(var p : server.getProfiles()) {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
if(p.getUUID().toString().equals(args[0]) || p.getTitle().equals(args[0])) {
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
profile = p;
|
||||||
} catch (IllegalArgumentException ex) {
|
break;
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
}
|
||||||
}
|
}
|
||||||
if(profile == null) {
|
if(profile == null) {
|
||||||
logger.error("Profile {} not found", args[0]);
|
logger.error("Profile {} not found", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", profile.getDir());
|
var clientDir = server.updatesDir.resolve(profile.getDir()).toAbsolutePath();
|
||||||
|
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", clientDir);
|
||||||
if(!showApplyDialog("Continue?")) {
|
if(!showApplyDialog("Continue?")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
logger.info("Delete {}", clientDir);
|
||||||
server.config.profileProvider.deleteProfile(profile);
|
IOHelper.deleteDir(clientDir, true);
|
||||||
logger.info("Delete {}", profile.getDir());
|
var profileFile = profile.getProfileFilePath();
|
||||||
server.config.updatesProvider.delete(profile.getDir());
|
if(profileFile == null) {
|
||||||
|
profileFile = server.profilesDir.resolve(profile.getTitle().concat(".json"));
|
||||||
|
}
|
||||||
|
logger.info("Delete {}", profileFile);
|
||||||
|
Files.deleteIfExists(profileFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public String getUsageDescription() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) {
|
public void invoke(String... args) throws Exception {
|
||||||
for(var profile : server.getProfiles()) {
|
for(var profile : server.getProfiles()) {
|
||||||
logger.info("{} ({}) {}", profile.getTitle(), profile.getVersion().toString(), profile.isLimited() ? "limited" : "");
|
logger.info("{} ({}) {}", profile.getTitle(), profile.getVersion().toString(), profile.isLimited() ? "limited" : "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,14 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
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.ClientProfile;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
public class MakeProfileCommand extends Command {
|
public class MakeProfileCommand extends Command {
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
|
@ -33,7 +37,9 @@ public void invoke(String... args) throws Exception {
|
||||||
logger.info("Detected option {}", option);
|
logger.info("Detected option {}", option);
|
||||||
}
|
}
|
||||||
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
||||||
server.config.profileProvider.addProfile(profile);
|
try (Writer writer = IOHelper.newWriter(server.profilesDir.resolve(args[0].concat(".json")))) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(profile, writer);
|
||||||
|
}
|
||||||
logger.info("Profile {} created", args[0]);
|
logger.info("Profile {} created", args[0]);
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,17 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
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.ClientProfile;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class SaveProfilesCommand extends Command {
|
public class SaveProfilesCommand extends Command {
|
||||||
|
@ -15,6 +22,21 @@ public SaveProfilesCommand(LaunchServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
serverProfile.name = profile.getTitle();
|
||||||
|
serverProfile.serverAddress = profile.getServerAddress();
|
||||||
|
serverProfile.serverPort = profile.getServerPort();
|
||||||
|
profile.getServers().add(serverProfile);
|
||||||
|
}
|
||||||
|
try (Writer w = IOHelper.newWriter(path)) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(profile, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArgsDescription() {
|
public String getArgsDescription() {
|
||||||
return "[profile names...]";
|
return "[profile names...]";
|
||||||
|
@ -30,14 +52,17 @@ public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 1);
|
verifyArgs(args, 1);
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
for (String profileName : args) {
|
for (String profileName : args) {
|
||||||
ClientProfile profile;
|
Path profilePath = server.profilesDir.resolve(profileName.concat(".json"));
|
||||||
try {
|
if (!Files.exists(profilePath)) {
|
||||||
UUID uuid = UUID.fromString(profileName);
|
logger.error("Profile {} not found", profilePath.toString());
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
return;
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
profile = server.config.profileProvider.getProfile(profileName);
|
|
||||||
}
|
}
|
||||||
server.config.profileProvider.addProfile(profile);
|
ClientProfile profile;
|
||||||
|
try (Reader reader = IOHelper.newReader(profilePath)) {
|
||||||
|
profile = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
saveProfile(profile, profilePath);
|
||||||
|
logger.info("Profile {} save successful", profilePath.toString());
|
||||||
}
|
}
|
||||||
server.syncProfilesDir();
|
server.syncProfilesDir();
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ public void invoke(String... args) throws Exception {
|
||||||
Files.deleteIfExists(proguardConf.mappings);
|
Files.deleteIfExists(proguardConf.mappings);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return commands;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ProGuardMultiReleaseFixer implements LauncherBuildTask {
|
public static class ProGuardMultiReleaseFixer implements LauncherBuildTask {
|
||||||
|
@ -213,7 +213,7 @@ public Path process(Path inputFile) throws IOException {
|
||||||
args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString());
|
args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString());
|
||||||
args.addAll(component.jvmArgs);
|
args.addAll(component.jvmArgs);
|
||||||
args.add("-cp");
|
args.add("-cp");
|
||||||
try(Stream<Path> files = Files.walk(server.librariesDir, FileVisitOption.FOLLOW_LINKS)) {
|
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
|
||||||
args.add(files
|
args.add(files
|
||||||
.filter(e -> e.getFileName().toString().endsWith(".jar"))
|
.filter(e -> e.getFileName().toString().endsWith(".jar"))
|
||||||
.map(path -> path.toAbsolutePath().toString())
|
.map(path -> path.toAbsolutePath().toString())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.launchserver.config;
|
package pro.gravit.launchserver.config;
|
||||||
|
|
||||||
|
import io.netty.channel.epoll.Epoll;
|
||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
@ -8,17 +9,12 @@
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.profiles.LocalProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||||
import pro.gravit.launchserver.auth.updates.LocalUpdatesProvider;
|
|
||||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
|
||||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.components.ProGuardComponent;
|
import pro.gravit.launchserver.components.ProGuardComponent;
|
||||||
import pro.gravit.launchserver.socket.NettyObjectFactory;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -34,13 +30,12 @@ public final class LaunchServerConfig {
|
||||||
public String[] mirrors;
|
public String[] mirrors;
|
||||||
public String binaryName;
|
public String binaryName;
|
||||||
public boolean copyBinaries = true;
|
public boolean copyBinaries = true;
|
||||||
|
public boolean cacheUpdates = true;
|
||||||
public LauncherConfig.LauncherEnvironment env;
|
public LauncherConfig.LauncherEnvironment env;
|
||||||
public Map<String, AuthProviderPair> auth;
|
public Map<String, AuthProviderPair> auth;
|
||||||
// Handlers & Providers
|
// Handlers & Providers
|
||||||
public ProtectHandler protectHandler;
|
public ProtectHandler protectHandler;
|
||||||
public Map<String, Component> components;
|
public Map<String, Component> components;
|
||||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
|
||||||
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
|
||||||
public NettyConfig netty;
|
public NettyConfig netty;
|
||||||
public LauncherConf launcher;
|
public LauncherConf launcher;
|
||||||
public JarSignerConf sign;
|
public JarSignerConf sign;
|
||||||
|
@ -64,7 +59,12 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
newConfig.netty.fileServerEnabled = true;
|
newConfig.netty.fileServerEnabled = true;
|
||||||
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
||||||
newConfig.netty.performance = new NettyPerformanceConfig();
|
newConfig.netty.performance = new NettyPerformanceConfig();
|
||||||
newConfig.netty.performance.mode = NettyObjectFactory.NettyFactoryMode.AUTO;
|
try {
|
||||||
|
newConfig.netty.performance.usingEpoll = Epoll.isAvailable();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Epoll class line 51+ catch (Exception) but Error will be thrown by System.load
|
||||||
|
newConfig.netty.performance.usingEpoll = false;
|
||||||
|
} // such as on ARM
|
||||||
newConfig.netty.performance.bossThread = 2;
|
newConfig.netty.performance.bossThread = 2;
|
||||||
newConfig.netty.performance.workerThread = 8;
|
newConfig.netty.performance.workerThread = 8;
|
||||||
newConfig.netty.performance.schedulerThread = 2;
|
newConfig.netty.performance.schedulerThread = 2;
|
||||||
|
@ -85,7 +85,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||||
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
||||||
newConfig.components.put("proguard", proGuardComponent);
|
newConfig.components.put("proguard", proGuardComponent);
|
||||||
newConfig.profileProvider = new LocalProfileProvider();
|
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,14 +166,6 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
server.registerObject("protectHandler", protectHandler);
|
server.registerObject("protectHandler", protectHandler);
|
||||||
protectHandler.init(server);
|
protectHandler.init(server);
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
|
||||||
server.registerObject("profileProvider", profileProvider);
|
|
||||||
profileProvider.init(server);
|
|
||||||
}
|
|
||||||
if(updatesProvider != null) {
|
|
||||||
server.registerObject("updatesProvider", updatesProvider);
|
|
||||||
updatesProvider.init(server);
|
|
||||||
}
|
|
||||||
if (components != null) {
|
if (components != null) {
|
||||||
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
||||||
}
|
}
|
||||||
|
@ -215,14 +206,6 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
server.unregisterObject("protectHandler", protectHandler);
|
server.unregisterObject("protectHandler", protectHandler);
|
||||||
protectHandler.close();
|
protectHandler.close();
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
|
||||||
server.unregisterObject("profileProvider", profileProvider);
|
|
||||||
profileProvider.close();
|
|
||||||
}
|
|
||||||
if(updatesProvider != null) {
|
|
||||||
server.unregisterObject("updatesProvider", updatesProvider);
|
|
||||||
updatesProvider.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class JarSignerConf {
|
public static class JarSignerConf {
|
||||||
|
@ -272,7 +255,7 @@ public static class NettyConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class NettyPerformanceConfig {
|
public static class NettyPerformanceConfig {
|
||||||
public NettyObjectFactory.NettyFactoryMode mode = NettyObjectFactory.NettyFactoryMode.AUTO;
|
public boolean usingEpoll;
|
||||||
public int bossThread;
|
public int bossThread;
|
||||||
public int workerThread;
|
public int workerThread;
|
||||||
public int schedulerThread;
|
public int schedulerThread;
|
||||||
|
|
|
@ -49,6 +49,7 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
||||||
// Official Mojang launcher java arguments
|
// Official Mojang launcher java arguments
|
||||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) <= 0) {
|
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) <= 0) {
|
||||||
// lwjgl3ify arguments https://github.com/GTNewHorizons/lwjgl3ify
|
// lwjgl3ify arguments https://github.com/GTNewHorizons/lwjgl3ify
|
||||||
|
jvmArgs.add("-Djava.security.manager=allow");
|
||||||
jvmArgs.add("--add-opens");
|
jvmArgs.add("--add-opens");
|
||||||
jvmArgs.add("java.base/jdk.internal.loader=ALL-UNNAMED");
|
jvmArgs.add("java.base/jdk.internal.loader=ALL-UNNAMED");
|
||||||
jvmArgs.add("--add-opens");
|
jvmArgs.add("--add-opens");
|
||||||
|
@ -102,7 +103,6 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
||||||
}
|
}
|
||||||
if (fabric.isPresent()) {
|
if (fabric.isPresent()) {
|
||||||
builder.setAltClassPath(fabric.orElseThrow().getAltClassPath());
|
builder.setAltClassPath(fabric.orElseThrow().getAltClassPath());
|
||||||
jvmArgs.add("-Dsodium.checks.issue2561=false"); // Please don't check LWJL3 version (Sodium: https://github.com/CaffeineMC/sodium-fabric/issues/2561 )
|
|
||||||
}
|
}
|
||||||
if(quilt.isPresent()) {
|
if(quilt.isPresent()) {
|
||||||
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
||||||
|
@ -203,7 +203,7 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr
|
||||||
return "cpw.mods.modlauncher.Launcher";
|
return "cpw.mods.modlauncher.Launcher";
|
||||||
}
|
}
|
||||||
if (findOption(options, MakeProfileOptionFabric.class).isPresent()) {
|
if (findOption(options, MakeProfileOptionFabric.class).isPresent()) {
|
||||||
return "net.fabricmc.loader.impl.launch.knot.KnotClient";
|
return "net.fabricmc.loader.launch.knot.KnotClient";
|
||||||
}
|
}
|
||||||
if(findOption(options, MakeProfilesOptionsQuilt.class).isPresent()) {
|
if(findOption(options, MakeProfilesOptionsQuilt.class).isPresent()) {
|
||||||
return "org.quiltmc.loader.impl.launch.knot.KnotClient";
|
return "org.quiltmc.loader.impl.launch.knot.KnotClient";
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class LauncherModuleLoader {
|
||||||
|
|
||||||
public LauncherModuleLoader(LaunchServer server) {
|
public LauncherModuleLoader(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
modulesDir = server.launcherModulesDir;
|
modulesDir = server.dir.resolve("launcher-modules");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
public class CertificateManager {
|
public class CertificateManager {
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
public LauncherTrustManager trustManager;
|
public LauncherTrustManager trustManager;
|
||||||
private Path truststorePath;
|
|
||||||
|
|
||||||
public void writePrivateKey(Path file, PrivateKey privateKey) throws IOException {
|
public void writePrivateKey(Path file, PrivateKey privateKey) throws IOException {
|
||||||
writePrivateKey(IOHelper.newWriter(file), privateKey);
|
writePrivateKey(IOHelper.newWriter(file), privateKey);
|
||||||
|
@ -92,7 +91,6 @@ public X509CertificateHolder readCertificate(Reader reader) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readTrustStore(Path dir) throws IOException, CertificateException {
|
public void readTrustStore(Path dir) throws IOException, CertificateException {
|
||||||
this.truststorePath = dir;
|
|
||||||
if (!IOHelper.isDir(dir)) {
|
if (!IOHelper.isDir(dir)) {
|
||||||
Files.createDirectories(dir);
|
Files.createDirectories(dir);
|
||||||
try {
|
try {
|
||||||
|
@ -133,8 +131,4 @@ public LauncherTrustManager.CheckClassResult checkClass(Class<?> clazz) {
|
||||||
X509Certificate[] certificates = JVMHelper.getCertificates(clazz);
|
X509Certificate[] certificates = JVMHelper.getCertificates(clazz);
|
||||||
return trustManager.checkCertificates(certificates, trustManager::stdCertificateChecker);
|
return trustManager.checkCertificates(certificates, trustManager::stdCertificateChecker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getTruststorePath() {
|
|
||||||
return truststorePath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ public class KeyAgreementManager {
|
||||||
public final RSAPublicKey rsaPublicKey;
|
public final RSAPublicKey rsaPublicKey;
|
||||||
public final RSAPrivateKey rsaPrivateKey;
|
public final RSAPrivateKey rsaPrivateKey;
|
||||||
public final String legacySalt;
|
public final String legacySalt;
|
||||||
public final Path keyDirectory;
|
|
||||||
|
|
||||||
public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey, String legacySalt) {
|
public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivateKey, RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey, String legacySalt) {
|
||||||
this.ecdsaPublicKey = ecdsaPublicKey;
|
this.ecdsaPublicKey = ecdsaPublicKey;
|
||||||
|
@ -30,11 +29,9 @@ public KeyAgreementManager(ECPublicKey ecdsaPublicKey, ECPrivateKey ecdsaPrivate
|
||||||
this.rsaPublicKey = rsaPublicKey;
|
this.rsaPublicKey = rsaPublicKey;
|
||||||
this.rsaPrivateKey = rsaPrivateKey;
|
this.rsaPrivateKey = rsaPrivateKey;
|
||||||
this.legacySalt = legacySalt;
|
this.legacySalt = legacySalt;
|
||||||
this.keyDirectory = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpecException {
|
public KeyAgreementManager(Path keyDirectory) throws IOException, InvalidKeySpecException {
|
||||||
this.keyDirectory = keyDirectory;
|
|
||||||
Path ecdsaPublicKeyPath = keyDirectory.resolve("ecdsa_id.pub"), ecdsaPrivateKeyPath = keyDirectory.resolve("ecdsa_id");
|
Path ecdsaPublicKeyPath = keyDirectory.resolve("ecdsa_id.pub"), ecdsaPrivateKeyPath = keyDirectory.resolve("ecdsa_id");
|
||||||
Logger logger = LogManager.getLogger();
|
Logger logger = LogManager.getLogger();
|
||||||
if (IOHelper.isFile(ecdsaPublicKeyPath) && IOHelper.isFile(ecdsaPrivateKeyPath)) {
|
if (IOHelper.isFile(ecdsaPublicKeyPath) && IOHelper.isFile(ecdsaPrivateKeyPath)) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import marcono1234.gson.recordadapter.RecordTypeAdapterFactory;
|
||||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||||
import pro.gravit.launcher.core.managers.GsonManager;
|
import pro.gravit.launcher.core.managers.GsonManager;
|
||||||
import pro.gravit.launcher.base.modules.events.PreGsonPhase;
|
import pro.gravit.launcher.base.modules.events.PreGsonPhase;
|
||||||
|
@ -14,10 +15,8 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.launchserver.socket.WebSocketService;
|
import pro.gravit.launchserver.socket.WebSocketService;
|
||||||
|
@ -35,6 +34,9 @@ public LaunchServerGsonManager(LaunchServerModulesManager modulesManager) {
|
||||||
@Override
|
@Override
|
||||||
public void registerAdapters(GsonBuilder builder) {
|
public void registerAdapters(GsonBuilder builder) {
|
||||||
super.registerAdapters(builder);
|
super.registerAdapters(builder);
|
||||||
|
builder.registerTypeAdapterFactory(RecordTypeAdapterFactory.builder()
|
||||||
|
.allowMissingComponentValues()
|
||||||
|
.create());
|
||||||
builder.registerTypeAdapter(ClientProfile.Version.class, new ClientProfile.Version.GsonSerializer());
|
builder.registerTypeAdapter(ClientProfile.Version.class, new ClientProfile.Version.GsonSerializer());
|
||||||
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
|
||||||
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
builder.registerTypeAdapter(AuthCoreProvider.class, new UniversalJsonAdapter<>(AuthCoreProvider.providers));
|
||||||
|
@ -48,8 +50,6 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
||||||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||||
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
|
||||||
builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers));
|
|
||||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,129 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launcher.core.serialize.HInput;
|
||||||
|
import pro.gravit.launcher.core.serialize.HOutput;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class UpdatesManager {
|
public class UpdatesManager {
|
||||||
private final LaunchServer server;
|
private final LaunchServer server;
|
||||||
|
private final Logger logger = LogManager.getLogger();
|
||||||
|
private final Path cacheFile;
|
||||||
|
private volatile Map<String, HashedDir> updatesDirMap;
|
||||||
|
|
||||||
public UpdatesManager(LaunchServer server) {
|
public UpdatesManager(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
this.cacheFile = server.dir.resolve(".updates-cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
private void writeCache(Path file) throws IOException {
|
||||||
public void readUpdatesFromCache() {
|
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||||
|
output.writeLength(updatesDirMap.size(), 0);
|
||||||
|
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
||||||
|
output.writeString(entry.getKey(), 0);
|
||||||
|
entry.getValue().write(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
private void readCache(Path file) throws IOException {
|
||||||
public void readUpdatesDir() {
|
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
||||||
|
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||||
|
int size = input.readLength(0);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
String name = input.readString(0);
|
||||||
|
HashedDir dir = new HashedDir(input);
|
||||||
|
updatesDirMap.put(name, dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
||||||
|
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readUpdatesFromCache() throws IOException {
|
||||||
|
readCache(cacheFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readUpdatesDir() throws IOException {
|
||||||
|
if (server.config.cacheUpdates) {
|
||||||
|
if (Files.exists(cacheFile)) {
|
||||||
|
try {
|
||||||
|
readCache(cacheFile);
|
||||||
|
return;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Read updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syncUpdatesDir(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
||||||
server.config.updatesProvider.sync(dirs);
|
logger.info("Syncing updates dir");
|
||||||
|
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
||||||
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(server.updatesDir)) {
|
||||||
|
for (final Path updateDir : dirStream) {
|
||||||
|
if (Files.isHidden(updateDir))
|
||||||
|
continue; // Skip hidden
|
||||||
|
|
||||||
|
// Resolve name and verify is dir
|
||||||
|
String name = IOHelper.getFileName(updateDir);
|
||||||
|
if (!IOHelper.isDir(updateDir)) {
|
||||||
|
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
||||||
|
logger.warn("Not update dir: '{}'", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add from previous map (it's guaranteed to be non-null)
|
||||||
|
if (dirs != null && !dirs.contains(name)) {
|
||||||
|
HashedDir hdir = updatesDirMap.get(name);
|
||||||
|
if (hdir != null) {
|
||||||
|
newUpdatesDirMap.put(name, hdir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync and sign update dir
|
||||||
|
logger.info("Syncing '{}' update dir", name);
|
||||||
|
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||||
|
newUpdatesDirMap.put(name, updateHDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||||
|
if (server.config.cacheUpdates) {
|
||||||
|
try {
|
||||||
|
writeCache(cacheFile);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Write updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public HashSet<String> getUpdatesList() {
|
public HashSet<String> getUpdatesList() {
|
||||||
return new HashSet<>();
|
HashSet<String> set = new HashSet<>();
|
||||||
|
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet())
|
||||||
|
set.add(entry.getKey());
|
||||||
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public HashedDir getUpdate(String name) {
|
public HashedDir getUpdate(String name) {
|
||||||
return server.config.updatesProvider.getUpdatesDir(name);
|
return updatesDirMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void addUpdate(String name, HashedDir dir) {
|
public void addUpdate(String name, HashedDir dir) {
|
||||||
throw new UnsupportedOperationException();
|
updatesDirMap.put(name, dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.epoll.Epoll;
|
||||||
import io.netty.channel.group.DefaultChannelGroup;
|
import io.netty.channel.group.DefaultChannelGroup;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
|
@ -35,9 +36,14 @@ public class LauncherNettyServer implements AutoCloseable {
|
||||||
|
|
||||||
public LauncherNettyServer(LaunchServer server) {
|
public LauncherNettyServer(LaunchServer server) {
|
||||||
LaunchServerConfig.NettyConfig config = server.config.netty;
|
LaunchServerConfig.NettyConfig config = server.config.netty;
|
||||||
NettyObjectFactory.setMode(config.performance.mode);
|
NettyObjectFactory.setUsingEpoll(config.performance.usingEpoll);
|
||||||
Logger logger = LogManager.getLogger();
|
Logger logger = LogManager.getLogger();
|
||||||
logger.info("Netty usage {} transport mode", NettyObjectFactory.getMode());
|
if (config.performance.usingEpoll) {
|
||||||
|
logger.debug("Netty: Epoll enabled");
|
||||||
|
}
|
||||||
|
if (config.performance.usingEpoll && !Epoll.isAvailable()) {
|
||||||
|
logger.error("Epoll is not available: (netty,perfomance.usingEpoll configured wrongly)", Epoll.unavailabilityCause());
|
||||||
|
}
|
||||||
bossGroup = NettyObjectFactory.newEventLoopGroup(config.performance.bossThread, "LauncherNettyServer.bossGroup");
|
bossGroup = NettyObjectFactory.newEventLoopGroup(config.performance.bossThread, "LauncherNettyServer.bossGroup");
|
||||||
workerGroup = NettyObjectFactory.newEventLoopGroup(config.performance.workerThread, "LauncherNettyServer.workerGroup");
|
workerGroup = NettyObjectFactory.newEventLoopGroup(config.performance.workerThread, "LauncherNettyServer.workerGroup");
|
||||||
serverBootstrap = new ServerBootstrap();
|
serverBootstrap = new ServerBootstrap();
|
||||||
|
|
|
@ -2,58 +2,30 @@
|
||||||
|
|
||||||
import io.netty.channel.ChannelFactory;
|
import io.netty.channel.ChannelFactory;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.MultiThreadIoEventLoopGroup;
|
|
||||||
import io.netty.channel.ServerChannel;
|
import io.netty.channel.ServerChannel;
|
||||||
import io.netty.channel.epoll.Epoll;
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
import io.netty.channel.epoll.EpollIoHandler;
|
|
||||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||||
import io.netty.channel.nio.NioIoHandler;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.channel.uring.IoUring;
|
|
||||||
import io.netty.channel.uring.IoUringIoHandler;
|
|
||||||
import io.netty.channel.uring.IoUringServerSocketChannel;
|
|
||||||
|
|
||||||
public class NettyObjectFactory {
|
public class NettyObjectFactory {
|
||||||
private static NettyFactoryMode mode;
|
private static boolean epoll = false;
|
||||||
|
|
||||||
public static void setMode(NettyFactoryMode mode) {
|
public static void setUsingEpoll(boolean value) {
|
||||||
NettyObjectFactory.mode = mode;
|
epoll = value;
|
||||||
if(mode == NettyFactoryMode.AUTO) {
|
|
||||||
if(IoUring.isAvailable()) {
|
|
||||||
NettyObjectFactory.mode = NettyFactoryMode.IO_URING;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(Epoll.isAvailable()) {
|
|
||||||
NettyObjectFactory.mode = NettyFactoryMode.EPOLL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NettyObjectFactory.mode = NettyFactoryMode.NIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NettyFactoryMode getMode() {
|
|
||||||
return mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EventLoopGroup newEventLoopGroup(int threads, String poolName) {
|
public static EventLoopGroup newEventLoopGroup(int threads, String poolName) {
|
||||||
return switch (mode) {
|
if (epoll)
|
||||||
case AUTO -> null;
|
return new EpollEventLoopGroup(threads);
|
||||||
case NIO -> new MultiThreadIoEventLoopGroup(threads, NioIoHandler.newFactory());
|
else
|
||||||
case EPOLL -> new MultiThreadIoEventLoopGroup(threads, EpollIoHandler.newFactory());
|
return new NioEventLoopGroup(threads);
|
||||||
case IO_URING -> new MultiThreadIoEventLoopGroup(threads, IoUringIoHandler.newFactory());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChannelFactory<? extends ServerChannel> getServerSocketChannelFactory() {
|
public static ChannelFactory<? extends ServerChannel> getServerSocketChannelFactory() {
|
||||||
return switch (mode) {
|
if (epoll)
|
||||||
case AUTO -> null;
|
return EpollServerSocketChannel::new;
|
||||||
case NIO -> NioServerSocketChannel::new;
|
else
|
||||||
case EPOLL -> EpollServerSocketChannel::new;
|
return NioServerSocketChannel::new;
|
||||||
case IO_URING -> IoUringServerSocketChannel::new;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum NettyFactoryMode {
|
|
||||||
AUTO, NIO, EPOLL, IO_URING
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
package pro.gravit.launchserver.socket;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launchserver.config.log4j.LogAppender;
|
|
||||||
import pro.gravit.utils.command.CommandHandler;
|
|
||||||
|
|
||||||
import java.net.StandardProtocolFamily;
|
|
||||||
import java.net.UnixDomainSocketAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.ServerSocketChannel;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class SocketCommandServer implements Runnable {
|
|
||||||
private final Logger logger = LogManager.getLogger(SocketCommandServer.class);
|
|
||||||
private ServerSocketChannel channel;
|
|
||||||
private Path path;
|
|
||||||
private UnixDomainSocketAddress address;
|
|
||||||
private ServerSocketChannel serverChannel;
|
|
||||||
private CommandHandler commandHandler;
|
|
||||||
private transient SocketChannel clientChannel;
|
|
||||||
|
|
||||||
public SocketCommandServer(CommandHandler commandHandler, Path path) {
|
|
||||||
this.commandHandler = commandHandler;
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runCommand(SocketChannel channel, String command) {
|
|
||||||
logger.info("Command '{}' from socket", command);
|
|
||||||
clientChannel = channel;
|
|
||||||
try {
|
|
||||||
commandHandler.evalNative(command, false);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Error when execute command", e);
|
|
||||||
} finally {
|
|
||||||
clientChannel = null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Files.deleteIfExists(path);
|
|
||||||
this.address = UnixDomainSocketAddress.of(path);
|
|
||||||
serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
|
||||||
serverChannel.configureBlocking(true);
|
|
||||||
serverChannel.bind(address);
|
|
||||||
LogAppender.getInstance().addListener((logEvent -> {
|
|
||||||
if(clientChannel != null && clientChannel.isOpen()) {
|
|
||||||
try {
|
|
||||||
String s = logEvent.getMessage().getFormattedMessage()+"\n";
|
|
||||||
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
|
||||||
clientChannel.write(buffer);
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
|
||||||
while (true) {
|
|
||||||
SocketChannel channel = serverChannel.accept();
|
|
||||||
try (channel) {
|
|
||||||
channel.configureBlocking(true);
|
|
||||||
String command = null;
|
|
||||||
mark:
|
|
||||||
while (true) {
|
|
||||||
int bytesRead = channel.read(buffer);
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < buffer.limit(); i++) {
|
|
||||||
if (buffer.get(i) == '\n') {
|
|
||||||
command = new String(buffer.array(), 0, i);
|
|
||||||
break mark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (command != null) {
|
|
||||||
runCommand(channel, command);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Unix command socket server error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,6 +22,7 @@
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
public interface WebSocketServerResponse extends WebSocketRequest {
|
public interface WebSocketServerResponse extends WebSocketRequest {
|
||||||
String getType();
|
String getType();
|
||||||
|
|
||||||
void execute(ChannelHandlerContext ctx, Client client);
|
void execute(ChannelHandlerContext ctx, Client client) throws Exception;
|
||||||
|
|
||||||
default ThreadSafeStatus getThreadSafeStatus() {
|
default ThreadSafeStatus getThreadSafeStatus() {
|
||||||
return ThreadSafeStatus.READ;
|
return ThreadSafeStatus.READ;
|
||||||
|
|
|
@ -23,7 +23,7 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
sendResult(new CurrentUserRequestEvent(collectUserInfoFromClient(server, client)));
|
sendResult(new CurrentUserRequestEvent(collectUserInfoFromClient(server, client)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProfilesResponse extends SimpleResponse {
|
public class ProfilesResponse extends SimpleResponse {
|
||||||
@Deprecated
|
|
||||||
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
||||||
List<ClientProfile> profileList;
|
List<ClientProfile> profileList;
|
||||||
Set<ClientProfile> serverProfiles = server.getProfiles();
|
Set<ClientProfile> serverProfiles = server.getProfiles();
|
||||||
|
@ -41,6 +40,6 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
sendError("Access denied");
|
sendError("Access denied");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendResult(new ProfilesRequestEvent(server.config.profileProvider.getProfiles(client)));
|
sendResult(new ProfilesRequestEvent(getListVisibleProfiles(server, client)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
if (accessToken == null && !client.isAuth && needUserInfo) {
|
if (accessToken == null && !client.isAuth && needUserInfo) {
|
||||||
sendError("Invalid request");
|
sendError("Invalid request");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,7 +12,7 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
||||||
sendError("Access denied");
|
sendError("Access denied");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -14,7 +14,7 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
if(!client.isAuth || client.auth == null || client.getUser() == null) {
|
||||||
sendError("Access denied");
|
sendError("Access denied");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,7 +12,7 @@ public String getType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
sendResult(new GetConnectUUIDRequestEvent(connectUUID, server.shardId));
|
sendResult(new GetConnectUUIDRequestEvent(connectUUID, server.shardId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, null, 0));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
}
|
}
|
||||||
} else if (launcher_type == 2) //EXE
|
} else if (launcher_type == 2) //EXE
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
client.checkSign = true;
|
client.checkSign = true;
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
} else {
|
} else {
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, null, 0));
|
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
}
|
}
|
||||||
} else sendError("Request launcher type error");
|
} else sendError("Request launcher type error");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
apply plugin: 'com.github.johnrengelman.shadow'
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
|
||||||
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
||||||
|
String mainAgentName = "pro.gravit.launcher.runtime.LauncherAgent"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
|
"Premain-Class": mainAgentName,
|
||||||
"Multi-Release": "true",
|
"Multi-Release": "true",
|
||||||
"Automatic-Module-Name": "GravitLauncher")
|
"Automatic-Module-Name": "GravitLauncher")
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,7 @@ public static void main(String... args) throws Throwable {
|
||||||
LogHelper.printLicense("Launcher");
|
LogHelper.printLicense("Launcher");
|
||||||
LauncherEngine.checkClass(LauncherEngineWrapper.class);
|
LauncherEngine.checkClass(LauncherEngineWrapper.class);
|
||||||
LauncherEngine.checkClass(LauncherEngine.class);
|
LauncherEngine.checkClass(LauncherEngine.class);
|
||||||
|
LauncherEngine.checkClass(LauncherAgent.class);
|
||||||
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
||||||
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
LauncherEngine.modulesManager = new RuntimeModuleManager();
|
||||||
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule());
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ClientLauncherProcess {
|
public class ClientLauncherProcess {
|
||||||
public final List<String> pre = new LinkedList<>();
|
public final List<String> pre = new LinkedList<>();
|
||||||
|
@ -108,14 +109,14 @@ public static String getPathSeparator() {
|
||||||
|
|
||||||
private void applyClientProfile() {
|
private void applyClientProfile() {
|
||||||
this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString());
|
this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString());
|
||||||
this.jvmArgs.addAll(this.params.profile.getJvmArgs());
|
Collections.addAll(this.jvmArgs, this.params.profile.getJvmArgs());
|
||||||
for (OptionalAction a : this.params.actions) {
|
for (OptionalAction a : this.params.actions) {
|
||||||
if (a instanceof OptionalActionJvmArgs) {
|
if (a instanceof OptionalActionJvmArgs) {
|
||||||
this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args);
|
this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.systemEnv.put("JAVA_HOME", javaVersion.jvmDir.toString());
|
this.systemEnv.put("JAVA_HOME", javaVersion.jvmDir.toString());
|
||||||
this.systemClassPath.addAll(this.params.profile.getAlternativeClassPath());
|
Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath());
|
||||||
if (params.ram > 0) {
|
if (params.ram > 0) {
|
||||||
this.jvmArgs.add("-Xmx" + params.ram + 'M');
|
this.jvmArgs.add("-Xmx" + params.ram + 'M');
|
||||||
}
|
}
|
||||||
|
@ -127,6 +128,8 @@ private void applyClientProfile() {
|
||||||
this.params.oauthExpiredTime = Request.getTokenExpiredTime();
|
this.params.oauthExpiredTime = Request.getTokenExpiredTime();
|
||||||
this.params.extendedTokens = Request.getExtendedTokens();
|
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));
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessBuilderCreateEvent(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,41 +144,11 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
|
||||||
}
|
}
|
||||||
//ADD CLASSPATH
|
//ADD CLASSPATH
|
||||||
processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir));
|
processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir));
|
||||||
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) {
|
||||||
Set<Path> ignorePath = new HashSet<>();
|
processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()));
|
||||||
var moduleConf = params.profile.getModuleConf();
|
} else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
||||||
if(moduleConf != null) {
|
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(new HashSet<>(), workDir, params.actions, params.profile)
|
||||||
if(moduleConf.modulePath != null && !moduleConf.modulePath.isEmpty()) {
|
.filter(x -> !params.profile.getModulePath().contains(workDir.relativize(x).toString()))
|
||||||
processArgs.add("-p");
|
|
||||||
for(var e : moduleConf.modulePath) {
|
|
||||||
ignorePath.add(Path.of(e));
|
|
||||||
}
|
|
||||||
processArgs.add(String.join(File.pathSeparator, moduleConf.modulePath));
|
|
||||||
}
|
|
||||||
if(moduleConf.modules != null && !moduleConf.modules.isEmpty()) {
|
|
||||||
processArgs.add("--add-modules");
|
|
||||||
processArgs.add(String.join(",", moduleConf.modules));
|
|
||||||
}
|
|
||||||
if(moduleConf.exports != null && !moduleConf.exports.isEmpty()) {
|
|
||||||
for(var e : moduleConf.exports.entrySet()) {
|
|
||||||
processArgs.add("--add-exports");
|
|
||||||
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(moduleConf.opens != null && !moduleConf.opens.isEmpty()) {
|
|
||||||
for(var e : moduleConf.opens.entrySet()) {
|
|
||||||
processArgs.add("--add-opens");
|
|
||||||
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(moduleConf.reads != null && !moduleConf.reads.isEmpty()) {
|
|
||||||
for(var e : moduleConf.reads.entrySet()) {
|
|
||||||
processArgs.add("--add-reads");
|
|
||||||
processArgs.add(String.format("%s=%s", e.getKey(), e.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile)
|
|
||||||
.map(Path::toString)
|
.map(Path::toString)
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,7 @@ public void cancel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tasks.clear();
|
tasks.clear();
|
||||||
|
executor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCanceled() {
|
public boolean isCanceled() {
|
||||||
|
@ -255,7 +256,7 @@ protected HttpRequest makeHttpRequest(URI baseUri, String filePath) throws URISy
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
|
protected ProgressTrackingBodyHandler<Path> makeBodyHandler(Path file, DownloadCallback callback) {
|
||||||
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), callback);
|
return new ProgressTrackingBodyHandler<>(HttpResponse.BodyHandlers.ofFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DownloadCallback {
|
public interface DownloadCallback {
|
||||||
|
|
|
@ -12,11 +12,13 @@
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public final class ClientProfile implements Comparable<ClientProfile> {
|
public final class ClientProfile implements Comparable<ClientProfile> {
|
||||||
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
|
||||||
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
new String[0], new String[]{"indexes", "objects"}, new String[0]);
|
||||||
|
private transient Path profileFilePath;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private String title;
|
private String title;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
@ -39,6 +41,8 @@ public final class ClientProfile implements Comparable<ClientProfile> {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private List<String> updateExclusions;
|
private List<String> updateExclusions;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
private List<String> updateShared;
|
||||||
|
@LauncherNetworkAPI
|
||||||
private List<String> updateVerify;
|
private List<String> updateVerify;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private Set<OptionalFile> updateOptional;
|
private Set<OptionalFile> updateOptional;
|
||||||
|
@ -47,6 +51,10 @@ public final class ClientProfile implements Comparable<ClientProfile> {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private List<String> classPath;
|
private List<String> classPath;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
private List<String> modulePath = new ArrayList<>();
|
||||||
|
@LauncherNetworkAPI
|
||||||
|
private List<String> modules = new ArrayList<>();
|
||||||
|
@LauncherNetworkAPI
|
||||||
private List<String> altClassPath;
|
private List<String> altClassPath;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private List<String> clientArgs;
|
private List<String> clientArgs;
|
||||||
|
@ -81,37 +89,54 @@ public final class ClientProfile implements Comparable<ClientProfile> {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
private LaunchOptions.ModuleConf moduleConf;
|
private LaunchOptions.ModuleConf moduleConf;
|
||||||
|
|
||||||
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) {
|
public ClientProfile() {
|
||||||
this.title = title;
|
update = new ArrayList<>();
|
||||||
this.uuid = uuid;
|
updateExclusions = new ArrayList<>();
|
||||||
this.version = version;
|
updateShared = new ArrayList<>();
|
||||||
this.info = info;
|
updateVerify = new ArrayList<>();
|
||||||
this.dir = dir;
|
updateOptional = new HashSet<>();
|
||||||
this.sortIndex = sortIndex;
|
jvmArgs = new ArrayList<>();
|
||||||
this.assetIndex = assetIndex;
|
classPath = new ArrayList<>();
|
||||||
this.assetDir = assetDir;
|
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) {
|
||||||
this.update = update;
|
this.update = update;
|
||||||
this.updateExclusions = updateExclusions;
|
this.updateExclusions = updateExclusions;
|
||||||
|
this.updateShared = updateShared;
|
||||||
this.updateVerify = updateVerify;
|
this.updateVerify = updateVerify;
|
||||||
this.updateOptional = updateOptional;
|
this.updateOptional = updateOptional;
|
||||||
this.jvmArgs = jvmArgs;
|
this.jvmArgs = jvmArgs;
|
||||||
this.classPath = classPath;
|
this.classPath = classPath;
|
||||||
|
this.modulePath = modulePath;
|
||||||
|
this.modules = modules;
|
||||||
this.altClassPath = altClassPath;
|
this.altClassPath = altClassPath;
|
||||||
this.clientArgs = clientArgs;
|
this.clientArgs = clientArgs;
|
||||||
this.compatClasses = compatClasses;
|
this.compatClasses = compatClasses;
|
||||||
this.loadNatives = loadNatives;
|
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
this.classLoaderConfig = classLoaderConfig;
|
this.classLoaderConfig = classLoaderConfig;
|
||||||
this.flags = flags;
|
this.version = version;
|
||||||
|
this.assetIndex = assetIndex;
|
||||||
|
this.dir = dir;
|
||||||
|
this.assetDir = assetDir;
|
||||||
this.recommendJavaVersion = recommendJavaVersion;
|
this.recommendJavaVersion = recommendJavaVersion;
|
||||||
this.minJavaVersion = minJavaVersion;
|
this.minJavaVersion = minJavaVersion;
|
||||||
this.maxJavaVersion = maxJavaVersion;
|
this.maxJavaVersion = maxJavaVersion;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.limited = limited;
|
this.sortIndex = sortIndex;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.title = title;
|
||||||
|
this.info = info;
|
||||||
this.mainClass = mainClass;
|
this.mainClass = mainClass;
|
||||||
this.mainModule = mainModule;
|
this.flags = flags;
|
||||||
this.moduleConf = moduleConf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerProfile getDefaultServerProfile() {
|
public ServerProfile getDefaultServerProfile() {
|
||||||
|
@ -134,22 +159,34 @@ public FileNameMatcher getAssetUpdateMatcher() {
|
||||||
return getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0 ? ASSET_MATCHER : null;
|
return getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_7_10) >= 0 ? ASSET_MATCHER : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getClassPath() {
|
public String[] getClassPath() {
|
||||||
return Collections.unmodifiableList(classPath);
|
return classPath.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getAlternativeClassPath() {
|
public List<String> getModulePath() {
|
||||||
return Collections.unmodifiableList(altClassPath);
|
return Collections.unmodifiableList(modulePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getClientArgs() {
|
public List<String> getModules() {
|
||||||
return Collections.unmodifiableList(clientArgs);
|
return Collections.unmodifiableList(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAlternativeClassPath() {
|
||||||
|
return altClassPath.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getClientArgs() {
|
||||||
|
return clientArgs.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDir() {
|
public String getDir() {
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDir(String dir) {
|
||||||
|
this.dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAssetDir() {
|
public String getAssetDir() {
|
||||||
return assetDir;
|
return assetDir;
|
||||||
}
|
}
|
||||||
|
@ -158,25 +195,24 @@ public List<String> getUpdateExclusions() {
|
||||||
return Collections.unmodifiableList(updateExclusions);
|
return Collections.unmodifiableList(updateExclusions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getUpdate() {
|
public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
|
||||||
return Collections.unmodifiableList(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getUpdateVerify() {
|
|
||||||
return Collections.unmodifiableList(updateVerify);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileNameMatcher getClientUpdateMatcher() {
|
|
||||||
String[] updateArray = update.toArray(new String[0]);
|
String[] updateArray = update.toArray(new String[0]);
|
||||||
String[] verifyArray = updateVerify.toArray(new String[0]);
|
String[] verifyArray = updateVerify.toArray(new String[0]);
|
||||||
List<String> excludeList;
|
List<String> excludeList;
|
||||||
|
//if(excludeOptional)
|
||||||
|
//{
|
||||||
|
// excludeList = new ArrayList<>();
|
||||||
|
// excludeList.addAll(updateExclusions);
|
||||||
|
// excludeList.addAll(updateOptional);
|
||||||
|
//}
|
||||||
|
//else
|
||||||
excludeList = updateExclusions;
|
excludeList = updateExclusions;
|
||||||
String[] exclusionsArray = excludeList.toArray(new String[0]);
|
String[] exclusionsArray = excludeList.toArray(new String[0]);
|
||||||
return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
|
return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getJvmArgs() {
|
public String[] getJvmArgs() {
|
||||||
return Collections.unmodifiableList(jvmArgs);
|
return jvmArgs.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMainClass() {
|
public String getMainClass() {
|
||||||
|
@ -253,6 +289,10 @@ public OptionalFile getOptionalFile(String file) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<String> getShared() {
|
||||||
|
return updateShared;
|
||||||
|
}
|
||||||
|
|
||||||
public int getServerPort() {
|
public int getServerPort() {
|
||||||
ServerProfile profile = getDefaultServerProfile();
|
ServerProfile profile = getDefaultServerProfile();
|
||||||
return profile == null ? 25565 : profile.serverPort;
|
return profile == null ? 25565 : profile.serverPort;
|
||||||
|
@ -266,14 +306,26 @@ public String getTitle() {
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
public String getInfo() {
|
public String getInfo() {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInfo(String info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
public Version getVersion() {
|
public Version getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVersion(Version version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public boolean isUpdateFastCheck() {
|
public boolean isUpdateFastCheck() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,6 +340,10 @@ public UUID getUUID() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUUID(UUID uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasFlag(CompatibilityFlags flag) {
|
public boolean hasFlag(CompatibilityFlags flag) {
|
||||||
return flags.contains(flag);
|
return flags.contains(flag);
|
||||||
}
|
}
|
||||||
|
@ -357,6 +413,18 @@ public String getProperty(String name) {
|
||||||
return properties.get(name);
|
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() {
|
public Map<String, String> getProperties() {
|
||||||
return Collections.unmodifiableMap(properties);
|
return Collections.unmodifiableMap(properties);
|
||||||
}
|
}
|
||||||
|
@ -382,6 +450,10 @@ public ClassLoaderConfig getClassLoaderConfig() {
|
||||||
return classLoaderConfig;
|
return classLoaderConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setClassLoaderConfig(ClassLoaderConfig classLoaderConfig) {
|
||||||
|
this.classLoaderConfig = classLoaderConfig;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isLimited() {
|
public boolean isLimited() {
|
||||||
return limited;
|
return limited;
|
||||||
}
|
}
|
||||||
|
@ -390,8 +462,16 @@ public List<CompatibilityFlags> getFlags() {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getProfileFilePath() {
|
||||||
|
return profileFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfileFilePath(Path profileFilePath) {
|
||||||
|
this.profileFilePath = profileFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
public enum ClassLoaderConfig {
|
public enum ClassLoaderConfig {
|
||||||
LAUNCHER, MODULE, SYSTEM_ARGS
|
AGENT, LAUNCHER, MODULE, SYSTEM_ARGS
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CompatibilityFlags {
|
public enum CompatibilityFlags {
|
||||||
|
|
|
@ -1,144 +1,42 @@
|
||||||
package pro.gravit.launcher.base.profiles;
|
package pro.gravit.launcher.base.profiles;
|
||||||
|
|
||||||
import pro.gravit.launcher.base.profiles.optional.OptionalFile;
|
import pro.gravit.launcher.base.profiles.optional.OptionalFile;
|
||||||
import pro.gravit.utils.launch.LaunchOptions;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ClientProfileBuilder {
|
public class ClientProfileBuilder {
|
||||||
private String title;
|
private List<String> update = new ArrayList<>();
|
||||||
private UUID uuid;
|
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 ClientProfile.Version version;
|
||||||
private String info;
|
|
||||||
private String dir;
|
|
||||||
private int sortIndex;
|
|
||||||
private String assetIndex;
|
private String assetIndex;
|
||||||
|
private String dir;
|
||||||
private String assetDir;
|
private String assetDir;
|
||||||
private List<String> update;
|
private int recommendJavaVersion = 8;
|
||||||
private List<String> updateExclusions;
|
private int minJavaVersion = 8;
|
||||||
private List<String> updateVerify;
|
private int maxJavaVersion = 999;
|
||||||
private Set<OptionalFile> updateOptional;
|
private ClientProfile.ProfileDefaultSettings settings = new ClientProfile.ProfileDefaultSettings();
|
||||||
private List<String> jvmArgs;
|
private int sortIndex;
|
||||||
private List<String> classPath;
|
private UUID uuid;
|
||||||
private List<String> altClassPath;
|
private String title;
|
||||||
private List<String> clientArgs;
|
private String info;
|
||||||
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 mainClass;
|
||||||
private String mainModule;
|
|
||||||
private LaunchOptions.ModuleConf moduleConf;
|
|
||||||
|
|
||||||
public ClientProfileBuilder() {
|
public void setUpdate(List<String> update) {
|
||||||
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<>();
|
|
||||||
this.settings = new ClientProfile.ProfileDefaultSettings();
|
|
||||||
this.recommendJavaVersion = 21;
|
|
||||||
this.minJavaVersion = 17;
|
|
||||||
this.maxJavaVersion = 999;
|
|
||||||
this.classLoaderConfig = ClientProfile.ClassLoaderConfig.LAUNCHER;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.classLoaderConfig = profile.getClassLoaderConfig();
|
|
||||||
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 setUuid(UUID uuid) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setVersion(ClientProfile.Version version) {
|
|
||||||
this.version = version;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setInfo(String info) {
|
|
||||||
this.info = info;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setDir(String dir) {
|
|
||||||
this.dir = dir;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setSortIndex(int sortIndex) {
|
|
||||||
this.sortIndex = sortIndex;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setAssetIndex(String assetIndex) {
|
|
||||||
this.assetIndex = assetIndex;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setAssetDir(String assetDir) {
|
|
||||||
this.assetDir = assetDir;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setUpdate(List<String> update) {
|
|
||||||
this.update = update;
|
this.update = update;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder update(String value) {
|
|
||||||
this.update.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setUpdateExclusions(List<String> updateExclusions) {
|
public ClientProfileBuilder setUpdateExclusions(List<String> updateExclusions) {
|
||||||
|
@ -146,70 +44,33 @@ public ClientProfileBuilder setUpdateExclusions(List<String> updateExclusions) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder updateExclusions(String value) {
|
public ClientProfileBuilder setUpdateShared(List<String> updateShared) {
|
||||||
this.updateExclusions.add(value);
|
this.updateShared = updateShared;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setUpdateVerify(List<String> updateVerify) {
|
public void setUpdateVerify(List<String> updateVerify) {
|
||||||
this.updateVerify = updateVerify;
|
this.updateVerify = updateVerify;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder updateVerify(String value) {
|
public void setUpdateOptional(Set<OptionalFile> updateOptional) {
|
||||||
this.updateVerify.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setUpdateOptional(Set<OptionalFile> updateOptional) {
|
|
||||||
this.updateOptional = updateOptional;
|
this.updateOptional = updateOptional;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder updateOptional(OptionalFile value) {
|
public void setJvmArgs(List<String> jvmArgs) {
|
||||||
this.updateOptional.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setJvmArgs(List<String> jvmArgs) {
|
|
||||||
this.jvmArgs = jvmArgs;
|
this.jvmArgs = jvmArgs;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder jvmArg(String value) {
|
public void setClassPath(List<String> classPath) {
|
||||||
this.jvmArgs.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ClientProfileBuilder setClassPath(List<String> classPath) {
|
|
||||||
this.classPath = classPath;
|
this.classPath = classPath;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder classPath(String value) {
|
public void setAltClassPath(List<String> altClassPath) {
|
||||||
this.classPath.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setAltClassPath(List<String> altClassPath) {
|
|
||||||
this.altClassPath = altClassPath;
|
this.altClassPath = altClassPath;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder altClassPath(String value) {
|
public void setClientArgs(List<String> clientArgs) {
|
||||||
this.altClassPath.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setClientArgs(List<String> clientArgs) {
|
|
||||||
this.clientArgs = clientArgs;
|
this.clientArgs = clientArgs;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder clientArg(String value) {
|
|
||||||
this.clientArgs.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setCompatClasses(List<String> compatClasses) {
|
public ClientProfileBuilder setCompatClasses(List<String> compatClasses) {
|
||||||
|
@ -217,69 +78,55 @@ public ClientProfileBuilder setCompatClasses(List<String> compatClasses) {
|
||||||
return this;
|
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) {
|
public ClientProfileBuilder setProperties(Map<String, String> properties) {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder property(String name, String value) {
|
public void setServers(List<ClientProfile.ServerProfile> servers) {
|
||||||
this.properties.put(name, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setServers(List<ClientProfile.ServerProfile> servers) {
|
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder server(ClientProfile.ServerProfile value) {
|
public void setClassLoaderConfig(ClientProfile.ClassLoaderConfig classLoaderConfig) {
|
||||||
this.servers.add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setClassLoaderConfig(ClientProfile.ClassLoaderConfig classLoaderConfig) {
|
|
||||||
this.classLoaderConfig = classLoaderConfig;
|
this.classLoaderConfig = classLoaderConfig;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setFlags(List<ClientProfile.CompatibilityFlags> flags) {
|
public void setVersion(ClientProfile.Version version) {
|
||||||
this.flags = flags;
|
this.version = version;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder flag(ClientProfile.CompatibilityFlags value) {
|
public void setAssetIndex(String assetIndex) {
|
||||||
this.flags.add(value);
|
this.assetIndex = assetIndex;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setRecommendJavaVersion(int recommendJavaVersion) {
|
public void setDir(String dir) {
|
||||||
|
this.dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssetDir(String assetDir) {
|
||||||
|
this.assetDir = assetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecommendJavaVersion(int recommendJavaVersion) {
|
||||||
this.recommendJavaVersion = recommendJavaVersion;
|
this.recommendJavaVersion = recommendJavaVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientProfileBuilder setModulePath(List<String> modulePath) {
|
||||||
|
this.modulePath = modulePath;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setMinJavaVersion(int minJavaVersion) {
|
public ClientProfileBuilder setModules(List<String> modules) {
|
||||||
|
this.modules = modules;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinJavaVersion(int minJavaVersion) {
|
||||||
this.minJavaVersion = minJavaVersion;
|
this.minJavaVersion = minJavaVersion;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setMaxJavaVersion(int maxJavaVersion) {
|
public void setMaxJavaVersion(int maxJavaVersion) {
|
||||||
this.maxJavaVersion = maxJavaVersion;
|
this.maxJavaVersion = maxJavaVersion;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setSettings(ClientProfile.ProfileDefaultSettings settings) {
|
public ClientProfileBuilder setSettings(ClientProfile.ProfileDefaultSettings settings) {
|
||||||
|
@ -287,27 +134,33 @@ public ClientProfileBuilder setSettings(ClientProfile.ProfileDefaultSettings set
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setLimited(boolean limited) {
|
public ClientProfileBuilder setSortIndex(int sortIndex) {
|
||||||
this.limited = limited;
|
this.sortIndex = sortIndex;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setMainClass(String mainClass) {
|
public void setUuid(UUID uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(String info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainClass(String mainClass) {
|
||||||
this.mainClass = mainClass;
|
this.mainClass = mainClass;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfileBuilder setMainModule(String mainModule) {
|
public ClientProfileBuilder setFlags(List<ClientProfile.CompatibilityFlags> flags) {
|
||||||
this.mainModule = mainModule;
|
this.flags = flags;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfileBuilder setModuleConf(LaunchOptions.ModuleConf moduleConf) {
|
|
||||||
this.moduleConf = moduleConf;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientProfile createClientProfile() {
|
public ClientProfile createClientProfile() {
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,5 +18,4 @@ private ClientProfileVersions() {
|
||||||
public static final ClientProfile.Version MINECRAFT_1_20 = ClientProfile.Version.of("1.20");
|
public static final ClientProfile.Version MINECRAFT_1_20 = ClientProfile.Version.of("1.20");
|
||||||
public static final ClientProfile.Version MINECRAFT_1_20_2 = ClientProfile.Version.of("1.20.2");
|
public static final ClientProfile.Version MINECRAFT_1_20_2 = ClientProfile.Version.of("1.20.2");
|
||||||
public static final ClientProfile.Version MINECRAFT_1_20_3 = ClientProfile.Version.of("1.20.3");
|
public static final ClientProfile.Version MINECRAFT_1_20_3 = ClientProfile.Version.of("1.20.3");
|
||||||
public static final ClientProfile.Version MINECRAFT_1_20_5 = ClientProfile.Version.of("1.20.5");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ public Set<OptionalAction> getEnabledActions() {
|
||||||
public void fixDependencies() {
|
public void fixDependencies() {
|
||||||
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
|
Set<OptionalFile> disabled = all.stream().filter(t -> !isEnabled(t)).collect(Collectors.toSet());
|
||||||
for (OptionalFile file : disabled) {
|
for (OptionalFile file : disabled) {
|
||||||
if (file.group != null && file.group.length > 0 && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
if (file.group != null && Arrays.stream(file.group).noneMatch(this::isEnabled)) {
|
||||||
enable(file.group[0], false, null);
|
enable(file.group[0], false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
package pro.gravit.launcher.base.profiles.optional.actions;
|
package pro.gravit.launcher.base.profiles.optional.actions;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class OptionalActionClassPath extends OptionalAction {
|
public class OptionalActionClassPath extends OptionalAction {
|
||||||
public List<String> args;
|
public String[] args;
|
||||||
public boolean useAltClasspath = false;
|
public boolean useAltClasspath = false;
|
||||||
|
|
||||||
public OptionalActionClassPath() {
|
public OptionalActionClassPath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionalActionClassPath(List<String> args) {
|
public OptionalActionClassPath(String[] args) {
|
||||||
this.args = args;
|
this.args = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionalActionClassPath(List<String> args, boolean useAltClasspath) {
|
public OptionalActionClassPath(String[] args, boolean useAltClasspath) {
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.useAltClasspath = useAltClasspath;
|
this.useAltClasspath = useAltClasspath;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public static String getRefreshToken() {
|
||||||
|
|
||||||
public static void reconnect() throws Exception {
|
public static void reconnect() throws Exception {
|
||||||
|
|
||||||
getRequestService().connect();
|
getRequestService().open();
|
||||||
restore();
|
restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public final class RequestException extends IOException {
|
public final class RequestException extends IOException {
|
||||||
|
private static final long serialVersionUID = 7558237657082664821L;
|
||||||
|
|
||||||
|
|
||||||
public RequestException(String message) {
|
public RequestException(String message) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
public interface RequestService {
|
public interface RequestService {
|
||||||
<T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException;
|
<T extends WebSocketEvent> CompletableFuture<T> request(Request<T> request) throws IOException;
|
||||||
void connect() throws Exception;
|
void open() throws Exception;
|
||||||
|
|
||||||
void registerEventHandler(EventHandler handler);
|
void registerEventHandler(EventHandler handler);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.WebSocket;
|
import java.net.http.WebSocket;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
@ -34,7 +33,7 @@ public abstract class ClientJSONPoint implements WebSocket.Listener {
|
||||||
private final Object sendSyncObject = new Object();
|
private final Object sendSyncObject = new Object();
|
||||||
private volatile StringBuilder builder = new StringBuilder();
|
private volatile StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
public ClientJSONPoint(final String uri) {
|
public ClientJSONPoint(final String uri) throws SSLException {
|
||||||
this(URI.create(uri));
|
this(URI.create(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ public ClientJSONPoint(URI uri) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() throws Exception {
|
public void open() throws Exception {
|
||||||
webSocket = webSocketBuilder.buildAsync(uri, this).get();
|
webSocket = webSocketBuilder.buildAsync(uri, this).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,17 +97,6 @@ public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String re
|
||||||
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOpen(WebSocket webSocket) {
|
|
||||||
onOpen();
|
|
||||||
WebSocket.Listener.super.onOpen(webSocket);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
|
||||||
return WebSocket.Listener.super.onBinary(webSocket, data, last);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(WebSocket webSocket, Throwable error) {
|
public void onError(WebSocket webSocket, Throwable error) {
|
||||||
LogHelper.error(error);
|
LogHelper.error(error);
|
||||||
|
@ -126,7 +114,7 @@ public void send(String text) {
|
||||||
|
|
||||||
abstract void onOpen();
|
abstract void onOpen();
|
||||||
|
|
||||||
public void close() {
|
public void close() throws InterruptedException {
|
||||||
webSocket.abort();
|
webSocket.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public abstract class ClientWebSocketService extends ClientJSONPoint {
|
||||||
public OnCloseCallback onCloseCallback;
|
public OnCloseCallback onCloseCallback;
|
||||||
public ReconnectCallback reconnectCallback;
|
public ReconnectCallback reconnectCallback;
|
||||||
|
|
||||||
public ClientWebSocketService(String address) {
|
public ClientWebSocketService(String address) throws SSLException {
|
||||||
super(createURL(address));
|
super(createURL(address));
|
||||||
this.gson = Launcher.gsonManager.gson;
|
this.gson = Launcher.gsonManager.gson;
|
||||||
this.onConnect = true;
|
this.onConnect = true;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> reques
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect() {
|
public void open() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,9 @@
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.http.WebSocket;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
@ -43,7 +40,11 @@ public static CompletableFuture<StdWebSocketService> initWebSockets(String addre
|
||||||
service.openAsync(() -> {
|
service.openAsync(() -> {
|
||||||
future.complete(service);
|
future.complete(service);
|
||||||
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
|
JVMHelper.RUNTIME.addShutdownHook(new Thread(() -> {
|
||||||
service.close();
|
try {
|
||||||
|
service.close();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}, future::completeExceptionally);
|
}, future::completeExceptionally);
|
||||||
return future;
|
return future;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public <T extends WebSocketEvent> CompletableFuture<T> request(Request<T> reques
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect() {
|
public void open() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
public class ClientVersionTest {
|
public class ClientVersionTest {
|
||||||
@Test
|
@Test
|
||||||
public void parseTest() {
|
public void parseTest() {
|
||||||
Assertions.assertEquals("1.0.0", ClientProfile.Version.of("1.0.0").toCleanString());
|
Assertions.assertEquals(ClientProfile.Version.of("1.0.0").toCleanString(), "1.0.0");
|
||||||
Assertions.assertEquals("1.0.0.1", ClientProfile.Version.of("1.0.0-1").toCleanString());
|
Assertions.assertEquals(ClientProfile.Version.of("1.0.0-1").toCleanString(), "1.0.0.1");
|
||||||
Assertions.assertEquals("1.0.0", ClientProfile.Version.of("-----1.0.0").toCleanString());
|
Assertions.assertEquals(ClientProfile.Version.of("-----1.0.0").toCleanString(), "1.0.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -49,12 +49,12 @@ public void dependenciesTest() {
|
||||||
moduleManager.loadModule(new Depend3Module());
|
moduleManager.loadModule(new Depend3Module());
|
||||||
moduleManager.loadModule(new MainModule());
|
moduleManager.loadModule(new MainModule());
|
||||||
moduleManager.initModules(null);
|
moduleManager.initModules(null);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("depend1").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("depend1").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("depend2").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("depend2").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("depend3").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("depend3").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("internal").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("internal").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("virtual").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("virtual").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("main").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("main").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -62,7 +62,7 @@ public void cyclicTest() {
|
||||||
moduleManager.loadModule(new CyclicDependModule());
|
moduleManager.loadModule(new CyclicDependModule());
|
||||||
moduleManager.loadModule(new Cyclic2DependModule());
|
moduleManager.loadModule(new Cyclic2DependModule());
|
||||||
moduleManager.initModules(null);
|
moduleManager.initModules(null);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("cyclic1").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("cyclic1").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
Assertions.assertEquals(LauncherModule.InitStatus.FINISH, moduleManager.getModule("cyclic2").getInitStatus());
|
Assertions.assertEquals(moduleManager.getModule("cyclic2").getInitStatus(), LauncherModule.InitStatus.FINISH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ public Depend1Module() {
|
||||||
@Override
|
@Override
|
||||||
public void init(LauncherInitContext initContext) {
|
public void init(LauncherInitContext initContext) {
|
||||||
InternalModule module = modulesManager.getModule(InternalModule.class);
|
InternalModule module = modulesManager.getModule(InternalModule.class);
|
||||||
Assertions.assertEquals(InitStatus.FINISH, module.getInitStatus());
|
Assertions.assertEquals(module.getInitStatus(), InitStatus.FINISH);
|
||||||
Depend3Module module1 = modulesManager.getModule(Depend3Module.class);
|
Depend3Module module1 = modulesManager.getModule(Depend3Module.class);
|
||||||
Assertions.assertEquals(InitStatus.FINISH, module1.getInitStatus());
|
Assertions.assertEquals(module1.getInitStatus(), InitStatus.FINISH);
|
||||||
VirtualInterface virtualInterface = modulesManager.getModuleByInterface(VirtualInterface.class);
|
VirtualInterface virtualInterface = modulesManager.getModuleByInterface(VirtualInterface.class);
|
||||||
Assertions.assertEquals(InitStatus.FINISH, ((LauncherModule) virtualInterface).getInitStatus());
|
Assertions.assertEquals(((LauncherModule) virtualInterface).getInitStatus(), InitStatus.FINISH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ public MainModule() {
|
||||||
@Override
|
@Override
|
||||||
public void init(LauncherInitContext initContext) {
|
public void init(LauncherInitContext initContext) {
|
||||||
Depend1Module module = modulesManager.getModule(Depend1Module.class);
|
Depend1Module module = modulesManager.getModule(Depend1Module.class);
|
||||||
Assertions.assertEquals(InitStatus.FINISH, module.getInitStatus());
|
Assertions.assertEquals(module.getInitStatus(), InitStatus.FINISH);
|
||||||
Depend2Module module2 = modulesManager.getModule(Depend2Module.class);
|
Depend2Module module2 = modulesManager.getModule(Depend2Module.class);
|
||||||
Assertions.assertEquals(InitStatus.FINISH, module2.getInitStatus());
|
Assertions.assertEquals(module2.getInitStatus(), InitStatus.FINISH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
apply plugin: 'org.openjfx.javafxplugin'
|
apply plugin: 'org.openjfx.javafxplugin'
|
||||||
|
|
||||||
String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper"
|
String mainClassName = "pro.gravit.launcher.ClientLauncherWrapper"
|
||||||
|
String mainAgentName = "pro.gravit.launcher.LauncherAgent"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
|
"Premain-Class": mainAgentName,
|
||||||
"Multi-Release": "true")
|
"Multi-Release": "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,9 +86,11 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
modulesManager.invokeEvent(new PreConfigPhase());
|
modulesManager.invokeEvent(new PreConfigPhase());
|
||||||
LogHelper.debug("Reading ClientLauncher params");
|
LogHelper.debug("Reading ClientLauncher params");
|
||||||
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
||||||
ClientLauncherMethods.verifyNoAgent();
|
if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) {
|
||||||
|
ClientLauncherMethods.verifyNoAgent();
|
||||||
|
}
|
||||||
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) {
|
||||||
LogHelper.error("Timestamp failed: current %d | params %d | diff %d", System.currentTimeMillis(), params.timestamp, System.currentTimeMillis() - params.timestamp);
|
LogHelper.error("Timestamp failed. Exit");
|
||||||
ClientLauncherMethods.exitLauncher(-662);
|
ClientLauncherMethods.exitLauncher(-662);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -118,13 +120,14 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
LogHelper.debug("Verifying ClientLauncher sign and classpath");
|
LogHelper.debug("Verifying ClientLauncher sign and classpath");
|
||||||
Set<Path> ignoredPath = new HashSet<>();
|
Set<Path> ignoredPath = new HashSet<>();
|
||||||
List<Path> classpath = resolveClassPath(ignoredPath, clientDir, params.actions, params.profile)
|
List<Path> classpath = resolveClassPath(ignoredPath, clientDir, params.actions, params.profile)
|
||||||
|
.filter(x -> !profile.getModulePath().contains(clientDir.relativize(x).toString()))
|
||||||
.collect(Collectors.toCollection(ArrayList::new));
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
if(LogHelper.isDevEnabled()) {
|
if(LogHelper.isDevEnabled()) {
|
||||||
for(var e : classpath) {
|
for(var e : classpath) {
|
||||||
LogHelper.dev("Classpath entry %s", e);
|
LogHelper.dev("Classpath entry %s", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<URL> classpathURLs = classpath.stream().map(IOHelper::toURL).toList();
|
List<URL> classpathURLs = classpath.stream().map(IOHelper::toURL).collect(Collectors.toList());
|
||||||
// Start client with WatchService monitoring
|
// Start client with WatchService monitoring
|
||||||
RequestService service;
|
RequestService service;
|
||||||
if (params.offlineMode) {
|
if (params.offlineMode) {
|
||||||
|
@ -158,7 +161,7 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
|
System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER || classLoaderConfig == ClientProfile.ClassLoaderConfig.MODULE) {
|
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
||||||
if(JVMHelper.JVM_VERSION <= 11) {
|
if(JVMHelper.JVM_VERSION <= 11) {
|
||||||
launch = new LegacyLaunch();
|
launch = new LegacyLaunch();
|
||||||
} else {
|
} else {
|
||||||
|
@ -168,12 +171,20 @@ private static void realMain(String[] args) throws Throwable {
|
||||||
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
|
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
|
||||||
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile));
|
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile));
|
||||||
ClientService.baseURLs = classLoaderControl.getURLs();
|
ClientService.baseURLs = classLoaderControl.getURLs();
|
||||||
|
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.AGENT) {
|
||||||
|
launch = new BasicLaunch(LauncherAgent.inst);
|
||||||
|
classpathURLs.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL());
|
||||||
|
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
||||||
|
for (URL url : classpathURLs) {
|
||||||
|
LauncherAgent.addJVMClassPath(Paths.get(url.toURI()));
|
||||||
|
}
|
||||||
|
ClientService.instrumentation = LauncherAgent.inst;
|
||||||
|
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, null, profile));
|
||||||
|
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
||||||
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
||||||
launch = new BasicLaunch();
|
launch = new BasicLaunch();
|
||||||
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
classLoaderControl = launch.init(classpath, params.nativesDir, options);
|
||||||
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException(String.format("Unknown classLoaderConfig %s", classLoaderConfig));
|
|
||||||
}
|
}
|
||||||
if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) {
|
if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) {
|
||||||
ClientService.classLoaderControl = classLoaderControl;
|
ClientService.classLoaderControl = classLoaderControl;
|
||||||
|
@ -242,11 +253,11 @@ public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedList<Path> resolveClassPathList(Set<Path> ignorePaths, Path clientDir, List<String> classPath) throws IOException {
|
private static LinkedList<Path> resolveClassPathList(Set<Path> ignorePaths, Path clientDir, String... classPath) throws IOException {
|
||||||
return resolveClassPathStream(ignorePaths, clientDir, classPath).collect(Collectors.toCollection(LinkedList::new));
|
return resolveClassPathStream(ignorePaths, clientDir, classPath).collect(Collectors.toCollection(LinkedList::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<Path> resolveClassPathStream(Set<Path> ignorePaths, Path clientDir, List<String> classPath) throws IOException {
|
private static Stream<Path> resolveClassPathStream(Set<Path> ignorePaths, Path clientDir, String... classPath) throws IOException {
|
||||||
Stream.Builder<Path> builder = Stream.builder();
|
Stream.Builder<Path> builder = Stream.builder();
|
||||||
for (String classPathEntry : classPath) {
|
for (String classPathEntry : classPath) {
|
||||||
Path path = clientDir.resolve(IOHelper.toPath(classPathEntry.replace(IOHelper.CROSS_SEPARATOR, IOHelper.PLATFORM_SEPARATOR)));
|
Path path = clientDir.resolve(IOHelper.toPath(classPathEntry.replace(IOHelper.CROSS_SEPARATOR, IOHelper.PLATFORM_SEPARATOR)));
|
||||||
|
@ -290,7 +301,7 @@ private static void launch(ClientProfile profile, ClientParams params) throws Th
|
||||||
params.addClientLegacyArgs(args);
|
params.addClientLegacyArgs(args);
|
||||||
System.setProperty("minecraft.applet.TargetDirectory", params.clientDir);
|
System.setProperty("minecraft.applet.TargetDirectory", params.clientDir);
|
||||||
}
|
}
|
||||||
args.addAll(profile.getClientArgs());
|
Collections.addAll(args, profile.getClientArgs());
|
||||||
for (OptionalAction action : params.actions) {
|
for (OptionalAction action : params.actions) {
|
||||||
if (action instanceof OptionalActionClientArgs) {
|
if (action instanceof OptionalActionClientArgs) {
|
||||||
args.addAll(((OptionalActionClientArgs) action).args);
|
args.addAll(((OptionalActionClientArgs) action).args);
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package pro.gravit.launcher.client;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.client.utils.NativeJVMHalt;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
|
||||||
|
public final class LauncherAgent {
|
||||||
|
public static Instrumentation inst;
|
||||||
|
private static boolean isAgentStarted = false;
|
||||||
|
|
||||||
|
public static void addJVMClassPath(String path) throws IOException {
|
||||||
|
LogHelper.debug("Launcher Agent addJVMClassPath");
|
||||||
|
inst.appendToSystemClassLoaderSearch(new JarFile(new File(path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addJVMClassPath(Path path) throws IOException {
|
||||||
|
LogHelper.debug("Launcher Agent addJVMClassPath");
|
||||||
|
inst.appendToSystemClassLoaderSearch(new JarFile(path.toFile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String agentArgument, Instrumentation instrumentation) {
|
||||||
|
System.out.println("Launcher Agent");
|
||||||
|
checkAgentStacktrace();
|
||||||
|
inst = instrumentation;
|
||||||
|
NativeJVMHalt.initFunc();
|
||||||
|
isAgentStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkAgentStacktrace() {
|
||||||
|
RuntimeException ex = new SecurityException("Error check agent stacktrace");
|
||||||
|
boolean isFoundNative = false;
|
||||||
|
boolean foundPreMain = false;
|
||||||
|
for (StackTraceElement e : ex.getStackTrace()) {
|
||||||
|
if (e.isNativeMethod()) {
|
||||||
|
if (!isFoundNative) isFoundNative = true;
|
||||||
|
else throw ex;
|
||||||
|
}
|
||||||
|
if (e.getMethodName().equals("premain")) {
|
||||||
|
if (!foundPreMain) foundPreMain = true;
|
||||||
|
else throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isFoundNative || !foundPreMain) throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStarted() {
|
||||||
|
return isAgentStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAgentStarted() {
|
||||||
|
return isAgentStarted;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
compileOnly group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline', version: rootProject['verJline']
|
||||||
compileOnly group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline-reader', version: rootProject['verJline']
|
||||||
compileOnly group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
compileOnly group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
||||||
|
compileOnly group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: rootProject['verBcprov']
|
||||||
compileOnly group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
compileOnly group: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
|
||||||
api group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
api group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
||||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||||
|
|
|
@ -282,7 +282,7 @@ public enum WalkAction {
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface WalkCallback {
|
public interface WalkCallback {
|
||||||
WalkAction walked(String path, String name, HashedEntry entry);
|
WalkAction walked(String path, String name, HashedEntry entry) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FindRecursiveResult {
|
public static class FindRecursiveResult {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.utils;
|
package pro.gravit.utils;
|
||||||
|
|
||||||
public class HookException extends RuntimeException {
|
public class HookException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = -529141998961943161L;
|
||||||
|
|
||||||
public HookException(String message) {
|
public HookException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|
|
@ -6,7 +6,7 @@ public final class Version implements Comparable<Version> {
|
||||||
|
|
||||||
public static final int MAJOR = 5;
|
public static final int MAJOR = 5;
|
||||||
public static final int MINOR = 6;
|
public static final int MINOR = 6;
|
||||||
public static final int PATCH = 11;
|
public static final int PATCH = 1;
|
||||||
public static final int BUILD = 1;
|
public static final int BUILD = 1;
|
||||||
public static final Version.Type RELEASE = Type.STABLE;
|
public static final Version.Type RELEASE = Type.STABLE;
|
||||||
public final int major;
|
public final int major;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.utils.command;
|
package pro.gravit.utils.command;
|
||||||
|
|
||||||
public final class CommandException extends Exception {
|
public final class CommandException extends Exception {
|
||||||
|
private static final long serialVersionUID = -6588814993972117772L;
|
||||||
|
|
||||||
|
|
||||||
public CommandException(String message) {
|
public CommandException(String message) {
|
||||||
|
|
|
@ -10,18 +10,8 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class CommandHandler implements Runnable {
|
public abstract class CommandHandler implements Runnable {
|
||||||
protected final List<Category> categories;
|
private final List<Category> categories = new ArrayList<>();
|
||||||
protected final CommandCategory baseCategory;
|
private final CommandCategory baseCategory = new BaseCommandCategory();
|
||||||
|
|
||||||
public CommandHandler() {
|
|
||||||
this.categories = new ArrayList<>();
|
|
||||||
this.baseCategory = new BaseCommandCategory();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CommandHandler(List<Category> categories, CommandCategory baseCategory) {
|
|
||||||
this.categories = categories;
|
|
||||||
this.baseCategory = baseCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void eval(String line, boolean bell) {
|
public void eval(String line, boolean bell) {
|
||||||
LogHelper.info("Command '%s'", line);
|
LogHelper.info("Command '%s'", line);
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class StdCommandHandler extends CommandHandler {
|
public class StdCommandHandler extends CommandHandler {
|
||||||
private final BufferedReader reader;
|
private final BufferedReader reader;
|
||||||
|
@ -16,31 +14,6 @@ public StdCommandHandler(boolean readCommands) {
|
||||||
reader = readCommands ? IOHelper.newReader(System.in) : null;
|
reader = readCommands ? IOHelper.newReader(System.in) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StdCommandHandler(InputStream stream) {
|
|
||||||
super();
|
|
||||||
this.reader = IOHelper.newReader(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdCommandHandler(BufferedReader reader) {
|
|
||||||
super();
|
|
||||||
this.reader = reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, boolean readCommands) {
|
|
||||||
super(categories, baseCategory);
|
|
||||||
this.reader = readCommands ? IOHelper.newReader(System.in) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, InputStream stream) {
|
|
||||||
super(categories, baseCategory);
|
|
||||||
this.reader = IOHelper.newReader(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected StdCommandHandler(List<Category> categories, CommandCategory baseCategory, BufferedReader reader) {
|
|
||||||
super(categories, baseCategory);
|
|
||||||
this.reader = reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bell() {
|
public void bell() {
|
||||||
}
|
}
|
||||||
|
@ -64,16 +37,4 @@ public void clear() throws IOException {
|
||||||
public String readLine() throws IOException {
|
public String readLine() throws IOException {
|
||||||
return reader == null ? null : reader.readLine();
|
return reader == null ? null : reader.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, boolean readCommands) {
|
|
||||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, readCommands);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, InputStream stream) {
|
|
||||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdCommandHandler ofHandler(CommandHandler commandHandler, BufferedReader reader) {
|
|
||||||
return new StdCommandHandler(commandHandler.categories, commandHandler.baseCategory, reader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,39 +221,37 @@ public static ArgsParseResult parseJavaArgs(List<String> args) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (arg) {
|
if(arg.equals("--module-path") || arg.equals("-p")) {
|
||||||
case "--module-path", "-p" -> {
|
prevArgType = PrevArgType.MODULE_PATH;
|
||||||
prevArgType = PrevArgType.MODULE_PATH;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--classpath") || arg.equals("-cp")) {
|
||||||
case "--classpath", "-cp" -> {
|
prevArgType = PrevArgType.CLASSPATH;
|
||||||
prevArgType = PrevArgType.CLASSPATH;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--add-modules")) {
|
||||||
case "--add-modules" -> {
|
prevArgType = PrevArgType.ADD_MODULES;
|
||||||
prevArgType = PrevArgType.ADD_MODULES;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--add-opens")) {
|
||||||
case "--add-opens" -> {
|
prevArgType = PrevArgType.ADD_OPENS;
|
||||||
prevArgType = PrevArgType.ADD_OPENS;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--add-exports")) {
|
||||||
case "--add-exports" -> {
|
prevArgType = PrevArgType.ADD_EXPORTS;
|
||||||
prevArgType = PrevArgType.ADD_EXPORTS;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--add-reads")) {
|
||||||
case "--add-reads" -> {
|
prevArgType = PrevArgType.ADD_READS;
|
||||||
prevArgType = PrevArgType.ADD_READS;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("--module") || arg.equals("-m")) {
|
||||||
case "--module", "-m" -> {
|
prevArgType = PrevArgType.MODULE;
|
||||||
prevArgType = PrevArgType.MODULE;
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if(arg.equals("-jar")) {
|
||||||
case "-jar" -> {
|
prevArgType = PrevArgType.JAR;
|
||||||
prevArgType = PrevArgType.JAR;
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jvmArgs.add(arg);
|
jvmArgs.add(arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public static byte[] getClassBytes(Class<?> clazz, ClassLoader classLoader) thro
|
||||||
return IOHelper.read(classLoader.getResourceAsStream(getClassFile(clazz)));
|
return IOHelper.read(classLoader.getResourceAsStream(getClassFile(clazz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputStream getClassBytesStream(Class<?> clazz) {
|
public static InputStream getClassBytesStream(Class<?> clazz) throws IOException {
|
||||||
return getClassBytesStream(clazz, clazz.getClassLoader());
|
return getClassBytesStream(clazz, clazz.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ public void addTransformer(ClassTransformer transformer) {
|
||||||
}
|
}
|
||||||
instrumentation.addTransformer(new ClassFileTransformer() {
|
instrumentation.addTransformer(new ClassFileTransformer() {
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
|
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||||
if(transformer.filter(null, className)) {
|
if(transformer.filter(null, className)) {
|
||||||
return transformer.transform(null, className, protectionDomain, classfileBuffer);
|
return transformer.transform(null, className, protectionDomain, classfileBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,10 +54,6 @@ private class LegacyClassLoader extends URLClassLoader {
|
||||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||||
private String nativePath;
|
private String nativePath;
|
||||||
|
|
||||||
static {
|
|
||||||
ClassLoader.registerAsParallelCapable();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
private final List<String> packages = new ArrayList<>();
|
||||||
public LegacyClassLoader(URL[] urls) {
|
public LegacyClassLoader(URL[] urls) {
|
||||||
super(urls);
|
super(urls);
|
||||||
|
@ -123,9 +119,6 @@ protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
if(nativePath == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,11 +164,6 @@ private class ModuleClassLoader extends URLClassLoader {
|
||||||
private String nativePath;
|
private String nativePath;
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
private final List<String> packages = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
|
||||||
ClassLoader.registerAsParallelCapable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
||||||
super("LAUNCHER", urls, parent);
|
super("LAUNCHER", urls, parent);
|
||||||
packages.add("pro.gravit.launcher.");
|
packages.add("pro.gravit.launcher.");
|
||||||
|
@ -262,9 +257,6 @@ protected Class<?> findClass(String moduleName, String name) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findLibrary(String name) {
|
public String findLibrary(String name) {
|
||||||
if(nativePath == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@ public void main() {
|
||||||
String json2 = gson.toJson(new MyTestClass2("BBBB"), TestInterface.class);
|
String json2 = gson.toJson(new MyTestClass2("BBBB"), TestInterface.class);
|
||||||
TestInterface test1 = gson.fromJson(json, TestInterface.class);
|
TestInterface test1 = gson.fromJson(json, TestInterface.class);
|
||||||
TestInterface test2 = gson.fromJson(json2, TestInterface.class);
|
TestInterface test2 = gson.fromJson(json2, TestInterface.class);
|
||||||
Assertions.assertEquals("AAAA", test1.get());
|
Assertions.assertEquals(test1.get(), "AAAA");
|
||||||
Assertions.assertEquals("BBBB", test2.get());
|
Assertions.assertEquals(test2.get(), "BBBB");
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestInterface {
|
public interface TestInterface {
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
||||||
|
@ -122,7 +121,6 @@ public void run(String... args) throws Throwable {
|
||||||
}
|
}
|
||||||
LogHelper.debug("Read ServerWrapperConfig.json");
|
LogHelper.debug("Read ServerWrapperConfig.json");
|
||||||
loadConfig();
|
loadConfig();
|
||||||
config.applyEnv();
|
|
||||||
updateLauncherConfig();
|
updateLauncherConfig();
|
||||||
Launcher.applyLauncherEnv(Objects.requireNonNullElse(config.env, LauncherConfig.LauncherEnvironment.STD));
|
Launcher.applyLauncherEnv(Objects.requireNonNullElse(config.env, LauncherConfig.LauncherEnvironment.STD));
|
||||||
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address).get();
|
StdWebSocketService service = StdWebSocketService.initWebSockets(config.address).get();
|
||||||
|
@ -306,38 +304,5 @@ public void apply() {
|
||||||
ConfigService.checkServerConfig.needProperties = checkServerNeedProperties;
|
ConfigService.checkServerConfig.needProperties = checkServerNeedProperties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyEnv() {
|
|
||||||
this.authId = applyEnvOrDefault("SERVERWRAPPER_AUTH_ID", this.authId);
|
|
||||||
this.address = applyEnvOrDefault("SERVERWRAPPER_ADDRESS", this.address);
|
|
||||||
this.serverName = applyEnvOrDefault("SERVERWRAPPER_SERVER_NAME", this.serverName);
|
|
||||||
this.encodedServerEcPublicKey = applyEnvOrDefault("SERVERWRAPPER_EC_PUBLIC_KEY", Base64.getUrlDecoder()::decode, null);
|
|
||||||
this.encodedServerRsaPublicKey = applyEnvOrDefault("SERVERWRAPPER_RSA_PUBLIC_KEY", Base64.getUrlDecoder()::decode, null);
|
|
||||||
{
|
|
||||||
String token = System.getenv("SERVERWRAPPER_CHECK_SERVER_TOKEN");
|
|
||||||
if(token != null) {
|
|
||||||
if(extendedTokens == null) {
|
|
||||||
extendedTokens = new HashMap<>();
|
|
||||||
}
|
|
||||||
extendedTokens.put("checkServer", new Request.ExtendedToken(token, 0L));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String applyEnvOrDefault(String envName, String def) {
|
|
||||||
String value = System.getenv(envName);
|
|
||||||
if(value == null) {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static<T> T applyEnvOrDefault(String envName, Function<String, T> mappingFunction, T def) {
|
|
||||||
String value = System.getenv(envName);
|
|
||||||
if(value == null) {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
return mappingFunction.apply(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,8 @@ public ServerWrapperSetup() throws IOException {
|
||||||
|
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
ServerWrapper wrapper = ServerWrapper.wrapper;
|
ServerWrapper wrapper = ServerWrapper.wrapper;
|
||||||
String jarName = System.getenv("SERVERWRAPPER_JAR_NAME");
|
System.out.println("Print server jar filename:");
|
||||||
if(jarName == null) {
|
String jarName = commands.commandHandler.readLine();
|
||||||
System.out.println("Print server jar filename:");
|
|
||||||
jarName = commands.commandHandler.readLine();
|
|
||||||
}
|
|
||||||
Path jarPath = Paths.get(jarName);
|
Path jarPath = Paths.get(jarName);
|
||||||
String mainClassName;
|
String mainClassName;
|
||||||
String agentClassName;
|
String agentClassName;
|
||||||
|
@ -59,18 +56,14 @@ public void run() throws Exception {
|
||||||
if (agentClassName != null) {
|
if (agentClassName != null) {
|
||||||
LogHelper.info("Found PremainClass %s", agentClassName);
|
LogHelper.info("Found PremainClass %s", agentClassName);
|
||||||
}
|
}
|
||||||
if(wrapper.config.serverName == null || wrapper.config.serverName.isEmpty()) {
|
System.out.println("Print your server name:");
|
||||||
System.out.println("Print your server name:");
|
wrapper.config.serverName = commands.commandHandler.readLine();
|
||||||
wrapper.config.serverName = commands.commandHandler.readLine();
|
|
||||||
}
|
|
||||||
wrapper.config.mainclass = mainClassName;
|
wrapper.config.mainclass = mainClassName;
|
||||||
boolean altMode = false;
|
boolean altMode = false;
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
if(!Request.isAvailable() || Request.getRequestService().isClosed()) {
|
if(!Request.isAvailable() || Request.getRequestService().isClosed()) {
|
||||||
if(wrapper.config.address == null || wrapper.config.address.isEmpty()) {
|
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
||||||
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
wrapper.config.address = commands.commandHandler.readLine();
|
||||||
wrapper.config.address = commands.commandHandler.readLine();
|
|
||||||
}
|
|
||||||
StdWebSocketService service;
|
StdWebSocketService service;
|
||||||
try {
|
try {
|
||||||
service = StdWebSocketService.initWebSockets(wrapper.config.address).get();
|
service = StdWebSocketService.initWebSockets(wrapper.config.address).get();
|
||||||
|
@ -80,11 +73,9 @@ public void run() throws Exception {
|
||||||
}
|
}
|
||||||
Request.setRequestService(service);
|
Request.setRequestService(service);
|
||||||
}
|
}
|
||||||
if(wrapper.config.extendedTokens == null || wrapper.config.extendedTokens.get("checkServer") == null) {
|
System.out.println("Print server token:");
|
||||||
System.out.println("Print server token:");
|
String checkServerToken = commands.commandHandler.readLine();
|
||||||
String checkServerToken = commands.commandHandler.readLine();
|
wrapper.config.extendedTokens.put("checkServer", new Request.ExtendedToken(checkServerToken, 0));
|
||||||
wrapper.config.extendedTokens.put("checkServer", new Request.ExtendedToken(checkServerToken, 0));
|
|
||||||
}
|
|
||||||
wrapper.updateLauncherConfig();
|
wrapper.updateLauncherConfig();
|
||||||
try {
|
try {
|
||||||
wrapper.restore();
|
wrapper.restore();
|
||||||
|
@ -102,9 +93,7 @@ public void run() throws Exception {
|
||||||
}
|
}
|
||||||
if(wrapper.profile != null && wrapper.profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_18) >= 0) {
|
if(wrapper.profile != null && wrapper.profile.getVersion().compareTo(ClientProfileVersions.MINECRAFT_1_18) >= 0) {
|
||||||
LogHelper.info("Switch to alternative start mode (1.18)");
|
LogHelper.info("Switch to alternative start mode (1.18)");
|
||||||
if(!wrapper.config.classpath.contains(jarName)) {
|
wrapper.config.classpath.add(jarName);
|
||||||
wrapper.config.classpath.add(jarName);
|
|
||||||
}
|
|
||||||
wrapper.config.classLoaderConfig = ClientProfile.ClassLoaderConfig.LAUNCHER;
|
wrapper.config.classLoaderConfig = ClientProfile.ClassLoaderConfig.LAUNCHER;
|
||||||
altMode = true;
|
altMode = true;
|
||||||
}
|
}
|
||||||
|
|
11
build.gradle
11
build.gradle
|
@ -1,11 +1,11 @@
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'signing'
|
id 'signing'
|
||||||
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
id 'org.openjfx.javafxplugin' version '0.1.0' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.6.11'
|
version = '5.6.1'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
@ -30,13 +30,6 @@
|
||||||
maven {
|
maven {
|
||||||
url "https://jitpack.io/"
|
url "https://jitpack.io/"
|
||||||
}
|
}
|
||||||
maven {
|
|
||||||
url 'https://maven.gravit-support.ru/repository/jitpack'
|
|
||||||
credentials {
|
|
||||||
username = 'gravitlauncher'
|
|
||||||
password = 'gravitlauncher'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue