mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-01-09 17:19:47 +03:00
Merge branch 'release/5.1.9'
This commit is contained in:
commit
1b2be8389a
43 changed files with 682 additions and 164 deletions
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master, dev ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master, dev ]
|
||||||
|
schedule:
|
||||||
|
- cron: '28 4 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'java' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||||
|
# Learn more:
|
||||||
|
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
- name: Set up JDK 11
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
17
Dockerfile
Normal file
17
Dockerfile
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
FROM archlinux/base
|
||||||
|
RUN pacman -Sy --noconfirm jdk11-openjdk unzip && pacman -Scc --noconfirm
|
||||||
|
ADD https://download2.gluonhq.com/openjfx/11.0.2/openjfx-11.0.2_linux-x64_bin-jmods.zip .
|
||||||
|
RUN unzip openjfx-11.0.2_linux-x64_bin-jmods.zip && mv javafx-jmods-11.0.2/* /usr/lib/jvm/java-11-openjdk/jmods/ && rmdir javafx-jmods-11.0.2 && rm openjfx-11.0.2_linux-x64_bin-jmods.zip
|
||||||
|
RUN mkdir ./libraries ./launcher-libraries ./launcher-libraries-compile
|
||||||
|
COPY ./LaunchServer/build/libs/LaunchServer.jar .
|
||||||
|
COPY ./LaunchServer/build/libs/libraries ./libraries
|
||||||
|
COPY ./LaunchServer/build/libs/launcher-libraries ./launcher-libraries
|
||||||
|
COPY ./LaunchServer/build/libs/launcher-libraries-compile ./launcher-libraries-compile
|
||||||
|
RUN mkdir ./compat/
|
||||||
|
COPY ./compat/authlib/authlib-clean.jar ./compat
|
||||||
|
COPY ./LauncherAuthlib/build/libs/* ./compat/
|
||||||
|
COPY ./ServerWrapper/build/libs/ServerWrapper.jar ./compat/
|
||||||
|
RUN mkdir ./compat/modules
|
||||||
|
COPY ./modules/*_module/build/libs/* ./compat/modules/
|
||||||
|
COPY ./modules/*_lmodule/build/libs/* ./compat/modules/
|
||||||
|
CMD java -javaagent:LaunchServer.jar -jar LaunchServer.jar
|
|
@ -10,6 +10,7 @@
|
||||||
import pro.gravit.launcher.modules.events.ClosePhase;
|
import pro.gravit.launcher.modules.events.ClosePhase;
|
||||||
import pro.gravit.launcher.profiles.ClientProfile;
|
import pro.gravit.launcher.profiles.ClientProfile;
|
||||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||||
|
import pro.gravit.launchserver.auth.session.MemorySessionStorage;
|
||||||
import pro.gravit.launchserver.binary.*;
|
import pro.gravit.launchserver.binary.*;
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
|
@ -80,6 +81,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
public final ReconfigurableManager reconfigurableManager;
|
public final ReconfigurableManager reconfigurableManager;
|
||||||
public final ConfigManager configManager;
|
public final ConfigManager configManager;
|
||||||
public final PingServerManager pingServerManager;
|
public final PingServerManager pingServerManager;
|
||||||
|
public final FeaturesManager featuresManager;
|
||||||
// HWID ban + anti-brutforce
|
// HWID ban + anti-brutforce
|
||||||
public final CertificateManager certificateManager;
|
public final CertificateManager certificateManager;
|
||||||
public final ProguardConf proguardConf;
|
public final ProguardConf proguardConf;
|
||||||
|
@ -128,6 +130,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
|
|
||||||
runtime.verify();
|
runtime.verify();
|
||||||
config.verify();
|
config.verify();
|
||||||
|
if(config.sessions == null) config.sessions = new MemorySessionStorage();
|
||||||
if (config.components != null) {
|
if (config.components != null) {
|
||||||
LogHelper.debug("PreInit components");
|
LogHelper.debug("PreInit components");
|
||||||
config.components.forEach((k, v) -> {
|
config.components.forEach((k, v) -> {
|
||||||
|
@ -139,15 +142,17 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
|
|
||||||
// build hooks, anti-brutforce and other
|
// build hooks, anti-brutforce and other
|
||||||
proguardConf = new ProguardConf(this);
|
proguardConf = new ProguardConf(this);
|
||||||
sessionManager = new SessionManager();
|
sessionManager = new SessionManager(this);
|
||||||
mirrorManager = new MirrorManager();
|
mirrorManager = new MirrorManager();
|
||||||
reconfigurableManager = new ReconfigurableManager();
|
reconfigurableManager = new ReconfigurableManager();
|
||||||
authHookManager = new AuthHookManager();
|
authHookManager = new AuthHookManager();
|
||||||
configManager = new ConfigManager();
|
configManager = new ConfigManager();
|
||||||
pingServerManager = new PingServerManager(this);
|
pingServerManager = new PingServerManager(this);
|
||||||
|
featuresManager = new FeaturesManager(this);
|
||||||
//Generate or set new Certificate API
|
//Generate or set new Certificate API
|
||||||
certificateManager.orgName = config.projectName;
|
certificateManager.orgName = config.projectName;
|
||||||
if (config.certificate != null && config.certificate.enabled) {
|
/*
|
||||||
|
if (false) {
|
||||||
if (IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile)) {
|
if (IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile)) {
|
||||||
certificateManager.ca = certificateManager.readCertificate(caCertFile);
|
certificateManager.ca = certificateManager.readCertificate(caCertFile);
|
||||||
certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile);
|
certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile);
|
||||||
|
@ -175,6 +180,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
config.init(ReloadType.FULL);
|
config.init(ReloadType.FULL);
|
||||||
registerObject("launchServer", this);
|
registerObject("launchServer", this);
|
||||||
GarbageManager.registerNeedGC(sessionManager);
|
GarbageManager.registerNeedGC(sessionManager);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||||
|
import pro.gravit.launchserver.auth.session.SessionStorage;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
|
@ -215,6 +216,7 @@ public static void registerAll() {
|
||||||
AuthRequest.registerProviders();
|
AuthRequest.registerProviders();
|
||||||
HWIDProvider.registerProviders();
|
HWIDProvider.registerProviders();
|
||||||
OptionalAction.registerProviders();
|
OptionalAction.registerProviders();
|
||||||
|
SessionStorage.registerProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException {
|
public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launchserver.auth;
|
||||||
|
|
||||||
|
public interface RequiredDAO {
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package pro.gravit.launchserver.auth.handler;
|
package pro.gravit.launchserver.auth.handler;
|
||||||
|
|
||||||
|
import pro.gravit.launchserver.auth.RequiredDAO;
|
||||||
import pro.gravit.launchserver.dao.User;
|
import pro.gravit.launchserver.dao.User;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class HibernateAuthHandler extends CachedAuthHandler {
|
public class HibernateAuthHandler extends CachedAuthHandler implements RequiredDAO {
|
||||||
@Override
|
@Override
|
||||||
protected Entry fetchEntry(String username) {
|
protected Entry fetchEntry(String username) {
|
||||||
User user = srv.config.dao.userDAO.findByUsername(username);
|
User user = srv.config.dao.userDAO.findByUsername(username);
|
||||||
|
|
|
@ -84,11 +84,11 @@ public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo har
|
||||||
for (MemoryHWIDEntity e : db) {
|
for (MemoryHWIDEntity e : db) {
|
||||||
HardwareInfoCompareResult result = compareHardwareInfo(e.hardware, hardwareInfo);
|
HardwareInfoCompareResult result = compareHardwareInfo(e.hardware, hardwareInfo);
|
||||||
if (warningSpoofingLevel > 0 && result.firstSpoofingLevel > warningSpoofingLevel && !isAlreadyWarning) {
|
if (warningSpoofingLevel > 0 && result.firstSpoofingLevel > warningSpoofingLevel && !isAlreadyWarning) {
|
||||||
LogHelper.warning("HardwareInfo spoofing level too high: %d", result.firstSpoofingLevel);
|
LogHelper.warning("HardwareInfo spoofing level too high: %f", result.firstSpoofingLevel);
|
||||||
isAlreadyWarning = true;
|
isAlreadyWarning = true;
|
||||||
}
|
}
|
||||||
if (result.compareLevel > criticalCompareLevel) {
|
if (result.compareLevel > criticalCompareLevel) {
|
||||||
LogHelper.debug("HardwareInfo publicKey change: compareLevel %d", result.compareLevel);
|
LogHelper.debug("HardwareInfo publicKey change: compareLevel %f", result.compareLevel);
|
||||||
if (e.banned) throw new HWIDException("You HWID banned");
|
if (e.banned) throw new HWIDException("You HWID banned");
|
||||||
e.publicKey = publicKey;
|
e.publicKey = publicKey;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
import pro.gravit.launcher.request.auth.AuthRequest;
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
||||||
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
|
||||||
import pro.gravit.launchserver.auth.AuthException;
|
import pro.gravit.launchserver.auth.AuthException;
|
||||||
|
import pro.gravit.launchserver.auth.RequiredDAO;
|
||||||
import pro.gravit.launchserver.dao.User;
|
import pro.gravit.launchserver.dao.User;
|
||||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
public class HibernateAuthProvider extends AuthProvider {
|
public class HibernateAuthProvider extends AuthProvider implements RequiredDAO {
|
||||||
public boolean autoReg;
|
public boolean autoReg;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package pro.gravit.launchserver.auth.session;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.NeedGarbageCollection;
|
||||||
|
import pro.gravit.launchserver.manangers.SessionManager;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class MemorySessionStorage extends SessionStorage implements NeedGarbageCollection {
|
||||||
|
|
||||||
|
private final Map<UUID, Entry> clientSet = new ConcurrentHashMap<>(128);
|
||||||
|
private final Map<UUID, Set<Entry>> uuidIndex = new ConcurrentHashMap<>(32);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getSessionData(UUID session) {
|
||||||
|
|
||||||
|
Entry e = clientSet.get(session);
|
||||||
|
if(e == null) return null;
|
||||||
|
return e.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<UUID> getSessionsFromUserUUID(UUID userUUID) {
|
||||||
|
Set<Entry> set = uuidIndex.get(userUUID);
|
||||||
|
if(set != null) return set.stream().map((e) -> e.sessionUuid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data) {
|
||||||
|
deleteSession(sessionUUID);
|
||||||
|
Entry e = new Entry(data, sessionUUID);
|
||||||
|
clientSet.put(sessionUUID, e);
|
||||||
|
if(userUUID != null) {
|
||||||
|
Set<Entry> uuidSet = uuidIndex.computeIfAbsent(userUUID, k -> ConcurrentHashMap.newKeySet());
|
||||||
|
uuidSet.add(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteSession(UUID sessionUUID) {
|
||||||
|
Entry e =clientSet.remove(sessionUUID);
|
||||||
|
if(e != null) {
|
||||||
|
Set<Entry> set = uuidIndex.get(sessionUUID);
|
||||||
|
if(set != null) {
|
||||||
|
removeUuidFromIndexSet(set, e, sessionUUID);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteSessionsByUserUUID(UUID userUUID) {
|
||||||
|
Set<Entry> set = uuidIndex.get(userUUID);
|
||||||
|
if(set != null) {
|
||||||
|
for(Entry e : set) {
|
||||||
|
clientSet.remove(e.sessionUuid);
|
||||||
|
}
|
||||||
|
set.clear();
|
||||||
|
uuidIndex.remove(userUUID);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
clientSet.clear();
|
||||||
|
uuidIndex.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockSession(UUID sessionUUID) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockUser(UUID userUUID) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockSession(UUID sessionUUID) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockUser(UUID userUUID) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeUuidFromIndexSet(Set<Entry> set, Entry e, UUID session) {
|
||||||
|
set.remove(e);
|
||||||
|
if(set.isEmpty()) {
|
||||||
|
uuidIndex.remove(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void garbageCollection() {
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
long session_timeout = server.config.netty.performance.sessionLifetimeMs;
|
||||||
|
Set<UUID> to_delete = new HashSet<>(32);
|
||||||
|
clientSet.forEach((uuid, entry) -> {
|
||||||
|
long timestamp = entry.timestamp;
|
||||||
|
if(timestamp + session_timeout < time)
|
||||||
|
to_delete.add(uuid);
|
||||||
|
});
|
||||||
|
for(UUID session : to_delete) {
|
||||||
|
deleteSession(session);
|
||||||
|
}
|
||||||
|
to_delete.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Entry {
|
||||||
|
public byte[] data;
|
||||||
|
public UUID sessionUuid;
|
||||||
|
public long timestamp;
|
||||||
|
|
||||||
|
public Entry(byte[] data, UUID sessionUuid) {
|
||||||
|
this.data = data;
|
||||||
|
this.sessionUuid = sessionUuid;
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package pro.gravit.launchserver.auth.session;
|
||||||
|
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public abstract class SessionStorage {
|
||||||
|
protected transient LaunchServer server;
|
||||||
|
public static ProviderMap<SessionStorage> providers = new ProviderMap<>();
|
||||||
|
private static boolean registeredProviders = false;
|
||||||
|
public abstract byte[] getSessionData(UUID session);
|
||||||
|
public abstract Stream<UUID> getSessionsFromUserUUID(UUID userUUID);
|
||||||
|
public abstract boolean writeSession(UUID userUUID, UUID sessionUUID, byte[] data);
|
||||||
|
public abstract boolean deleteSession(UUID sessionUUID);
|
||||||
|
public boolean deleteSessionsByUserUUID(UUID userUUID) {
|
||||||
|
getSessionsFromUserUUID(userUUID).forEach(this::deleteSession);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public abstract void clear();
|
||||||
|
public abstract void lockSession(UUID sessionUUID);
|
||||||
|
public abstract void lockUser(UUID userUUID);
|
||||||
|
public abstract void unlockSession(UUID sessionUUID);
|
||||||
|
public abstract void unlockUser(UUID userUUID);
|
||||||
|
public void init(LaunchServer server)
|
||||||
|
{
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
public static void registerProviders() {
|
||||||
|
if(!registeredProviders) {
|
||||||
|
providers.register("memory", MemorySessionStorage.class);
|
||||||
|
registeredProviders = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.dump;
|
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import pro.gravit.launcher.Launcher;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.utils.command.SubCommand;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class DumpSessionsCommand extends Command {
|
|
||||||
public DumpSessionsCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
childCommands.put("load", new SubCommand() {
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
LogHelper.info("Sessions read from %s", args[0]);
|
|
||||||
int size;
|
|
||||||
try (Reader reader = IOHelper.newReader(Paths.get(args[0]))) {
|
|
||||||
Type setType = new TypeToken<HashSet<Client>>() {
|
|
||||||
}.getType();
|
|
||||||
Set<Client> clientSet = Launcher.gsonManager.configGson.fromJson(reader, setType);
|
|
||||||
size = clientSet.size();
|
|
||||||
server.sessionManager.loadSessions(clientSet);
|
|
||||||
}
|
|
||||||
LogHelper.subInfo("Readed %d sessions", size);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
childCommands.put("unload", new SubCommand() {
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
LogHelper.info("Sessions write to %s", args[0]);
|
|
||||||
Collection<Client> clientSet = server.sessionManager.getSessions();
|
|
||||||
try (Writer writer = IOHelper.newWriter(Paths.get(args[0]))) {
|
|
||||||
Launcher.gsonManager.configGson.toJson(clientSet, writer);
|
|
||||||
}
|
|
||||||
LogHelper.subInfo("Write %d sessions", clientSet.size());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[load/unload] [filename]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Load or unload sessions";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
invokeSubcommands(args);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand;
|
import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand;
|
||||||
import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand;
|
import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand;
|
||||||
import pro.gravit.launchserver.command.basic.*;
|
import pro.gravit.launchserver.command.basic.*;
|
||||||
import pro.gravit.launchserver.command.dump.DumpSessionsCommand;
|
|
||||||
import pro.gravit.launchserver.command.hash.*;
|
import pro.gravit.launchserver.command.hash.*;
|
||||||
import pro.gravit.launchserver.command.install.CheckInstallCommand;
|
import pro.gravit.launchserver.command.install.CheckInstallCommand;
|
||||||
import pro.gravit.launchserver.command.install.MultiCommand;
|
import pro.gravit.launchserver.command.install.MultiCommand;
|
||||||
|
@ -61,12 +60,6 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
||||||
Category authCategory = new Category(auth, "auth", "User Management");
|
Category authCategory = new Category(auth, "auth", "User Management");
|
||||||
handler.registerCategory(authCategory);
|
handler.registerCategory(authCategory);
|
||||||
|
|
||||||
//Register dump commands
|
|
||||||
BaseCommandCategory dump = new BaseCommandCategory();
|
|
||||||
dump.registerCommand("dumpSessions", new DumpSessionsCommand(server));
|
|
||||||
Category dumpCategory = new Category(dump, "dump", "Dump runtime data");
|
|
||||||
handler.registerCategory(dumpCategory);
|
|
||||||
|
|
||||||
//Register service commands
|
//Register service commands
|
||||||
BaseCommandCategory service = new BaseCommandCategory();
|
BaseCommandCategory service = new BaseCommandCategory();
|
||||||
service.registerCommand("config", new ConfigCommand(server));
|
service.registerCommand("config", new ConfigCommand(server));
|
||||||
|
@ -78,6 +71,7 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
||||||
service.registerCommand("clients", new ClientsCommand(server));
|
service.registerCommand("clients", new ClientsCommand(server));
|
||||||
service.registerCommand("signJar", new SignJarCommand(server));
|
service.registerCommand("signJar", new SignJarCommand(server));
|
||||||
service.registerCommand("signDir", new SignDirCommand(server));
|
service.registerCommand("signDir", new SignDirCommand(server));
|
||||||
|
service.registerCommand("pingServers", new PingServersCommand(server));
|
||||||
service.registerCommand("securitycheck", new SecurityCheckCommand(server));
|
service.registerCommand("securitycheck", new SecurityCheckCommand(server));
|
||||||
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
|
||||||
handler.registerCategory(serviceCategory);
|
handler.registerCategory(serviceCategory);
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
public class ClientsCommand extends Command {
|
public class ClientsCommand extends Command {
|
||||||
public ClientsCommand(LaunchServer server) {
|
public ClientsCommand(LaunchServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
|
@ -34,8 +36,12 @@ public void invoke(String... args) {
|
||||||
LogHelper.info("Channel %s | connectUUID %s | checkSign %s", ip, frameHandler.getConnectUUID(), client.checkSign ? "true" : "false");
|
LogHelper.info("Channel %s | connectUUID %s | checkSign %s", ip, frameHandler.getConnectUUID(), client.checkSign ? "true" : "false");
|
||||||
else {
|
else {
|
||||||
LogHelper.info("Client name %s | ip %s | connectUUID %s", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID());
|
LogHelper.info("Client name %s | ip %s | connectUUID %s", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID());
|
||||||
|
LogHelper.subInfo("userUUID: %s | session %s", client.uuid == null ? "null" : client.uuid.toString(), client.session == null ? "null" : client.session);
|
||||||
LogHelper.subInfo("Data: checkSign %s | auth_id %s", client.checkSign ? "true" : "false",
|
LogHelper.subInfo("Data: checkSign %s | auth_id %s", client.checkSign ? "true" : "false",
|
||||||
client.auth_id);
|
client.auth_id);
|
||||||
|
if(client.trustLevel != null) {
|
||||||
|
LogHelper.subInfo("trustLevel | key %s | pubkey %s", client.trustLevel.keyChecked ? "checked" : "unchecked", client.trustLevel.publicKey == null ? "null" : Base64.getEncoder().encode(client.trustLevel.publicKey));
|
||||||
|
}
|
||||||
LogHelper.subInfo("Permissions: %s (permissions %d | flags %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.permissions, client.permissions == null ? 0 : client.permissions.flags);
|
LogHelper.subInfo("Permissions: %s (permissions %d | flags %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.permissions, client.permissions == null ? 0 : client.permissions.flags);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package pro.gravit.launchserver.command.service;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.request.management.PingServerReportRequest;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
public class PingServersCommand extends Command {
|
||||||
|
public PingServersCommand(LaunchServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getArgsDescription() {
|
||||||
|
return "[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsageDescription() {
|
||||||
|
return "show modern pings status";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(String... args) throws Exception {
|
||||||
|
server.pingServerManager.map.forEach((name, data) -> {
|
||||||
|
LogHelper.info("[%s] online %d / %d", name, data.lastReport == null ? -1 : data.lastReport.playersOnline, data.lastReport == null ? -1 : data.lastReport.maxPlayers);
|
||||||
|
if(data.lastReport != null && data.lastReport.users != null)
|
||||||
|
{
|
||||||
|
for(PingServerReportRequest.PingServerReport.UsernameInfo user : data.lastReport.users)
|
||||||
|
{
|
||||||
|
LogHelper.subInfo("User %s", user.username == null ? "null" : user.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,8 +158,10 @@ public void invoke(String... args) throws Exception {
|
||||||
if (tokenizer.hasMoreTokens() && tokenizer.nextToken().equals("mods")) {
|
if (tokenizer.hasMoreTokens() && tokenizer.nextToken().equals("mods")) {
|
||||||
String nextToken = tokenizer.nextToken();
|
String nextToken = tokenizer.nextToken();
|
||||||
if (!tokenizer.hasMoreTokens()) {
|
if (!tokenizer.hasMoreTokens()) {
|
||||||
|
if(!exc.endsWith("/")) {
|
||||||
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
||||||
bad = true;
|
bad = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nextToken.equals("memory_repo") || nextToken.equals(profile.getVersion().name)) {
|
if (nextToken.equals("memory_repo") || nextToken.equals(profile.getVersion().name)) {
|
||||||
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
printCheckResult(LogHelper.Level.INFO, profileModuleName, String.format("updateExclusions %s not safe. Cheats may be injected very easy!", exc), false);
|
||||||
|
|
|
@ -38,7 +38,7 @@ public void invoke(String... args) {
|
||||||
for (CommandHandler.Category category : server.commandHandler.getCategories()) {
|
for (CommandHandler.Category category : server.commandHandler.getCategories()) {
|
||||||
commands += category.category.commandsMap().size();
|
commands += category.category.commandsMap().size();
|
||||||
}
|
}
|
||||||
LogHelper.info("Sessions: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), commands, server.commandHandler.getCategories().size() + 1);
|
LogHelper.info("Commands: %d(%d categories)", commands, server.commandHandler.getCategories().size() + 1);
|
||||||
for (AuthProviderPair pair : server.config.auth.values()) {
|
for (AuthProviderPair pair : server.config.auth.values()) {
|
||||||
if (pair.handler instanceof CachedAuthHandler) {
|
if (pair.handler instanceof CachedAuthHandler) {
|
||||||
LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size());
|
LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size());
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.provider.RejectAuthProvider;
|
import pro.gravit.launchserver.auth.provider.RejectAuthProvider;
|
||||||
|
import pro.gravit.launchserver.auth.session.MemorySessionStorage;
|
||||||
|
import pro.gravit.launchserver.auth.session.SessionStorage;
|
||||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||||
import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask;
|
import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask;
|
||||||
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
import pro.gravit.launchserver.components.AuthLimiterComponent;
|
||||||
|
@ -33,6 +35,7 @@ public final class LaunchServerConfig {
|
||||||
public LauncherConfig.LauncherEnvironment env;
|
public LauncherConfig.LauncherEnvironment env;
|
||||||
public Map<String, AuthProviderPair> auth;
|
public Map<String, AuthProviderPair> auth;
|
||||||
public DaoProvider dao;
|
public DaoProvider dao;
|
||||||
|
public SessionStorage sessions;
|
||||||
|
|
||||||
// Handlers & Providers
|
// Handlers & Providers
|
||||||
public ProtectHandler protectHandler;
|
public ProtectHandler protectHandler;
|
||||||
|
@ -40,7 +43,6 @@ public final class LaunchServerConfig {
|
||||||
public ExeConf launch4j;
|
public ExeConf launch4j;
|
||||||
public NettyConfig netty;
|
public NettyConfig netty;
|
||||||
public LauncherConf launcher;
|
public LauncherConf launcher;
|
||||||
public CertificateConf certificate;
|
|
||||||
public JarSignerConf sign;
|
public JarSignerConf sign;
|
||||||
public String startScript;
|
public String startScript;
|
||||||
private transient LaunchServer server = null;
|
private transient LaunchServer server = null;
|
||||||
|
@ -71,6 +73,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
a.displayName = "Default";
|
a.displayName = "Default";
|
||||||
newConfig.auth.put("std", a);
|
newConfig.auth.put("std", a);
|
||||||
newConfig.protectHandler = new StdProtectHandler();
|
newConfig.protectHandler = new StdProtectHandler();
|
||||||
|
newConfig.sessions = new MemorySessionStorage();
|
||||||
newConfig.binaryName = "Launcher";
|
newConfig.binaryName = "Launcher";
|
||||||
|
|
||||||
newConfig.netty = new NettyConfig();
|
newConfig.netty = new NettyConfig();
|
||||||
|
@ -97,8 +100,6 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
newConfig.launcher.stripLineNumbers = true;
|
newConfig.launcher.stripLineNumbers = true;
|
||||||
newConfig.launcher.proguardGenMappings = true;
|
newConfig.launcher.proguardGenMappings = true;
|
||||||
|
|
||||||
newConfig.certificate = new LaunchServerConfig.CertificateConf();
|
|
||||||
newConfig.certificate.enabled = false;
|
|
||||||
newConfig.sign = new JarSignerConf();
|
newConfig.sign = new JarSignerConf();
|
||||||
|
|
||||||
newConfig.components = new HashMap<>();
|
newConfig.components = new HashMap<>();
|
||||||
|
@ -187,6 +188,10 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
protectHandler.init(server);
|
protectHandler.init(server);
|
||||||
protectHandler.checkLaunchServerLicense();
|
protectHandler.checkLaunchServerLicense();
|
||||||
}
|
}
|
||||||
|
if(sessions != null) {
|
||||||
|
sessions.init(server);
|
||||||
|
server.registerObject("sessions", sessions);
|
||||||
|
}
|
||||||
if (components != null) {
|
if (components != null) {
|
||||||
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
components.forEach((k, v) -> server.registerObject("component.".concat(k), v));
|
||||||
}
|
}
|
||||||
|
@ -229,6 +234,9 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
server.unregisterObject("protectHandler", protectHandler);
|
server.unregisterObject("protectHandler", protectHandler);
|
||||||
protectHandler.close();
|
protectHandler.close();
|
||||||
}
|
}
|
||||||
|
if(sessions != null) {
|
||||||
|
server.unregisterObject("sessions", sessions);
|
||||||
|
}
|
||||||
if (dao != null) {
|
if (dao != null) {
|
||||||
server.unregisterObject("dao", dao);
|
server.unregisterObject("dao", dao);
|
||||||
if (dao instanceof AutoCloseable) {
|
if (dao instanceof AutoCloseable) {
|
||||||
|
@ -260,10 +268,6 @@ public static class ExeConf {
|
||||||
public String txtProductVersion;
|
public String txtProductVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CertificateConf {
|
|
||||||
public boolean enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class JarSignerConf {
|
public static class JarSignerConf {
|
||||||
public boolean enabled = false;
|
public boolean enabled = false;
|
||||||
public String keyStore = "pathToKey";
|
public String keyStore = "pathToKey";
|
||||||
|
@ -312,6 +316,8 @@ public static class NettyPerformanceConfig {
|
||||||
public boolean usingEpoll;
|
public boolean usingEpoll;
|
||||||
public int bossThread;
|
public int bossThread;
|
||||||
public int workerThread;
|
public int workerThread;
|
||||||
|
public long sessionLifetimeMs = 24 * 60 * 60 * 1000;
|
||||||
|
public int maxWebSocketRequestBytes = 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class NettyBindAddress {
|
public static class NettyBindAddress {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.utils.Version;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class FeaturesManager {
|
||||||
|
private transient LaunchServer server;
|
||||||
|
private Map<String, String> map;
|
||||||
|
|
||||||
|
public FeaturesManager(LaunchServer server) {
|
||||||
|
this.server = server;
|
||||||
|
map = new HashMap<>();
|
||||||
|
addFeatureInfo("version", Version.getVersion().getVersionString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFeatureInfo(String name) {
|
||||||
|
return map.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String addFeatureInfo(String name, String featureInfo) {
|
||||||
|
return map.put(name, featureInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String removeFeatureInfo(String name) {
|
||||||
|
return map.remove(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||||
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
import pro.gravit.launchserver.auth.provider.AuthProvider;
|
||||||
|
import pro.gravit.launchserver.auth.session.SessionStorage;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||||
|
@ -41,6 +42,7 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers));
|
builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers));
|
||||||
builder.registerTypeAdapter(HWIDProvider.class, new UniversalJsonAdapter<>(HWIDProvider.providers));
|
builder.registerTypeAdapter(HWIDProvider.class, new UniversalJsonAdapter<>(HWIDProvider.providers));
|
||||||
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
||||||
|
builder.registerTypeAdapter(SessionStorage.class, new UniversalJsonAdapter<>(SessionStorage.providers));
|
||||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,112 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.NeedGarbageCollection;
|
import pro.gravit.launcher.NeedGarbageCollection;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.RequiredDAO;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.utils.HookSet;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class SessionManager implements NeedGarbageCollection {
|
public class SessionManager implements NeedGarbageCollection {
|
||||||
|
|
||||||
public static final long SESSION_TIMEOUT = 3 * 60 * 60 * 1000; // 3 часа
|
private final LaunchServer server;
|
||||||
private final Map<UUID, Client> clientSet = new HashMap<>(128);
|
public HookSet<Client> clientRestoreHook = new HookSet<>();
|
||||||
|
|
||||||
|
public SessionManager(LaunchServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean addClient(Client client) {
|
public boolean addClient(Client client) {
|
||||||
clientSet.put(client.session, client);
|
if(client == null || client.session == null) return false;
|
||||||
return true;
|
return server.config.sessions.writeSession(client.uuid, client.session, compressClient(client));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<UUID> findSessionsByUUID(UUID uuid) {
|
||||||
|
return server.config.sessions.getSessionsFromUserUUID(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeByUUID(UUID uuid) {
|
||||||
|
return server.config.sessions.deleteSessionsByUserUUID(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public Set<UUID> getSavedUUIDs()
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
server.config.sessions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] compressClient(Client client) {
|
||||||
|
return Launcher.gsonManager.gson.toJson(client).getBytes(StandardCharsets.UTF_8); //Compress using later
|
||||||
|
}
|
||||||
|
|
||||||
|
private Client decompressClient(byte[] client) {
|
||||||
|
return Launcher.gsonManager.gson.fromJson(new String(client, StandardCharsets.UTF_8), Client.class); //Compress using later
|
||||||
|
}
|
||||||
|
private Client restoreFromString(byte[] data) {
|
||||||
|
Client result = decompressClient(data);
|
||||||
|
result.updateAuth(server);
|
||||||
|
if(result.auth != null && (result.username != null)) {
|
||||||
|
if(result.auth.handler instanceof RequiredDAO || result.auth.provider instanceof RequiredDAO || result.auth.textureProvider instanceof RequiredDAO) {
|
||||||
|
result.daoObject = server.config.dao.userDAO.findByUsername(result.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(result.refCount == null) result.refCount = new AtomicInteger(1);
|
||||||
|
clientRestoreHook.hook(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void garbageCollection() {
|
public void garbageCollection() {
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
clientSet.entrySet().removeIf(entry -> {
|
|
||||||
Client c = entry.getValue();
|
|
||||||
return (c.timestamp + SESSION_TIMEOUT < time);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Client getClient(UUID session) {
|
public Client getClient(UUID session) {
|
||||||
return clientSet.get(session);
|
if(session == null) return null;
|
||||||
|
byte[] data = server.config.sessions.getSessionData(session);
|
||||||
|
if(data == null) return null;
|
||||||
|
return restoreFromString(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Client getOrNewClient(UUID session) {
|
public Client getOrNewClient(UUID session) {
|
||||||
return clientSet.computeIfAbsent(session, Client::new);
|
Client client = getClient(session);
|
||||||
|
return client == null ? new Client(session) : client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client removeClient(UUID session) {
|
public boolean remove(UUID session) {
|
||||||
return clientSet.remove(session);
|
return server.config.sessions.deleteSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void removeClient(UUID session) {
|
||||||
|
remove(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void updateClient(UUID session) {
|
public void updateClient(UUID session) {
|
||||||
Client c = clientSet.get(session);
|
LogHelper.warning("Using deprecated method: sessionManager.updateClient");
|
||||||
if (c != null) {
|
|
||||||
c.up();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Client newClient = new Client(session);
|
|
||||||
clientSet.put(session, newClient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Set<Client> getSessions() {
|
public Set<Client> getSessions() {
|
||||||
// TODO: removeme
|
LogHelper.warning("Using deprecated method: sessionManager.getSession");
|
||||||
return new HashSet<>(clientSet.values());
|
return new HashSet<>();
|
||||||
}
|
}
|
||||||
|
@Deprecated
|
||||||
public void loadSessions(Set<Client> set) {
|
public void loadSessions(Set<Client> set) {
|
||||||
clientSet.putAll(set.stream().collect(Collectors.toMap(c -> c.session, Function.identity())));
|
LogHelper.warning("Using deprecated method: sessionManager.loadSessions");
|
||||||
|
//clientSet.putAll(set.stream().collect(Collectors.toMap(c -> c.session, Function.identity())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
public UUID session;
|
public UUID session;
|
||||||
|
@ -22,6 +23,7 @@ public class Client {
|
||||||
public boolean checkSign;
|
public boolean checkSign;
|
||||||
public ClientPermissions permissions;
|
public ClientPermissions permissions;
|
||||||
public String username;
|
public String username;
|
||||||
|
public UUID uuid;
|
||||||
public TrustLevel trustLevel;
|
public TrustLevel trustLevel;
|
||||||
|
|
||||||
public transient AuthProviderPair auth;
|
public transient AuthProviderPair auth;
|
||||||
|
@ -30,6 +32,8 @@ public class Client {
|
||||||
|
|
||||||
public transient Map<String, Object> properties;
|
public transient Map<String, Object> properties;
|
||||||
|
|
||||||
|
public transient AtomicInteger refCount = new AtomicInteger(1);
|
||||||
|
|
||||||
public Client(UUID session) {
|
public Client(UUID session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
|
|
|
@ -56,11 +56,11 @@ public void initChannel(SocketChannel ch) {
|
||||||
NettyConnectContext context = new NettyConnectContext();
|
NettyConnectContext context = new NettyConnectContext();
|
||||||
//p.addLast(new LoggingHandler(LogLevel.INFO));
|
//p.addLast(new LoggingHandler(LogLevel.INFO));
|
||||||
pipeline.addLast("http-codec", new HttpServerCodec());
|
pipeline.addLast("http-codec", new HttpServerCodec());
|
||||||
pipeline.addLast("http-codec-compressor", new HttpObjectAggregator(65536));
|
pipeline.addLast("http-codec-compressor", new HttpObjectAggregator(server.config.netty.performance.maxWebSocketRequestBytes));
|
||||||
if (server.config.netty.ipForwarding)
|
if (server.config.netty.ipForwarding)
|
||||||
pipeline.addLast("forward-http", new NettyIpForwardHandler(context));
|
pipeline.addLast("forward-http", new NettyIpForwardHandler(context));
|
||||||
pipeline.addLast("websock-comp", new WebSocketServerCompressionHandler());
|
pipeline.addLast("websock-comp", new WebSocketServerCompressionHandler());
|
||||||
pipeline.addLast("websock-codec", new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
|
pipeline.addLast("websock-codec", new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true, server.config.netty.performance.maxWebSocketRequestBytes));
|
||||||
if (!server.config.netty.disableWebApiInterface)
|
if (!server.config.netty.disableWebApiInterface)
|
||||||
pipeline.addLast("webapi", new NettyWebAPIHandler(context));
|
pipeline.addLast("webapi", new NettyWebAPIHandler(context));
|
||||||
if (server.config.netty.fileServerEnabled)
|
if (server.config.netty.fileServerEnabled)
|
||||||
|
|
|
@ -11,12 +11,15 @@
|
||||||
import pro.gravit.launcher.events.ExceptionEvent;
|
import pro.gravit.launcher.events.ExceptionEvent;
|
||||||
import pro.gravit.launcher.events.RequestEvent;
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
import pro.gravit.launcher.events.request.ErrorRequestEvent;
|
import pro.gravit.launcher.events.request.ErrorRequestEvent;
|
||||||
|
import pro.gravit.launcher.events.request.ExitRequestEvent;
|
||||||
import pro.gravit.launcher.request.WebSocketEvent;
|
import pro.gravit.launcher.request.WebSocketEvent;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.dao.User;
|
||||||
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
|
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
|
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
|
||||||
import pro.gravit.launchserver.socket.response.auth.*;
|
import pro.gravit.launchserver.socket.response.auth.*;
|
||||||
|
import pro.gravit.launchserver.socket.response.management.FeaturesResponse;
|
||||||
import pro.gravit.launchserver.socket.response.management.PingServerReportResponse;
|
import pro.gravit.launchserver.socket.response.management.PingServerReportResponse;
|
||||||
import pro.gravit.launchserver.socket.response.management.PingServerResponse;
|
import pro.gravit.launchserver.socket.response.management.PingServerResponse;
|
||||||
import pro.gravit.launchserver.socket.response.management.ServerStatusResponse;
|
import pro.gravit.launchserver.socket.response.management.ServerStatusResponse;
|
||||||
|
@ -36,8 +39,10 @@
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class WebSocketService {
|
public class WebSocketService {
|
||||||
public static final ProviderMap<WebSocketServerResponse> providers = new ProviderMap<>();
|
public static final ProviderMap<WebSocketServerResponse> providers = new ProviderMap<>();
|
||||||
|
@ -68,12 +73,12 @@ public WebSocketService(ChannelGroup channels, LaunchServer server) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
|
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
|
||||||
channels.forEach((channel) -> {
|
for(Channel channel : channels) {
|
||||||
if (channel == null || channel.pipeline() == null) return;
|
if (channel == null || channel.pipeline() == null) continue;
|
||||||
WebSocketFrameHandler wsHandler = channel.pipeline().get(WebSocketFrameHandler.class);
|
WebSocketFrameHandler wsHandler = channel.pipeline().get(WebSocketFrameHandler.class);
|
||||||
if (wsHandler == null) return;
|
if (wsHandler == null) continue;
|
||||||
callback.accept(channel, wsHandler);
|
callback.accept(channel, wsHandler);
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerResponses() {
|
public static void registerResponses() {
|
||||||
|
@ -99,6 +104,7 @@ public static void registerResponses() {
|
||||||
providers.register("pingServerReport", PingServerReportResponse.class);
|
providers.register("pingServerReport", PingServerReportResponse.class);
|
||||||
providers.register("pingServer", PingServerResponse.class);
|
providers.register("pingServer", PingServerResponse.class);
|
||||||
providers.register("currentUser", CurrentUserResponse.class);
|
providers.register("currentUser", CurrentUserResponse.class);
|
||||||
|
providers.register("features", FeaturesResponse.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
|
public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
|
||||||
|
@ -208,6 +214,88 @@ public void sendObjectAll(Object obj, Type type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendObjectToUUID(UUID userUuid, Object obj, Type type) {
|
||||||
|
for (Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (wsHandler == null) continue;
|
||||||
|
Client client = wsHandler.getClient();
|
||||||
|
if(client == null || !userUuid.equals(client.uuid)) continue;
|
||||||
|
ch.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, type)), ch.voidPromise());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateDaoObject(UUID userUuid, User daoObject, Consumer<Channel> callback) {
|
||||||
|
for(Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (wsHandler == null) continue;
|
||||||
|
Client client = wsHandler.getClient();
|
||||||
|
if(client == null || client.daoObject == null || !userUuid.equals(client.uuid)) continue;
|
||||||
|
client.daoObject = daoObject;
|
||||||
|
if(callback != null) callback.accept(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Channel getChannelFromConnectUUID(UUID connectUuid) {
|
||||||
|
for(Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (wsHandler == null) continue;
|
||||||
|
if(connectUuid.equals(wsHandler.getConnectUUID())) {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean kickByUserUUID(UUID userUuid, boolean isClose) {
|
||||||
|
boolean result = false;
|
||||||
|
for(Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (wsHandler == null) continue;
|
||||||
|
Client client = wsHandler.getClient();
|
||||||
|
if(client == null || client.daoObject == null || !userUuid.equals(client.uuid)) continue;
|
||||||
|
ExitResponse.exit(server, wsHandler, ch, ExitRequestEvent.ExitReason.SERVER);
|
||||||
|
if(isClose) ch.close();
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean kickByConnectUUID(UUID connectUuid, boolean isClose) {
|
||||||
|
for(Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if (wsHandler == null) continue;
|
||||||
|
if(connectUuid.equals(wsHandler.getConnectUUID())) {
|
||||||
|
ExitResponse.exit(server, wsHandler, ch, ExitRequestEvent.ExitReason.SERVER);
|
||||||
|
if(isClose) ch.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean kickByIP(String ip, boolean isClose) {
|
||||||
|
boolean result = false;
|
||||||
|
for(Channel ch : channels) {
|
||||||
|
if (ch == null || ch.pipeline() == null) continue;
|
||||||
|
WebSocketFrameHandler wsHandler = ch.pipeline().get(WebSocketFrameHandler.class);
|
||||||
|
if(wsHandler == null) continue;
|
||||||
|
String clientIp;
|
||||||
|
if(wsHandler.context != null && wsHandler.context.ip != null) clientIp = wsHandler.context.ip;
|
||||||
|
else clientIp = IOHelper.getIP(ch.remoteAddress());
|
||||||
|
if(ip.equals(clientIp)) {
|
||||||
|
ExitResponse.exit(server, wsHandler, ch, ExitRequestEvent.ExitReason.SERVER);
|
||||||
|
if(isClose) ch.close();
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public void sendObjectAndClose(ChannelHandlerContext ctx, Object obj) {
|
public void sendObjectAndClose(ChannelHandlerContext ctx, Object obj) {
|
||||||
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, WebSocketEvent.class))).addListener(ChannelFutureListener.CLOSE);
|
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, WebSocketEvent.class))).addListener(ChannelFutureListener.CLOSE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ public Client getClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClient(Client client) {
|
public void setClient(Client client) {
|
||||||
|
if(this.client != null) this.client.refCount.decrementAndGet();
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
if(client != null) client.refCount.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final UUID getConnectUUID() {
|
public final UUID getConnectUUID() {
|
||||||
|
@ -85,6 +87,7 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||||
} else if ((frame instanceof PongWebSocketFrame)) {
|
} else if ((frame instanceof PongWebSocketFrame)) {
|
||||||
LogHelper.dev("WebSocket Client received pong");
|
LogHelper.dev("WebSocket Client received pong");
|
||||||
} else if ((frame instanceof CloseWebSocketFrame)) {
|
} else if ((frame instanceof CloseWebSocketFrame)) {
|
||||||
|
int statusCode = ((CloseWebSocketFrame) frame).statusCode();
|
||||||
ctx.channel().close();
|
ctx.channel().close();
|
||||||
} else {
|
} else {
|
||||||
String message = "unsupported frame type: " + frame.getClass().getName();
|
String message = "unsupported frame type: " + frame.getClass().getName();
|
||||||
|
@ -95,6 +98,18 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
if (future != null) future.cancel(true);
|
if (future != null) future.cancel(true);
|
||||||
|
if(LogHelper.isDevEnabled()) {
|
||||||
|
LogHelper.dev("Client %s disconnected", IOHelper.getIP(ctx.channel().remoteAddress()));
|
||||||
|
}
|
||||||
|
int refCount = client.refCount.decrementAndGet();
|
||||||
|
if(client.session != null) {
|
||||||
|
if(refCount == 0) {
|
||||||
|
srv.sessionManager.addClient(client);
|
||||||
|
}
|
||||||
|
else if(refCount < 0) {
|
||||||
|
LogHelper.warning("Client session %s reference counter invalid - %d", client.session, refCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
super.channelInactive(ctx);
|
super.channelInactive(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import io.netty.handler.stream.ChunkedFile;
|
import io.netty.handler.stream.ChunkedFile;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import pro.gravit.launchserver.socket.handlers.ContentType;
|
import pro.gravit.launchserver.socket.handlers.ContentType;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
import pro.gravit.utils.helper.VerifyHelper;
|
import pro.gravit.utils.helper.VerifyHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -220,12 +222,18 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
||||||
|
|
||||||
// Only compare up to the second because the datetime format we send to the client
|
// Only compare up to the second because the datetime format we send to the client
|
||||||
// does not have milliseconds
|
// does not have milliseconds
|
||||||
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.get(ChronoField.INSTANT_SECONDS);
|
try {
|
||||||
|
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getLong(ChronoField.INSTANT_SECONDS);
|
||||||
long fileLastModifiedSeconds = file.lastModified() / 1000;
|
long fileLastModifiedSeconds = file.lastModified() / 1000;
|
||||||
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
|
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
|
||||||
sendNotModified(ctx);
|
sendNotModified(ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} catch (UnsupportedTemporalTypeException e) {
|
||||||
|
if(LogHelper.isDebugEnabled()) {
|
||||||
|
LogHelper.warning("Request access If-Modifed-Since: %s not parsed correctly", ifModifiedSince);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomAccessFile raf;
|
RandomAccessFile raf;
|
||||||
|
|
|
@ -100,21 +100,21 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
|
||||||
if (getSession) {
|
if (getSession) {
|
||||||
if (clientData.session == null) {
|
if (clientData.session == null) {
|
||||||
clientData.session = UUID.randomUUID();
|
clientData.session = UUID.randomUUID();
|
||||||
server.sessionManager.addClient(clientData);
|
//server.sessionManager.addClient(clientData);
|
||||||
}
|
}
|
||||||
result.session = clientData.session;
|
result.session = clientData.session;
|
||||||
}
|
}
|
||||||
UUID uuid;
|
|
||||||
if (authType == ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) {
|
if (authType == ConnectTypes.CLIENT && server.config.protectHandler.allowGetAccessToken(context)) {
|
||||||
uuid = pair.handler.auth(aresult);
|
clientData.uuid = pair.handler.auth(aresult);
|
||||||
if (LogHelper.isDebugEnabled()) {
|
if (LogHelper.isDebugEnabled()) {
|
||||||
LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, uuid.toString());
|
LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, clientData.uuid.toString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uuid = pair.handler.usernameToUUID(aresult.username);
|
clientData.uuid = pair.handler.usernameToUUID(aresult.username);
|
||||||
result.accessToken = null;
|
result.accessToken = null;
|
||||||
}
|
}
|
||||||
result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, aresult.username, client, clientData.auth.textureProvider);
|
|
||||||
|
result.playerProfile = ProfileByUUIDResponse.getProfile(clientData.uuid, aresult.username, client, clientData.auth.textureProvider);
|
||||||
|
|
||||||
clientData.type = authType;
|
clientData.type = authType;
|
||||||
sendResult(result);
|
sendResult(result);
|
||||||
|
|
|
@ -23,7 +23,7 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
public static CurrentUserRequestEvent.UserInfo collectUserInfoFromClient(Client client) throws IOException {
|
public static CurrentUserRequestEvent.UserInfo collectUserInfoFromClient(Client client) throws IOException {
|
||||||
CurrentUserRequestEvent.UserInfo result = new CurrentUserRequestEvent.UserInfo();
|
CurrentUserRequestEvent.UserInfo result = new CurrentUserRequestEvent.UserInfo();
|
||||||
if (client.auth != null && client.isAuth && client.username != null) {
|
if (client.auth != null && client.isAuth && client.username != null) {
|
||||||
UUID uuid = client.auth.handler.usernameToUUID(client.username);
|
UUID uuid = client.uuid != null ? client.uuid : client.auth.handler.usernameToUUID(client.username);
|
||||||
if (uuid != null) {
|
if (uuid != null) {
|
||||||
result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider);
|
result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
Client newClient = new Client(null);
|
Client newClient = new Client(null);
|
||||||
newClient.checkSign = client.checkSign;
|
newClient.checkSign = client.checkSign;
|
||||||
handler.setClient(newClient);
|
handler.setClient(newClient);
|
||||||
if (client.session != null) server.sessionManager.removeClient(client.session);
|
if (client.session != null) server.sessionManager.remove(client.session);
|
||||||
if (exitAll) {
|
if (exitAll) {
|
||||||
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
|
||||||
Client client1 = webSocketFrameHandler.getClient();
|
Client client1 = webSocketFrameHandler.getClient();
|
||||||
|
@ -68,7 +68,7 @@ public static void exit(LaunchServer server, WebSocketFrameHandler wsHandler, Ch
|
||||||
Client newCusClient = new Client(null);
|
Client newCusClient = new Client(null);
|
||||||
newCusClient.checkSign = chClient.checkSign;
|
newCusClient.checkSign = chClient.checkSign;
|
||||||
wsHandler.setClient(newCusClient);
|
wsHandler.setClient(newCusClient);
|
||||||
if (chClient.session != null) server.sessionManager.removeClient(chClient.session);
|
if (chClient.session != null) server.sessionManager.remove(chClient.session);
|
||||||
ExitRequestEvent event = new ExitRequestEvent(reason);
|
ExitRequestEvent event = new ExitRequestEvent(reason);
|
||||||
event.requestUUID = RequestEvent.eventUUID;
|
event.requestUUID = RequestEvent.eventUUID;
|
||||||
wsHandler.service.sendObject(channel, event);
|
wsHandler.service.sendObject(channel, event);
|
||||||
|
|
|
@ -21,15 +21,28 @@ public String getType() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
Client rClient = server.sessionManager.getClient(session);
|
if(session == null) {
|
||||||
if (rClient == null) {
|
sendError("Session invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Client[] rClient = {null};
|
||||||
|
service.forEachActiveChannels((channel, handler) -> {
|
||||||
|
Client c = handler.getClient();
|
||||||
|
if(c != null && session.equals(c.session)) {
|
||||||
|
rClient[0] = c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(rClient[0] == null) {
|
||||||
|
rClient[0] = server.sessionManager.getClient(session);
|
||||||
|
}
|
||||||
|
if (rClient[0] == null) {
|
||||||
sendError("Session invalid");
|
sendError("Session invalid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class);
|
WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class);
|
||||||
frameHandler.setClient(rClient);
|
frameHandler.setClient(rClient[0]);
|
||||||
if (needUserInfo) {
|
if (needUserInfo) {
|
||||||
sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient)));
|
sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient[0])));
|
||||||
} else {
|
} else {
|
||||||
sendResult(new RestoreSessionRequestEvent());
|
sendResult(new RestoreSessionRequestEvent());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package pro.gravit.launchserver.socket.response.management;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import pro.gravit.launcher.events.request.FeaturesRequestEvent;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
|
||||||
|
public class FeaturesResponse extends SimpleResponse {
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "features";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
|
sendResult(new FeaturesRequestEvent(server.featuresManager.getMap()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,6 +63,6 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
|
||||||
sendError(String.format("ProfileByUUIDResponse: User with uuid %s not found or AuthProvider#uuidToUsername returned null", uuid));
|
sendError(String.format("ProfileByUUIDResponse: User with uuid %s not found or AuthProvider#uuidToUsername returned null", uuid));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendResult(new ProfileByUUIDRequestEvent(getProfile(uuid, username, this.client, client.auth.textureProvider)));
|
sendResult(new ProfileByUUIDRequestEvent(getProfile(uuid, username, this.client, pair.textureProvider)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,6 @@ public static void main(String[] args) throws Throwable {
|
||||||
verifyHDir(clientDir, params.clientHDir, clientMatcher, digest);
|
verifyHDir(clientDir, params.clientHDir, clientMatcher, digest);
|
||||||
if (javaWatcher != null)
|
if (javaWatcher != null)
|
||||||
verifyHDir(javaDir, params.javaHDir, null, digest);
|
verifyHDir(javaDir, params.javaHDir, null, digest);
|
||||||
if (params.javaHDir != null)
|
|
||||||
LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params));
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params));
|
||||||
launch(profile, params);
|
launch(profile, params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,6 @@ private void applyClientProfile() {
|
||||||
this.systemEnv.put("JAVA_HOME", javaDir.toString());
|
this.systemEnv.put("JAVA_HOME", javaDir.toString());
|
||||||
Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath());
|
Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath());
|
||||||
if (params.ram > 0) {
|
if (params.ram > 0) {
|
||||||
this.jvmArgs.add("-Xms" + params.ram + 'M');
|
|
||||||
this.jvmArgs.add("-Xmx" + params.ram + 'M');
|
this.jvmArgs.add("-Xmx" + params.ram + 'M');
|
||||||
}
|
}
|
||||||
this.params.session = Request.getSession();
|
this.params.session = Request.getSession();
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package pro.gravit.launcher.events.request;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class FeaturesRequestEvent extends RequestEvent {
|
||||||
|
public Map<String, String> features;
|
||||||
|
|
||||||
|
public FeaturesRequestEvent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeaturesRequestEvent(Map<String, String> features) {
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "features";
|
||||||
|
}
|
||||||
|
}
|
|
@ -352,8 +352,6 @@ public void verify() {
|
||||||
// Client
|
// Client
|
||||||
VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Profile title can't be empty");
|
VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Profile title can't be empty");
|
||||||
VerifyHelper.verify(getInfo(), VerifyHelper.NOT_EMPTY, "Profile info can't be empty");
|
VerifyHelper.verify(getInfo(), VerifyHelper.NOT_EMPTY, "Profile info can't be empty");
|
||||||
VerifyHelper.verify(getServerAddress(), VerifyHelper.NOT_EMPTY, "Server address can't be empty");
|
|
||||||
VerifyHelper.verifyInt(getServerPort(), VerifyHelper.range(0, 65535), "Illegal server port: " + getServerPort());
|
|
||||||
|
|
||||||
// Client launcher
|
// Client launcher
|
||||||
VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Main class can't be empty");
|
VerifyHelper.verify(getTitle(), VerifyHelper.NOT_EMPTY, "Main class can't be empty");
|
||||||
|
@ -428,7 +426,8 @@ public enum Version {
|
||||||
MC1152("1.15.2", 578),
|
MC1152("1.15.2", 578),
|
||||||
MC1161("1.16.1", 736),
|
MC1161("1.16.1", 736),
|
||||||
MC1162("1.16.2", 751),
|
MC1162("1.16.2", 751),
|
||||||
MC1163("1.16.3", 753);
|
MC1163("1.16.3", 753),
|
||||||
|
MC1164("1.16.4", 754);
|
||||||
private static final Map<String, Version> VERSIONS;
|
private static final Map<String, Version> VERSIONS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package pro.gravit.launcher.request.management;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.events.request.FeaturesRequestEvent;
|
||||||
|
import pro.gravit.launcher.request.Request;
|
||||||
|
|
||||||
|
public class FeaturesRequest extends Request<FeaturesRequestEvent> {
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "features";
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ public final class BatchProfileByUsernameRequest extends Request<BatchProfileByU
|
||||||
public BatchProfileByUsernameRequest(String... usernames) throws IOException {
|
public BatchProfileByUsernameRequest(String... usernames) throws IOException {
|
||||||
this.list = new Entry[usernames.length];
|
this.list = new Entry[usernames.length];
|
||||||
for (int i = 0; i < usernames.length; ++i) {
|
for (int i = 0; i < usernames.length; ++i) {
|
||||||
|
this.list[i] = new Entry();
|
||||||
this.list[i].client = "";
|
this.list[i].client = "";
|
||||||
this.list[i].username = usernames[i];
|
this.list[i].username = usernames[i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ public void registerResults() {
|
||||||
results.register("pingServerReport", PingServerReportRequestEvent.class);
|
results.register("pingServerReport", PingServerReportRequestEvent.class);
|
||||||
results.register("pingServer", PingServerRequestEvent.class);
|
results.register("pingServer", PingServerRequestEvent.class);
|
||||||
results.register("currentUser", CurrentUserRequestEvent.class);
|
results.register("currentUser", CurrentUserRequestEvent.class);
|
||||||
|
results.register("features", FeaturesRequestEvent.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitIfNotConnected() {
|
public void waitIfNotConnected() {
|
||||||
|
|
|
@ -6,7 +6,7 @@ public final class Version {
|
||||||
|
|
||||||
public static final int MAJOR = 5;
|
public static final int MAJOR = 5;
|
||||||
public static final int MINOR = 1;
|
public static final int MINOR = 1;
|
||||||
public static final int PATCH = 8;
|
public static final int PATCH = 9;
|
||||||
public static final int BUILD = 1;
|
public static final int BUILD = 1;
|
||||||
public static final Version.Type RELEASE = Type.STABLE;
|
public static final Version.Type RELEASE = Type.STABLE;
|
||||||
public final int major;
|
public final int major;
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.LauncherConfig;
|
import pro.gravit.launcher.LauncherConfig;
|
||||||
import pro.gravit.launcher.config.JsonConfigurable;
|
import pro.gravit.launcher.config.JsonConfigurable;
|
||||||
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
import pro.gravit.launcher.events.request.ProfilesRequestEvent;
|
import pro.gravit.launcher.events.request.ProfilesRequestEvent;
|
||||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||||
import pro.gravit.launcher.profiles.ClientProfile;
|
import pro.gravit.launcher.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||||
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.RequestException;
|
import pro.gravit.launcher.request.RequestException;
|
||||||
|
@ -46,6 +48,8 @@ public class ServerWrapper extends JsonConfigurable<ServerWrapper.Config> {
|
||||||
public ClassLoader loader;
|
public ClassLoader loader;
|
||||||
public ClientPermissions permissions;
|
public ClientPermissions permissions;
|
||||||
public ClientProfile profile;
|
public ClientProfile profile;
|
||||||
|
public PlayerProfile playerProfile;
|
||||||
|
public ClientProfile.ServerProfile serverProfile;
|
||||||
|
|
||||||
public ServerWrapper(Type type, Path configPath) {
|
public ServerWrapper(Type type, Path configPath) {
|
||||||
super(type, configPath);
|
super(type, configPath);
|
||||||
|
@ -70,20 +74,28 @@ public boolean auth() {
|
||||||
try {
|
try {
|
||||||
Launcher.getConfig();
|
Launcher.getConfig();
|
||||||
AuthRequest request = new AuthRequest(config.login, config.password, config.auth_id, AuthRequest.ConnectTypes.API);
|
AuthRequest request = new AuthRequest(config.login, config.password, config.auth_id, AuthRequest.ConnectTypes.API);
|
||||||
permissions = request.request().permissions;
|
AuthRequestEvent authResult = request.request();
|
||||||
|
permissions = authResult.permissions;
|
||||||
|
playerProfile = authResult.playerProfile;
|
||||||
ProfilesRequestEvent result = new ProfilesRequest().request();
|
ProfilesRequestEvent result = new ProfilesRequest().request();
|
||||||
for (ClientProfile p : result.profiles) {
|
for (ClientProfile p : result.profiles) {
|
||||||
LogHelper.debug("Get profile: %s", p.getTitle());
|
LogHelper.debug("Get profile: %s", p.getTitle());
|
||||||
if (p.getTitle().equals(config.title)) {
|
boolean isFound = false;
|
||||||
profile = p;
|
for(ClientProfile.ServerProfile srv : p.getServers())
|
||||||
|
{
|
||||||
|
if(srv != null && srv.name.equals(config.serverName)) {
|
||||||
|
this.serverProfile = srv;
|
||||||
|
this.profile = p;
|
||||||
Launcher.profile = p;
|
Launcher.profile = p;
|
||||||
LogHelper.debug("Found profile: %s", Launcher.profile.getTitle());
|
LogHelper.debug("Found profile: %s", Launcher.profile.getTitle());
|
||||||
|
isFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(isFound) break;
|
||||||
|
}
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
LogHelper.error("Your profile not found");
|
LogHelper.warning("Not connected to ServerProfile. May be serverName incorrect?");
|
||||||
if (config.stopOnError) System.exit(-1);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
@ -183,7 +195,7 @@ public void run(String... args) throws Throwable {
|
||||||
}
|
}
|
||||||
auth();
|
auth();
|
||||||
};
|
};
|
||||||
LogHelper.info("ServerWrapper: Project %s, LaunchServer address: %s. Title: %s", config.projectname, config.address, config.title);
|
LogHelper.info("ServerWrapper: Project %s, LaunchServer address: %s. Title: %s", config.projectname, config.address, Launcher.profile != null ? Launcher.profile.getTitle() : "unknown");
|
||||||
LogHelper.info("Minecraft Version (for profile): %s", wrapper.profile == null ? "unknown" : wrapper.profile.getVersion().name);
|
LogHelper.info("Minecraft Version (for profile): %s", wrapper.profile == null ? "unknown" : wrapper.profile.getVersion().name);
|
||||||
LogHelper.info("Start Minecraft Server");
|
LogHelper.info("Start Minecraft Server");
|
||||||
LogHelper.debug("Invoke main method %s", mainClass.getName());
|
LogHelper.debug("Invoke main method %s", mainClass.getName());
|
||||||
|
@ -228,7 +240,7 @@ public void setConfig(Config config) {
|
||||||
@Override
|
@Override
|
||||||
public Config getDefaultConfig() {
|
public Config getDefaultConfig() {
|
||||||
Config newConfig = new Config();
|
Config newConfig = new Config();
|
||||||
newConfig.title = "Your profile title";
|
newConfig.serverName = "your server name";
|
||||||
newConfig.projectname = "MineCraft";
|
newConfig.projectname = "MineCraft";
|
||||||
newConfig.login = "login";
|
newConfig.login = "login";
|
||||||
newConfig.password = "password";
|
newConfig.password = "password";
|
||||||
|
@ -244,9 +256,11 @@ public Config getDefaultConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Config {
|
public static final class Config {
|
||||||
|
@Deprecated
|
||||||
public String title;
|
public String title;
|
||||||
public String projectname;
|
public String projectname;
|
||||||
public String address;
|
public String address;
|
||||||
|
public String serverName;
|
||||||
public WebSocketConf websocket;
|
public WebSocketConf websocket;
|
||||||
public int reconnectCount;
|
public int reconnectCount;
|
||||||
public int reconnectSleep;
|
public int reconnectSleep;
|
||||||
|
|
|
@ -46,6 +46,8 @@ public void run() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogHelper.info("Found MainClass %s", mainClassName);
|
LogHelper.info("Found MainClass %s", mainClassName);
|
||||||
|
System.out.println("Print your server name:");
|
||||||
|
wrapper.config.serverName = commands.commandHandler.readLine();
|
||||||
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
System.out.println("Print launchserver websocket host( ws://host:port/api ):");
|
||||||
String address = commands.commandHandler.readLine();
|
String address = commands.commandHandler.readLine();
|
||||||
wrapper.config.mainclass = mainClassName;
|
wrapper.config.mainclass = mainClassName;
|
||||||
|
@ -56,14 +58,10 @@ public void run() throws IOException {
|
||||||
String login = commands.commandHandler.readLine();
|
String login = commands.commandHandler.readLine();
|
||||||
System.out.println("Print server account password:");
|
System.out.println("Print server account password:");
|
||||||
String password = commands.commandHandler.readLine();
|
String password = commands.commandHandler.readLine();
|
||||||
System.out.println("Print profile title:");
|
|
||||||
String title = commands.commandHandler.readLine();
|
|
||||||
wrapper.config.login = login;
|
wrapper.config.login = login;
|
||||||
wrapper.config.password = password;
|
wrapper.config.password = password;
|
||||||
wrapper.config.title = title;
|
|
||||||
wrapper.config.stopOnError = false;
|
wrapper.config.stopOnError = false;
|
||||||
wrapper.updateLauncherConfig();
|
wrapper.updateLauncherConfig();
|
||||||
|
|
||||||
if (wrapper.auth()) {
|
if (wrapper.auth()) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.8' apply false
|
id 'org.openjfx.javafxplugin' version '0.0.8' apply false
|
||||||
}
|
}
|
||||||
group = 'pro.gravit.launcher'
|
group = 'pro.gravit.launcher'
|
||||||
version = '5.1.8'
|
version = '5.1.9'
|
||||||
|
|
||||||
apply from: 'props.gradle'
|
apply from: 'props.gradle'
|
||||||
|
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 71c224e4d7a0950d3b5599ba4dec8d6fd04ededd
|
Subproject commit 5c4f6850bd4feeee0caff5561564b7e54bb94774
|
Loading…
Reference in a new issue