mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-03-26 11:08:15 +03:00
Compare commits
213 commits
Author | SHA1 | Date | |
---|---|---|---|
|
df77a1ebd6 | ||
|
641796b44e | ||
|
b7ed56b27e | ||
|
f119bd4b30 | ||
|
bbff0eac64 | ||
|
41f93b9f8d | ||
|
263cf26258 | ||
|
b9ad7c0f26 | ||
|
5ba32e3405 | ||
|
907332ff06 | ||
|
1d63fbbd93 | ||
|
2f4667f5a6 | ||
|
92ada65079 | ||
|
29d98defff | ||
|
d7a379383b | ||
|
0111b2ca2b | ||
|
4671dfe49d | ||
|
bb63aaa0ab | ||
|
912caa6b8a | ||
|
926094076c | ||
|
a1af61a599 | ||
|
81b16cb54e | ||
|
a486f21fa2 | ||
|
86ea247f07 | ||
|
d26b179006 | ||
|
c4d1251429 | ||
|
f16f5fbc6d | ||
|
abe904d73c | ||
|
eaf685897f | ||
|
c8934d887a | ||
|
070a5d9b69 | ||
|
cc2bce4300 | ||
|
c7f4d8ac49 | ||
|
7dcb08fdaf | ||
|
9d870849a1 | ||
|
dda3ebc7b4 | ||
|
537623afaf | ||
|
0cff6e247a | ||
|
b85075c559 | ||
|
3e654f4d79 | ||
|
46f1f7b69e | ||
|
981f2ac3dd | ||
|
8509cbb6b5 | ||
|
1119625d12 | ||
|
9a69426547 | ||
|
31cbfe2919 | ||
|
27ebadcd19 | ||
|
b3349044b5 | ||
|
c43edeb982 | ||
|
1ff58099bd | ||
|
9fba637f83 | ||
|
ca70ee78d1 | ||
|
5e116a81e5 | ||
|
b0f799d194 | ||
|
63f9f8e21d | ||
|
b8ccbc5e48 | ||
|
a687c5afd8 | ||
|
3969d81db7 | ||
|
a30d0624a1 | ||
|
d5abe0d411 | ||
|
1e7a856a99 | ||
|
e6f5b585a7 | ||
|
2ed4abf9b0 | ||
|
af2dcec8cd | ||
|
9bffe07d36 | ||
|
4be299f6ca | ||
|
ef4f14f9b4 | ||
|
d720328bc4 | ||
|
88f1eaf750 | ||
|
a5ef86b105 | ||
|
b1a5ecdc13 | ||
|
68e9affbe0 | ||
|
7d7485afdc | ||
|
c2926b5b40 | ||
|
9c82d76781 | ||
|
450774de7e | ||
|
f88c0308f8 | ||
|
20f713be05 | ||
|
5bf92d9a00 | ||
|
903c4d40c5 | ||
|
ede9ab2c85 | ||
|
c8c83c0dba | ||
|
1bd5d8854c | ||
|
992d31c883 | ||
|
accbbe6b13 | ||
|
0894e0b9c3 | ||
|
925007015f | ||
|
ec526a343d | ||
|
1bebd8de2c | ||
|
c7781b30be | ||
|
df9d05a49c | ||
|
03d53d4a09 | ||
|
c261496af8 | ||
|
8c11ab0cbe | ||
|
78b4f1e3aa | ||
|
bbc5f1722b | ||
|
51411c5838 | ||
|
3b22b76278 | ||
|
ef9cbfe0da | ||
|
353b663e12 | ||
|
78be606029 | ||
|
584acdb8c3 | ||
|
7f6a645dd7 | ||
|
c6930ded74 | ||
|
c2a6a408c4 | ||
|
01cd50840a | ||
|
bb4d5b99c6 | ||
|
ff2f647b50 | ||
|
79fc42e86a | ||
|
5b8aa8cd5e | ||
|
a4e5ef9d01 | ||
|
1d5044c24a | ||
|
b84911d445 | ||
|
6a173b9b1b | ||
|
6a53891c6a | ||
|
7c637e078d | ||
|
c9a81da60c | ||
|
6c0ead015b | ||
|
b5457ee866 | ||
|
52c9196dcc | ||
|
095a5aef8b | ||
|
765f1a9d8f | ||
|
9bd65c797b | ||
|
8908710ad6 | ||
|
748612783c | ||
|
42cf9bc79e | ||
|
8a81989d65 | ||
|
58fd3a7e8b | ||
|
cc6ed82afb | ||
|
00ab20473c | ||
|
cdb54b34de | ||
|
1ebe68f5b8 | ||
|
b719255bd5 | ||
|
6ecf716fca | ||
|
873100cf0a | ||
|
a8b165f081 | ||
|
06ada30459 | ||
|
6017a89e20 | ||
|
bd677c26ba | ||
|
e5840243b3 | ||
|
09d36e066a | ||
|
038af764a1 | ||
|
f7decac23d | ||
|
1710eb7bec | ||
|
3926f3e5bf | ||
|
7759ea9182 | ||
|
ac6c312ed4 | ||
|
3e6af5afd3 | ||
|
044813cca2 | ||
|
730efae7c7 | ||
|
bc6da641d6 | ||
|
5c7f7eedec | ||
|
e72e4ebb92 | ||
|
d811a04cba | ||
|
572052163b | ||
|
666c8a4b3e | ||
|
ef5f932afb | ||
|
3002371fad | ||
|
998db80837 | ||
|
494b3227b6 | ||
|
d686d9a388 | ||
|
e28c9773fc | ||
|
7ff062f9e4 | ||
|
29619bb7a4 | ||
|
3179ee00eb | ||
|
f484f045ca | ||
|
ead4689bcf | ||
|
7a96e67517 | ||
|
b21082e201 | ||
|
8cd43b0324 | ||
|
3e8c1adebe | ||
|
666644c9e0 | ||
|
3152758d31 | ||
|
80176ff1e1 | ||
|
11382d3465 | ||
|
31285a8066 | ||
|
3ec79e3e93 | ||
|
a4bf033aa8 | ||
|
4e50cea93a | ||
|
d40dc09aca | ||
|
0b59d6c0ed | ||
|
80fc2900c8 | ||
|
4f47398211 | ||
|
9676e55bcb | ||
|
aa7b007616 | ||
|
35bdf1607f | ||
|
7060697bad | ||
|
34ac6a0f28 | ||
|
5370130c2d | ||
|
a0788e4623 | ||
|
0c754ae5e6 | ||
|
c9ccf36252 | ||
|
b7b7afbdbb | ||
|
2fdd7d0199 | ||
|
f1922c52e2 | ||
|
efe967587c | ||
|
f2b92c2bbd | ||
|
4251725467 | ||
|
82bf2fdf56 | ||
|
f1bc0ea28a | ||
|
b3eb0ebb98 | ||
|
8e82f5cd84 | ||
|
90f6d002d1 | ||
|
449798d52b | ||
|
f321b8bd27 | ||
|
64635cbb9b | ||
|
4607ab88bf | ||
|
e6516a8991 | ||
|
dfbb6e507a | ||
|
0855fc589d | ||
|
c9b6b0279a | ||
|
f8b060422e | ||
|
f6f6ea13ad |
430 changed files with 5611 additions and 3785 deletions
14
.github/workflows/push.yml
vendored
14
.github/workflows/push.yml
vendored
|
@ -6,20 +6,21 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: gravit-${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}-launcher
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: temurin
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
@ -27,6 +28,9 @@ jobs:
|
|||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Generate and submit dependency graph
|
||||
uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5
|
||||
|
||||
- name: Create artifacts
|
||||
run: |
|
||||
mkdir -p artifacts/modules
|
||||
|
@ -40,7 +44,7 @@ jobs:
|
|||
cp modules/*_lmodule/build/libs/*.jar artifacts/modules || true
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Launcher
|
||||
path: artifacts
|
||||
|
@ -61,7 +65,7 @@ jobs:
|
|||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.event.ref, 'refs/tags')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
def mainClassName = "pro.gravit.launchserver.LaunchServerStarter"
|
||||
def mainClassName = "pro.gravit.launchserver.Main"
|
||||
def mainAgentName = "pro.gravit.launchserver.StarterAgent"
|
||||
|
||||
evaluationDependsOn(':Launcher')
|
||||
|
@ -13,20 +13,24 @@
|
|||
maven {
|
||||
url "https://jitpack.io/"
|
||||
}
|
||||
maven {
|
||||
url 'https://maven.gravit-support.ru/repository/jitpack'
|
||||
credentials {
|
||||
username = 'gravitlauncher'
|
||||
password = 'gravitlauncher'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceCompatibility = '21'
|
||||
targetCompatibility = '21'
|
||||
|
||||
configurations {
|
||||
compileOnlyA
|
||||
bundleOnly
|
||||
bundle
|
||||
hikari
|
||||
pack
|
||||
launch4j
|
||||
bundleOnly.extendsFrom bundle
|
||||
api.extendsFrom bundle, hikari, pack, launch4j
|
||||
api.extendsFrom bundle, pack
|
||||
}
|
||||
|
||||
jar {
|
||||
|
@ -37,9 +41,6 @@
|
|||
manifest.attributes("Main-Class": mainClassName,
|
||||
"Premain-Class": mainAgentName,
|
||||
"Multi-Release": "true",
|
||||
"Can-Redefine-Classes": "true",
|
||||
"Can-Retransform-Classes": "true",
|
||||
"Can-Set-Native-Method-Prefix": "true"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -64,10 +65,7 @@
|
|||
dependsOn jar
|
||||
archiveClassifier.set('clean')
|
||||
manifest.attributes("Main-Class": mainClassName,
|
||||
"Premain-Class": mainAgentName,
|
||||
"Can-Redefine-Classes": "true",
|
||||
"Can-Retransform-Classes": "true",
|
||||
"Can-Set-Native-Method-Prefix": "true"
|
||||
"Automatic-Module-Name": "launchserver"
|
||||
)
|
||||
from sourceSets.main.output
|
||||
}
|
||||
|
@ -75,95 +73,60 @@
|
|||
|
||||
dependencies {
|
||||
pack project(':LauncherAPI')
|
||||
pack project(':LauncherModernCore')
|
||||
bundle group: 'me.tongfei', name: 'progressbar', version: '0.9.2'
|
||||
bundle group: 'com.github.Marcono1234', name: 'gson-record-type-adapter-factory', version: 'v0.2.0'
|
||||
bundle group: 'me.tongfei', name: 'progressbar', version: '0.10.1'
|
||||
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-reader', version: rootProject['verJline']
|
||||
bundle group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
|
||||
bundle group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: rootProject['verBcpkix']
|
||||
bundle group: 'org.bouncycastle', name: 'bcprov-jdk18on', 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: 'io.netty', name: 'netty-all', 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-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: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
|
||||
bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn']
|
||||
bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn']
|
||||
bundle group: 'com.h2database', name: 'h2', version: rootProject['verH2Conn']
|
||||
bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard']
|
||||
bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j']
|
||||
bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j-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-impl', 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'])
|
||||
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: rootProject['verJunit']
|
||||
|
||||
hikari 'io.micrometer:micrometer-core:1.8.4'
|
||||
hikari('com.zaxxer:HikariCP:5.0.1') {
|
||||
bundle 'io.micrometer:micrometer-core:1.14.4'
|
||||
bundle('com.zaxxer:HikariCP:6.2.1') {
|
||||
exclude group: 'javassist'
|
||||
exclude group: 'io.micrometer'
|
||||
exclude group: 'org.slf4j'
|
||||
}
|
||||
|
||||
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j']) {
|
||||
exclude group: 'org.apache.ant'
|
||||
exclude group: 'net.java.abeille'
|
||||
exclude group: 'foxtrot'
|
||||
exclude group: 'com.jgoodies'
|
||||
exclude group: 'org.slf4j'
|
||||
}
|
||||
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-win32') { transitive = false }
|
||||
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-linux64') { transitive = false }
|
||||
|
||||
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('launch4j', Copy) {
|
||||
duplicatesStrategy = 'EXCLUDE'
|
||||
into "$buildDir/libs/libraries/launch4j"
|
||||
from(configurations.launch4j.collect {
|
||||
it.isDirectory() ? it : ((it.getName().startsWith("launch4j") && it.getName().contains("workdir")) ? zipTree(it) : it)
|
||||
})
|
||||
includeEmptyDirs false
|
||||
eachFile { FileCopyDetails fcp ->
|
||||
if (fcp.relativePath.pathString.startsWith("launch4j-") &&
|
||||
fcp.relativePath.pathString.contains("workdir")) {
|
||||
def segments = fcp.relativePath.segments
|
||||
def pathSegments = segments[1..-1] as String[]
|
||||
fcp.relativePath = new RelativePath(!fcp.file.isDirectory(), pathSegments)
|
||||
} else if (fcp.relativePath.pathString.contains("META-INF")) fcp.exclude()
|
||||
fcp.mode = 0755
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('dumpLibs', Copy) {
|
||||
duplicatesStrategy = 'EXCLUDE'
|
||||
dependsOn tasks.hikari, tasks.launch4j
|
||||
into "$buildDir/libs/libraries"
|
||||
from configurations.bundleOnly
|
||||
}
|
||||
|
||||
tasks.register('dumpCompileOnlyLibs', Copy) {
|
||||
duplicatesStrategy = 'EXCLUDE'
|
||||
into "$buildDir/libs/launcher-libraries-compile"
|
||||
from configurations.compileOnlyA
|
||||
}
|
||||
|
||||
tasks.register('bundle', Zip) {
|
||||
duplicatesStrategy = 'EXCLUDE'
|
||||
dependsOn parent.childProjects.Launcher.tasks.build, tasks.dumpLibs, tasks.dumpCompileOnlyLibs, tasks.jar
|
||||
dependsOn parent.childProjects.Launcher.tasks.build, tasks.dumpLibs, tasks.jar
|
||||
archiveFileName = 'LaunchServer.zip'
|
||||
destinationDirectory = file("$buildDir")
|
||||
from(tasks.dumpLibs.destinationDir) { into 'libraries' }
|
||||
from(tasks.dumpCompileOnlyLibs.destinationDir) { into 'launcher-libraries-compile' }
|
||||
from(tasks.jar)
|
||||
from(parent.childProjects.Launcher.tasks.dumpLibs) { into 'launcher-libraries' }
|
||||
}
|
||||
|
@ -174,7 +137,7 @@ pack project(':LauncherModernCore')
|
|||
from parent.childProjects.Launcher.tasks.dumpLibs
|
||||
}
|
||||
|
||||
assemble.dependsOn tasks.dumpLibs, tasks.dumpCompileOnlyLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar
|
||||
assemble.dependsOn tasks.dumpLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar
|
||||
|
||||
|
||||
publishing {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launchserver.helper.HttpHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -2,15 +2,13 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.events.RequestEvent;
|
||||
import pro.gravit.launcher.events.request.ProfilesRequestEvent;
|
||||
import pro.gravit.launcher.managers.ConfigManager;
|
||||
import pro.gravit.launcher.modules.events.ClosePhase;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.events.RequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
|
||||
import pro.gravit.launcher.base.modules.events.ClosePhase;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
||||
import pro.gravit.launchserver.binary.EXEL4JLauncherBinary;
|
||||
import pro.gravit.launchserver.binary.EXELauncherBinary;
|
||||
import pro.gravit.launchserver.binary.JARLauncherBinary;
|
||||
import pro.gravit.launchserver.binary.LauncherBinary;
|
||||
|
@ -23,6 +21,7 @@
|
|||
import pro.gravit.launchserver.modules.events.*;
|
||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.SocketCommandServer;
|
||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||
import pro.gravit.launchserver.socket.response.auth.ProfilesResponse;
|
||||
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
||||
|
@ -36,7 +35,6 @@
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.ProcessBuilder.Redirect;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.KeyStore;
|
||||
|
@ -73,6 +71,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
/**
|
||||
* The path to the folder with updates/webroot
|
||||
*/
|
||||
@Deprecated
|
||||
public final Path updatesDir;
|
||||
|
||||
// Constant paths
|
||||
|
@ -83,8 +82,11 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
/**
|
||||
* The path to the folder with profiles
|
||||
*/
|
||||
public final Path profilesDir;
|
||||
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
|
||||
*/
|
||||
|
@ -113,22 +115,21 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
// Server
|
||||
public final CommandHandler commandHandler;
|
||||
public final NettyServerSocketHandler nettyServerSocketHandler;
|
||||
public final SocketCommandServer socketCommandServer;
|
||||
public final ScheduledExecutorService service;
|
||||
public final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public final LauncherModuleLoader launcherModuleLoader;
|
||||
private final Logger logger = LogManager.getLogger();
|
||||
public final int shardId;
|
||||
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) 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.tmpDir = directories.tmpDir;
|
||||
this.env = env;
|
||||
this.config = config;
|
||||
this.launchServerConfigManager = launchServerConfigManager;
|
||||
this.modulesManager = modulesManager;
|
||||
this.profilesDir = directories.profilesDir;
|
||||
this.updatesDir = directories.updatesDir;
|
||||
this.keyAgreementManager = keyAgreementManager;
|
||||
this.commandHandler = commandHandler;
|
||||
|
@ -138,6 +139,11 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
launcherLibraries = directories.launcherLibrariesDir;
|
||||
launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
|
||||
launcherPack = directories.launcherPackDir;
|
||||
modulesDir = directories.modules;
|
||||
launcherModulesDir = directories.launcherModules;
|
||||
librariesDir = directories.librariesDir;
|
||||
controlFile = directories.controlFile;
|
||||
this.shardId = shardId;
|
||||
if(!Files.isDirectory(launcherPack)) {
|
||||
Files.createDirectories(launcherPack);
|
||||
}
|
||||
|
@ -188,6 +194,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
}
|
||||
launcherModuleLoader.init();
|
||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||
socketCommandServer = new SocketCommandServer(commandHandler, controlFile);
|
||||
if(config.sign.checkCertificateExpired) {
|
||||
checkCertificateExpired();
|
||||
service.scheduleAtFixedRate(this::checkCertificateExpired, 24, 24, TimeUnit.HOURS);
|
||||
|
@ -268,7 +275,7 @@ public void invoke(String... args) throws Exception {
|
|||
}
|
||||
pair.core.close();
|
||||
pair.core = new RejectAuthCoreProvider();
|
||||
pair.core.init(instance);
|
||||
pair.core.init(instance, pair);
|
||||
}
|
||||
};
|
||||
commands.put("resetauth", resetauth);
|
||||
|
@ -300,12 +307,6 @@ private LauncherBinary binary() {
|
|||
if(event.binary != null) {
|
||||
return event.binary;
|
||||
}
|
||||
try {
|
||||
Class.forName("net.sf.launch4j.Builder");
|
||||
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
logger.warn("Launch4J isn't in classpath.");
|
||||
}
|
||||
return new EXELauncherBinary(this);
|
||||
}
|
||||
|
||||
|
@ -327,12 +328,14 @@ public void close() throws Exception {
|
|||
logger.info("LaunchServer stopped");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Set<ClientProfile> getProfiles() {
|
||||
return profilesList;
|
||||
return config.profileProvider.getProfiles();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setProfiles(Set<ClientProfile> profilesList) {
|
||||
this.profilesList = Collections.unmodifiableSet(profilesList);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void rebindNettyServerSocket() {
|
||||
|
@ -355,17 +358,17 @@ public void run() {
|
|||
}
|
||||
}));
|
||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
||||
// Sync updates dir
|
||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
||||
try {
|
||||
if (!IOHelper.isDir(updatesDir))
|
||||
Files.createDirectory(updatesDir);
|
||||
updatesManager.readUpdatesDir();
|
||||
|
||||
// Sync profiles dir
|
||||
if (!IOHelper.isDir(profilesDir))
|
||||
Files.createDirectory(profilesDir);
|
||||
syncProfilesDir();
|
||||
|
||||
// Sync updates dir
|
||||
config.updatesProvider.syncInitially();
|
||||
|
||||
|
||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
||||
} catch (IOException e) {
|
||||
logger.error("Updates/Profiles not synced", e);
|
||||
|
@ -393,19 +396,14 @@ public void syncLauncherBinaries() throws IOException {
|
|||
|
||||
// Syncing launcher EXE binary
|
||||
logger.info("Syncing launcher EXE binary file");
|
||||
if (!launcherEXEBinary.sync() && config.launch4j.enabled)
|
||||
if (!launcherEXEBinary.sync())
|
||||
logger.warn("Missing launcher EXE binary file");
|
||||
|
||||
}
|
||||
|
||||
public void syncProfilesDir() throws IOException {
|
||||
logger.info("Syncing profiles dir");
|
||||
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);
|
||||
config.profileProvider.sync();
|
||||
if (config.netty.sendProfileUpdatesEvent) {
|
||||
sendUpdateProfilesEvent();
|
||||
}
|
||||
|
@ -420,7 +418,7 @@ private void sendUpdateProfilesEvent() {
|
|||
if (client == null || !client.isAuth) {
|
||||
return;
|
||||
}
|
||||
ProfilesRequestEvent event = new ProfilesRequestEvent(ProfilesResponse.getListVisibleProfiles(this, client));
|
||||
ProfilesRequestEvent event = new ProfilesRequestEvent(config.profileProvider.getProfiles(client));
|
||||
event.requestUUID = RequestEvent.eventUUID;
|
||||
handler.service.sendObject(ch, event);
|
||||
});
|
||||
|
@ -430,21 +428,6 @@ public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
|||
updatesManager.syncUpdatesDir(dirs);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
if (config.startScript != null) builder.command(Collections.singletonList(config.startScript));
|
||||
else throw new IllegalArgumentException("Please create start script and link it as startScript in config.");
|
||||
builder.directory(this.dir.toFile());
|
||||
builder.inheritIO();
|
||||
builder.redirectErrorStream(true);
|
||||
builder.redirectOutput(Redirect.PIPE);
|
||||
try {
|
||||
builder.start();
|
||||
} catch (IOException e) {
|
||||
logger.error("Restart failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerObject(String name, Object object) {
|
||||
if (object instanceof Reconfigurable) {
|
||||
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
||||
|
@ -457,11 +440,6 @@ public void unregisterObject(String name, Object object) {
|
|||
}
|
||||
}
|
||||
|
||||
public void fullyRestart() {
|
||||
restart();
|
||||
JVMHelper.RUNTIME.exit(0);
|
||||
}
|
||||
|
||||
|
||||
public enum ReloadType {
|
||||
NO_AUTH,
|
||||
|
@ -486,37 +464,12 @@ public interface LaunchServerConfigManager {
|
|||
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();
|
||||
|
||||
// Add SIGNED profile to result list
|
||||
result.add(profile);
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LaunchServerDirectories {
|
||||
public static final String UPDATES_NAME = "updates", PROFILES_NAME = "profiles",
|
||||
public static final String UPDATES_NAME = "updates",
|
||||
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
|
||||
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys";
|
||||
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", LIBRARIES = "libraries", CONTROL_FILE = "control-file";
|
||||
public Path updatesDir;
|
||||
public Path profilesDir;
|
||||
public Path librariesDir;
|
||||
public Path launcherLibrariesDir;
|
||||
public Path launcherLibrariesCompileDir;
|
||||
public Path launcherPackDir;
|
||||
|
@ -524,17 +477,23 @@ public static class LaunchServerDirectories {
|
|||
public Path dir;
|
||||
public Path trustStore;
|
||||
public Path tmpDir;
|
||||
public Path modules;
|
||||
public Path launcherModules;
|
||||
public Path controlFile;
|
||||
|
||||
public void collect() {
|
||||
if (updatesDir == null) updatesDir = getPath(UPDATES_NAME);
|
||||
if (profilesDir == null) profilesDir = getPath(PROFILES_NAME);
|
||||
if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME);
|
||||
if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME);
|
||||
if (launcherLibrariesCompileDir == null)
|
||||
launcherLibrariesCompileDir = getPath(LAUNCHERLIBRARIESCOMPILE_NAME);
|
||||
if(launcherPackDir == null)
|
||||
if (launcherPackDir == null)
|
||||
launcherPackDir = getPath(LAUNCHERPACK_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)
|
||||
tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken()));
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ public class LaunchServerBuilder {
|
|||
private KeyAgreementManager keyAgreementManager;
|
||||
private CertificateManager certificateManager;
|
||||
private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
|
||||
private Integer shardId;
|
||||
|
||||
public LaunchServerBuilder setConfig(LaunchServerConfig config) {
|
||||
this.config = config;
|
||||
|
@ -55,6 +56,11 @@ public LaunchServerBuilder setDir(Path dir) {
|
|||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setShardId(Integer shardId) {
|
||||
this.shardId = shardId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServerConfigManager launchServerConfigManager) {
|
||||
this.launchServerConfigManager = launchServerConfigManager;
|
||||
return this;
|
||||
|
@ -63,32 +69,15 @@ public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServe
|
|||
public LaunchServer build() throws Exception {
|
||||
directories.collect();
|
||||
if (launchServerConfigManager == null) {
|
||||
launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
launchServerConfigManager = new NullLaunchServerConfigManager();
|
||||
}
|
||||
if (keyAgreementManager == null) {
|
||||
keyAgreementManager = new KeyAgreementManager(directories.keyDirectory);
|
||||
}
|
||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, keyAgreementManager, commandHandler, certificateManager);
|
||||
if(shardId == null) {
|
||||
shardId = Integer.parseInt(System.getProperty("launchserver.shardId", "0"));
|
||||
}
|
||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, keyAgreementManager, commandHandler, certificateManager, shardId);
|
||||
}
|
||||
|
||||
public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) {
|
||||
|
@ -99,4 +88,26 @@ public LaunchServerBuilder setCertificateManager(CertificateManager certificateM
|
|||
public void setKeyAgreementManager(KeyAgreementManager keyAgreementManager) {
|
||||
this.keyAgreementManager = keyAgreementManager;
|
||||
}
|
||||
|
||||
private static class NullLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,20 @@
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherTrustManager;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
||||
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.core.LauncherTrustManager;
|
||||
import pro.gravit.launcher.base.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launcher.base.profiles.optional.actions.OptionalAction;
|
||||
import pro.gravit.launcher.base.profiles.optional.triggers.OptionalTrigger;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.GetAvailabilityAuthRequest;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
|
@ -34,6 +36,7 @@
|
|||
import java.nio.file.Path;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LaunchServerStarter {
|
||||
|
@ -42,27 +45,25 @@ public class LaunchServerStarter {
|
|||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
JVMHelper.checkStackTrace(LaunchServerStarter.class);
|
||||
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
||||
JVMHelper.verifySystemProperties(LaunchServer.class, false);
|
||||
//LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
||||
LogHelper.printVersion("LaunchServer");
|
||||
LogHelper.printLicense("LaunchServer");
|
||||
if (!StarterAgent.isAgentStarted()) {
|
||||
LogHelper.error("StarterAgent is not started!");
|
||||
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
||||
}
|
||||
Path dir = IOHelper.WORKING_DIR;
|
||||
Path configFile, runtimeConfigFile;
|
||||
try {
|
||||
Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
||||
LogHelper.error("Library BouncyCastle not found! Is directory 'libraries' empty?");
|
||||
return;
|
||||
}
|
||||
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||
directories.dir = dir;
|
||||
directories.collect();
|
||||
CertificateManager certificateManager = new CertificateManager();
|
||||
try {
|
||||
certificateManager.readTrustStore(dir.resolve("truststore"));
|
||||
certificateManager.readTrustStore(directories.trustStore);
|
||||
} catch (CertificateException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ public static void main(String[] args) throws Exception {
|
|||
LaunchServerRuntimeConfig runtimeConfig;
|
||||
LaunchServerConfig config;
|
||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
|
||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(directories.modules, dir.resolve("config"), certificateManager.trustManager);
|
||||
modulesManager.autoload();
|
||||
modulesManager.initModules(null);
|
||||
registerAll();
|
||||
|
@ -127,59 +128,7 @@ public static void main(String[] args) throws Exception {
|
|||
}
|
||||
}
|
||||
|
||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
LaunchServerConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
LaunchServerRuntimeConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(configFile, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(runtimeConfigFile, bytes);
|
||||
}
|
||||
}
|
||||
};
|
||||
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||
directories.dir = dir;
|
||||
LaunchServer.LaunchServerConfigManager launchServerConfigManager = new BasicLaunchServerConfigManager(configFile, runtimeConfigFile);
|
||||
LaunchServer server = new LaunchServerBuilder()
|
||||
.setDirectories(directories)
|
||||
.setEnv(env)
|
||||
|
@ -190,7 +139,24 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOExcept
|
|||
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||
.setCertificateManager(certificateManager)
|
||||
.build();
|
||||
if (!prepareMode) {
|
||||
List<String> allArgs = List.of(args);
|
||||
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();
|
||||
} else {
|
||||
server.close();
|
||||
|
@ -214,6 +180,8 @@ public static void registerAll() {
|
|||
OptionalAction.registerProviders();
|
||||
OptionalTrigger.registerProviders();
|
||||
MixProvider.registerProviders();
|
||||
ProfileProvider.registerProviders();
|
||||
UpdatesProvider.registerProviders();
|
||||
}
|
||||
|
||||
private static void printExperimentalBranch() {
|
||||
|
@ -256,7 +224,7 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
|||
address = System.getProperty("launchserver.address", null);
|
||||
}
|
||||
if (address == null) {
|
||||
System.out.println("LaunchServer address(default: localhost): ");
|
||||
System.out.println("External launchServer address:port (default: localhost:9274): ");
|
||||
address = commandHandler.readLine();
|
||||
}
|
||||
String projectName = System.getenv("PROJECTNAME");
|
||||
|
@ -270,18 +238,29 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
|||
newConfig.setProjectName(projectName);
|
||||
}
|
||||
if (address == null || address.isEmpty()) {
|
||||
logger.error("Address null. Using localhost");
|
||||
address = "localhost";
|
||||
logger.error("Address null. Using localhost:9274");
|
||||
address = "localhost:9274";
|
||||
}
|
||||
if (newConfig.projectName == null || newConfig.projectName.isEmpty()) {
|
||||
logger.error("ProjectName null. Using MineCraft");
|
||||
newConfig.projectName = "MineCraft";
|
||||
}
|
||||
|
||||
newConfig.netty.address = "ws://" + address + ":9274/api";
|
||||
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
|
||||
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
|
||||
newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe";
|
||||
int port = 9274;
|
||||
if(address.contains(":")) {
|
||||
String portString = address.substring(address.indexOf(':')+1);
|
||||
try {
|
||||
port = Integer.parseInt(portString);
|
||||
} 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
|
||||
logger.info("Writing LaunchServer config file");
|
||||
|
@ -289,4 +268,64 @@ public static void generateConfigIfNotExists(Path configFile, CommandHandler com
|
|||
Launcher.gsonManager.configGson.toJson(newConfig, writer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BasicLaunchServerConfigManager implements LaunchServer.LaunchServerConfigManager {
|
||||
private final Path configFile;
|
||||
private final Path runtimeConfigFile;
|
||||
|
||||
public BasicLaunchServerConfigManager(Path configFile, Path runtimeConfigFile) {
|
||||
this.configFile = configFile;
|
||||
this.runtimeConfigFile = runtimeConfigFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerConfig readConfig() throws IOException {
|
||||
LaunchServerConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(configFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException {
|
||||
LaunchServerRuntimeConfig config1;
|
||||
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
|
||||
config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
|
||||
}
|
||||
return config1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfig(LaunchServerConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(configFile, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
try (Writer writer = IOHelper.newWriter(output)) {
|
||||
if (Launcher.gsonManager.configGson != null) {
|
||||
Launcher.gsonManager.configGson.toJson(config, writer);
|
||||
} else {
|
||||
logger.error("Error writing LaunchServer runtime config file. Gson is null");
|
||||
}
|
||||
}
|
||||
byte[] bytes = output.toByteArray();
|
||||
if(bytes.length > 0) {
|
||||
IOHelper.write(runtimeConfigFile, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
94
LaunchServer/src/main/java/pro/gravit/launchserver/Main.java
Normal file
94
LaunchServer/src/main/java/pro/gravit/launchserver/Main.java
Normal file
|
@ -0,0 +1,94 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import pro.gravit.launchserver.holder.LaunchServerControlHolder;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.launch.ClassLoaderControl;
|
||||
import pro.gravit.utils.launch.LaunchOptions;
|
||||
import pro.gravit.utils.launch.ModuleLaunch;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static final List<String> classpathOnly = List.of("proguard", "jline", "progressbar", "kotlin");
|
||||
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) {
|
||||
var fileName = path.getFileName().toString();
|
||||
for(var e : classpathOnly) {
|
||||
if(fileName.contains(e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void unpackLog4j() {
|
||||
String log4jConfigurationFile = System.getProperty(LOG4J_PROPERTY);
|
||||
if(log4jConfigurationFile == null) {
|
||||
Path log4jConfigPath = Path.of("log4j2.xml");
|
||||
if(!Files.exists(log4jConfigPath)) {
|
||||
try(FileOutputStream output = new FileOutputStream(log4jConfigPath.toFile())) {
|
||||
try(InputStream input = Main.class.getResourceAsStream("/log4j2.xml")) {
|
||||
if(input == null) {
|
||||
return;
|
||||
}
|
||||
input.transferTo(output);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
System.setProperty(LOG4J_PROPERTY, log4jConfigPath.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
unpackLog4j();
|
||||
ModuleLaunch launch = new ModuleLaunch();
|
||||
LaunchOptions options = new LaunchOptions();
|
||||
options.moduleConf = new LaunchOptions.ModuleConf();
|
||||
Path librariesPath = Path.of(System.getProperty(LIBRARIES_PROPERTY, "libraries"));
|
||||
List<Path> libraries;
|
||||
try(Stream<Path> files = Files.walk(librariesPath, FileVisitOption.FOLLOW_LINKS)) {
|
||||
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
|
||||
}
|
||||
List<Path> classpath = new ArrayList<>();
|
||||
List<String> modulepath = new ArrayList<>();
|
||||
for(var l : libraries) {
|
||||
if(isClasspathOnly(l)) {
|
||||
classpath.add(l);
|
||||
} else {
|
||||
modulepath.add(l.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
classpath.add(IOHelper.getCodeSource(LaunchServerStarter.class));
|
||||
options.moduleConf.modulePath.addAll(modulepath);
|
||||
options.moduleConf.modules.add("ALL-MODULE-PATH");
|
||||
ClassLoaderControl control = launch.init(classpath, "natives", options);
|
||||
control.clearLauncherPackages();
|
||||
control.addLauncherPackage("pro.gravit.utils.launch");
|
||||
control.addLauncherPackage("pro.gravit.launchserver.holder");
|
||||
ModuleLayer.Controller controller = (ModuleLayer.Controller) control.getJava9ModuleController();
|
||||
LaunchServerControlHolder.setControl(control);
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -1,13 +1,7 @@
|
|||
package pro.gravit.launchserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public final class StarterAgent {
|
||||
|
||||
|
@ -20,47 +14,6 @@ public static boolean isAgentStarted() {
|
|||
}
|
||||
|
||||
public static void premain(String agentArgument, Instrumentation inst) {
|
||||
StarterAgent.inst = inst;
|
||||
libraries = Paths.get(Optional.ofNullable(agentArgument).map(String::trim).filter(e -> !e.isEmpty()).orElse("libraries"));
|
||||
isStarted = true;
|
||||
try {
|
||||
Files.walkFileTree(libraries, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StarterVisitor extends SimpleFileVisitor<Path> {
|
||||
private static final Set<PosixFilePermission> DPERMS;
|
||||
|
||||
static {
|
||||
Set<PosixFilePermission> perms = new HashSet<>(Arrays.asList(PosixFilePermission.values()));
|
||||
perms.remove(PosixFilePermission.OTHERS_WRITE);
|
||||
perms.remove(PosixFilePermission.GROUP_WRITE);
|
||||
DPERMS = Collections.unmodifiableSet(perms);
|
||||
}
|
||||
|
||||
private final boolean fixLib;
|
||||
|
||||
private StarterVisitor() {
|
||||
Path filef = StarterAgent.libraries.resolve(".libraries_chmoded");
|
||||
this.fixLib = !Files.exists(filef) && !Boolean.getBoolean("launcher.noLibrariesPosixPermsFix");
|
||||
if (fixLib) {
|
||||
try {
|
||||
Files.deleteIfExists(filef);
|
||||
Files.createFile(filef);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (fixLib && Files.getFileAttributeView(file, PosixFileAttributeView.class) != null)
|
||||
Files.setPosixFilePermissions(file, DPERMS);
|
||||
if (file.toFile().getName().endsWith(".jar"))
|
||||
inst.appendToSystemClassLoaderSearch(new JarFile(file.toFile()));
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
throw new UnsupportedOperationException("Please remove -javaagent option from start.sh");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.*;
|
||||
import pro.gravit.launcher.LauncherInject;
|
||||
import pro.gravit.launcher.LauncherInjectionConstructor;
|
||||
import pro.gravit.launcher.core.LauncherInject;
|
||||
import pro.gravit.launcher.core.LauncherInjectionConstructor;
|
||||
import pro.gravit.launchserver.binary.BuildContext;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth;
|
||||
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.AuthRequestEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
|
@ -16,6 +16,10 @@ public AuthException(String message) {
|
|||
super(message);
|
||||
}
|
||||
|
||||
public AuthException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public static AuthException need2FA() {
|
||||
return new AuthException(AuthRequestEvent.TWO_FACTOR_NEED_ERROR_MESSAGE);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public static void getFeatures(Class<?> clazz, Set<String> list) {
|
|||
}
|
||||
}
|
||||
|
||||
public final <T> T isSupport(Class<T> clazz) {
|
||||
public <T> T isSupport(Class<T> clazz) {
|
||||
if (core == null) return null;
|
||||
T result = core.isSupport(clazz);
|
||||
if (result == null && mixes != null) {
|
||||
|
@ -71,10 +71,10 @@ public final <T> T isSupport(Class<T> clazz) {
|
|||
return result;
|
||||
}
|
||||
|
||||
public final void init(LaunchServer srv, String name) {
|
||||
public void init(LaunchServer srv, String name) {
|
||||
this.name = name;
|
||||
if (links != null) link(srv);
|
||||
core.init(srv);
|
||||
core.init(srv, this);
|
||||
features = new HashSet<>();
|
||||
getFeatures(core.getClass(), features);
|
||||
if(mixes != null) {
|
||||
|
@ -85,7 +85,7 @@ public final void init(LaunchServer srv, String name) {
|
|||
}
|
||||
}
|
||||
|
||||
public final void link(LaunchServer srv) {
|
||||
public void link(LaunchServer srv) {
|
||||
links.forEach((k, v) -> {
|
||||
AuthProviderPair pair = srv.config.getAuthProviderPair(v);
|
||||
if (pair == null) {
|
||||
|
@ -99,7 +99,7 @@ public final void link(LaunchServer srv) {
|
|||
});
|
||||
}
|
||||
|
||||
public final void close() throws IOException {
|
||||
public void close() throws IOException {
|
||||
core.close();
|
||||
if (textureProvider != null) {
|
||||
textureProvider.close();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,15 @@
|
|||
import io.jsonwebtoken.JwtException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.password.AuthPlainPassword;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportSudo;
|
||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||
import pro.gravit.launchserver.helper.LegacySessionHelper;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
|
@ -32,7 +34,7 @@
|
|||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
public abstract class AbstractSQLCoreProvider extends AuthCoreProvider {
|
||||
public abstract class AbstractSQLCoreProvider extends AuthCoreProvider implements AuthSupportSudo {
|
||||
public final transient Logger logger = LogManager.getLogger();
|
||||
public long expireSeconds = HOURS.toSeconds(1);
|
||||
public String uuidColumn;
|
||||
|
@ -66,7 +68,6 @@ public abstract class AbstractSQLCoreProvider extends AuthCoreProvider {
|
|||
|
||||
public transient String updateAuthSQL;
|
||||
public transient String updateServerIDSQL;
|
||||
public transient LaunchServer server;
|
||||
|
||||
public abstract SQLSourceConfig getSQLConfig();
|
||||
|
||||
|
@ -142,14 +143,12 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
|||
if (user == null) {
|
||||
throw AuthException.userNotFound();
|
||||
}
|
||||
if (context != null) {
|
||||
AuthPlainPassword plainPassword = (AuthPlainPassword) password;
|
||||
if (plainPassword == null) {
|
||||
throw AuthException.wrongPassword();
|
||||
}
|
||||
if (!passwordVerifier.check(user.password, plainPassword.password)) {
|
||||
throw AuthException.wrongPassword();
|
||||
}
|
||||
AuthPlainPassword plainPassword = (AuthPlainPassword) password;
|
||||
if (plainPassword == null) {
|
||||
throw AuthException.wrongPassword();
|
||||
}
|
||||
if (!passwordVerifier.check(user.password, plainPassword.password)) {
|
||||
throw AuthException.wrongPassword();
|
||||
}
|
||||
SQLUserSession session = createSession(user);
|
||||
var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(user, LocalDateTime.now(Clock.systemUTC()).plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey);
|
||||
|
@ -163,6 +162,17 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthManager.AuthReport sudo(User user, boolean shadow) throws IOException {
|
||||
SQLUser sqlUser = (SQLUser) user;
|
||||
SQLUserSession session = createSession(sqlUser);
|
||||
var accessToken = LegacySessionHelper.makeAccessJwtTokenFromString(sqlUser, LocalDateTime.now(Clock.systemUTC()).plusSeconds(expireSeconds), server.keyAgreementManager.ecdsaPrivateKey);
|
||||
var refreshToken = sqlUser.username.concat(".").concat(LegacySessionHelper.makeRefreshTokenFromPassword(sqlUser.username, sqlUser.password, server.keyAgreementManager.legacySalt));
|
||||
String minecraftAccessToken = SecurityHelper.randomStringToken();
|
||||
updateAuth(user, minecraftAccessToken);
|
||||
return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftAccessToken, accessToken, refreshToken, SECONDS.toMillis(expireSeconds), session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
SQLUser user = (SQLUser) getUserByUsername(username);
|
||||
|
@ -183,8 +193,8 @@ public boolean joinServer(Client client, String username, UUID uuid, String acce
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
this.server = server;
|
||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||
super.init(server, pair);
|
||||
if (getSQLConfig() == null) logger.error("SQLHolder cannot be null");
|
||||
if (uuidColumn == null) logger.error("uuidColumn cannot be null");
|
||||
if (usernameColumn == null) logger.error("usernameColumn cannot be null");
|
||||
|
@ -266,7 +276,7 @@ public void close() {
|
|||
|
||||
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), requestPermissions(set.getString(uuidColumn))) : null;
|
||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn)) : null;
|
||||
}
|
||||
|
||||
public ClientPermissions requestPermissions (String uuid) throws SQLException
|
||||
|
@ -276,14 +286,19 @@ public ClientPermissions requestPermissions (String uuid) throws SQLException
|
|||
}
|
||||
|
||||
private SQLUser queryUser(String sql, String value) throws SQLException {
|
||||
SQLUser user;
|
||||
try (Connection c = getSQLConfig().getConnection()) {
|
||||
PreparedStatement s = c.prepareStatement(sql);
|
||||
s.setString(1, value);
|
||||
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||
try (ResultSet set = s.executeQuery()) {
|
||||
return constructUser(set);
|
||||
user = constructUser(set);
|
||||
}
|
||||
}
|
||||
if(user != null) {
|
||||
user.permissions = requestPermissions(user.uuid.toString());
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private List<String> queryPermissions(String sql, String value) throws SQLException {
|
||||
|
@ -330,15 +345,14 @@ public static class SQLUser implements User {
|
|||
protected String accessToken;
|
||||
protected String serverId;
|
||||
protected final String password;
|
||||
protected final ClientPermissions permissions;
|
||||
protected ClientPermissions permissions;
|
||||
|
||||
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions) {
|
||||
public SQLUser(UUID uuid, String username, String accessToken, String serverId, String password) {
|
||||
this.uuid = uuid;
|
||||
this.username = username;
|
||||
this.accessToken = accessToken;
|
||||
this.serverId = serverId;
|
||||
this.password = password;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,19 +3,25 @@
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.details.AuthPasswordDetails;
|
||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.events.RequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||
import pro.gravit.launcher.base.profiles.PlayerProfile;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.details.AuthPasswordDetails;
|
||||
import pro.gravit.launcher.base.request.auth.password.AuthPlainPassword;
|
||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportGetAllUsers;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportRegistration;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportSudo;
|
||||
import pro.gravit.launchserver.auth.core.openid.OpenIDAuthCoreProvider;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
|
@ -29,6 +35,7 @@
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/*
|
||||
All-In-One provider
|
||||
|
@ -37,6 +44,8 @@ public abstract class AuthCoreProvider implements AutoCloseable, Reconfigurable
|
|||
public static final ProviderMap<AuthCoreProvider> providers = new ProviderMap<>("AuthCoreProvider");
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private static boolean registredProviders = false;
|
||||
protected transient LaunchServer server;
|
||||
protected transient AuthProviderPair pair;
|
||||
|
||||
public static void registerProviders() {
|
||||
if (!registredProviders) {
|
||||
|
@ -45,6 +54,8 @@ public static void registerProviders() {
|
|||
providers.register("postgresql", PostgresSQLCoreProvider.class);
|
||||
providers.register("memory", MemoryAuthCoreProvider.class);
|
||||
providers.register("merge", MergeAuthCoreProvider.class);
|
||||
providers.register("openid", OpenIDAuthCoreProvider.class);
|
||||
providers.register("sql", SQLCoreProvider.class);
|
||||
registredProviders = true;
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +82,10 @@ public AuthManager.AuthReport authorize(User user, AuthResponse.AuthContext cont
|
|||
return authorize(user.getUsername(), context, password, minecraftAccess);
|
||||
}
|
||||
|
||||
public abstract void init(LaunchServer server);
|
||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||
this.server = server;
|
||||
this.pair = pair;
|
||||
}
|
||||
|
||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||
return List.of(new AuthPasswordDetails());
|
||||
|
@ -260,6 +274,72 @@ public void invoke(String... args) throws Exception {
|
|||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
var instance = isSupport(AuthSupportSudo.class);
|
||||
if(instance != null) {
|
||||
map.put("sudo", new SubCommand("[connectUUID] [username/uuid] [isShadow] (CLIENT/API)", "Authorize connectUUID as another user without password") {
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 3);
|
||||
UUID connectUUID = UUID.fromString(args[0]);
|
||||
String login = args[1];
|
||||
boolean isShadow = Boolean.parseBoolean(args[2]);
|
||||
AuthResponse.ConnectTypes type;
|
||||
if(args.length > 3) {
|
||||
type = AuthResponse.ConnectTypes.valueOf(args[3]);
|
||||
} else {
|
||||
type = AuthResponse.ConnectTypes.CLIENT;
|
||||
}
|
||||
User user;
|
||||
if(login.length() == 36) {
|
||||
UUID uuid = UUID.fromString(login);
|
||||
user = getUserByUUID(uuid);
|
||||
} else {
|
||||
user = getUserByUsername(login);
|
||||
}
|
||||
if(user == null) {
|
||||
logger.error("User {} not found", login);
|
||||
return;
|
||||
}
|
||||
AtomicBoolean founded = new AtomicBoolean();
|
||||
server.nettyServerSocketHandler.nettyServer.service.forEachActiveChannels((ch, fh) -> {
|
||||
var client = fh.getClient();
|
||||
if(client == null || !connectUUID.equals(fh.getConnectUUID())) {
|
||||
return;
|
||||
}
|
||||
logger.info("Found connectUUID {} with IP {}", fh.getConnectUUID(), fh.context == null ? "null" : fh.context.ip);
|
||||
var lock = server.config.netty.performance.disableThreadSafeClientObject ? null : client.writeLock();
|
||||
if(lock != null) {
|
||||
lock.lock();
|
||||
}
|
||||
try {
|
||||
var report = instance.sudo(user, isShadow);
|
||||
User user1 = report.session().getUser();
|
||||
server.authManager.internalAuth(client, type, pair, user1.getUsername(), user1.getUUID(), user1.getPermissions(), true);
|
||||
client.sessionObject = report.session();
|
||||
client.coreObject = report.session().getUser();
|
||||
PlayerProfile playerProfile = server.authManager.getPlayerProfile(client);
|
||||
AuthRequestEvent request = new AuthRequestEvent(user1.getPermissions(), playerProfile,
|
||||
report.minecraftAccessToken(), null, null,
|
||||
new AuthRequestEvent.OAuthRequestEvent(report.oauthAccessToken(), report.oauthRefreshToken(), report.oauthExpire()));
|
||||
request.requestUUID = RequestEvent.eventUUID;
|
||||
server.nettyServerSocketHandler.nettyServer.service.sendObject(ch, request);
|
||||
} catch (Throwable e) {
|
||||
logger.error("Sudo error", e);
|
||||
} finally {
|
||||
if(lock != null) {
|
||||
lock.unlock();
|
||||
}
|
||||
founded.set(true);
|
||||
}
|
||||
});
|
||||
if(!founded.get()) {
|
||||
logger.error("ConnectUUID {} not found", connectUUID);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.request.auth.details.AuthLoginOnlyDetails;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
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.details.AuthLoginOnlyDetails;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportSudo;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
|
@ -18,7 +18,7 @@
|
|||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MemoryAuthCoreProvider extends AuthCoreProvider {
|
||||
public class MemoryAuthCoreProvider extends AuthCoreProvider implements AuthSupportSudo {
|
||||
private transient final List<MemoryUser> memory = new ArrayList<>(16);
|
||||
|
||||
@Override
|
||||
|
@ -114,13 +114,13 @@ public boolean joinServer(Client client, String username, UUID uuid, String acce
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
public AuthManager.AuthReport sudo(User user, boolean shadow) throws IOException {
|
||||
return authorize(user.getUsername(), null, null, true);
|
||||
}
|
||||
|
||||
public static class MemoryUser implements User {
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
|
@ -72,7 +73,7 @@ public boolean joinServer(Client client, String username, UUID uuid, String acce
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
public void init(LaunchServer server, AuthProviderPair pair1) {
|
||||
for(var e : list) {
|
||||
var pair = server.config.auth.get(e);
|
||||
if(pair != null) {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.MySQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
|
@ -41,8 +42,9 @@ public SQLSourceConfig getSQLConfig() {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
super.init(server);
|
||||
public void init(LaunchServer server, AuthProviderPair 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 hardwareInfoCols = "id, hwDiskId, baseboardSerialNumber, displayId, bitness, totalMemory, logicalProcessors, physicalProcessors, processorMaxFreq, battery, id, graphicCard, banned, publicKey";
|
||||
if (sqlFindHardwareByPublicKey == null)
|
||||
|
@ -71,7 +73,7 @@ protected String makeUserCols() {
|
|||
@Override
|
||||
protected MySQLUser constructUser(ResultSet set) throws SQLException {
|
||||
return set.next() ? new MySQLUser(UUID.fromString(set.getString(uuidColumn)), set.getString(usernameColumn),
|
||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), requestPermissions(set.getString(uuidColumn)), set.getLong(hardwareIdColumn)) : null;
|
||||
set.getString(accessTokenColumn), set.getString(serverIDColumn), set.getString(passwordColumn), set.getLong(hardwareIdColumn)) : null;
|
||||
}
|
||||
|
||||
private MySQLUserHardware fetchHardwareInfo(ResultSet set) throws SQLException, IOException {
|
||||
|
@ -332,11 +334,11 @@ public String toString() {
|
|||
}
|
||||
}
|
||||
|
||||
public class MySQLUser extends SQLUser {
|
||||
public static class MySQLUser extends SQLUser {
|
||||
protected long hwidId;
|
||||
|
||||
public MySQLUser(UUID uuid, String username, String accessToken, String serverId, String password, ClientPermissions permissions, long hwidId) {
|
||||
super(uuid, username, accessToken, serverId, password, permissions);
|
||||
public MySQLUser(UUID uuid, String username, String accessToken, String serverId, String password, long hwidId) {
|
||||
super(uuid, username, accessToken, serverId, password);
|
||||
this.hwidId = hwidId;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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.SQLSourceConfig;
|
||||
|
||||
|
@ -10,4 +12,10 @@ public class PostgresSQLCoreProvider extends AbstractSQLCoreProvider {
|
|||
public SQLSourceConfig getSQLConfig() {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
|
@ -41,11 +40,6 @@ public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext c
|
|||
throw new AuthException("Please configure AuthCoreProvider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,393 @@
|
|||
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 pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
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, IOException {
|
||||
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 | IOException 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 | IOException 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 | IOException 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) throws IOException {
|
||||
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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces;
|
||||
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||
|
||||
public interface UserHardware {
|
||||
HardwareReportRequest.HardwareInfo getHardwareInfo();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.events.request.GetAssetUploadUrlRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.GetAssetUploadUrlRequestEvent;
|
||||
import pro.gravit.launchserver.auth.Feature;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.UserSession;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launcher.base.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.UserSession;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launchserver.auth.Feature;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface AuthSupportSudo {
|
||||
AuthManager.AuthReport sudo(User user, boolean shadow) throws IOException;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.user;
|
||||
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public record AccessTokenResponse(@SerializedName("access_token") String accessToken,
|
||||
@SerializedName("expires_in") Long expiresIn,
|
||||
@SerializedName("refresh_expires_in") Long refreshExpiresIn,
|
||||
@SerializedName("refresh_token") String refreshToken,
|
||||
@SerializedName("token_type") String tokenType,
|
||||
@SerializedName("id_token") String idToken,
|
||||
@SerializedName("not-before-policy") Integer notBeforePolicy,
|
||||
@SerializedName("session_state") String sessionState,
|
||||
@SerializedName("scope") String scope) {
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
import pro.gravit.launcher.base.events.request.GetAvailabilityAuthRequestEvent;
|
||||
import pro.gravit.launcher.base.request.auth.AuthRequest;
|
||||
import pro.gravit.launcher.base.request.auth.password.AuthCodePassword;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthException;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.UserSession;
|
||||
import pro.gravit.launchserver.manangers.AuthManager;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class OpenIDAuthCoreProvider extends AuthCoreProvider {
|
||||
private transient SQLUserStore sqlUserStore;
|
||||
private transient SQLServerSessionStore sqlSessionStore;
|
||||
private transient OpenIDAuthenticator openIDAuthenticator;
|
||||
|
||||
private OpenIDConfig openIDConfig;
|
||||
private HikariSQLSourceConfig sqlSourceConfig;
|
||||
|
||||
@Override
|
||||
public List<GetAvailabilityAuthRequestEvent.AuthAvailabilityDetails> getDetails(Client client) {
|
||||
return openIDAuthenticator.getDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByUsername(String username) {
|
||||
return sqlUserStore.getByUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByUUID(UUID uuid) {
|
||||
return sqlUserStore.getUserByUUID(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSession getUserSessionByOAuthAccessToken(String accessToken) throws OAuthAccessTokenExpired {
|
||||
return openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthManager.AuthReport refreshAccessToken(String oldRefreshToken, AuthResponse.AuthContext context) {
|
||||
var tokens = openIDAuthenticator.refreshAccessToken(oldRefreshToken);
|
||||
var accessToken = tokens.accessToken();
|
||||
var refreshToken = tokens.refreshToken();
|
||||
long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn());
|
||||
|
||||
UserSession session;
|
||||
try {
|
||||
session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
|
||||
} catch (OAuthAccessTokenExpired e) {
|
||||
throw new RuntimeException("invalid token", e);
|
||||
}
|
||||
|
||||
|
||||
return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken,
|
||||
expiresIn, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthManager.AuthReport authorize(String login, AuthResponse.AuthContext context, AuthRequest.AuthPasswordInterface password, boolean minecraftAccess) throws IOException {
|
||||
if (password == null) {
|
||||
throw AuthException.wrongPassword();
|
||||
}
|
||||
var authCodePassword = (AuthCodePassword) password;
|
||||
|
||||
var tokens = openIDAuthenticator.authorize(authCodePassword);
|
||||
|
||||
var accessToken = tokens.accessToken();
|
||||
var refreshToken = tokens.refreshToken();
|
||||
var user = openIDAuthenticator.createUserFromToken(accessToken);
|
||||
long expiresIn = TimeUnit.SECONDS.toMillis(tokens.accessTokenExpiresIn());
|
||||
|
||||
sqlUserStore.createOrUpdateUser(user);
|
||||
|
||||
UserSession session;
|
||||
try {
|
||||
session = openIDAuthenticator.getUserSessionByOAuthAccessToken(accessToken);
|
||||
} catch (OAuthAccessTokenExpired e) {
|
||||
throw new AuthException("invalid token", e);
|
||||
}
|
||||
|
||||
if (minecraftAccess) {
|
||||
var minecraftToken = generateMinecraftToken(user);
|
||||
return AuthManager.AuthReport.ofOAuthWithMinecraft(minecraftToken, accessToken, refreshToken,
|
||||
expiresIn, session);
|
||||
} else {
|
||||
return AuthManager.AuthReport.ofOAuth(accessToken, refreshToken,
|
||||
expiresIn, session);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateMinecraftToken(User user) {
|
||||
return Jwts.builder()
|
||||
.issuer("LaunchServer")
|
||||
.subject(user.getUUID().toString())
|
||||
.claim("preferred_username", user.getUsername())
|
||||
.expiration(Date.from(Instant.now().plus(24, ChronoUnit.HOURS)))
|
||||
.signWith(server.keyAgreementManager.ecdsaPrivateKey)
|
||||
.compact();
|
||||
}
|
||||
|
||||
private User createUserFromMinecraftToken(String accessToken) throws AuthException {
|
||||
try {
|
||||
var parser = Jwts.parser()
|
||||
.requireIssuer("LaunchServer")
|
||||
.verifyWith(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.build();
|
||||
var claims = parser.parseSignedClaims(accessToken);
|
||||
var username = claims.getPayload().get("preferred_username", String.class);
|
||||
var uuid = UUID.fromString(claims.getPayload().getSubject());
|
||||
return new UserEntity(username, uuid, new ClientPermissions());
|
||||
} catch (JwtException e) {
|
||||
throw new AuthException("Bad minecraft token", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer server, AuthProviderPair pair) {
|
||||
super.init(server, pair);
|
||||
this.sqlSourceConfig.init();
|
||||
this.sqlUserStore = new SQLUserStore(sqlSourceConfig);
|
||||
this.sqlUserStore.init();
|
||||
this.sqlSessionStore = new SQLServerSessionStore(sqlSourceConfig);
|
||||
this.sqlSessionStore.init();
|
||||
this.openIDAuthenticator = new OpenIDAuthenticator(openIDConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User checkServer(Client client, String username, String serverID) throws IOException {
|
||||
var savedServerId = sqlSessionStore.getServerIdByUsername(username);
|
||||
if (!serverID.equals(savedServerId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sqlUserStore.getByUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(Client client, String username, UUID uuid, String accessToken, String serverID) throws IOException {
|
||||
User user;
|
||||
try {
|
||||
user = createUserFromMinecraftToken(accessToken);
|
||||
} catch (AuthException e) {
|
||||
LogHelper.error(e);
|
||||
return false;
|
||||
}
|
||||
if (!user.getUUID().equals(uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlUserStore.createOrUpdateUser(user);
|
||||
|
||||
return sqlSessionStore.joinServer(user.getUUID(), user.getUsername(), serverID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
sqlSourceConfig.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
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) {}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Xakep_SDK
|
||||
*/
|
||||
public class QueryBuilder {
|
||||
private final String uri;
|
||||
private final StringBuilder query = new StringBuilder();
|
||||
|
||||
public QueryBuilder(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public static QueryBuilder get(String uri) {
|
||||
Objects.requireNonNull(uri, "uri");
|
||||
if (uri.endsWith("/")) {
|
||||
uri = uri.substring(0, uri.length() - 1);
|
||||
}
|
||||
return new QueryBuilder(uri);
|
||||
}
|
||||
|
||||
public static QueryBuilder post() {
|
||||
return new QueryBuilder(null);
|
||||
}
|
||||
|
||||
public QueryBuilder addQuery(String key, String value) {
|
||||
if (!query.isEmpty()) {
|
||||
query.append('&');
|
||||
}
|
||||
query.append(URLEncoder.encode(key, StandardCharsets.UTF_8))
|
||||
.append('=')
|
||||
.append(URLEncoder.encode(value, StandardCharsets.UTF_8));
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toUriString() {
|
||||
if (uri != null) {
|
||||
if (query. isEmpty()) {
|
||||
return uri;
|
||||
}
|
||||
return uri + '?' + query;
|
||||
}
|
||||
return toQueryString();
|
||||
}
|
||||
|
||||
public String toQueryString() {
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toUriString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import pro.gravit.launchserver.auth.SQLSourceConfig;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SQLServerSessionStore implements ServerSessionStore {
|
||||
private static final String CREATE_TABLE = """
|
||||
create table if not exists `gravit_server_session` (
|
||||
id int auto_increment,
|
||||
uuid varchar(36),
|
||||
username varchar(255),
|
||||
server_id varchar(41),
|
||||
primary key (id),
|
||||
unique (uuid),
|
||||
unique (username)
|
||||
);
|
||||
""";
|
||||
private static final String DELETE_SERVER_ID = """
|
||||
delete from `gravit_server_session` where uuid = ?
|
||||
""";
|
||||
private static final String INSERT_SERVER_ID = """
|
||||
insert into `gravit_server_session` (uuid, username, server_id) values (?, ?, ?)
|
||||
""";
|
||||
private static final String SELECT_SERVER_ID_BY_USERNAME = """
|
||||
select server_id from `gravit_server_session` where username = ?
|
||||
""";
|
||||
|
||||
private final SQLSourceConfig sqlSourceConfig;
|
||||
|
||||
public SQLServerSessionStore(SQLSourceConfig sqlSourceConfig) {
|
||||
this.sqlSourceConfig = sqlSourceConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean joinServer(UUID uuid, String username, String serverId) {
|
||||
try (var connection = sqlSourceConfig.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
var savepoint = connection.setSavepoint();
|
||||
try (var deleteServerIdStmt = connection.prepareStatement(DELETE_SERVER_ID);
|
||||
var insertServerIdStmt = connection.prepareStatement(INSERT_SERVER_ID)) {
|
||||
deleteServerIdStmt.setString(1, uuid.toString());
|
||||
deleteServerIdStmt.execute();
|
||||
insertServerIdStmt.setString(1, uuid.toString());
|
||||
insertServerIdStmt.setString(2, username);
|
||||
insertServerIdStmt.setString(3, serverId);
|
||||
insertServerIdStmt.execute();
|
||||
connection.commit();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
connection.rollback(savepoint);
|
||||
throw e;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogHelper.debug("Can't join server. Username: %s".formatted(username));
|
||||
LogHelper.error(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerIdByUsername(String username) {
|
||||
try (var connection = sqlSourceConfig.getConnection();
|
||||
var selectServerId = connection.prepareStatement(SELECT_SERVER_ID_BY_USERNAME)) {
|
||||
selectServerId.setString(1, username);
|
||||
try (var rs = selectServerId.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
return null;
|
||||
}
|
||||
return rs.getString("server_id");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogHelper.debug("Can't find server id by username. Username: %s".formatted(username));
|
||||
LogHelper.error(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
try (var connection = sqlSourceConfig.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
var savepoint = connection.setSavepoint();
|
||||
try (var createTableStmt = connection.prepareStatement(CREATE_TABLE)) {
|
||||
createTableStmt.execute();
|
||||
connection.commit();
|
||||
} catch (Exception e) {
|
||||
connection.rollback(savepoint);
|
||||
throw e;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
import pro.gravit.launchserver.auth.HikariSQLSourceConfig;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SQLUserStore implements UserStore {
|
||||
private static final String CREATE_USER_TABLE = """
|
||||
create table if not exists `gravit_user` (
|
||||
id int auto_increment,
|
||||
uuid varchar(36),
|
||||
username varchar(255),
|
||||
primary key (id),
|
||||
unique (uuid),
|
||||
unique (username)
|
||||
)
|
||||
""";
|
||||
private static final String INSERT_USER = """
|
||||
insert into `gravit_user` (uuid, username) values (?, ?)
|
||||
""";
|
||||
private static final String DELETE_USER_BY_NAME = """
|
||||
delete `gravit_user` where username = ?
|
||||
""";
|
||||
private static final String SELECT_USER_BY_NAME = """
|
||||
select uuid, username from `gravit_user` where username = ?
|
||||
""";
|
||||
private static final String SELECT_USER_BY_UUID = """
|
||||
select uuid, username from `gravit_user` where uuid = ?
|
||||
""";
|
||||
|
||||
private final HikariSQLSourceConfig sqlSourceConfig;
|
||||
|
||||
public SQLUserStore(HikariSQLSourceConfig sqlSourceConfig) {
|
||||
this.sqlSourceConfig = sqlSourceConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByUsername(String username) {
|
||||
try (var connection = sqlSourceConfig.getConnection();
|
||||
var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_NAME)) {
|
||||
selectUserStmt.setString(1, username);
|
||||
try (var rs = selectUserStmt.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
LogHelper.debug("User not found, username: %s".formatted(username));
|
||||
return null;
|
||||
}
|
||||
return new UserEntity(rs.getString("username"),
|
||||
UUID.fromString(rs.getString("uuid")),
|
||||
new ClientPermissions());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByUUID(UUID uuid) {
|
||||
try (var connection = sqlSourceConfig.getConnection();
|
||||
var selectUserStmt = connection.prepareStatement(SELECT_USER_BY_UUID)) {
|
||||
selectUserStmt.setString(1, uuid.toString());
|
||||
try (var rs = selectUserStmt.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
LogHelper.debug("User not found, UUID: %s".formatted(uuid));
|
||||
return null;
|
||||
}
|
||||
return new UserEntity(rs.getString("username"),
|
||||
UUID.fromString(rs.getString("uuid")),
|
||||
new ClientPermissions());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createOrUpdateUser(User user) {
|
||||
try (var connection = sqlSourceConfig.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
var savepoint = connection.setSavepoint();
|
||||
try (var deleteUserStmt = connection.prepareStatement(DELETE_USER_BY_NAME);
|
||||
var insertUserStmt = connection.prepareStatement(INSERT_USER)) {
|
||||
deleteUserStmt.setString(1, user.getUsername());
|
||||
deleteUserStmt.execute();
|
||||
insertUserStmt.setString(1, user.getUUID().toString());
|
||||
insertUserStmt.setString(2, user.getUsername());
|
||||
insertUserStmt.execute();
|
||||
connection.commit();
|
||||
LogHelper.debug("User saved. UUID: %s, username: %s".formatted(user.getUUID(), user.getUsername()));
|
||||
} catch (Exception e) {
|
||||
connection.rollback(savepoint);
|
||||
throw e;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogHelper.debug("Failed to save user");
|
||||
LogHelper.error(e);
|
||||
throw new RuntimeException("Failed to save user", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
try (var connection = sqlSourceConfig.getConnection()) {
|
||||
connection.setAutoCommit(false);
|
||||
var savepoint = connection.setSavepoint();
|
||||
try (var createUserTableStmt = connection.prepareStatement(CREATE_USER_TABLE)) {
|
||||
createUserTableStmt.execute();
|
||||
connection.commit();
|
||||
} catch (Exception e) {
|
||||
connection.rollback(savepoint);
|
||||
throw e;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ServerSessionStore {
|
||||
boolean joinServer(UUID uuid, String username, String serverId);
|
||||
String getServerIdByUsername(String username);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
public record TokenResponse(String accessToken, long accessTokenExpiresIn,
|
||||
String refreshToken, long refreshTokenExpiresIn) {
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import pro.gravit.launcher.base.ClientPermissions;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
record UserEntity(String username, UUID uuid, ClientPermissions permissions) implements User {
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientPermissions getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package pro.gravit.launchserver.auth.core.openid;
|
||||
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserStore {
|
||||
User getByUsername(String username);
|
||||
|
||||
User getUserByUUID(UUID uuid);
|
||||
|
||||
void createOrUpdateUser(User user);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.mix;
|
||||
|
||||
import pro.gravit.launcher.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.AssetUploadInfoRequestEvent;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@
|
|||
import io.jsonwebtoken.Jwts;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent;
|
||||
import pro.gravit.launcher.events.request.HardwareReportRequestEvent;
|
||||
import pro.gravit.launcher.events.request.VerifySecureLevelKeyRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.GetSecureLevelInfoRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.HardwareReportRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.VerifySecureLevelKeyRequestEvent;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
|
@ -132,9 +132,9 @@ public static class HardwareInfoTokenVerifier implements RestoreResponse.Extende
|
|||
private final JwtParser parser;
|
||||
|
||||
public HardwareInfoTokenVerifier(LaunchServer server) {
|
||||
this.parser = Jwts.parserBuilder()
|
||||
this.parser = Jwts.parser()
|
||||
.requireIssuer("LaunchServer")
|
||||
.setSigningKey(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.verifyWith(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -164,9 +164,9 @@ public static class PublicKeyTokenVerifier implements RestoreResponse.ExtendedTo
|
|||
private final JwtParser parser;
|
||||
|
||||
public PublicKeyTokenVerifier(LaunchServer server) {
|
||||
this.parser = Jwts.parserBuilder()
|
||||
this.parser = Jwts.parser()
|
||||
.requireIssuer("LaunchServer")
|
||||
.setSigningKey(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.verifyWith(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
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;
|
||||
|
@ -22,19 +22,19 @@ public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
|||
|
||||
@Override
|
||||
public void init(LaunchServer server) {
|
||||
if (profileWhitelist != null && profileWhitelist.size() > 0) {
|
||||
if (profileWhitelist != null && !profileWhitelist.isEmpty()) {
|
||||
logger.warn("profileWhitelist deprecated. Please use permission 'launchserver.profile.PROFILE_UUID.show' and 'launchserver.profile.PROFILE_UUID.enter'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canGetProfile(ClientProfile profile, Client client) {
|
||||
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.show", profile, client);
|
||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.show", profile, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChangeProfile(ClientProfile profile, Client client) {
|
||||
return !profile.isLimited() || isWhitelisted("launchserver.profile.%s.enter", profile, client);
|
||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.enter", profile, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.protect.interfaces;
|
||||
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
|
||||
public interface ProfilesProtectHandler {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package pro.gravit.launchserver.auth.protect.interfaces;
|
||||
|
||||
import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent;
|
||||
import pro.gravit.launcher.events.request.SecurityReportRequestEvent;
|
||||
import pro.gravit.launcher.events.request.VerifySecureLevelKeyRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.GetSecureLevelInfoRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.SecurityReportRequestEvent;
|
||||
import pro.gravit.launcher.base.events.request.VerifySecureLevelKeyRequestEvent;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.secure.SecurityReportResponse;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
import pro.gravit.launchserver.HttpRequester;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.texture;
|
||||
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launchserver.auth.texture;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
import pro.gravit.utils.helper.CommonHelper;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.texture;
|
||||
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
import pro.gravit.utils.ProviderMap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.auth.texture;
|
||||
|
||||
import pro.gravit.launcher.profiles.Texture;
|
||||
import pro.gravit.launcher.base.profiles.Texture;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
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() {
|
||||
|
||||
}
|
||||
}
|
|
@ -7,20 +7,18 @@
|
|||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BinaryPipeline {
|
||||
public abstract class BinaryPipeline {
|
||||
public final List<LauncherBuildTask> tasks = new ArrayList<>();
|
||||
public final Path buildDir;
|
||||
public final String nameFormat;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
protected transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public BinaryPipeline(Path buildDir, String nameFormat) {
|
||||
this.buildDir = buildDir;
|
||||
|
@ -82,27 +80,6 @@ public Optional<LauncherBuildTask> getTaskBefore(Predicate<LauncherBuildTask> pr
|
|||
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) {
|
||||
return nameFormat.formatted(taskName);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.launcher.serialize.stream.StreamObject;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.core.serialize.HOutput;
|
||||
import pro.gravit.launcher.core.serialize.stream.StreamObject;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
@ -46,11 +46,14 @@ public class BuildContext {
|
|||
public final HashSet<String> fileList;
|
||||
public final HashSet<String> clientModules;
|
||||
public final HashSet<String> legacyClientModules;
|
||||
private Path runtimeDir;
|
||||
private boolean deleteRuntimeDir;
|
||||
|
||||
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task) {
|
||||
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task, Path runtimeDir) {
|
||||
this.output = output;
|
||||
this.readerClassPath = readerClassPath;
|
||||
this.task = task;
|
||||
this.runtimeDir = runtimeDir;
|
||||
fileList = new HashSet<>(1024);
|
||||
clientModules = new HashSet<>();
|
||||
legacyClientModules = new HashSet<>();
|
||||
|
@ -103,6 +106,14 @@ public void pushJarFile(Path jarfile, Predicate<ZipEntry> filter, Predicate<Stri
|
|||
pushJarFile(jarfile.toUri().toURL(), filter, needTransform);
|
||||
}
|
||||
|
||||
public Path getRuntimeDir() {
|
||||
return runtimeDir;
|
||||
}
|
||||
|
||||
public void setRuntimeDir(Path runtimeDir) {
|
||||
this.runtimeDir = runtimeDir;
|
||||
}
|
||||
|
||||
public void pushJarFile(URL jarfile, Predicate<ZipEntry> filter, Predicate<String> needTransform) throws IOException {
|
||||
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(jarfile))) {
|
||||
ZipEntry e = input.getNextEntry();
|
||||
|
@ -129,6 +140,16 @@ public void pushJarFile(URL jarfile, Predicate<ZipEntry> filter, Predicate<Strin
|
|||
e = input.getNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public boolean isDeleteRuntimeDir() {
|
||||
return deleteRuntimeDir;
|
||||
}
|
||||
|
||||
public void setDeleteRuntimeDir(boolean deleteRuntimeDir) {
|
||||
this.deleteRuntimeDir = deleteRuntimeDir;
|
||||
}
|
||||
|
||||
private final static class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
package pro.gravit.launchserver.binary;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask;
|
||||
|
||||
public final class EXEL4JLauncherBinary extends LauncherBinary {
|
||||
|
||||
|
||||
public EXEL4JLauncherBinary(LaunchServer server) {
|
||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
tasks.add(new Launch4JTask(server));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package pro.gravit.launchserver.binary;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.binary.tasks.*;
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package pro.gravit.launchserver.binary;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class LauncherBinary extends BinaryPipeline {
|
||||
public final LaunchServer server;
|
||||
|
@ -19,11 +22,27 @@ protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat
|
|||
}
|
||||
|
||||
public static Path resolve(LaunchServer server, String ext) {
|
||||
return server.config.copyBinaries ? server.updatesDir.resolve(server.config.binaryName + ext) : server.dir.resolve(server.config.binaryName + ext);
|
||||
return Path.of(server.config.binaryName + ext);
|
||||
}
|
||||
|
||||
public void build() throws IOException {
|
||||
build(syncBinaryFile, server.config.launcher.deleteTempFiles);
|
||||
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();
|
||||
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() {
|
||||
|
@ -38,9 +57,13 @@ public void init() {
|
|||
}
|
||||
|
||||
public final boolean sync() throws IOException {
|
||||
boolean exists = exists();
|
||||
digest = exists ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(syncBinaryFile)) : null;
|
||||
|
||||
return exists;
|
||||
try {
|
||||
var target = syncBinaryFile.toString();
|
||||
var path = server.config.updatesProvider.download(null, List.of(target)).get(target);
|
||||
digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(path));
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.LauncherConfig;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.asm.ClassMetadataReader;
|
||||
import pro.gravit.launchserver.asm.InjectClassAcceptor;
|
||||
|
@ -53,7 +53,7 @@ public String getName() {
|
|||
public Path process(Path inputJar) throws IOException {
|
||||
Path outputJar = server.launcherBinary.nextPath(this);
|
||||
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
|
||||
BuildContext context = new BuildContext(output, reader.getCp(), this);
|
||||
BuildContext context = new BuildContext(output, reader.getCp(), this, server.launcherBinary.runtimeDir);
|
||||
initProps();
|
||||
preBuildHook.hook(context);
|
||||
properties.put("launcher.legacymodules", context.legacyClientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
|
||||
|
@ -69,9 +69,12 @@ public Path process(Path inputJar) throws IOException {
|
|||
Map<String, byte[]> runtime = new HashMap<>(256);
|
||||
// Write launcher guard dir
|
||||
if (server.config.launcher.encryptRuntime) {
|
||||
context.pushEncryptedDir(server.launcherBinary.runtimeDir, Launcher.RUNTIME_DIR, server.runtime.runtimeEncryptKey, runtime, false);
|
||||
context.pushEncryptedDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, server.runtime.runtimeEncryptKey, runtime, false);
|
||||
} else {
|
||||
context.pushDir(server.launcherBinary.runtimeDir, Launcher.RUNTIME_DIR, runtime, false);
|
||||
context.pushDir(context.getRuntimeDir(), Launcher.RUNTIME_DIR, runtime, false);
|
||||
}
|
||||
if(context.isDeleteRuntimeDir()) {
|
||||
IOHelper.deleteDir(context.getRuntimeDir(), true);
|
||||
}
|
||||
|
||||
LauncherConfig launcherConfig = new LauncherConfig(server.config.netty.address, server.keyAgreementManager.ecdsaPublicKey, server.keyAgreementManager.rsaPublicKey, runtime, server.config.projectName);
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
import pro.gravit.utils.helper.UnpackHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -37,8 +34,10 @@ public Path process(Path inputFile) throws IOException {
|
|||
server.launcherBinary.addonLibs.clear();
|
||||
server.launcherBinary.files.clear();
|
||||
IOHelper.walk(server.launcherLibraries, new ListFileVisitor(server.launcherBinary.coreLibs), false);
|
||||
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
||||
try(Stream<Path> stream = Files.walk(server.launcherPack).filter((e) -> {
|
||||
if(Files.isDirectory(server.launcherLibrariesCompile)) {
|
||||
IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false);
|
||||
}
|
||||
try(Stream<Path> stream = Files.walk(server.launcherPack, FileVisitOption.FOLLOW_LINKS).filter((e) -> {
|
||||
try {
|
||||
return !Files.isDirectory(e) && !Files.isHidden(e);
|
||||
} catch (IOException ex) {
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
package pro.gravit.launchserver.binary.tasks.exe;
|
||||
|
||||
import net.sf.launch4j.Builder;
|
||||
import net.sf.launch4j.Log;
|
||||
import net.sf.launch4j.config.*;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Launch4JTask implements LauncherBuildTask, BuildExeMainTask {
|
||||
public static final String DOWNLOAD_URL = "https://bell-sw.com/pages/downloads/?version=java-8-lts&os=Windows&package=jre-full"; // BellSoft
|
||||
private static final String VERSION = Version.getVersion().getVersionString();
|
||||
private static final int BUILD = Version.getVersion().build;
|
||||
private final Path faviconFile;
|
||||
private final LaunchServer server;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public Launch4JTask(LaunchServer launchServer) {
|
||||
this.server = launchServer;
|
||||
faviconFile = launchServer.dir.resolve("favicon.ico");
|
||||
}
|
||||
|
||||
public static String formatVars(String mask) {
|
||||
return mask.formatted(VERSION, BUILD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "launch4j";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path process(Path inputFile) throws IOException {
|
||||
logger.info("Building launcher EXE binary file (Using Launch4J)");
|
||||
Path output = setConfig();
|
||||
|
||||
// Set favicon path
|
||||
Config config = ConfigPersister.getInstance().getConfig();
|
||||
if (IOHelper.isFile(faviconFile))
|
||||
config.setIcon(faviconFile.toFile());
|
||||
else {
|
||||
config.setIcon(null);
|
||||
logger.warn("Missing favicon.ico file");
|
||||
}
|
||||
|
||||
// Start building
|
||||
Builder builder = new Builder(Launch4JLog.INSTANCE);
|
||||
try {
|
||||
builder.build();
|
||||
} catch (Throwable e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private Path setConfig() {
|
||||
Path path = server.launcherEXEBinary.nextPath(getName());
|
||||
Config config = new Config();
|
||||
// Set file options
|
||||
config.setChdir(".");
|
||||
config.setErrTitle("JVM Error");
|
||||
config.setDownloadUrl(server.config.launch4j.downloadUrl);
|
||||
if (server.config.launch4j.supportURL != null) config.setSupportUrl(server.config.launch4j.supportURL);
|
||||
// Set boolean options
|
||||
config.setPriorityIndex(0);
|
||||
config.setHeaderType(Config.GUI_HEADER);
|
||||
config.setStayAlive(false);
|
||||
config.setRestartOnCrash(false);
|
||||
|
||||
// Prepare JRE
|
||||
Jre jre = new Jre();
|
||||
jre.setMinVersion(server.config.launch4j.minVersion);
|
||||
if (server.config.launch4j.setMaxVersion)
|
||||
jre.setMaxVersion(server.config.launch4j.maxVersion);
|
||||
jre.setPath(System.getProperty("java.home"));
|
||||
config.setJre(jre);
|
||||
|
||||
// Prepare version info (product)
|
||||
VersionInfo info = new VersionInfo();
|
||||
info.setProductName(server.config.launch4j.productName);
|
||||
info.setProductVersion(formatVars(server.config.launch4j.productVer));
|
||||
info.setFileDescription(server.config.launch4j.fileDesc);
|
||||
info.setFileVersion(formatVars(server.config.launch4j.fileVer));
|
||||
info.setCopyright(server.config.launch4j.copyright);
|
||||
info.setTrademarks(server.config.launch4j.trademarks);
|
||||
info.setInternalName(formatVars(server.config.launch4j.internalName));
|
||||
// Prepare version info (file)
|
||||
info.setTxtFileVersion(formatVars(server.config.launch4j.txtFileVersion));
|
||||
info.setTxtProductVersion(formatVars(server.config.launch4j.txtProductVersion));
|
||||
// Prepare version info (misc)
|
||||
info.setOriginalFilename(path.getFileName().toString());
|
||||
info.setLanguage(LanguageID.RUSSIAN);
|
||||
config.setVersionInfo(info);
|
||||
|
||||
// Set JAR wrapping options
|
||||
config.setDontWrapJar(false);
|
||||
config.setJar(server.launcherBinary.syncBinaryFile.toFile());
|
||||
config.setOutfile(path.toFile());
|
||||
|
||||
// Return prepared config
|
||||
ConfigPersister.getInstance().setAntConfig(config, null);
|
||||
return path;
|
||||
}
|
||||
|
||||
private final static class Launch4JLog extends Log {
|
||||
private static final Launch4JLog INSTANCE = new Launch4JLog();
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public void append(String s) {
|
||||
logger.info(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,9 +3,9 @@
|
|||
import me.tongfei.progressbar.ProgressBar;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
import me.tongfei.progressbar.ProgressBarStyle;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.modern.Downloader;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.Downloader;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.utils.command.CommandException;
|
||||
|
||||
|
@ -47,6 +47,9 @@ protected boolean showApplyDialog(String text) throws IOException {
|
|||
protected Downloader downloadWithProgressBar(String taskName, List<Downloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
||||
long total = 0;
|
||||
for (Downloader.SizedFile file : list) {
|
||||
if(file.size < 0) {
|
||||
continue;
|
||||
}
|
||||
total += file.size;
|
||||
}
|
||||
long totalFiles = list.size();
|
||||
|
|
|
@ -32,6 +32,7 @@ public void invoke(String... args) throws Exception {
|
|||
boolean value = Boolean.parseBoolean(args[0]);
|
||||
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
|
||||
Configuration config = ctx.getConfiguration();
|
||||
config.getWatchManager().setIntervalSeconds(-1);
|
||||
LoggerConfig loggerConfig = config.getLoggerConfig("pro.gravit");
|
||||
loggerConfig.setLevel(value ? Level.TRACE : Level.DEBUG);
|
||||
ctx.updateLoggers();
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package pro.gravit.launchserver.command.basic;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public final class RestartCommand extends Command {
|
||||
public RestartCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "Restart LaunchServer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) {
|
||||
server.fullyRestart();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,11 @@
|
|||
import pro.gravit.launchserver.command.hash.*;
|
||||
import pro.gravit.launchserver.command.modules.LoadModuleCommand;
|
||||
import pro.gravit.launchserver.command.modules.ModulesCommand;
|
||||
import pro.gravit.launchserver.command.profiles.ProfilesCommand;
|
||||
import pro.gravit.launchserver.command.service.*;
|
||||
import pro.gravit.launchserver.command.sync.*;
|
||||
import pro.gravit.launchserver.command.tools.SignDirCommand;
|
||||
import pro.gravit.launchserver.command.tools.SignJarCommand;
|
||||
import pro.gravit.utils.command.BaseCommandCategory;
|
||||
import pro.gravit.utils.command.basic.ClearCommand;
|
||||
import pro.gravit.utils.command.basic.GCCommand;
|
||||
|
@ -19,7 +23,6 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
basic.registerCommand("version", new VersionCommand(server));
|
||||
basic.registerCommand("build", new BuildCommand(server));
|
||||
basic.registerCommand("stop", new StopCommand(server));
|
||||
basic.registerCommand("restart", new RestartCommand(server));
|
||||
basic.registerCommand("debug", new DebugCommand(server));
|
||||
basic.registerCommand("clear", new ClearCommand(handler));
|
||||
basic.registerCommand("gc", new GCCommand());
|
||||
|
@ -34,12 +37,8 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
updates.registerCommand("unindexAsset", new UnindexAssetCommand(server));
|
||||
updates.registerCommand("downloadAsset", new DownloadAssetCommand(server));
|
||||
updates.registerCommand("downloadClient", new DownloadClientCommand(server));
|
||||
updates.registerCommand("syncBinaries", new SyncBinariesCommand(server));
|
||||
updates.registerCommand("syncUpdates", new SyncUpdatesCommand(server));
|
||||
updates.registerCommand("syncProfiles", new SyncProfilesCommand(server));
|
||||
updates.registerCommand("syncUP", new SyncUPCommand(server));
|
||||
updates.registerCommand("saveProfiles", new SaveProfilesCommand(server));
|
||||
updates.registerCommand("makeProfile", new MakeProfileCommand(server));
|
||||
updates.registerCommand("sync", new SyncCommand(server));
|
||||
updates.registerCommand("profile", new ProfilesCommand(server));
|
||||
Category updatesCategory = new Category(updates, "updates", "Update and Sync Management");
|
||||
handler.registerCategory(updatesCategory);
|
||||
|
||||
|
@ -50,11 +49,16 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
|||
service.registerCommand("notify", new NotifyCommand(server));
|
||||
service.registerCommand("component", new ComponentCommand(server));
|
||||
service.registerCommand("clients", new ClientsCommand(server));
|
||||
service.registerCommand("signJar", new SignJarCommand(server));
|
||||
service.registerCommand("signDir", new SignDirCommand(server));
|
||||
service.registerCommand("securitycheck", new SecurityCheckCommand(server));
|
||||
service.registerCommand("token", new TokenCommand(server));
|
||||
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
||||
handler.registerCategory(serviceCategory);
|
||||
|
||||
//Register tools commands
|
||||
BaseCommandCategory tools = new BaseCommandCategory();
|
||||
tools.registerCommand("signJar", new SignJarCommand(server));
|
||||
tools.registerCommand("signDir", new SignDirCommand(server));
|
||||
Category toolsCategory = new Category(tools, "tools", "Other tools");
|
||||
handler.registerCategory(toolsCategory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import com.google.gson.JsonObject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.modern.Downloader;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.Downloader;
|
||||
import pro.gravit.launchserver.HttpRequester;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
import com.google.gson.JsonElement;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.ClientProfileVersions;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
||||
|
@ -61,9 +62,11 @@ public void invoke(String... args) throws IOException, CommandException {
|
|||
try {
|
||||
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
|
||||
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
|
||||
clientProfile.setTitle(dirName);
|
||||
clientProfile.setDir(dirName);
|
||||
clientProfile.setUUID(UUID.randomUUID());
|
||||
var builder = new ClientProfileBuilder(clientProfile);
|
||||
builder.setTitle(dirName);
|
||||
builder.setDir(dirName);
|
||||
builder.setUuid(UUID.randomUUID());
|
||||
clientProfile = builder.createClientProfile();
|
||||
if (clientProfile.getServers() != null) {
|
||||
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
|
||||
if (serverProfile != null) {
|
||||
|
@ -94,10 +97,7 @@ public void invoke(String... args) throws IOException, CommandException {
|
|||
isMirrorClientDownload = true;
|
||||
}
|
||||
}
|
||||
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
|
||||
dirName, "json"))) {
|
||||
Launcher.gsonManager.configGson.toJson(clientProfile, writer);
|
||||
}
|
||||
server.config.profileProvider.addProfile(clientProfile);
|
||||
|
||||
// Finished
|
||||
server.syncProfilesDir();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import com.google.gson.JsonObject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.command.CommandException;
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
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;
|
||||
|
||||
public class SaveProfilesCommand extends Command {
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public SaveProfilesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
public static void saveProfile(ClientProfile profile, Path path) throws IOException {
|
||||
if (profile.getUUID() == null) profile.setUUID(UUID.randomUUID());
|
||||
if (profile.getServers().size() == 0) {
|
||||
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
|
||||
public String getArgsDescription() {
|
||||
return "[profile names...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "load and save profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
if (args.length > 0) {
|
||||
for (String profileName : args) {
|
||||
Path profilePath = server.profilesDir.resolve(profileName.concat(".json"));
|
||||
if (!Files.exists(profilePath)) {
|
||||
logger.error("Profile {} not found", profilePath.toString());
|
||||
return;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.LauncherTrustManager;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launcher.core.LauncherTrustManager;
|
||||
import pro.gravit.launcher.base.modules.LauncherModule;
|
||||
import pro.gravit.launcher.base.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.launchermodules.LauncherModuleLoader;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package pro.gravit.launchserver.command.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.launcher.base.profiles.ClientProfileBuilder;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.helper.CommonHelper;
|
||||
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.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class CloneProfileCommand extends Command {
|
||||
private final transient Logger logger = LogManager.getLogger(CloneProfileCommand.class);
|
||||
public CloneProfileCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[profile title/uuid] [new profile title]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "clone profile and profile dir";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 2);
|
||||
ClientProfile profile;
|
||||
try {
|
||||
UUID uuid = UUID.fromString(args[0]);
|
||||
profile = server.config.profileProvider.getProfile(uuid);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
profile = server.config.profileProvider.getProfile(args[0]);
|
||||
}
|
||||
var builder = new ClientProfileBuilder(profile);
|
||||
builder.setTitle(args[1]);
|
||||
builder.setUuid(UUID.randomUUID());
|
||||
if(profile.getServers().size() == 1) {
|
||||
profile.getServers().getFirst().name = args[1];
|
||||
}
|
||||
logger.info("Copy {} to {}", profile.getDir(), args[1]);
|
||||
var src = server.updatesDir.resolve(profile.getDir());
|
||||
var dest = server.updatesDir.resolve(args[1]);
|
||||
try (Stream<Path> stream = Files.walk(src)) {
|
||||
stream.forEach(source -> {
|
||||
try {
|
||||
IOHelper.copy(source, dest.resolve(src.relativize(source)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
builder.setDir(args[1]);
|
||||
profile = builder.createClientProfile();
|
||||
server.config.profileProvider.addProfile(profile);
|
||||
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
||||
server.syncProfilesDir();
|
||||
server.syncUpdatesDir(List.of(args[1]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package pro.gravit.launchserver.command.profiles;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.util.UUID;
|
||||
|
||||
public class DeleteProfileCommand extends Command {
|
||||
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
||||
public DeleteProfileCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[uuid/title]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "permanently delete profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
ClientProfile profile;
|
||||
try {
|
||||
UUID uuid = UUID.fromString(args[0]);
|
||||
profile = server.config.profileProvider.getProfile(uuid);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
profile = server.config.profileProvider.getProfile(args[0]);
|
||||
}
|
||||
if(profile == null) {
|
||||
logger.error("Profile {} not found", args[0]);
|
||||
return;
|
||||
}
|
||||
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", profile.getDir());
|
||||
if(!showApplyDialog("Continue?")) {
|
||||
return;
|
||||
}
|
||||
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
||||
server.config.profileProvider.deleteProfile(profile);
|
||||
logger.info("Delete {}", profile.getDir());
|
||||
server.config.updatesProvider.delete(profile.getDir());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package pro.gravit.launchserver.command.profiles;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class ListProfilesCommand extends Command {
|
||||
private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class);
|
||||
public ListProfilesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "show all profiles";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
for(var profile : server.getProfiles()) {
|
||||
logger.info("{} ({}) {}", profile.getTitle(), profile.getVersion().toString(), profile.isLimited() ? "limited" : "");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.profiles;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
||||
|
@ -37,9 +37,7 @@ public void invoke(String... args) throws Exception {
|
|||
logger.info("Detected option {}", option);
|
||||
}
|
||||
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
||||
try (Writer writer = IOHelper.newWriter(server.profilesDir.resolve(args[0].concat(".json")))) {
|
||||
Launcher.gsonManager.configGson.toJson(profile, writer);
|
||||
}
|
||||
server.config.profileProvider.addProfile(profile);
|
||||
logger.info("Profile {} created", args[0]);
|
||||
server.syncProfilesDir();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package pro.gravit.launchserver.command.profiles;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class ProfilesCommand extends Command {
|
||||
public ProfilesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
this.childCommands.put("make", new MakeProfileCommand(server));
|
||||
this.childCommands.put("save", new SaveProfilesCommand(server));
|
||||
this.childCommands.put("clone", new CloneProfileCommand(server));
|
||||
this.childCommands.put("list", new ListProfilesCommand(server));
|
||||
this.childCommands.put("delete", new DeleteProfileCommand(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[subcommand] [args...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "manage profiles";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
invokeSubcommands(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package pro.gravit.launchserver.command.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.launchserver.LaunchServer;
|
||||
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;
|
||||
|
||||
public class SaveProfilesCommand extends Command {
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public SaveProfilesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[profile names...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "load and save profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
if (args.length > 0) {
|
||||
for (String profileName : args) {
|
||||
ClientProfile profile;
|
||||
try {
|
||||
UUID uuid = UUID.fromString(profileName);
|
||||
profile = server.config.profileProvider.getProfile(uuid);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
profile = server.config.profileProvider.getProfile(profileName);
|
||||
}
|
||||
server.config.profileProvider.addProfile(profile);
|
||||
}
|
||||
server.syncProfilesDir();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.components.Component;
|
||||
|
@ -37,7 +37,6 @@ public void printHelp() {
|
|||
logger.info("Print help for component:");
|
||||
logger.info("component unload [componentName]");
|
||||
logger.info("component load [componentName] [filename]");
|
||||
logger.info("component gc [componentName]");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
|
||||
import pro.gravit.launcher.events.NotificationEvent;
|
||||
import pro.gravit.launcher.request.WebSocketEvent;
|
||||
import pro.gravit.launcher.base.events.NotificationEvent;
|
||||
import pro.gravit.launcher.base.request.WebSocketEvent;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.socket.WebSocketService;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.protect.AdvancedProtectHandler;
|
||||
import pro.gravit.launchserver.auth.protect.NoProtectHandler;
|
||||
|
@ -60,19 +60,19 @@ public void invoke(String... args) {
|
|||
LaunchServerConfig config = server.config;
|
||||
config.auth.forEach((name, pair) -> {
|
||||
});
|
||||
if (config.protectHandler instanceof NoProtectHandler) {
|
||||
printCheckResult("protectHandler", "protectHandler none", false);
|
||||
} else if (config.protectHandler instanceof AdvancedProtectHandler) {
|
||||
printCheckResult("protectHandler", "", true);
|
||||
if (!((AdvancedProtectHandler) config.protectHandler).enableHardwareFeature) {
|
||||
printCheckResult("protectHandler.hardwareId", "you can improve security by using hwid provider", null);
|
||||
} else {
|
||||
printCheckResult("protectHandler.hardwareId", "", true);
|
||||
switch (config.protectHandler) {
|
||||
case NoProtectHandler noProtectHandler -> printCheckResult("protectHandler", "protectHandler none", false);
|
||||
case AdvancedProtectHandler advancedProtectHandler -> {
|
||||
printCheckResult("protectHandler", "", true);
|
||||
if (!advancedProtectHandler.enableHardwareFeature) {
|
||||
printCheckResult("protectHandler.hardwareId", "you can improve security by using hwid provider", null);
|
||||
} else {
|
||||
printCheckResult("protectHandler.hardwareId", "", true);
|
||||
}
|
||||
}
|
||||
} else if (config.protectHandler instanceof StdProtectHandler) {
|
||||
printCheckResult("protectHandler", "you can improve security by using advanced", null);
|
||||
} else {
|
||||
printCheckResult("protectHandler", "unknown protectHandler", null);
|
||||
case StdProtectHandler stdProtectHandler ->
|
||||
printCheckResult("protectHandler", "you can improve security by using advanced", null);
|
||||
case null, default -> printCheckResult("protectHandler", "unknown protectHandler", null);
|
||||
}
|
||||
if (config.netty.address.startsWith("ws://")) {
|
||||
if (config.netty.ipForwarding)
|
||||
|
@ -110,7 +110,7 @@ public void invoke(String... args) {
|
|||
KeyStore keyStore = SignHelper.getStore(new File(config.sign.keyStore).toPath(), config.sign.keyStorePass, config.sign.keyStoreType);
|
||||
Certificate[] certChainPlain = keyStore.getCertificateChain(config.sign.keyAlias);
|
||||
List<X509Certificate> certChain = Arrays.stream(certChainPlain).map(e -> (X509Certificate) e).toList();
|
||||
X509Certificate cert = certChain.get(0);
|
||||
X509Certificate cert = certChain.getFirst();
|
||||
cert.checkValidity();
|
||||
if (certChain.size() == 1) {
|
||||
printCheckResult("sign", "certificate chain contains <2 element(recommend 2 and more)", false);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import io.jsonwebtoken.Jwts;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
@ -18,15 +18,16 @@ public TokenCommand(LaunchServer server) {
|
|||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
verifyArgs(args, 1);
|
||||
var parser = Jwts.parserBuilder().setSigningKey(server.keyAgreementManager.ecdsaPublicKey).build();
|
||||
var claims = parser.parseClaimsJws(args[0]);
|
||||
logger.info("Token: {}", claims.getBody());
|
||||
var parser = Jwts.parser().verifyWith(server.keyAgreementManager.ecdsaPublicKey).build();
|
||||
var claims = parser.parseSignedClaims(args[0]);
|
||||
logger.info("Token: {}", claims.getPayload());
|
||||
}
|
||||
});
|
||||
this.childCommands.put("server", new SubCommand("[profileName] (authId)", "generate new server token") {
|
||||
this.childCommands.put("server", new SubCommand("[profileName] (authId) (public only)", "generate new server token") {
|
||||
@Override
|
||||
public void invoke(String... args) {
|
||||
AuthProviderPair pair = args.length > 1 ? server.config.getAuthProviderPair(args[1]) : server.config.getAuthProviderPair();
|
||||
boolean publicOnly = args.length <= 2 || Boolean.parseBoolean(args[2]);
|
||||
ClientProfile profile = null;
|
||||
for (ClientProfile p : server.getProfiles()) {
|
||||
if (p.getTitle().equals(args[0]) || p.getUUID().toString().equals(args[0])) {
|
||||
|
@ -41,7 +42,7 @@ public void invoke(String... args) {
|
|||
logger.error("AuthId {} not found", args[1]);
|
||||
return;
|
||||
}
|
||||
String token = server.authManager.newCheckServerToken(profile != null ? profile.getUUID().toString() : args[0], pair.name);
|
||||
String token = server.authManager.newCheckServerToken(profile != null ? profile.getUUID().toString() : args[0], pair.name, publicOnly);
|
||||
logger.info("Server token {} authId {}: {}", args[0], pair.name, token);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -0,0 +1,31 @@
|
|||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class SyncCommand extends Command {
|
||||
public SyncCommand(LaunchServer server) {
|
||||
super(server);
|
||||
this.childCommands.put("profiles", new SyncProfilesCommand(server));
|
||||
this.childCommands.put("binaries", new SyncBinariesCommand(server));
|
||||
this.childCommands.put("updates", new SyncUpdatesCommand(server));
|
||||
this.childCommands.put("up", new SyncUPCommand(server));
|
||||
this.childCommands.put("launchermodules", new SyncLauncherModulesCommand(server));
|
||||
this.childCommands.put("updatescache", new SyncUpdatesCacheCommand(server));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "[updates/profiles/up/binaries/launchermodules/updatescache] [args...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "sync specified objects";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
invokeSubcommands(args);
|
||||
}
|
||||
}
|
|
@ -1,31 +1,31 @@
|
|||
package pro.gravit.launchserver.launchermodules;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class SyncLauncherModulesCommand extends Command {
|
||||
private final LauncherModuleLoader mod;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
|
||||
public SyncLauncherModulesCommand(LauncherModuleLoader mod) {
|
||||
this.mod = mod;
|
||||
public SyncLauncherModulesCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "Resync launcher modules";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "[]";
|
||||
return "Resync launcher modules";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
mod.syncModules();
|
||||
server.launcherModuleLoader.syncModules();
|
||||
logger.info("Launcher Modules synced");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -0,0 +1,25 @@
|
|||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
|
||||
public class SyncUpdatesCacheCommand extends Command {
|
||||
public SyncUpdatesCacheCommand(LaunchServer server) {
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "sync updates cache";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
server.updatesManager.readUpdatesFromCache();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.hash;
|
||||
package pro.gravit.launchserver.command.sync;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
package pro.gravit.launchserver.command.tools;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -1,4 +1,4 @@
|
|||
package pro.gravit.launchserver.command.service;
|
||||
package pro.gravit.launchserver.command.tools;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
|
@ -90,7 +90,7 @@ public boolean check(T address) {
|
|||
}
|
||||
}
|
||||
|
||||
static class LimitEntry {
|
||||
protected static class LimitEntry {
|
||||
long time;
|
||||
int trys;
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ public abstract class Component {
|
|||
public static void registerComponents() {
|
||||
if (!registredComp) {
|
||||
providers.register("authLimiter", AuthLimiterComponent.class);
|
||||
providers.register("regLimiter", RegLimiterComponent.class);
|
||||
providers.register("commandRemover", CommandRemoverComponent.class);
|
||||
providers.register("proguard", ProGuardComponent.class);
|
||||
providers.register("whitelist", WhitelistComponent.class);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
import pro.gravit.utils.command.SubCommand;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
import pro.gravit.utils.helper.UnpackHelper;
|
||||
|
||||
|
@ -20,7 +19,6 @@
|
|||
import java.nio.file.Paths;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -215,7 +213,7 @@ public Path process(Path inputFile) throws IOException {
|
|||
args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString());
|
||||
args.addAll(component.jvmArgs);
|
||||
args.add("-cp");
|
||||
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
|
||||
try(Stream<Path> files = Files.walk(server.librariesDir, FileVisitOption.FOLLOW_LINKS)) {
|
||||
args.add(files
|
||||
.filter(e -> e.getFileName().toString().endsWith(".jar"))
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package pro.gravit.launchserver.components;
|
||||
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||
import pro.gravit.utils.HookException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RegLimiterComponent extends IPLimiter implements AutoCloseable {
|
||||
|
||||
public transient LaunchServer launchServer;
|
||||
public String message;
|
||||
|
||||
public List<String> excludeIps = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void init(LaunchServer launchServer) {
|
||||
this.launchServer = launchServer;
|
||||
launchServer.authHookManager.registraion.registerHook(this::registerHook);
|
||||
}
|
||||
|
||||
public boolean registerHook(AuthHookManager.RegContext context) {
|
||||
if (!check(context.ip)) {
|
||||
throw new HookException(message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
launchServer.authHookManager.registraion.unregisterHook(this::registerHook);
|
||||
}
|
||||
}
|
|
@ -4,66 +4,54 @@
|
|||
import io.netty.handler.logging.LogLevel;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.LauncherConfig;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
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.StdProtectHandler;
|
||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||
import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask;
|
||||
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.Component;
|
||||
import pro.gravit.launchserver.components.ProGuardComponent;
|
||||
import pro.gravit.launchserver.components.RegLimiterComponent;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.launchserver.socket.NettyObjectFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
public final class LaunchServerConfig {
|
||||
private final static List<String> oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/", "https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/", "https://mirror.gravitlauncher.com/5.4.x/");
|
||||
private final static List<String> oldMirrorList = List.of("https://mirror.gravit.pro/5.2.x/", "https://mirror.gravit.pro/5.3.x/",
|
||||
"https://mirror.gravitlauncher.com/5.2.x/", "https://mirror.gravitlauncher.com/5.3.x/", "https://mirror.gravitlauncher.com/5.4.x/",
|
||||
"https://mirror.gravitlauncher.com/5.5.x/");
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
public String projectName;
|
||||
public String[] mirrors;
|
||||
public String binaryName;
|
||||
public boolean copyBinaries = true;
|
||||
public boolean cacheUpdates = true;
|
||||
public LauncherConfig.LauncherEnvironment env;
|
||||
public Map<String, AuthProviderPair> auth;
|
||||
// Handlers & Providers
|
||||
public ProtectHandler protectHandler;
|
||||
public Map<String, Component> components;
|
||||
public ExeConf launch4j;
|
||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
||||
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
||||
public NettyConfig netty;
|
||||
public LauncherConf launcher;
|
||||
public JarSignerConf sign;
|
||||
public String startScript;
|
||||
private transient LaunchServer server = null;
|
||||
private transient AuthProviderPair authDefault;
|
||||
|
||||
public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||
LaunchServerConfig newConfig = new LaunchServerConfig();
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.5.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"};
|
||||
newConfig.launch4j = new LaunchServerConfig.ExeConf();
|
||||
newConfig.launch4j.enabled = false;
|
||||
newConfig.launch4j.copyright = "© GravitLauncher Team";
|
||||
newConfig.launch4j.fileDesc = "GravitLauncher ".concat(Version.getVersion().getVersionString());
|
||||
newConfig.launch4j.fileVer = Version.getVersion().getVersionString().concat(".").concat(String.valueOf(Version.getVersion().patch));
|
||||
newConfig.launch4j.internalName = "Launcher";
|
||||
newConfig.launch4j.trademarks = "This product is licensed under GPLv3";
|
||||
newConfig.launch4j.txtFileVersion = "%s, build %d";
|
||||
newConfig.launch4j.txtProductVersion = "%s, build %d";
|
||||
newConfig.launch4j.productName = "GravitLauncher";
|
||||
newConfig.launch4j.productVer = newConfig.launch4j.fileVer;
|
||||
newConfig.launch4j.maxVersion = "99.0.0";
|
||||
newConfig.mirrors = new String[]{"https://mirror.gravitlauncher.com/5.6.x/", "https://gravit-launcher-mirror.storage.googleapis.com/"};
|
||||
newConfig.env = LauncherConfig.LauncherEnvironment.STD;
|
||||
newConfig.startScript = JVMHelper.OS_TYPE.equals(JVMHelper.OS.MUSTDIE) ? "." + File.separator + "start.bat" : "." + File.separator + "start.sh";
|
||||
newConfig.auth = new HashMap<>();
|
||||
AuthProviderPair a = new AuthProviderPair(new RejectAuthCoreProvider(),
|
||||
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
|
||||
|
@ -77,12 +65,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
|||
newConfig.netty.fileServerEnabled = true;
|
||||
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
|
||||
newConfig.netty.performance = new NettyPerformanceConfig();
|
||||
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.mode = NettyObjectFactory.NettyFactoryMode.AUTO;
|
||||
newConfig.netty.performance.bossThread = 2;
|
||||
newConfig.netty.performance.workerThread = 8;
|
||||
newConfig.netty.performance.schedulerThread = 2;
|
||||
|
@ -91,6 +74,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
|||
newConfig.launcher.compress = true;
|
||||
newConfig.launcher.deleteTempFiles = true;
|
||||
newConfig.launcher.stripLineNumbers = true;
|
||||
newConfig.launcher.customJvmOptions.add("-Dfile.encoding=UTF-8");
|
||||
|
||||
newConfig.sign = new JarSignerConf();
|
||||
|
||||
|
@ -100,13 +84,9 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
|||
authLimiterComponent.rateLimitMillis = SECONDS.toMillis(8);
|
||||
authLimiterComponent.message = "Превышен лимит авторизаций";
|
||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||
RegLimiterComponent regLimiterComponent = new RegLimiterComponent();
|
||||
regLimiterComponent.rateLimit = 3;
|
||||
regLimiterComponent.rateLimitMillis = HOURS.toMillis(10);
|
||||
regLimiterComponent.message = "Превышен лимит регистраций";
|
||||
newConfig.components.put("regLimiter", regLimiterComponent);
|
||||
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
||||
newConfig.components.put("proguard", proGuardComponent);
|
||||
newConfig.profileProvider = new LocalProfileProvider();
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
|
@ -142,7 +122,7 @@ public void setEnv(LauncherConfig.LauncherEnvironment env) {
|
|||
}
|
||||
|
||||
public void verify() {
|
||||
if (auth == null || auth.size() < 1) {
|
||||
if (auth == null || auth.isEmpty()) {
|
||||
throw new NullPointerException("AuthProviderPair`s count should be at least one");
|
||||
}
|
||||
|
||||
|
@ -171,8 +151,8 @@ public void verify() {
|
|||
if (!updateMirror) {
|
||||
for (int i = 0; i < mirrors.length; ++i) {
|
||||
if (mirrors[i] != null && oldMirrorList.contains(mirrors[i])) {
|
||||
logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.5.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]);
|
||||
mirrors[i] = "https://mirror.gravitlauncher.com/5.5.x/";
|
||||
logger.warn("Replace mirror '{}' to 'https://mirror.gravitlauncher.com/5.6.x/'. If you really need to use original url, use '-Dlaunchserver.config.disableUpdateMirror=true'", mirrors[i]);
|
||||
mirrors[i] = "https://mirror.gravitlauncher.com/5.6.x/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +168,14 @@ public void init(LaunchServer.ReloadType type) {
|
|||
server.registerObject("protectHandler", protectHandler);
|
||||
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) {
|
||||
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
||||
}
|
||||
|
@ -228,25 +216,14 @@ public void close(LaunchServer.ReloadType type) {
|
|||
server.unregisterObject("protectHandler", protectHandler);
|
||||
protectHandler.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExeConf {
|
||||
public boolean enabled;
|
||||
public boolean setMaxVersion;
|
||||
public String maxVersion;
|
||||
public String minVersion = "17.0.0";
|
||||
public String supportURL = null;
|
||||
public String downloadUrl = Launch4JTask.DOWNLOAD_URL;
|
||||
public String productName;
|
||||
public String productVer;
|
||||
public String fileDesc;
|
||||
public String fileVer;
|
||||
public String internalName;
|
||||
public String copyright;
|
||||
public String trademarks;
|
||||
|
||||
public String txtFileVersion;
|
||||
public String txtProductVersion;
|
||||
if(profileProvider != null) {
|
||||
server.unregisterObject("profileProvider", profileProvider);
|
||||
profileProvider.close();
|
||||
}
|
||||
if(updatesProvider != null) {
|
||||
server.unregisterObject("updatesProvider", updatesProvider);
|
||||
updatesProvider.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class JarSignerConf {
|
||||
|
@ -296,11 +273,17 @@ public static class NettyConfig {
|
|||
}
|
||||
|
||||
public static class NettyPerformanceConfig {
|
||||
public boolean usingEpoll;
|
||||
public NettyObjectFactory.NettyFactoryMode mode = NettyObjectFactory.NettyFactoryMode.AUTO;
|
||||
public int bossThread;
|
||||
public int workerThread;
|
||||
public int schedulerThread;
|
||||
public int maxWebSocketRequestBytes = 1024 * 1024;
|
||||
public boolean disableThreadSafeClientObject;
|
||||
public NettyExecutorType executorType = NettyExecutorType.VIRTUAL_THREADS;
|
||||
|
||||
public enum NettyExecutorType {
|
||||
NONE, DEFAULT, WORK_STEAL, VIRTUAL_THREADS
|
||||
}
|
||||
}
|
||||
|
||||
public static class NettyBindAddress {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import com.google.gson.JsonElement;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.request.RequestException;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.base.request.RequestException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
|
@ -25,14 +25,14 @@ public static String makeAccessJwtTokenFromString(User user, LocalDateTime expir
|
|||
}
|
||||
|
||||
public static JwtTokenInfo getJwtInfoFromAccessToken(String token, ECPublicKey publicKey) {
|
||||
var parser = Jwts.parserBuilder()
|
||||
var parser = Jwts.parser()
|
||||
.requireIssuer("LaunchServer")
|
||||
.setClock(() -> new Date(Clock.systemUTC().millis()))
|
||||
.setSigningKey(publicKey)
|
||||
.clock(() -> new Date(Clock.systemUTC().millis()))
|
||||
.verifyWith(publicKey)
|
||||
.build();
|
||||
var claims = parser.parseClaimsJws(token);
|
||||
var uuid = UUID.fromString(claims.getBody().get("uuid", String.class));
|
||||
var username = claims.getBody().getSubject();
|
||||
var claims = parser.parseSignedClaims(token);
|
||||
var uuid = UUID.fromString(claims.getPayload().get("uuid", String.class));
|
||||
var username = claims.getPayload().getSubject();
|
||||
return new JwtTokenInfo(username, uuid);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package pro.gravit.launchserver.helper;
|
||||
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.ClientProfileBuilder;
|
||||
import pro.gravit.launcher.profiles.ClientProfileVersions;
|
||||
import pro.gravit.launcher.profiles.optional.OptionalFile;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalActionFile;
|
||||
import pro.gravit.launcher.profiles.optional.actions.OptionalActionJvmArgs;
|
||||
import pro.gravit.launcher.profiles.optional.triggers.OSTrigger;
|
||||
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.optional.OptionalFile;
|
||||
import pro.gravit.launcher.base.profiles.optional.actions.OptionalActionFile;
|
||||
import pro.gravit.launcher.base.profiles.optional.actions.OptionalActionJvmArgs;
|
||||
import pro.gravit.launcher.base.profiles.optional.triggers.OSTrigger;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -27,9 +27,13 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
builder.setMainClass(getMainClassByVersion(version, options));
|
||||
builder.setServers(List.of(new ClientProfile.ServerProfile(title, "localhost", 25565)));
|
||||
// ------------
|
||||
var lwjgl3ify = findOption(options, Lwjgl3ifyOption.class);
|
||||
builder.setUpdateVerify(List.of("libraries", "natives", "mods", "minecraft.jar", "forge.jar", "liteloader.jar"));
|
||||
{
|
||||
List<String> classPath = new ArrayList<>(5);
|
||||
if(findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
||||
classPath.add("libraries/net/minecraft/launchwrapper/1.12/launchwrapper-1.12.jar");
|
||||
}
|
||||
classPath.add("libraries");
|
||||
classPath.add("minecraft.jar");
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) <= 0) {
|
||||
|
@ -44,8 +48,40 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
jvmArgs.add("-XX:+DisableAttachMechanism");
|
||||
// Official Mojang launcher java arguments
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) <= 0) {
|
||||
jvmArgs.add("-XX:+UseConcMarkSweepGC");
|
||||
jvmArgs.add("-XX:+CMSIncrementalMode");
|
||||
// lwjgl3ify arguments https://github.com/GTNewHorizons/lwjgl3ify
|
||||
jvmArgs.add("-Djava.security.manager=allow");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/jdk.internal.loader=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.net=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.nio=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.io=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.lang=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.lang.reflect=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.text=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/java.util=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/jdk.internal.reflect=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.base/sun.nio.ch=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED,java.naming");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.desktop/sun.awt=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.desktop/sun.awt.image=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.desktop/com.sun.imageio.plugins.png=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("jdk.dynalink/jdk.dynalink.beans=ALL-UNNAMED");
|
||||
jvmArgs.add("--add-opens");
|
||||
jvmArgs.add("java.sql.rowset/javax.sql.rowset.serial=ALL-UNNAMED");
|
||||
} else if (version.compareTo(ClientProfileVersions.MINECRAFT_1_18) <= 0) { // 1.13 - 1.16.5
|
||||
jvmArgs.add("-XX:+UseG1GC");
|
||||
jvmArgs.add("-XX:+UnlockExperimentalVMOptions");
|
||||
|
@ -67,6 +103,7 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
}
|
||||
if (fabric.isPresent()) {
|
||||
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()) {
|
||||
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
||||
|
@ -116,14 +153,8 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
}
|
||||
}
|
||||
}
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_17) >= 0 && version.compareTo(ClientProfileVersions.MINECRAFT_1_18) < 0) {
|
||||
builder.setMinJavaVersion(16);
|
||||
builder.setRecommendJavaVersion(16);
|
||||
}
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_18) >= 0) {
|
||||
builder.setMinJavaVersion(17);
|
||||
builder.setRecommendJavaVersion(17);
|
||||
}
|
||||
builder.setMinJavaVersion(17);
|
||||
builder.setRecommendJavaVersion(17);
|
||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_20_3) >= 0) {
|
||||
builder.setMinJavaVersion(21);
|
||||
builder.setRecommendJavaVersion(21);
|
||||
|
@ -133,7 +164,10 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
builder.setJvmArgs(jvmArgs);
|
||||
builder.setUpdateOptional(optionals);
|
||||
List<String> clientArgs = new ArrayList<>();
|
||||
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
||||
jvmArgs.add("-Drfb.skipClassLoaderCheck=true");
|
||||
}
|
||||
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent() || findOption(options, MakeProfileRfbOption.class).isPresent()) {
|
||||
if (findOption(options, MakeProfileOptionLiteLoader.class).isPresent()) {
|
||||
clientArgs.add("--tweakClass");
|
||||
clientArgs.add("com.mumfrey.liteloader.launch.LiteLoaderTweaker");
|
||||
|
@ -145,20 +179,9 @@ public static ClientProfile makeProfile(ClientProfile.Version version, String ti
|
|||
} else {
|
||||
clientArgs.add("cpw.mods.fml.common.launcher.FMLTweaker");
|
||||
}
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) <= 0) {
|
||||
builder.setMinJavaVersion(8);
|
||||
builder.setRecommendJavaVersion(8);
|
||||
builder.setMaxJavaVersion(8);
|
||||
}
|
||||
}
|
||||
} else if (version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) > 0) {
|
||||
if (forge.isPresent()) {
|
||||
clientArgs.addAll(forge.get().makeClientArgs());
|
||||
builder.setClassLoaderConfig(ClientProfile.ClassLoaderConfig.SYSTEM_ARGS);
|
||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_16_5) <= 0) {
|
||||
builder.setMaxJavaVersion(15);
|
||||
}
|
||||
}
|
||||
forge.ifPresent(makeProfileOptionForge -> clientArgs.addAll(makeProfileOptionForge.makeClientArgs()));
|
||||
}
|
||||
builder.setClientArgs(clientArgs);
|
||||
|
||||
|
@ -171,6 +194,9 @@ private static <T> Optional<T> findOption(MakeProfileOption[] options, Class<T>
|
|||
}
|
||||
|
||||
public static String getMainClassByVersion(ClientProfile.Version version, MakeProfileOption... options) {
|
||||
if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) {
|
||||
return "com.gtnewhorizons.retrofuturabootstrap.Main";
|
||||
}
|
||||
if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) {
|
||||
return "net.minecraft.launchwrapper.Launch";
|
||||
}
|
||||
|
@ -178,7 +204,7 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr
|
|||
return "cpw.mods.modlauncher.Launcher";
|
||||
}
|
||||
if (findOption(options, MakeProfileOptionFabric.class).isPresent()) {
|
||||
return "net.fabricmc.loader.launch.knot.KnotClient";
|
||||
return "net.fabricmc.loader.impl.launch.knot.KnotClient";
|
||||
}
|
||||
if(findOption(options, MakeProfilesOptionsQuilt.class).isPresent()) {
|
||||
return "org.quiltmc.loader.impl.launch.knot.KnotClient";
|
||||
|
@ -320,6 +346,13 @@ public static class MakeProfileOptionLaunchWrapper implements MakeProfileOption
|
|||
|
||||
}
|
||||
|
||||
public static class MakeProfileRfbOption implements MakeProfileOption {
|
||||
|
||||
}
|
||||
|
||||
public record Lwjgl3ifyOption(String lwjgl3ifyForgePatches) implements MakeProfileOption {
|
||||
}
|
||||
|
||||
public static class MakeProfileOptionFabric implements MakeProfileOption {
|
||||
public String jimfsPath;
|
||||
public String guavaPath;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package pro.gravit.launchserver.holder;
|
||||
|
||||
import pro.gravit.utils.launch.ClassLoaderControl;
|
||||
|
||||
public class LaunchServerControlHolder {
|
||||
private static ClassLoaderControl control;
|
||||
private static ModuleLayer.Controller controller;
|
||||
|
||||
public static ClassLoaderControl getControl() {
|
||||
return control;
|
||||
}
|
||||
|
||||
public static void setControl(ClassLoaderControl control) {
|
||||
LaunchServerControlHolder.control = control;
|
||||
}
|
||||
|
||||
public static ModuleLayer.Controller getController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
public static void setController(ModuleLayer.Controller controller) {
|
||||
LaunchServerControlHolder.controller = controller;
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherTrustManager;
|
||||
import pro.gravit.launcher.base.Launcher;
|
||||
import pro.gravit.launcher.core.LauncherTrustManager;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.asm.InjectClassAcceptor;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
|
@ -33,7 +33,7 @@ public class LauncherModuleLoader {
|
|||
|
||||
public LauncherModuleLoader(LaunchServer server) {
|
||||
this.server = server;
|
||||
modulesDir = server.dir.resolve("launcher-modules");
|
||||
modulesDir = server.launcherModulesDir;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
@ -44,7 +44,6 @@ public void init() {
|
|||
logger.error(e);
|
||||
}
|
||||
}
|
||||
server.commandHandler.registerCommand("syncLauncherModules", new SyncLauncherModulesCommand(this));
|
||||
MainBuildTask mainTask = server.launcherBinary.getTaskByClass(MainBuildTask.class).get();
|
||||
mainTask.preBuildHook.registerHook((buildContext) -> {
|
||||
for (ModuleEntity e : launcherModules) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue