Merge branch 'release/5.0.5'

This commit is contained in:
Gravit 2019-07-06 20:26:28 +07:00
commit bfa466397a
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
192 changed files with 1435 additions and 1891 deletions

View file

@ -1,14 +1,14 @@
image: java:8-jdk
image: frekele/java
stages:
- build
- test
- deploy
before_script:
# - echo `pwd` # debug
# - echo "$CI_BUILD_NAME, $CI_BUILD_REF_NAME $CI_BUILD_STAGE" # debug
- export GRADLE_USER_HOME=`pwd`/.gradle
- apt-get update -qq && apt-get install -y -qq git git-core
cache:
paths:
@ -28,10 +28,5 @@ build:
- ServerWrapper/build/libs/*.jar
expire_in: 1 week
test:
stage: test
script:
- ./gradlew check
after_script:
- echo "End CI"

View file

@ -1,4 +1,5 @@
language: java
dist: trusty
# Use https (public access) instead of git for git-submodules. This modifies only Travis-CI behavior!
# disable the default submodule logic
git:

View file

@ -54,6 +54,7 @@ bundle project(':Radon')
bundle 'org.javassist:javassist:3.25.0-GA'
bundle 'io.netty:netty-all:4.1.36.Final'
bundle 'org.hibernate:hibernate-core:5.4.3.Final'
bundle 'org.bouncycastle:bcpkix-jdk15on:1.61'
bundle 'org.slf4j:slf4j-simple:1.7.25'
bundle 'org.slf4j:slf4j-api:1.7.25'

View file

@ -7,8 +7,6 @@
import java.io.Writer;
import java.lang.ProcessBuilder.Redirect;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
@ -38,8 +36,8 @@
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherConfig;
import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launcher.config.JsonConfigurable;
import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.hwid.HWIDProvider;
import pro.gravit.launcher.managers.ConfigManager;
import pro.gravit.launcher.managers.GarbageManager;
import pro.gravit.launcher.profiles.ClientProfile;
@ -65,20 +63,15 @@
import pro.gravit.launchserver.binary.ProguardConf;
import pro.gravit.launchserver.components.AuthLimiterComponent;
import pro.gravit.launchserver.components.Component;
import pro.gravit.launchserver.components.RegLimiterComponent;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.dao.UserService;
import pro.gravit.launchserver.legacy.Response;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
import pro.gravit.launchserver.manangers.MirrorManager;
import pro.gravit.launchserver.manangers.ModulesManager;
import pro.gravit.launchserver.manangers.ReconfigurableManager;
import pro.gravit.launchserver.manangers.ReloadManager;
import pro.gravit.launchserver.manangers.SessionManager;
import pro.gravit.launchserver.dao.provider.DaoProvider;
import pro.gravit.launchserver.manangers.*;
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
import pro.gravit.launchserver.manangers.hook.BuildHookManager;
import pro.gravit.launchserver.manangers.hook.SocketHookManager;
import pro.gravit.launchserver.socket.ServerSocketHandler;
import pro.gravit.launchserver.websocket.NettyServerSocketHandler;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
import pro.gravit.utils.Version;
import pro.gravit.utils.command.CommandHandler;
import pro.gravit.utils.command.JLineCommandHandler;
@ -88,7 +81,6 @@
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.helper.VerifyHelper;
public final class LaunchServer implements Runnable, AutoCloseable, Reloadable {
@Override
@ -105,11 +97,6 @@ public void reload() throws Exception {
public static final class Config {
private transient LaunchServer server = null;
public int legacyPort;
private String legacyAddress;
private String legacyBindAddress;
public String projectName;
@ -125,6 +112,8 @@ public static final class Config {
public AuthProviderPair[] auth;
public DaoProvider dao;
private transient AuthProviderPair authDefault;
public AuthProviderPair getAuthProviderPair(String name) {
@ -153,11 +142,6 @@ public AuthProviderPair getAuthProviderPair() {
public Map<String, Component> components;
// Misc options
public int threadCount;
public int threadCoreCount;
public ExeConf launch4j;
public NettyConfig netty;
public GuardLicenseConf guardLicense;
@ -175,15 +159,6 @@ public AuthProviderPair getAuthProviderPair() {
public String startScript;
public String getLegacyAddress() {
return legacyAddress;
}
public String getLegacyBindAddress() {
return legacyBindAddress;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
@ -197,18 +172,7 @@ public void setEnv(LauncherConfig.LauncherEnvironment env) {
}
public SocketAddress getSocketAddress() {
return new InetSocketAddress(legacyBindAddress, legacyPort);
}
public void setLegacyAddress(String legacyAddress) {
this.legacyAddress = legacyAddress;
}
public void verify() {
VerifyHelper.verify(getLegacyAddress(), VerifyHelper.NOT_EMPTY, "LaunchServer address can't be empty");
if (auth == null || auth[0] == null) {
throw new NullPointerException("AuthHandler must not be null");
}
@ -243,10 +207,12 @@ public void init() {
}
permissionsHandler.init(server);
hwidHandler.init();
dao.init(server);
if (protectHandler != null) {
protectHandler.checkLaunchServerLicense();
}
server.registerObject("permissionsHandler", permissionsHandler);
server.registerObject("daoProvider", dao);
for (AuthProviderPair pair : auth) {
server.registerObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
server.registerObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
@ -327,6 +293,7 @@ public class NettyConfig {
}
public class NettyPerformanceConfig {
public boolean usingEpoll;
public int bossThread;
public int workerThread;
}
@ -452,15 +419,11 @@ public static void main(String... args) throws Throwable {
public final SessionManager sessionManager;
public final SocketHookManager socketHookManager;
public final AuthHookManager authHookManager;
// Server
public final ModulesManager modulesManager;
public final UserService userService;
public final MirrorManager mirrorManager;
public final ReloadManager reloadManager;
@ -469,6 +432,8 @@ public static void main(String... args) throws Throwable {
public final ConfigManager configManager;
public final CertificateManager certificateManager;
public final BuildHookManager buildHookManager;
@ -477,8 +442,6 @@ public static void main(String... args) throws Throwable {
public final CommandHandler commandHandler;
public final ServerSocketHandler serverSocketHandler;
public final NettyServerSocketHandler nettyServerSocketHandler;
private final AtomicBoolean started = new AtomicBoolean(false);
@ -498,8 +461,22 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
launcherLibraries = dir.resolve("launcher-libraries");
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
this.args = Arrays.asList(args);
configFile = dir.resolve("LaunchServer.conf");
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf");
if(IOHelper.exists(dir.resolve("LaunchServer.conf")))
{
configFile = dir.resolve("LaunchServer.conf");
}
else
{
configFile = dir.resolve("LaunchServer.json");
}
if(IOHelper.exists(dir.resolve("RuntimeLaunchServer.conf")))
{
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf");
}
else
{
runtimeConfigFile = dir.resolve("RuntimeLaunchServer.json");
}
publicKeyFile = dir.resolve("public.key");
privateKeyFile = dir.resolve("private.key");
updatesDir = dir.resolve("updates");
@ -511,9 +488,11 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
TextureProvider.registerProviders();
HWIDHandler.registerHandlers();
PermissionsHandler.registerHandlers();
Response.registerResponses();
Component.registerComponents();
ProtectHandler.registerHandlers();
WebSocketService.registerResponses();
HWIDProvider.registerHWIDs();
DaoProvider.registerProviders();
//LaunchServer.server = this;
// Set command handler
@ -531,7 +510,6 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
localCommandHandler = new StdCommandHandler(true);
LogHelper.warning("JLine2 isn't in classpath, using std");
}
pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(localCommandHandler, this);
commandHandler = localCommandHandler;
// Set key pair
@ -592,6 +570,8 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
}
config.permissionsHandler.init(this);
config.hwidHandler.init();
if(config.dao != null)
config.dao.init(this);
if (config.protectHandler != null) {
config.protectHandler.checkLaunchServerLicense();
}
@ -611,10 +591,9 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
mirrorManager = new MirrorManager();
reloadManager = new ReloadManager();
reconfigurableManager = new ReconfigurableManager();
socketHookManager = new SocketHookManager();
authHookManager = new AuthHookManager();
configManager = new ConfigManager();
userService = new UserService(this);
certificateManager = new CertificateManager();
GarbageManager.registerNeedGC(sessionManager);
reloadManager.registerReloadable("launchServer", this);
registerObject("permissionsHandler", config.permissionsHandler);
@ -627,6 +606,8 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
Arrays.stream(config.mirrors).forEach(mirrorManager::addMirror);
pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(localCommandHandler, this);
// init modules
modulesManager.initModules();
if (config.components != null) {
@ -657,10 +638,6 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
Files.createDirectory(profilesDir);
syncProfilesDir();
// Set server socket thread
serverSocketHandler = new ServerSocketHandler(this, sessionManager);
// post init modules
modulesManager.postInitModules();
if (config.components != null) {
@ -708,7 +685,6 @@ public void buildLauncherBinaries() throws IOException {
}
public void close() {
serverSocketHandler.close();
// Close handlers & providers
config.close();
@ -734,7 +710,7 @@ private void generateConfigIfNotExists(boolean testEnv) throws IOException {
// Create new config
LogHelper.info("Creating LaunchServer config");
Config newConfig = new Config();
newConfig.mirrors = new String[]{"http://mirror.gravitlauncher.ml/", "https://mirror.gravit.pro/"};
newConfig.mirrors = new String[]{"https://mirror.gravit.pro/"};
newConfig.launch4j = new ExeConf();
newConfig.launch4j.enabled = true;
newConfig.launch4j.copyright = "© GravitLauncher Team";
@ -758,8 +734,6 @@ private void generateConfigIfNotExists(boolean testEnv) throws IOException {
newConfig.protectHandler = new StdProtectHandler();
if (testEnv) newConfig.permissionsHandler = new DefaultPermissionsHandler();
else newConfig.permissionsHandler = new JsonFilePermissionsHandler();
newConfig.legacyPort = 7240;
newConfig.legacyBindAddress = "0.0.0.0";
newConfig.binaryName = "Launcher";
newConfig.whitelistRejectString = "Вас нет в белом списке";
@ -767,15 +741,13 @@ private void generateConfigIfNotExists(boolean testEnv) throws IOException {
newConfig.netty.fileServerEnabled = true;
newConfig.netty.binds = new NettyBindAddress[]{new NettyBindAddress("0.0.0.0", 9274)};
newConfig.netty.performance = new NettyPerformanceConfig();
newConfig.netty.performance.usingEpoll = JVMHelper.OS_TYPE == JVMHelper.OS.LINUX; //Only linux
newConfig.netty.performance.bossThread = 2;
newConfig.netty.performance.workerThread = 8;
newConfig.launcher = new LauncherConf();
newConfig.launcher.guardType = "no";
newConfig.threadCoreCount = 0; // on your own
newConfig.threadCount = JVMHelper.OPERATING_SYSTEM_MXBEAN.getAvailableProcessors() >= 4 ? JVMHelper.OPERATING_SYSTEM_MXBEAN.getAvailableProcessors() / 2 : JVMHelper.OPERATING_SYSTEM_MXBEAN.getAvailableProcessors();
newConfig.enabledRadon = true;
newConfig.genMappings = true;
newConfig.enabledProGuard = true;
@ -789,6 +761,11 @@ private void generateConfigIfNotExists(boolean testEnv) throws IOException {
authLimiterComponent.rateLimitMilis = 8000;
authLimiterComponent.message = "Превышен лимит авторизаций";
newConfig.components.put("authLimiter", authLimiterComponent);
RegLimiterComponent regLimiterComponent = new RegLimiterComponent();
regLimiterComponent.rateLimit = 3;
regLimiterComponent.rateLimitMilis = 1000 * 60 * 60 * 10; //Блок на 10 часов
regLimiterComponent.message = "Превышен лимит регистраций";
newConfig.components.put("regLimiter", regLimiterComponent);
// Set server address
String address;
@ -810,7 +787,6 @@ private void generateConfigIfNotExists(boolean testEnv) throws IOException {
newConfig.projectName = "MineCraft";
}
newConfig.legacyAddress = address;
newConfig.netty.address = "ws://" + address + ":9274/api";
newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/";
newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar";
@ -841,12 +817,6 @@ public Set<Entry<String, SignedObjectHolder<HashedDir>>> getUpdateDirs() {
return updatesDirMap.entrySet();
}
public void rebindServerSocket() {
serverSocketHandler.close();
CommonHelper.newThread("Server Socket Thread", false, serverSocketHandler).start();
}
public void rebindNettyServerSocket() {
nettyServerSocketHandler.close();
CommonHelper.newThread("Netty Server Socket Thread", false, nettyServerSocketHandler).start();
@ -862,7 +832,6 @@ public void run() {
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
CommonHelper.newThread("Command Thread", true, commandHandler).start();
}
rebindServerSocket();
if (config.netty != null)
rebindNettyServerSocket();
modulesManager.finishModules();
@ -954,9 +923,6 @@ public void registerObject(String name, Object object) {
if (object instanceof NeedGarbageCollection) {
GarbageManager.registerNeedGC((NeedGarbageCollection) object);
}
if (object instanceof JsonConfigurable) {
}
}
public void unregisterObject(String name, Object object) {
@ -969,9 +935,6 @@ public void unregisterObject(String name, Object object) {
if (object instanceof NeedGarbageCollection) {
GarbageManager.unregisterNeedGC((NeedGarbageCollection) object);
}
if (object instanceof JsonConfigurable) {
}
}
public void fullyRestart() {

View file

@ -1,7 +1,9 @@
package pro.gravit.launchserver;
public interface Reconfigurable {
void reconfig(String action, String[] args);
import pro.gravit.utils.command.Command;
void printConfigHelp();
import java.util.Map;
public interface Reconfigurable {
Map<String, Command> getCommands();
}

View file

@ -59,7 +59,7 @@ public void acceptVisitor(String className, ClassVisitor visitor) throws IOExcep
public byte[] getClassData(String className) throws IOException {
for (JarFile f : cp) {
if (f.getEntry(className + ".class") != null) {
byte[] bytes = null;
byte[] bytes;
try (InputStream in = f.getInputStream(f.getEntry(className + ".class"))) {
bytes = IOHelper.read(in);
}

View file

@ -8,31 +8,31 @@
public class HibernateAuthHandler extends CachedAuthHandler {
@Override
protected Entry fetchEntry(String username) throws IOException {
User user = srv.userService.findUserByUsername(username);
User user = srv.config.dao.userService.findUserByUsername(username);
if(user == null) return null;
return new Entry(user.uuid, username, user.getAccessToken(), user.serverID);
}
@Override
protected Entry fetchEntry(UUID uuid) throws IOException {
User user = srv.userService.findUserByUUID(uuid);
User user = srv.config.dao.userService.findUserByUUID(uuid);
if(user == null) return null;
return new Entry(user.uuid, user.username, user.getAccessToken(), user.serverID);
}
@Override
protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
User user = srv.userService.findUserByUUID(uuid);
User user = srv.config.dao.userService.findUserByUUID(uuid);
user.setAccessToken(accessToken);
srv.userService.updateUser(user);
srv.config.dao.userService.updateUser(user);
return true;
}
@Override
protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
User user = srv.userService.findUserByUUID(uuid);
User user = srv.config.dao.userService.findUserByUUID(uuid);
user.serverID = serverID;
srv.userService.updateUser(user);
srv.config.dao.userService.updateUser(user);
return true;
}

View file

@ -3,7 +3,7 @@
import java.util.ArrayList;
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
public class AcceptHWIDHandler extends HWIDHandler {

View file

@ -2,7 +2,7 @@
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.utils.ProviderMap;
public abstract class HWIDHandler implements AutoCloseable {

View file

@ -12,7 +12,7 @@
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.Launcher;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;

View file

@ -9,8 +9,8 @@
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.utils.HTTPRequest;
import pro.gravit.utils.helper.LogHelper;

View file

@ -4,7 +4,7 @@
import java.util.List;
import java.util.Objects;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
public class MemoryHWIDHandler extends HWIDHandler {
public class Entry {

View file

@ -7,8 +7,8 @@
import java.util.ArrayList;
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;

View file

@ -7,17 +7,17 @@ public class HibernatePermissionsHandler extends PermissionsHandler {
@Override
public ClientPermissions getPermissions(String username) {
User user = srv.userService.findUserByUsername(username);
User user = srv.config.dao.userService.findUserByUsername(username);
if(user == null) return ClientPermissions.DEFAULT;
return user.getPermissions();
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
User user = srv.userService.findUserByUsername(username);
User user = srv.config.dao.userService.findUserByUsername(username);
if(user == null) return;
user.setPermissions(permissions);
srv.userService.updateUser(user);
srv.config.dao.userService.updateUser(user);
}
@Override

View file

@ -1,6 +1,6 @@
package pro.gravit.launchserver.auth.protect;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.helper.SecurityHelper;
public class NoProtectHandler extends ProtectHandler {

View file

@ -1,6 +1,6 @@
package pro.gravit.launchserver.auth.protect;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.ProviderMap;
public abstract class ProtectHandler {

View file

@ -1,6 +1,6 @@
package pro.gravit.launchserver.auth.protect;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.helper.SecurityHelper;
public class StdProtectHandler extends ProtectHandler {

View file

@ -4,12 +4,26 @@
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
import pro.gravit.utils.helper.SecurityHelper;
public class HibernateAuthProvider extends AuthProvider {
public boolean autoReg;
@Override
public AuthProviderResult auth(String login, String password, String ip) throws Exception {
User user = srv.userService.findUserByUsername(login);
User user = srv.config.dao.userService.findUserByUsername(login);
if(user == null && autoReg)
{
AuthHookManager.RegContext context = new AuthHookManager.RegContext(login, password, ip, false);
if(srv.authHookManager.registraion.hook(context))
{
user = srv.config.dao.userService.registerNewUser(login, password);
}
else
{
throw new AuthException("Registration canceled. Try again later");
}
}
if(user == null || !user.verifyPassword(password))
{
if(user ==null) throw new AuthException("Username incorrect");

View file

@ -1,9 +1,13 @@
package pro.gravit.launchserver.auth.provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
@ -36,31 +40,15 @@ public void close() {
}
@Override
public void reconfig(String action, String[] args) {
switch (action) {
case "message":
public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>();
commands.put("message", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
message = args[0];
LogHelper.info("New reject message: %s", message);
break;
case "whitelist.add":
if (whitelist == null) whitelist = new ArrayList<>();
whitelist.add(args[0]);
break;
case "whitelist.remove":
if (whitelist == null) whitelist = new ArrayList<>();
whitelist.remove(args[0]);
break;
case "whitelist.clear":
whitelist.clear();
break;
}
}
@Override
public void printConfigHelp() {
LogHelper.info("message [new message] - set message");
LogHelper.info("whitelist.add [username] - add username to whitelist");
LogHelper.info("whitelist.remove [username] - remove username into whitelist");
LogHelper.info("whitelist.clear - clear whitelist");
}
});
return commands;
}
}

View file

@ -33,7 +33,7 @@ public AuthProviderResult auth(String login, String password, String ip) throws
// Match username
Matcher matcher = pattern.matcher(currentResponse);
return matcher.matches() && matcher.groupCount() >= 1 ?
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(Long.getLong(matcher.group("permission"))) : srv.config.permissionsHandler.getPermissions(login)) :
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(Long.parseLong(matcher.group("permission"))) : srv.config.permissionsHandler.getPermissions(login)) :
authError(currentResponse);
}

View file

@ -68,7 +68,7 @@ public static void apply(Path inputFile, Path addFile, ZipOutputStream output, L
String filename = e.getName();
output.putNextEntry(IOHelper.newZipEntry(e));
if (filename.endsWith(".class")) {
byte[] bytes = null;
byte[] bytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048)) {
IOHelper.transfer(input, outputStream);
bytes = outputStream.toByteArray();

View file

@ -2,6 +2,8 @@
import pro.gravit.launchserver.LaunchServer;
import java.util.Map;
public abstract class Command extends pro.gravit.utils.command.Command {
@ -9,6 +11,12 @@ public abstract class Command extends pro.gravit.utils.command.Command {
protected Command(LaunchServer server) {
super();
this.server = server;
}
public Command(Map<String, pro.gravit.utils.command.Command> childCommands, LaunchServer server) {
super(childCommands);
this.server = server;
}
}

View file

@ -2,7 +2,7 @@
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;

View file

@ -2,7 +2,7 @@
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;

View file

@ -2,7 +2,7 @@
import java.util.List;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;

View file

@ -1,32 +0,0 @@
package pro.gravit.launchserver.command.basic;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;
public final class LogConnectionsCommand extends Command {
public LogConnectionsCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[true/false]";
}
@Override
public String getUsageDescription() {
return "Enable or disable logging connections";
}
@Override
public void invoke(String... args) {
boolean newValue;
if (args.length >= 1) {
newValue = Boolean.parseBoolean(args[0]);
server.serverSocketHandler.logConnections = newValue;
} else
newValue = server.serverSocketHandler.logConnections;
LogHelper.subInfo("Log connections: " + newValue);
}
}

View file

@ -1,25 +0,0 @@
package pro.gravit.launchserver.command.basic;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
public final class RebindCommand extends Command {
public RebindCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return null;
}
@Override
public String getUsageDescription() {
return "Rebind server socket";
}
@Override
public void invoke(String... args) {
server.rebindServerSocket();
}
}

View file

@ -1,11 +1,16 @@
package pro.gravit.launchserver.command.basic;
import org.bouncycastle.cert.X509CertificateHolder;
import pro.gravit.launcher.events.PingEvent;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.websocket.NettyServerSocketHandler;
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
import pro.gravit.utils.helper.CommonHelper;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
public class TestCommand extends Command {
public TestCommand(LaunchServer server) {
super(server);
@ -34,8 +39,18 @@ public void invoke(String... args) throws Exception {
if (args[0].equals("stop")) {
handler.close();
}
if (args[0].equals("eventAll")) {
handler.nettyServer.frameHandler.service.sendObjectAll(new PingEvent());
if(args[0].equals("genCA")) {
server.certificateManager.generateCA();
server.certificateManager.writePrivateKey(Paths.get("ca.key"), server.certificateManager.caKey);
server.certificateManager.writeCertificate(Paths.get("ca.crt"), server.certificateManager.ca);
}
if(args[0].equals("genCert")) {
verifyArgs(args, 2);
String name = args[1];
KeyPair pair = server.certificateManager.generateKeyPair();
X509CertificateHolder cert = server.certificateManager.generateCertificate(name, pair.getPublic());
server.certificateManager.writePrivateKey(Paths.get(name.concat(".key")), pair.getPrivate());
server.certificateManager.writeCertificate(Paths.get(name.concat(".crt")), cert);
}
}
}

View file

@ -23,7 +23,7 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
int count = 0;
for(User user : server.userService.findAllUsers())
for(User user : server.config.dao.userService.findAllUsers())
{
LogHelper.subInfo("[%s] UUID: %s", user.username, user.uuid.toString());
count++;

View file

@ -24,7 +24,7 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
User user = server.userService.findUserByUsername(args[0]);
User user = server.config.dao.userService.findUserByUsername(args[0]);
if(user == null)
{
LogHelper.error("User %s not found", args[0]);

View file

@ -29,7 +29,7 @@ public void invoke(String... args) throws Exception {
user.username = args[0];
user.setPassword(args[1]);
user.uuid = UUID.randomUUID();
server.userService.saveUser(user);
server.config.dao.userService.saveUser(user);
LogHelper.info("User %s registered. UUID: %s", user.username, user.uuid.toString());
}
}

View file

@ -24,14 +24,14 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 2);
User user = server.userService.findUserByUsername(args[0]);
User user = server.config.dao.userService.findUserByUsername(args[0]);
if(user == null)
{
LogHelper.error("User %s not found", args[1]);
return;
}
user.setPassword(args[1]);
server.userService.updateUser(user);
server.config.dao.userService.updateUser(user);
LogHelper.info("[%s] UUID: %s | New Password: %s", user.username, user.uuid.toString(), args[1]);
}
}

View file

@ -11,12 +11,59 @@
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.auth.handler.CachedAuthHandler;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class DumpEntryCacheCommand extends Command {
public DumpEntryCacheCommand(LaunchServer server) {
super(server);
childCommands.put("load", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 2);
AuthProviderPair pair = server.config.getAuthProviderPair(args[0]);
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[0]));
if (!(pair.handler instanceof CachedAuthHandler))
throw new UnsupportedOperationException("This command used only CachedAuthHandler");
CachedAuthHandler authHandler = (CachedAuthHandler) pair.handler;
LogHelper.info("CachedAuthHandler read from %s", args[0]);
int size_entry;
int size_username;
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
EntryAndUsername entryAndUsername = Launcher.gsonManager.configGson.fromJson(reader, EntryAndUsername.class);
size_entry = entryAndUsername.entryCache.size();
size_username = entryAndUsername.usernameCache.size();
authHandler.loadEntryCache(entryAndUsername.entryCache);
authHandler.loadUsernameCache(entryAndUsername.usernameCache);
}
LogHelper.subInfo("Readed %d entryCache %d usernameCache", size_entry, size_username);
}
});
childCommands.put("unload", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 2);
AuthProviderPair pair = server.config.getAuthProviderPair(args[0]);
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[0]));
if (!(pair.handler instanceof CachedAuthHandler))
throw new UnsupportedOperationException("This command used only CachedAuthHandler");
CachedAuthHandler authHandler = (CachedAuthHandler) pair.handler;
LogHelper.info("CachedAuthHandler write to %s", args[1]);
Map<UUID, CachedAuthHandler.Entry> entryCache = authHandler.getEntryCache();
Map<String, UUID> usernamesCache = authHandler.getUsernamesCache();
EntryAndUsername serializable = new EntryAndUsername();
serializable.entryCache = entryCache;
serializable.usernameCache = usernamesCache;
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
Launcher.gsonManager.configGson.toJson(serializable, writer);
}
LogHelper.subInfo("Write %d entryCache, %d usernameCache", entryCache.size(), usernamesCache.size());
}
});
}
@Override
@ -31,37 +78,7 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 3);
AuthProviderPair pair = server.config.getAuthProviderPair(args[1]);
if (pair == null) throw new IllegalStateException(String.format("Auth %s not found", args[1]));
if (!(pair.handler instanceof CachedAuthHandler))
throw new UnsupportedOperationException("This command used only CachedAuthHandler");
CachedAuthHandler authHandler = (CachedAuthHandler) pair.handler;
if (args[0].equals("unload")) {
LogHelper.info("CachedAuthHandler write to %s", args[2]);
Map<UUID, CachedAuthHandler.Entry> entryCache = authHandler.getEntryCache();
Map<String, UUID> usernamesCache = authHandler.getUsernamesCache();
EntryAndUsername serializable = new EntryAndUsername();
serializable.entryCache = entryCache;
serializable.usernameCache = usernamesCache;
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
Launcher.gsonManager.configGson.toJson(serializable, writer);
}
LogHelper.subInfo("Write %d entryCache, %d usernameCache", entryCache.size(), usernamesCache.size());
} else if (args[0].equals("load")) {
LogHelper.info("CachedAuthHandler read from %s", args[1]);
int size_entry = 0;
int size_username = 0;
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
EntryAndUsername entryAndUsername = Launcher.gsonManager.configGson.fromJson(reader, EntryAndUsername.class);
size_entry = entryAndUsername.entryCache.size();
size_username = entryAndUsername.usernameCache.size();
authHandler.loadEntryCache(entryAndUsername.entryCache);
authHandler.loadUsernameCache(entryAndUsername.usernameCache);
}
LogHelper.subInfo("Readed %d entryCache %d usernameCache", size_entry, size_username);
}
invokeSubcommands(args);
}
public class EntryAndUsername {

View file

@ -13,12 +13,41 @@
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;
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]);
Set<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
@ -33,25 +62,6 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 2);
if (args[0].equals("unload")) {
LogHelper.info("Sessions write to %s", args[1]);
Set<Client> clientSet = server.sessionManager.getSessions();
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
Launcher.gsonManager.configGson.toJson(clientSet, writer);
}
LogHelper.subInfo("Write %d sessions", clientSet.size());
} else if (args[0].equals("load")) {
LogHelper.info("Sessions read from %s", args[1]);
int size = 0;
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
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);
}
invokeSubcommands(args);
}
}

View file

@ -8,9 +8,7 @@
import pro.gravit.launchserver.command.auth.UnbanCommand;
import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand;
import pro.gravit.launchserver.command.basic.BuildCommand;
import pro.gravit.launchserver.command.basic.LogConnectionsCommand;
import pro.gravit.launchserver.command.basic.ProguardCleanCommand;
import pro.gravit.launchserver.command.basic.RebindCommand;
import pro.gravit.launchserver.command.basic.RegenProguardDictCommand;
import pro.gravit.launchserver.command.basic.RemoveMappingsProguardCommand;
import pro.gravit.launchserver.command.basic.RestartCommand;
@ -34,17 +32,7 @@
import pro.gravit.launchserver.command.install.MultiCommand;
import pro.gravit.launchserver.command.modules.LoadModuleCommand;
import pro.gravit.launchserver.command.modules.ModulesCommand;
import pro.gravit.launchserver.command.service.ComponentCommand;
import pro.gravit.launchserver.command.service.ConfigCommand;
import pro.gravit.launchserver.command.service.ConfigHelpCommand;
import pro.gravit.launchserver.command.service.ConfigListCommand;
import pro.gravit.launchserver.command.service.GetModulusCommand;
import pro.gravit.launchserver.command.service.GetPermissionsCommand;
import pro.gravit.launchserver.command.service.GivePermissionsCommand;
import pro.gravit.launchserver.command.service.ReloadAllCommand;
import pro.gravit.launchserver.command.service.ReloadCommand;
import pro.gravit.launchserver.command.service.ReloadListCommand;
import pro.gravit.launchserver.command.service.ServerStatusCommand;
import pro.gravit.launchserver.command.service.*;
import pro.gravit.utils.command.BaseCommandCategory;
import pro.gravit.utils.command.basic.ClearCommand;
import pro.gravit.utils.command.basic.DebugCommand;
@ -60,14 +48,12 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
basic.registerCommand("build", new BuildCommand(server));
basic.registerCommand("stop", new StopCommand(server));
basic.registerCommand("restart", new RestartCommand(server));
basic.registerCommand("rebind", new RebindCommand(server));
basic.registerCommand("debug", new DebugCommand());
basic.registerCommand("clear", new ClearCommand(handler));
basic.registerCommand("gc", new GCCommand());
basic.registerCommand("proguardClean", new ProguardCleanCommand(server));
basic.registerCommand("proguardDictRegen", new RegenProguardDictCommand(server));
basic.registerCommand("proguardMappingsRemove", new RemoveMappingsProguardCommand(server));
basic.registerCommand("logConnections", new LogConnectionsCommand(server));
basic.registerCommand("loadModule", new LoadModuleCommand(server));
basic.registerCommand("modules", new ModulesCommand(server));
basic.registerCommand("test", new TestCommand(server));
@ -119,8 +105,6 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
service.registerCommand("reloadAll", new ReloadAllCommand(server));
service.registerCommand("reloadList", new ReloadListCommand(server));
service.registerCommand("config", new ConfigCommand(server));
service.registerCommand("configHelp", new ConfigHelpCommand(server));
service.registerCommand("configList", new ConfigListCommand(server));
service.registerCommand("serverStatus", new ServerStatusCommand(server));
service.registerCommand("checkInstall", new CheckInstallCommand(server));
service.registerCommand("multi", new MultiCommand(server));
@ -128,6 +112,7 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
service.registerCommand("component", new ComponentCommand(server));
service.registerCommand("givePermission", new GivePermissionsCommand(server));
service.registerCommand("getPermissions", new GetPermissionsCommand(server));
service.registerCommand("clients", new ClientsCommand(server));
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
handler.registerCategory(serviceCategory);
}

View file

@ -58,7 +58,7 @@ public void invoke(String... args) throws IOException, CommandException {
client.setTitle(dirName);
client.setDir(dirName);
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
dirName, "cfg"))) {
dirName, "json"))) {
Launcher.gsonManager.configGson.toJson(client, writer);
}

View file

@ -0,0 +1,44 @@
package pro.gravit.launchserver.command.service;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class ClientsCommand extends Command {
public ClientsCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return null;
}
@Override
public String getUsageDescription() {
return "Show all connected clients";
}
@Override
public void invoke(String... args) throws Exception {
WebSocketService service = server.nettyServerSocketHandler.nettyServer.service;
service.channels.forEach((channel -> {
WebSocketFrameHandler frameHandler = channel.pipeline().get(WebSocketFrameHandler.class);
Client client = frameHandler.getClient();
String ip = IOHelper.getIP(channel.remoteAddress());
if(!client.isAuth)
LogHelper.info("Channel %s | checkSign %s", ip, client.checkSign ? "true" : "false");
else
{
LogHelper.info("Client name %s | ip %s", client.username == null ? "null" : client.username, ip);
LogHelper.subInfo("Data: checkSign %s | isSecure %s | auth_id %s", client.checkSign ? "true" : "false", client.isSecure ? "true" : "false",
client.auth_id);
LogHelper.subInfo("Permissions: %s (long %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.toLong());
}
}));
}
}

View file

@ -2,11 +2,12 @@
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.manangers.ReconfigurableManager;
import pro.gravit.utils.helper.LogHelper;
public class ConfigCommand extends Command {
public ConfigCommand(LaunchServer server) {
super(server);
super(server.reconfigurableManager.getCommands(), server);
}
@Override
@ -21,10 +22,6 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 2);
LogHelper.info("Call %s module %s action", args[0], args[1]);
String[] new_args = new String[args.length - 2];
System.arraycopy(args, 2, new_args, 0, args.length - 2);
server.reconfigurableManager.call(args[0], args[1], new_args);
invokeSubcommands(args);
}
}

View file

@ -1,28 +0,0 @@
package pro.gravit.launchserver.command.service;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;
public class ConfigHelpCommand extends Command {
public ConfigHelpCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[name]";
}
@Override
public String getUsageDescription() {
return "print help for config command";
}
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
LogHelper.info("Help %s module", args[0]);
server.reconfigurableManager.printHelp(args[0]);
}
}

View file

@ -1,25 +0,0 @@
package pro.gravit.launchserver.command.service;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
public class ConfigListCommand extends Command {
public ConfigListCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[name]";
}
@Override
public String getUsageDescription() {
return "print help for config command";
}
@Override
public void invoke(String... args) {
server.reconfigurableManager.printReconfigurables();
}
}

View file

@ -7,7 +7,7 @@
import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.utils.BiHookSet.Hook;
import pro.gravit.utils.HookException;

View file

@ -10,8 +10,8 @@ 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("hibernate", HibernateConfiguratorComponent.class);
registredComp = true;
}
}

View file

@ -0,0 +1,76 @@
package pro.gravit.launchserver.components;
import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
import pro.gravit.utils.HookException;
import pro.gravit.utils.HookSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class RegLimiterComponent extends Component implements NeedGarbageCollection, AutoCloseable {
public static final long TIMEOUT = 12 * 60 * 60 * 1000; //12 часов
public transient LaunchServer launchServer;
public int rateLimit;
public int rateLimitMilis;
public String message;
public transient HookSet.Hook<AuthHookManager.RegContext> hook;
public transient HashMap<String, AuthLimiterComponent.AuthEntry> map = new HashMap<>();
public List<String> excludeIps = new ArrayList<>();
@Override
public void preInit(LaunchServer launchServer) {
this.launchServer = launchServer;
}
@Override
public void init(LaunchServer launchServer) {
}
@Override
public void postInit(LaunchServer launchServer) {
launchServer.authHookManager.registraion.registerHook(context -> {
if (isLimit(context.ip)) {
throw new HookException(message);
}
return false;
});
}
@Override
public void garbageCollection() {
long time = System.currentTimeMillis();
long max_timeout = Math.max(rateLimitMilis, TIMEOUT);
map.entrySet().removeIf(e -> e.getValue().ts + max_timeout < time);
}
public boolean isLimit(String ip) {
if (excludeIps.contains(ip)) return false;
if (map.containsKey(ip)) {
AuthLimiterComponent.AuthEntry rate = map.get(ip);
long currenttime = System.currentTimeMillis();
if (rate.ts + rateLimitMilis < currenttime) rate.value = 0;
if (rate.value >= rateLimit && rateLimit > 0) {
rate.value++;
rate.ts = currenttime;
return true;
}
rate.value++;
rate.ts = currenttime;
return false;
}
map.put(ip, new AuthLimiterComponent.AuthEntry(1, System.currentTimeMillis()));
return false;
}
@Override
public void close() throws Exception {
if(hook != null)
launchServer.authHookManager.registraion.unregisterHook(hook);
}
}

View file

@ -6,6 +6,7 @@
public class LaunchServerRuntimeConfig {
public String clientToken;
public String oemUnlockKey;
public String registerApiKey;
public void verify() {
if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null");
@ -13,5 +14,6 @@ public void verify() {
public void reset() {
clientToken = SecurityHelper.randomStringToken();
registerApiKey = SecurityHelper.randomStringToken();
}
}

View file

@ -1,22 +0,0 @@
package pro.gravit.launchserver.dao;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.dao.impl.DefaultUserDAOImpl;
public class LaunchServerDaoFactory {
private static final Function<LaunchServer, UserDAO> defDao = DefaultUserDAOImpl::new;
private static final Map<LaunchServer, Function<LaunchServer, UserDAO>> daos = new ConcurrentHashMap<>();
public static void setUserDaoProvider(LaunchServer srv, Function<LaunchServer, UserDAO> getDao) {
daos.put(srv, getDao);
}
public static UserDAO createUserDao(LaunchServer srv)
{
return daos.getOrDefault(srv, defDao).apply(srv);
}
}

View file

@ -1,6 +1,6 @@
package pro.gravit.launchserver.dao;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.OshiHWID;
import java.util.List;
import java.util.UUID;

View file

@ -1,7 +1,7 @@
package pro.gravit.launchserver.dao;
import pro.gravit.launcher.HWID;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import javax.persistence.*;
import java.util.function.Supplier;

View file

@ -9,8 +9,8 @@ public class UserService {
private final UserDAO usersDao;
public UserService(LaunchServer server) {
usersDao = LaunchServerDaoFactory.createUserDao(server);
public UserService(UserDAO usersDAO) {
this.usersDao = usersDAO;
}
public User findUser(int id) {
@ -24,6 +24,15 @@ public User findUserByUUID(UUID uuid) {
return usersDao.findByUUID(uuid);
}
public User registerNewUser(String username, String password)
{
User user = new User();
user.username = username;
user.setPassword(password);
user.uuid = UUID.randomUUID();
return user;
}
public void saveUser(User user) {
usersDao.save(user);
}

View file

@ -4,7 +4,7 @@
import java.util.List;
import java.util.UUID;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.UserDAO;

View file

@ -9,30 +9,29 @@
import javax.persistence.criteria.Root;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.UserDAO;
import pro.gravit.launchserver.dao.UserHWID;
import pro.gravit.launchserver.hibernate.SessionFactoryManager;
public class HibernateUserDAOImpl implements UserDAO {
private final SessionFactoryManager manager;
private final SessionFactory factory;
public HibernateUserDAOImpl(LaunchServer srv) {
manager = SessionFactoryManager.forLaunchServer(srv);
public HibernateUserDAOImpl(SessionFactory factory) {
this.factory = factory;
}
public User findById(int id) {
try (Session s = manager.fact.openSession()) {
try (Session s = factory.openSession()) {
return s.get(User.class, id);
}
}
public User findByUsername(String username) {
EntityManager em = manager.fact.createEntityManager();
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> personCriteria = cb.createQuery(User.class);
@ -44,7 +43,7 @@ public User findByUsername(String username) {
}
public User findByUUID(UUID uuid) {
EntityManager em = manager.fact.createEntityManager();
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> personCriteria = cb.createQuery(User.class);
@ -57,7 +56,7 @@ public User findByUUID(UUID uuid) {
@Override
public List<UserHWID> findHWID(OshiHWID hwid) {
EntityManager em = manager.fact.createEntityManager();
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<UserHWID> personCriteria = cb.createQuery(UserHWID.class);
@ -77,7 +76,7 @@ public List<UserHWID> findHWID(OshiHWID hwid) {
}
public void save(User user) {
try (Session session = manager.fact.openSession()) {
try (Session session = factory.openSession()) {
Transaction tx1 = session.beginTransaction();
session.save(user);
tx1.commit();
@ -85,7 +84,7 @@ public void save(User user) {
}
public void update(User user) {
try (Session session = manager.fact.openSession()) {
try (Session session = factory.openSession()) {
Transaction tx1 = session.beginTransaction();
session.update(user);
tx1.commit();
@ -93,7 +92,7 @@ public void update(User user) {
}
public void delete(User user) {
try (Session session = manager.fact.openSession()) {
try (Session session = factory.openSession()) {
Transaction tx1 = session.beginTransaction();
session.delete(user);
tx1.commit();
@ -102,7 +101,7 @@ public void delete(User user) {
@SuppressWarnings("unchecked")
public List<User> findAll() {
try (Session s = manager.fact.openSession()) {
try (Session s = factory.openSession()) {
return (List<User>) s.createQuery("From User").list();
}
}

View file

@ -0,0 +1,17 @@
package pro.gravit.launchserver.dao.provider;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.dao.UserDAO;
import pro.gravit.launchserver.dao.UserService;
import pro.gravit.utils.ProviderMap;
public abstract class DaoProvider {
public static ProviderMap<DaoProvider> providers = new ProviderMap<>("DaoProvider");
public UserDAO userDAO;
public UserService userService;
public static void registerProviders()
{
providers.register("hibernate", HibernateDaoProvider.class);
}
public abstract void init(LaunchServer server);
}

View file

@ -1,18 +1,16 @@
package pro.gravit.launchserver.components;
package pro.gravit.launchserver.dao.provider;
import org.hibernate.cfg.Configuration;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.UserHWID;
import pro.gravit.launchserver.dao.UserService;
import pro.gravit.launchserver.dao.impl.HibernateUserDAOImpl;
import pro.gravit.utils.helper.CommonHelper;
import java.nio.file.Paths;
import org.hibernate.cfg.Configuration;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.dao.LaunchServerDaoFactory;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.dao.UserHWID;
import pro.gravit.launchserver.dao.impl.HibernateUserDAOImpl;
import pro.gravit.launchserver.hibernate.SessionFactoryManager;
import pro.gravit.utils.helper.CommonHelper;
public class HibernateConfiguratorComponent extends Component {
public class HibernateDaoProvider extends DaoProvider {
public String driver;
public String url;
public String username;
@ -20,9 +18,9 @@ public class HibernateConfiguratorComponent extends Component {
public String pool_size;
public String hibernateConfig;
public boolean parallelHibernateInit;
@Override
public void preInit(LaunchServer launchServer) {
LaunchServerDaoFactory.setUserDaoProvider(launchServer, HibernateUserDAOImpl::new);
public void init(LaunchServer server) {
Runnable init = () -> {
Configuration cfg = new Configuration()
.addAnnotatedClass(User.class)
@ -34,30 +32,12 @@ public void preInit(LaunchServer launchServer) {
.setProperty("hibernate.connection.pool_size", pool_size);
if(hibernateConfig != null)
cfg.configure(Paths.get(hibernateConfig).toFile());
SessionFactoryManager.forLaunchServer(launchServer).fact = cfg.buildSessionFactory();
userDAO = new HibernateUserDAOImpl(cfg.buildSessionFactory());
userService = new UserService(userDAO);
};
if(parallelHibernateInit)
CommonHelper.newThread("Hibernate Thread", true, init);
else
init.run();
}
@Override
public void init(LaunchServer launchServer) {
}
@Override
public void postInit(LaunchServer launchServer) {
//UserService service = new UserService();
//List<User> users = service.findAllUsers();
//User newUser = new User();
//newUser.username = "VeryTestUser";
//newUser.setPassword("12345");
//service.saveUser(newUser);
//for(User u : users)
//{
// LogHelper.info("Found User %s", u.username);
//}
}
}

View file

@ -1,18 +0,0 @@
package pro.gravit.launchserver.hibernate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.hibernate.SessionFactory;
import pro.gravit.launchserver.LaunchServer;
public class SessionFactoryManager {
public SessionFactory fact;
private static final Map<LaunchServer, SessionFactoryManager> sessionFactories = new ConcurrentHashMap<>();
private static final Function<LaunchServer, SessionFactoryManager> cr = e -> new SessionFactoryManager();
public static SessionFactoryManager forLaunchServer(LaunchServer srv) {
return sessionFactories.computeIfAbsent(srv, cr);
}
}

View file

@ -1,20 +0,0 @@
package pro.gravit.launchserver.legacy;
import java.io.IOException;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.SerializeLimits;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
public final class PingResponse extends Response {
public PingResponse(LaunchServer server, long id, HInput input, HOutput output, String ip, Client clientData) {
super(server, id, input, output, ip, clientData);
}
@Override
public void reply() throws IOException {
output.writeUnsignedByte(SerializeLimits.EXPECTED_BYTE);
}
}

View file

@ -1,88 +0,0 @@
package pro.gravit.launchserver.legacy;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.RequestType;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.legacy.update.LauncherResponse;
import pro.gravit.launchserver.legacy.update.LegacyLauncherResponse;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.utils.helper.LogHelper;
public abstract class Response {
@FunctionalInterface
public interface Factory<R> {
Response newResponse(LaunchServer server, long id, HInput input, HOutput output, String ip, Client clientData);
}
private static final Map<Integer, Factory<?>> RESPONSES = new ConcurrentHashMap<>(8);
public static Response getResponse(int type, LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
return RESPONSES.get(type).newResponse(server, session, input, output, ip, clientData);
}
public static void registerResponse(int type, Factory<?> factory) {
RESPONSES.put(type, factory);
}
public static void registerResponses() {
registerResponse(RequestType.PING.getNumber(), PingResponse::new);
registerResponse(RequestType.LEGACYLAUNCHER.getNumber(), LegacyLauncherResponse::new);
registerResponse(RequestType.LAUNCHER.getNumber(), LauncherResponse::new);
}
public static void requestError(String message) throws RequestException {
throw new RequestException(message);
}
protected final LaunchServer server;
protected final HInput input;
protected final HOutput output;
protected final String ip;
protected final Client clientData;
protected final long session;
protected Response(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
this.server = server;
this.input = input;
this.output = output;
this.ip = ip;
this.session = session;
this.clientData = clientData;
}
protected final void debug(String message) {
LogHelper.subDebug("#%d %s", session, message);
}
protected final void debug(String message, Object... args) {
debug(String.format(message, args));
}
public abstract void reply() throws Exception;
protected static void writeNoError(HOutput output) throws IOException {
output.writeString("", 0);
}
}

View file

@ -1,40 +0,0 @@
package pro.gravit.launchserver.legacy.update;
import java.io.IOException;
import java.util.Arrays;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.SerializeLimits;
import pro.gravit.launcher.serialize.signed.DigestBytesHolder;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.legacy.Response;
import pro.gravit.launchserver.socket.Client;
public final class LauncherResponse extends Response {
public LauncherResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws IOException {
// Resolve launcher binary
DigestBytesHolder bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary).getBytes();
if (bytes == null) {
requestError("Missing launcher binary");
return;
}
byte[] digest = input.readByteArray(SerializeLimits.MAX_DIGEST);
if (!Arrays.equals(bytes.getDigest(), digest)) {
writeNoError(output);
output.writeBoolean(true);
output.writeByteArray(bytes.getBytes(), 0);
clientData.checkSign = false;
return;
}
writeNoError(output);
output.writeBoolean(false);
clientData.checkSign = true;
}
}

View file

@ -1,38 +0,0 @@
package pro.gravit.launchserver.legacy.update;
import java.io.IOException;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.LauncherBinary;
import pro.gravit.launchserver.legacy.Response;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.utils.helper.SecurityHelper;
public final class LegacyLauncherResponse extends Response {
public LegacyLauncherResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws IOException {
// Resolve launcher binary
LauncherBinary bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary);
if (bytes == null) {
requestError("Missing launcher binary");
return;
}
writeNoError(output);
// Update launcher binary
output.writeByteArray(bytes.getSign(), -SecurityHelper.RSA_KEY_LENGTH);
output.flush();
if (input.readBoolean()) {
output.writeByteArray(bytes.getBytes().getBytes(), 0);
return; // Launcher will be restarted
}
requestError("You must update");
}
}

View file

@ -0,0 +1,117 @@
package pro.gravit.launchserver.manangers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcECContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.spec.ECGenParameterSpec;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
public class CertificateManager {
public X509CertificateHolder ca;
public AsymmetricKeyParameter caKey;
//public X509CertificateHolder server;
//public AsymmetricKeyParameter serverKey;
public int validDays = 60;
public int minusHours = 6;
public X509CertificateHolder generateCertificate(String subjectName, PublicKey subjectPublicKey) throws OperatorCreationException {
SubjectPublicKeyInfo subjectPubKeyInfo = SubjectPublicKeyInfo.getInstance(subjectPublicKey.getEncoded());
BigInteger serial = BigInteger.valueOf(SecurityHelper.newRandom().nextLong());
Date startDate = Date.from(Instant.now().minus(minusHours, ChronoUnit.HOURS));
Date endDate = Date.from(startDate.toInstant().plus(validDays, ChronoUnit.DAYS));
X500NameBuilder subject = new X500NameBuilder();
subject.addRDN(BCStyle.CN, subjectName);
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(ca.getSubject(), serial,
startDate, endDate, subject.build(), subjectPubKeyInfo);
AlgorithmIdentifier sigAlgId = ca.getSignatureAlgorithm();
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
ContentSigner sigGen = new BcECContentSignerBuilder(sigAlgId, digAlgId).build(caKey);
return v3CertGen.build(sigGen);
}
public void generateCA() throws NoSuchAlgorithmException, IOException, OperatorCreationException, InvalidAlgorithmParameterException {
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384r1");
KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
generator.initialize(ecGenSpec, SecurityHelper.newRandom());
KeyPair pair = generator.generateKeyPair();
LocalDateTime startDate = LocalDate.now().atStartOfDay();
X509v3CertificateBuilder builder= new X509v3CertificateBuilder(
new X500Name("CN=ca"),
new BigInteger("0"),
Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()),
Date.from(startDate.plusDays(3650).atZone(ZoneId.systemDefault()).toInstant()),
new X500Name("CN=ca"),
SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded()));
JcaContentSignerBuilder csBuilder= new JcaContentSignerBuilder("SHA256WITHECDSA");
ContentSigner signer = csBuilder.build(pair.getPrivate());
ca = builder.build(signer);
caKey = PrivateKeyFactory.createKey(pair.getPrivate().getEncoded());
}
public KeyPair generateKeyPair() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384r1");
KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
generator.initialize(ecGenSpec, SecurityHelper.newRandom());
return generator.generateKeyPair();
}
public void writePrivateKey(Path file, PrivateKey privateKey) throws IOException {
try (PemWriter writer = new PemWriter(IOHelper.newWriter(file))) {
writer.writeObject(new PemObject("PRIVATE KEY", privateKey.getEncoded()));
}
}
public void writePrivateKey(Path file, AsymmetricKeyParameter key) throws IOException {
PrivateKeyInfo info = PrivateKeyInfoFactory.createPrivateKeyInfo(key);
try (PemWriter writer = new PemWriter(IOHelper.newWriter(file))) {
writer.writeObject(new PemObject("PRIVATE KEY", info.getEncoded()));
}
}
public void writeCertificate(Path file, X509CertificateHolder holder) throws IOException {
try (PemWriter writer = new PemWriter(IOHelper.newWriter(file))) {
writer.writeObject(new PemObject("CERTIFICATE", holder.toASN1Structure().getEncoded()));
}
}
}

View file

@ -2,7 +2,14 @@
import com.google.gson.GsonBuilder;
import pro.gravit.launcher.hasher.HashedEntry;
import pro.gravit.launcher.hasher.HashedEntryAdapter;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.HWIDProvider;
import pro.gravit.launcher.managers.GsonManager;
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
import pro.gravit.launcher.request.WebSocketEvent;
import pro.gravit.launcher.request.websockets.ClientWebSocketService;
import pro.gravit.launchserver.auth.handler.AuthHandler;
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
@ -10,6 +17,9 @@
import pro.gravit.launchserver.auth.provider.AuthProvider;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import pro.gravit.launchserver.components.Component;
import pro.gravit.launchserver.dao.provider.DaoProvider;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
import pro.gravit.utils.UniversalJsonAdapter;
public class LaunchServerGsonManager extends GsonManager {
@ -23,5 +33,10 @@ public void registerAdapters(GsonBuilder builder) {
builder.registerTypeAdapter(HWIDHandler.class, new UniversalJsonAdapter<>(HWIDHandler.providers));
builder.registerTypeAdapter(Component.class, new UniversalJsonAdapter<>(Component.providers));
builder.registerTypeAdapter(ProtectHandler.class, new UniversalJsonAdapter<>(ProtectHandler.providers));
builder.registerTypeAdapter(DaoProvider.class, new UniversalJsonAdapter<>(DaoProvider.providers));
builder.registerTypeAdapter(HWID.class, new UniversalJsonAdapter<>(HWIDProvider.hwids));
builder.registerTypeAdapter(WebSocketServerResponse.class, new UniversalJsonAdapter<>(WebSocketService.providers));
builder.registerTypeAdapter(WebSocketEvent.class, new JsonResultSerializeAdapter());
//ClientWebSocketService.appendTypeAdapters(builder);
}
}

View file

@ -1,35 +1,65 @@
package pro.gravit.launchserver.manangers;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.command.basic.HelpCommand;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.VerifyHelper;
public class ReconfigurableManager {
private final HashMap<String, Reconfigurable> RECONFIGURABLE = new HashMap<>();
private class ReconfigurableVirtualCommand extends Command {
public ReconfigurableVirtualCommand(Map<String, Command> childs) {
super(childs);
}
@Override
public String getArgsDescription() {
return null;
}
@Override
public String getUsageDescription() {
return null;
}
@Override
public void invoke(String... args) throws Exception {
invokeSubcommands(args);
}
}
private final HashMap<String, Command> RECONFIGURABLE = new HashMap<>();
public void registerReconfigurable(String name, Reconfigurable reconfigurable) {
VerifyHelper.putIfAbsent(RECONFIGURABLE, name.toLowerCase(), Objects.requireNonNull(reconfigurable, "adapter"),
VerifyHelper.putIfAbsent(RECONFIGURABLE, name.toLowerCase(), new ReconfigurableVirtualCommand(reconfigurable.getCommands()),
String.format("Reloadable has been already registered: '%s'", name));
}
public Reconfigurable unregisterReconfigurable(String name) {
return RECONFIGURABLE.remove(name);
public void unregisterReconfigurable(String name) {
RECONFIGURABLE.remove(name);
}
public void printHelp(String name) {
RECONFIGURABLE.get(name.toLowerCase()).printConfigHelp();
public void call(String name, String action, String[] args) throws Exception
{
Command commands = RECONFIGURABLE.get(name);
if(commands == null) throw new CommandException(String.format("Reconfigurable %s not found", name));
Command command = commands.childCommands.get(action);
if(command == null) throw new CommandException(String.format("Action %s.%s not found", name, action));
command.invoke(args);
}
public void call(String name, String action, String[] args) {
RECONFIGURABLE.get(name.toLowerCase()).reconfig(action.toLowerCase(), args);
public void printHelp(String name) throws CommandException
{
Command commands = RECONFIGURABLE.get(name);
if(commands == null) throw new CommandException(String.format("Reconfigurable %s not found", name));
HelpCommand.printSubCommandsHelp(name, commands);
}
public void printReconfigurables() {
LogHelper.info("Print reconfigurables");
RECONFIGURABLE.forEach((k, v) -> LogHelper.subInfo(k));
LogHelper.info("Found %d reconfigurables", RECONFIGURABLE.size());
public Map<String, Command> getCommands()
{
return RECONFIGURABLE;
}
}

View file

@ -1,11 +1,12 @@
package pro.gravit.launchserver.manangers.hook;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.websocket.json.auth.CheckServerResponse;
import pro.gravit.launchserver.websocket.json.auth.JoinServerResponse;
import pro.gravit.launchserver.websocket.json.auth.SetProfileResponse;
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
import pro.gravit.launchserver.socket.response.auth.CheckServerResponse;
import pro.gravit.launchserver.socket.response.auth.JoinServerResponse;
import pro.gravit.launchserver.socket.response.auth.SetProfileResponse;
import pro.gravit.utils.BiHookSet;
import pro.gravit.utils.HookSet;
public class AuthHookManager {
public BiHookSet<AuthResponse.AuthContext, Client> preHook = new BiHookSet<>();
@ -13,4 +14,18 @@ public class AuthHookManager {
public BiHookSet<CheckServerResponse, Client> checkServerHook = new BiHookSet<>();
public BiHookSet<JoinServerResponse, Client> joinServerHook = new BiHookSet<>();
public BiHookSet<SetProfileResponse, Client> setProfileHook = new BiHookSet<>();
public static class RegContext
{
public String login;
public String password;
public String ip;
public boolean trustContext;
public RegContext(String login, String password, String ip, boolean trustContext) {
this.login = login;
this.password = password;
this.ip = ip;
this.trustContext = trustContext;
}
}
public HookSet<RegContext> registraion = new HookSet<>();
}

View file

@ -1,86 +0,0 @@
package pro.gravit.launchserver.manangers.hook;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launchserver.socket.SocketContext;
public class SocketHookManager {
@FunctionalInterface
public interface SocketPreHook {
boolean preHook(SocketContext context); //Вернуть true если необходимо продолжть обработку, false если остановить обработку
}
@FunctionalInterface
public interface SocketPostHook {
void postHook(SocketContext context);
}
@FunctionalInterface
public interface SocketErrorHook {
boolean errorHook(SocketContext context, RequestException e); //Вернуть true если необходимо продолжть обработку, false если остановить обработку
}
@FunctionalInterface
public interface SocketFatalErrorHook {
boolean fatalErrorHook(Socket socket, Exception e); //Вернуть true если необходимо продолжть обработку, false если остановить обработку
}
private Set<SocketPostHook> POST_HOOKS;
private Set<SocketPreHook> PRE_HOOKS;
private Set<SocketErrorHook> ERROR_HOOKS;
private Set<SocketFatalErrorHook> FATALERROR_HOOKS;
public void registerPostHook(SocketPostHook hook) {
if (POST_HOOKS == null) POST_HOOKS = new HashSet<>();
POST_HOOKS.add(hook);
}
public void registerPreHook(SocketPreHook hook) {
if (PRE_HOOKS == null) PRE_HOOKS = new HashSet<>();
PRE_HOOKS.add(hook);
}
public void registerErrorHook(SocketErrorHook hook) {
if (ERROR_HOOKS == null) ERROR_HOOKS = new HashSet<>();
ERROR_HOOKS.add(hook);
}
public void registerFatalErrorHook(SocketFatalErrorHook hook) {
if (FATALERROR_HOOKS == null) FATALERROR_HOOKS = new HashSet<>();
FATALERROR_HOOKS.add(hook);
}
public boolean preHook(SocketContext context) {
if (PRE_HOOKS == null) return true;
for (SocketPreHook preHook : PRE_HOOKS) {
if (!preHook.preHook(context)) return false;
}
return true;
}
public void postHook(SocketContext context) {
if (POST_HOOKS == null) return;
for (SocketPostHook postHook : POST_HOOKS) {
postHook.postHook(context);
}
}
public boolean errorHook(SocketContext context, RequestException e) {
if (ERROR_HOOKS == null) return true;
for (SocketErrorHook errorHook : ERROR_HOOKS) {
if (!errorHook.errorHook(context, e)) return false;
}
return true;
}
public boolean fatalErrorHook(Socket socket, Exception e) {
if (FATALERROR_HOOKS == null) return true;
for (SocketFatalErrorHook errorHook : FATALERROR_HOOKS) {
if (!errorHook.fatalErrorHook(socket, e)) return false;
}
return true;
}
}

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket;
import java.net.InetSocketAddress;
@ -7,39 +7,52 @@
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.GlobalEventExecutor;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.websocket.fileserver.FileServerHandler;
import pro.gravit.launchserver.socket.handlers.NettyIpForwardHandler;
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
import pro.gravit.launchserver.socket.handlers.fileserver.FileServerHandler;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
public class LauncherNettyServer implements AutoCloseable {
public final ServerBootstrap serverBootstrap;
public final EventLoopGroup bossGroup;
public final EventLoopGroup workerGroup;
public WebSocketFrameHandler frameHandler = null;
public final WebSocketService service;
private static final String WEBSOCKET_PATH = "/api";
public LauncherNettyServer(LaunchServer server) {
LaunchServer.NettyConfig config = server.config.netty;
bossGroup = new NioEventLoopGroup(config.performance.bossThread);
workerGroup = new NioEventLoopGroup(config.performance.workerThread);
NettyObjectFactory.setUsingEpoll(config.performance.usingEpoll);
if(config.performance.usingEpoll)
{
LogHelper.debug("Netty: Epoll enabled");
}
if(config.performance.usingEpoll && JVMHelper.OS_TYPE != JVMHelper.OS.LINUX)
{
LogHelper.error("netty,perfomance.usingEpoll work only Linux systems");
}
bossGroup = NettyObjectFactory.newEventLoopGroup(config.performance.bossThread);
workerGroup = NettyObjectFactory.newEventLoopGroup(config.performance.workerThread);
serverBootstrap = new ServerBootstrap();
service = new WebSocketService(new DefaultChannelGroup(GlobalEventExecutor.INSTANCE), server);
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.channel(NettyObjectFactory.getServerSocketChannelClass())
.handler(new LoggingHandler(config.logLevel))
.childHandler(new ChannelInitializer<NioSocketChannel>() {
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(NioSocketChannel ch) {
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
NettyConnectContext context = new NettyConnectContext();
//p.addLast(new LoggingHandler(LogLevel.INFO));
@ -51,8 +64,7 @@ public void initChannel(NioSocketChannel ch) {
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
if (server.config.netty.fileServerEnabled)
pipeline.addLast(new FileServerHandler(server.updatesDir, true));
frameHandler = new WebSocketFrameHandler(context, server);
pipeline.addLast(frameHandler);
pipeline.addLast(new WebSocketFrameHandler(context, server, service));
}
});
if (config.proxy != null && config.proxy.enabled) {

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket;
public class NettyConnectContext {
public String ip = null;

View file

@ -0,0 +1,31 @@
package pro.gravit.launchserver.socket;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyObjectFactory {
private static boolean epoll = false;
public static void setUsingEpoll(boolean value)
{
epoll = value;
}
public static EventLoopGroup newEventLoopGroup(int threads)
{
if(epoll)
return new EpollEventLoopGroup(threads);
else
return new NioEventLoopGroup(threads);
}
public static Class<? extends ServerChannel> getServerSocketChannelClass()
{
if(epoll)
return EpollServerSocketChannel.class;
else
return NioServerSocketChannel.class;
}
}

View file

@ -1,144 +0,0 @@
package pro.gravit.launchserver.socket;
import java.io.IOException;
import java.math.BigInteger;
import java.net.Socket;
import java.net.SocketException;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.legacy.Response;
import pro.gravit.launchserver.manangers.SessionManager;
import pro.gravit.launchserver.manangers.hook.SocketHookManager;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
public final class ResponseThread implements Runnable {
class Handshake {
int type;
long session;
public Handshake(int type, long session) {
this.type = type;
this.session = session;
}
}
private final LaunchServer server;
private final Socket socket;
private final SessionManager sessions;
private final SocketHookManager socketHookManager;
public ResponseThread(LaunchServer server, long id, Socket socket, SessionManager sessionManager, SocketHookManager socketHookManager) throws SocketException {
this.server = server;
this.socket = socket;
sessions = sessionManager;
this.socketHookManager = socketHookManager;
// Fix socket flags
IOHelper.setSocketFlags(socket);
}
private Handshake readHandshake(HInput input, HOutput output) throws IOException {
boolean legacy = false;
long session = 0;
// Verify magic number
int magicNumber = input.readInt();
if (magicNumber != Launcher.PROTOCOL_MAGIC)
if (magicNumber == Launcher.PROTOCOL_MAGIC_LEGACY - 1) { // Previous launcher protocol
session = 0;
legacy = true;
} else if (magicNumber == ServerSocketHandler.LEGACY_LAUNCHER_MAGIC) { // Previous launcher protocol
session = 0;
legacy = true;
} else if (magicNumber == Launcher.PROTOCOL_MAGIC_LEGACY) {
} else
throw new IOException("Invalid Handshake");
// Verify key modulus
BigInteger keyModulus = input.readBigInteger(SecurityHelper.RSA_KEY_LENGTH + 1);
if (!legacy) {
session = input.readLong();
sessions.updateClient(session);
}
if (!keyModulus.equals(server.privateKey.getModulus())) {
output.writeBoolean(false);
throw new IOException(String.format("#%d Key modulus mismatch", session));
}
// Read request type
int type = input.readVarInt();
if (!server.serverSocketHandler.onHandshake(session, type)) {
output.writeBoolean(false);
return null;
}
// Protocol successfully verified
output.writeBoolean(true);
output.flush();
return new Handshake(type, session);
}
private void respond(Integer type, HInput input, HOutput output, long session, String ip, Client clientData) throws Exception {
if (server.serverSocketHandler.logConnections)
LogHelper.info("Connection #%d from %s", session, ip);
// Choose response based on type
Response response = Response.getResponse(type, server, session, input, output, ip, clientData);
// Reply
response.reply();
LogHelper.subDebug("#%d Replied", session);
}
@Override
public void run() {
if (!server.serverSocketHandler.logConnections)
LogHelper.debug("Connection from %s", IOHelper.getIP(socket.getRemoteSocketAddress()));
// Process connection
boolean cancelled = false;
Exception savedError = null;
try (HInput input = new HInput(socket.getInputStream());
HOutput output = new HOutput(socket.getOutputStream())) {
Handshake handshake = readHandshake(input, output);
if (handshake == null) { // Not accepted
cancelled = true;
return;
}
SocketContext context = new SocketContext();
context.input = input;
context.output = output;
context.ip = IOHelper.getIP(socket.getRemoteSocketAddress());
context.session = handshake.session;
context.type = handshake.type;
Client clientData = server.sessionManager.getOrNewClient(context.session);
context.client = clientData;
// Start response
if (socketHookManager.preHook(context)) {
try {
respond(handshake.type, input, output, handshake.session, context.ip, clientData);
socketHookManager.postHook(context);
} catch (RequestException e) {
if (server.socketHookManager.errorHook(context, e)) {
LogHelper.subDebug(String.format("#%d Request error: %s", handshake.session, e.getMessage()));
if (e.getMessage() == null) LogHelper.error(e);
output.writeString(e.getMessage(), 0);
}
}
}
} catch (Exception e) {
savedError = e;
if (server.socketHookManager.fatalErrorHook(socket, e))
LogHelper.error(e);
} finally {
IOHelper.close(socket);
if (!cancelled)
server.serverSocketHandler.onDisconnect(savedError);
}
}
}

View file

@ -1,125 +0,0 @@
package pro.gravit.launchserver.socket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.managers.GarbageManager;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.manangers.SessionManager;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;
public final class ServerSocketHandler implements Runnable, AutoCloseable {
public interface Listener {
boolean onConnect(InetAddress address);
void onDisconnect(Exception e);
boolean onHandshake(long session, int type);
}
private static final ThreadFactory THREAD_FACTORY = r -> CommonHelper.newThread("Network Thread", true, r);
public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
// Instance
private final LaunchServer server;
private final AtomicReference<ServerSocket> serverSocket = new AtomicReference<>();
private final ExecutorService threadPool;
public final SessionManager sessionManager;
private final AtomicLong idCounter = new AtomicLong(0L);
public static int LEGACY_LAUNCHER_MAGIC = Launcher.PROTOCOL_MAGIC_LEGACY - 2;
private volatile Listener listener;
public ServerSocketHandler(LaunchServer server) {
this(server, new SessionManager());
GarbageManager.registerNeedGC(sessionManager);
}
public ServerSocketHandler(LaunchServer server, SessionManager sessionManager) {
this.server = server;
threadPool = new ThreadPoolExecutor(server.config.threadCoreCount, Integer.MAX_VALUE,
server.config.threadCount, TimeUnit.SECONDS,
new SynchronousQueue<>(),
THREAD_FACTORY);
this.sessionManager = sessionManager;
}
@Override
public void close() {
ServerSocket socket = serverSocket.getAndSet(null);
if (socket != null) {
LogHelper.info("Closing server socket listener");
try {
socket.close();
} catch (IOException e) {
LogHelper.error(e);
}
}
}
/*package*/ void onDisconnect(Exception e) {
if (listener != null)
listener.onDisconnect(e);
}
/*package*/ boolean onHandshake(long session, int type) {
return listener == null || listener.onHandshake(session, type);
}
@Override
public void run() {
LogHelper.info("Starting server socket thread");
try (ServerSocket serverSocket = new ServerSocket()) {
if (!this.serverSocket.compareAndSet(null, serverSocket))
throw new IllegalStateException("Previous socket wasn't closed");
// Set socket params
serverSocket.setReuseAddress(true);
serverSocket.setPerformancePreferences(1, 0, 2);
//serverSocket.setReceiveBufferSize(0x10000);
serverSocket.bind(server.config.getSocketAddress());
LogHelper.info("Server socket thread successfully started");
// Listen for incoming connections
while (serverSocket.isBound()) {
Socket socket = serverSocket.accept();
// Invoke pre-connect listener
long id = idCounter.incrementAndGet();
if (listener != null && !listener.onConnect(socket.getInetAddress())) {
socket.close();
continue; // Listener didn't accepted this connection
}
// Reply in separate thread
threadPool.execute(new ResponseThread(server, id, socket, sessionManager, server.socketHookManager));
}
} catch (IOException e) {
// Ignore error after close/rebind
if (serverSocket.get() != null)
LogHelper.error(e);
}
}
public void setListener(Listener listener) {
this.listener = listener;
}
}

View file

@ -1,13 +0,0 @@
package pro.gravit.launchserver.socket;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
public class SocketContext {
public HInput input;
public HOutput output;
public long session;
public String ip;
public Integer type;
public Client client;
}

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket;
import java.lang.reflect.Type;
import java.util.HashMap;
@ -6,73 +6,61 @@
import java.util.UUID;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.events.ExceptionEvent;
import pro.gravit.launcher.events.RequestEvent;
import pro.gravit.launcher.events.request.AuthRequestEvent;
import pro.gravit.launcher.events.request.ErrorRequestEvent;
import pro.gravit.launcher.hasher.HashedEntry;
import pro.gravit.launcher.hasher.HashedEntryAdapter;
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.ResultInterface;
import pro.gravit.launcher.request.WebSocketEvent;
import pro.gravit.launcher.request.admin.ProxyRequest;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.JsonResponseAdapter;
import pro.gravit.launchserver.websocket.json.JsonResponseInterface;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.websocket.json.admin.AddLogListenerResponse;
import pro.gravit.launchserver.websocket.json.admin.ExecCommandResponse;
import pro.gravit.launchserver.websocket.json.admin.ProxyCommandResponse;
import pro.gravit.launchserver.websocket.json.auth.AuthResponse;
import pro.gravit.launchserver.websocket.json.auth.CheckServerResponse;
import pro.gravit.launchserver.websocket.json.auth.GetAvailabilityAuthResponse;
import pro.gravit.launchserver.websocket.json.auth.JoinServerResponse;
import pro.gravit.launchserver.websocket.json.auth.ProfilesResponse;
import pro.gravit.launchserver.websocket.json.auth.RestoreSessionResponse;
import pro.gravit.launchserver.websocket.json.auth.SetProfileResponse;
import pro.gravit.launchserver.websocket.json.profile.BatchProfileByUsername;
import pro.gravit.launchserver.websocket.json.profile.ProfileByUUIDResponse;
import pro.gravit.launchserver.websocket.json.profile.ProfileByUsername;
import pro.gravit.launchserver.websocket.json.secure.GetSecureTokenResponse;
import pro.gravit.launchserver.websocket.json.secure.VerifySecureTokenResponse;
import pro.gravit.launchserver.websocket.json.update.LauncherResponse;
import pro.gravit.launchserver.websocket.json.update.UpdateListResponse;
import pro.gravit.launchserver.websocket.json.update.UpdateResponse;
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.socket.response.admin.AddLogListenerResponse;
import pro.gravit.launchserver.socket.response.admin.ExecCommandResponse;
import pro.gravit.launchserver.socket.response.admin.ProxyCommandResponse;
import pro.gravit.launchserver.socket.response.auth.*;
import pro.gravit.launchserver.socket.response.profile.BatchProfileByUsername;
import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse;
import pro.gravit.launchserver.socket.response.profile.ProfileByUsername;
import pro.gravit.launchserver.socket.response.secure.GetSecureTokenResponse;
import pro.gravit.launchserver.socket.response.secure.VerifySecureTokenResponse;
import pro.gravit.launchserver.socket.response.update.LauncherResponse;
import pro.gravit.launchserver.socket.response.update.UpdateListResponse;
import pro.gravit.launchserver.socket.response.update.UpdateResponse;
import pro.gravit.utils.ProviderMap;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
@SuppressWarnings("rawtypes")
public class WebSocketService {
public final ChannelGroup channels;
public static ProviderMap<WebSocketServerResponse> providers = new ProviderMap<>();
public WebSocketService(ChannelGroup channels, LaunchServer server, GsonBuilder gson) {
public WebSocketService(ChannelGroup channels, LaunchServer server) {
this.channels = channels;
this.server = server;
this.gsonBuiler = gson;
this.gsonBuiler.registerTypeAdapter(JsonResponseInterface.class, new JsonResponseAdapter(this));
this.gsonBuiler.registerTypeAdapter(ResultInterface.class, new JsonResultSerializeAdapter());
this.gsonBuiler.registerTypeAdapter(HashedEntry.class, new HashedEntryAdapter());
this.gson = gsonBuiler.create();
//this.gsonBuiler.registerTypeAdapter(WebSocketServerResponse.class, new JsonResponseAdapter(this));
//this.gsonBuiler.registerTypeAdapter(WebSocketEvent.class, new JsonResultSerializeAdapter());
//this.gsonBuiler.registerTypeAdapter(HashedEntry.class, new HashedEntryAdapter());
this.gson = Launcher.gsonManager.gson;
}
private final LaunchServer server;
private static final HashMap<String, Class> responses = new HashMap<>();
private final Gson gson;
private final GsonBuilder gsonBuiler;
@SuppressWarnings("unchecked")
void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
String request = frame.text();
JsonResponseInterface response = gson.fromJson(request, JsonResponseInterface.class);
WebSocketServerResponse response = gson.fromJson(request, WebSocketServerResponse.class);
if (server.config.netty.proxy.enabled) {
if (server.config.netty.proxy.requests.contains(response.getType())) {
@ -94,7 +82,7 @@ void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client,
}
proxyRequest.isCheckSign = client.checkSign;
try {
ResultInterface result = proxyRequest.request();
WebSocketEvent result = proxyRequest.request();
if (result instanceof AuthRequestEvent) {
LogHelper.debug("Client auth params get successful");
AuthRequestEvent authRequestEvent = (AuthRequestEvent) result;
@ -128,7 +116,7 @@ void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client,
process(ctx, response, client, ip);
}
void process(ChannelHandlerContext ctx, JsonResponseInterface response, Client client, String ip) {
void process(ChannelHandlerContext ctx, WebSocketServerResponse response, Client client, String ip) {
if (response instanceof SimpleResponse) {
SimpleResponse simpleResponse = (SimpleResponse) response;
simpleResponse.server = server;
@ -158,46 +146,43 @@ public Class getResponseClass(String type) {
return responses.get(type);
}
public void registerResponse(String key, Class responseInterfaceClass) {
responses.put(key, responseInterfaceClass);
}
public void registerClient(Channel channel) {
channels.add(channel);
}
public void registerResponses() {
registerResponse("auth", AuthResponse.class);
registerResponse("checkServer", CheckServerResponse.class);
registerResponse("joinServer", JoinServerResponse.class);
registerResponse("profiles", ProfilesResponse.class);
registerResponse("launcher", LauncherResponse.class);
registerResponse("updateList", UpdateListResponse.class);
registerResponse("cmdExec", ExecCommandResponse.class);
registerResponse("setProfile", SetProfileResponse.class);
registerResponse("addLogListener", AddLogListenerResponse.class);
registerResponse("update", UpdateResponse.class);
registerResponse("restoreSession", RestoreSessionResponse.class);
registerResponse("batchProfileByUsername", BatchProfileByUsername.class);
registerResponse("profileByUsername", ProfileByUsername.class);
registerResponse("profileByUUID", ProfileByUUIDResponse.class);
registerResponse("getSecureToken", GetSecureTokenResponse.class);
registerResponse("verifySecureToken", VerifySecureTokenResponse.class);
registerResponse("getAvailabilityAuth", GetAvailabilityAuthResponse.class);
registerResponse("proxy", ProxyCommandResponse.class);
public static void registerResponses() {
providers.register("auth", AuthResponse.class);
providers.register("checkServer", CheckServerResponse.class);
providers.register("joinServer", JoinServerResponse.class);
providers.register("profiles", ProfilesResponse.class);
providers.register("launcher", LauncherResponse.class);
providers.register("updateList", UpdateListResponse.class);
providers.register("cmdExec", ExecCommandResponse.class);
providers.register("setProfile", SetProfileResponse.class);
providers.register("addLogListener", AddLogListenerResponse.class);
providers.register("update", UpdateResponse.class);
providers.register("restoreSession", RestoreSessionResponse.class);
providers.register("batchProfileByUsername", BatchProfileByUsername.class);
providers.register("profileByUsername", ProfileByUsername.class);
providers.register("profileByUUID", ProfileByUUIDResponse.class);
providers.register("getSecureToken", GetSecureTokenResponse.class);
providers.register("verifySecureToken", VerifySecureTokenResponse.class);
providers.register("getAvailabilityAuth", GetAvailabilityAuthResponse.class);
providers.register("proxy", ProxyCommandResponse.class);
providers.register("register", RegisterResponse.class);
}
public void sendObject(ChannelHandlerContext ctx, Object obj) {
ctx.channel().writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, ResultInterface.class)));
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, WebSocketEvent.class)));
}
public void sendObject(ChannelHandlerContext ctx, Object obj, Type type) {
ctx.channel().writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, type)));
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, type)));
}
public void sendObjectAll(Object obj) {
for (Channel ch : channels) {
ch.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, ResultInterface.class)));
ch.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, WebSocketEvent.class)));
}
}
@ -208,18 +193,18 @@ public void sendObjectAll(Object obj, Type type) {
}
public void sendObjectAndClose(ChannelHandlerContext ctx, Object obj) {
ctx.channel().writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, ResultInterface.class))).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, WebSocketEvent.class))).addListener(ChannelFutureListener.CLOSE);
}
public void sendObjectAndClose(ChannelHandlerContext ctx, Object obj, Type type) {
ctx.channel().writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, type))).addListener(ChannelFutureListener.CLOSE);
ctx.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj, type))).addListener(ChannelFutureListener.CLOSE);
}
public void sendEvent(EventResult obj) {
channels.writeAndFlush(new TextWebSocketFrame(gson.toJson(obj)));
}
public static class EventResult implements ResultInterface {
public static class EventResult implements WebSocketEvent {
public EventResult() {
}

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket.handlers;
import java.util.List;
@ -7,6 +7,7 @@
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.ReferenceCounted;
import pro.gravit.launchserver.socket.NettyConnectContext;
import pro.gravit.utils.helper.LogHelper;
public class NettyIpForwardHandler extends MessageToMessageDecoder<HttpRequest> {

View file

@ -1,9 +1,7 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket.handlers;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
@ -12,12 +10,7 @@
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@ -27,9 +20,8 @@
import pro.gravit.launcher.ssl.LauncherKeyStore;
import pro.gravit.launcher.ssl.LauncherTrustManager;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.legacy.Response;
import pro.gravit.launchserver.socket.LauncherNettyServer;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.VerifyHelper;
@SuppressWarnings({"unused", "rawtypes"})
public final class NettyServerSocketHandler implements Runnable, AutoCloseable {
@ -39,13 +31,8 @@ public final class NettyServerSocketHandler implements Runnable, AutoCloseable {
public LauncherNettyServer nettyServer;
private final AtomicReference<ServerSocket> serverSocket = new AtomicReference<>();
// API
private final Map<String, Response.Factory> customResponses = new ConcurrentHashMap<>(2);
private final AtomicLong idCounter = new AtomicLong(0L);
private Set<Socket> sockets;
private volatile Listener listener;
private transient final LaunchServer server;
@ -55,15 +42,7 @@ public NettyServerSocketHandler(LaunchServer server) {
@Override
public void close() {
ServerSocket socket = serverSocket.getAndSet(null);
if (socket != null) {
LogHelper.info("Closing server socket listener");
try {
socket.close();
} catch (IOException e) {
LogHelper.error(e);
}
}
//TODO: Close Impl
}
public SSLContext SSLContextInit() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException, IOException, CertificateException {
@ -149,37 +128,4 @@ public void run() {
}
*/
}
public void registerCustomResponse(String name, Response.Factory factory) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(customResponses, name, Objects.requireNonNull(factory, "factory"),
String.format("Custom response has been already registered: '%s'", name));
}
public void setListener(Listener listener) {
this.listener = listener;
}
/*package*/ void onDisconnect(long id, Exception e) {
if (listener != null) {
listener.onDisconnect(id, e);
}
}
/*package*/ boolean onHandshake(long id, Integer type) {
return listener == null || listener.onHandshake(id, type);
}
public interface Listener {
boolean onConnect(long id, InetAddress address);
void onDisconnect(long id, Exception e);
boolean onHandshake(long id, Integer type);
}
}

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket;
package pro.gravit.launchserver.socket.handlers;
import java.util.concurrent.TimeUnit;
@ -15,21 +15,21 @@
import io.netty.util.concurrent.GlobalEventExecutor;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.NettyConnectContext;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
public final LaunchServer srv;
public static GsonBuilder builder = CommonHelper.newBuilder();
public final WebSocketService service;
public NettyConnectContext context;
public WebSocketFrameHandler(NettyConnectContext context, LaunchServer srv) {
public WebSocketFrameHandler(NettyConnectContext context, LaunchServer srv, WebSocketService service) {
this.context = context;
this.srv = srv;
service = new WebSocketService(new DefaultChannelGroup(GlobalEventExecutor.INSTANCE), srv, builder);
service.registerResponses();
this.service = service;
}
private Client client;
@ -41,6 +41,8 @@ public void setClient(Client client) {
this.client = client;
}
public Client getClient() { return client; }
@Override
public void channelActive(ChannelHandlerContext ctx) {
LogHelper.dev("New client %s", IOHelper.getIP(ctx.channel().remoteAddress()));

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.fileserver;
package pro.gravit.launchserver.socket.handlers.fileserver;
import java.io.Closeable;

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.fileserver;
package pro.gravit.launchserver.socket.handlers.fileserver;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
@ -17,6 +17,7 @@
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@ -45,7 +46,6 @@
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil;
@ -55,6 +55,7 @@ public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpReque
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
public static final String READ = "r";
public static final int HTTP_CACHE_SECONDS = 60;
private static final boolean OLD_ALGO = Boolean.parseBoolean(System.getProperty("launcher.fileserver.oldalgo", "true"));
private final Path base;
private final boolean fullOut;
@ -143,11 +144,12 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
if (OLD_ALGO) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
lastContentFuture.addListener(new ClosingChannelFutureListener(raf));
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
@ -158,7 +160,6 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
// Decide whether to close the connection or not.
if (!HttpUtil.isKeepAlive(request)) {
lastContentFuture.addListener(new ClosingChannelFutureListener(raf));
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}
}
@ -188,15 +189,7 @@ private static String sanitizeUri(String uri) {
// Convert file separators.
uri = uri.replace(File.separatorChar, '/');
// Simplistic dumb security check.
// You will have to do something serious in the production environment.
if (uri.contains(File.separator + '.') ||
uri.contains('.' + File.separator) ||
uri.charAt(0) == '.' || uri.charAt(uri.length() - 1) == '.' ||
INSECURE_URI.matcher(uri).matches()) {
return null;
}
return uri.substring(1);
return Paths.get(uri).normalize().toString().substring(1);
}
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[^-\\._]?[^<>&\\\"]*");

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json;
package pro.gravit.launchserver.socket.response;
import java.util.UUID;
@ -6,10 +6,9 @@
import pro.gravit.launcher.events.RequestEvent;
import pro.gravit.launcher.events.request.ErrorRequestEvent;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.WebSocketService;
import pro.gravit.launchserver.socket.WebSocketService;
public abstract class SimpleResponse implements JsonResponseInterface {
public abstract class SimpleResponse implements WebSocketServerResponse {
public UUID requestUUID;
public transient LaunchServer server;
public transient WebSocketService service;
@ -31,9 +30,4 @@ public void sendError(String errorMessage) {
event.requestUUID = requestUUID;
service.sendObject(ctx, event);
}
@Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
}
}

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.websocket.json;
package pro.gravit.launchserver.socket.response;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.request.websockets.RequestInterface;
import pro.gravit.launcher.request.websockets.WebSocketRequest;
import pro.gravit.launchserver.socket.Client;
public interface JsonResponseInterface extends RequestInterface {
public interface WebSocketServerResponse extends WebSocketRequest {
String getType();
void execute(ChannelHandlerContext ctx, Client client) throws Exception;

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.websocket.json.admin;
package pro.gravit.launchserver.socket.response.admin;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.LogEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.helper.LogHelper;
public class AddLogListenerResponse extends SimpleResponse {

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.websocket.json.admin;
package pro.gravit.launchserver.socket.response.admin;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ExecCommandRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class ExecCommandResponse extends SimpleResponse {
public String cmd;

View file

@ -1,12 +1,12 @@
package pro.gravit.launchserver.websocket.json.admin;
package pro.gravit.launchserver.socket.response.admin;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.JsonResponseInterface;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.WebSocketServerResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class ProxyCommandResponse extends SimpleResponse {
public JsonResponseInterface response;
public WebSocketServerResponse response;
public long session;
public boolean isCheckSign;

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import java.security.SecureRandom;
import java.util.Collection;
@ -9,7 +9,8 @@
import javax.crypto.IllegalBlockSizeException;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.OshiHWID;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launcher.events.request.AuthRequestEvent;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launchserver.auth.AuthException;
@ -18,8 +19,8 @@
import pro.gravit.launchserver.auth.provider.AuthProvider;
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.websocket.json.profile.ProfileByUUIDResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse;
import pro.gravit.utils.HookException;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
@ -46,7 +47,7 @@ public AuthResponse(String login, String password, String auth_id, OshiHWID hwid
public String auth_id;
public boolean initProxy;
public ConnectTypes authType;
public OshiHWID hwid;
public HWID hwid;
public enum ConnectTypes {
SERVER, CLIENT, BOT
@ -76,7 +77,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
AuthProviderPair pair;
if (auth_id.isEmpty()) pair = server.config.getAuthProviderPair();
else pair = server.config.getAuthProviderPair(auth_id);
AuthContext context = new AuthContext(0, login, password.length(), customText, client, ip, null, authType);
AuthContext context = new AuthContext(0, login, password.length(), customText, client, null, ip, authType);
AuthProvider provider = pair.provider;
server.authHookManager.preHook.hook(context, clientData);
provider.preAuth(login, password, customText, ip);
@ -104,6 +105,10 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
clientData.permissions = aresult.permissions;
clientData.auth_id = auth_id;
clientData.updateAuth(server);
if(result.playerProfile != null)
clientData.username = result.playerProfile.username;
else
clientData.username = login;
result.accessToken = aresult.accessToken;
result.permissions = clientData.permissions;
if (authType == ConnectTypes.BOT && !clientData.permissions.canBot) {

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.CheckServerRequestEvent;
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.websocket.json.profile.ProfileByUUIDResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.socket.response.profile.ProfileByUUIDResponse;
import pro.gravit.utils.HookException;
import pro.gravit.utils.helper.LogHelper;

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import java.util.ArrayList;
import java.util.List;
@ -7,7 +7,7 @@
import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class GetAvailabilityAuthResponse extends SimpleResponse {
@Override

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.JoinServerRequestEvent;
import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.HookException;
import pro.gravit.utils.helper.LogHelper;

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ErrorRequestEvent;
import pro.gravit.launcher.events.request.ProfilesRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class ProfilesResponse extends SimpleResponse {
@Override

View file

@ -0,0 +1,48 @@
package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launchserver.dao.User;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.UUID;
public class RegisterResponse extends SimpleResponse {
public String login;
public String password;
public byte[] verifyHash;
@Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception
{
byte[] normalHash = registerHash(login, server.runtime.registerApiKey);
if(!( client.isAuth && client.permissions.canAdmin ) && !Arrays.equals(normalHash, verifyHash))
{
sendError("Hash invalid");
return;
}
User checkUser = server.config.dao.userService.findUserByUsername(login);
if(checkUser != null)
{
sendError("User already register");
return;
}
User user = new User();
user.username = login;
user.setPassword(password);
user.uuid = UUID.randomUUID();
server.config.dao.userService.saveUser(user);
}
@Override
public String getType() {
return "register";
}
public static byte[] registerHash(String login, String secret) throws NoSuchAlgorithmException {
String text = login.concat("+").concat(secret);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return digest.digest(text.getBytes(StandardCharsets.UTF_8));
}
}

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.RestoreSessionRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.WebSocketFrameHandler;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.handlers.WebSocketFrameHandler;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class RestoreSessionResponse extends SimpleResponse {
@LauncherNetworkAPI

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.auth;
package pro.gravit.launchserver.socket.response.auth;
import java.util.Collection;
@ -6,7 +6,7 @@
import pro.gravit.launcher.events.request.SetProfileRequestEvent;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.HookException;
public class SetProfileResponse extends SimpleResponse {

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.profile;
package pro.gravit.launchserver.socket.response.profile;
import java.util.UUID;
@ -6,7 +6,7 @@
import pro.gravit.launcher.events.request.BatchProfileByUsernameRequestEvent;
import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.helper.LogHelper;
public class BatchProfileByUsername extends SimpleResponse {

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.profile;
package pro.gravit.launchserver.socket.response.profile;
import java.io.IOException;
import java.util.UUID;
@ -10,7 +10,7 @@
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.helper.LogHelper;
public class ProfileByUUIDResponse extends SimpleResponse {

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.websocket.json.profile;
package pro.gravit.launchserver.socket.response.profile;
import java.util.UUID;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.helper.LogHelper;
public class ProfileByUsername extends SimpleResponse {

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.websocket.json.secure;
package pro.gravit.launchserver.socket.response.secure;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.GetSecureTokenRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class GetSecureTokenResponse extends SimpleResponse {
@Override

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.websocket.json.secure;
package pro.gravit.launchserver.socket.response.secure;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.VerifySecureTokenRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class VerifySecureTokenResponse extends SimpleResponse {
public String secureToken;

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.update;
package pro.gravit.launchserver.socket.response.update;
import java.util.Arrays;
import java.util.Base64;
@ -6,7 +6,7 @@
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.LauncherRequestEvent;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.Version;
public class LauncherResponse extends SimpleResponse {

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.update;
package pro.gravit.launchserver.socket.response.update;
import java.util.HashSet;
import java.util.Map;
@ -8,7 +8,7 @@
import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.serialize.signed.SignedObjectHolder;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
public class UpdateListResponse extends SimpleResponse {

View file

@ -1,4 +1,4 @@
package pro.gravit.launchserver.websocket.json.update;
package pro.gravit.launchserver.socket.response.update;
import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ErrorRequestEvent;
@ -8,7 +8,8 @@
import pro.gravit.launcher.serialize.signed.SignedObjectHolder;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.websocket.json.SimpleResponse;
import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.utils.helper.IOHelper;
public class UpdateResponse extends SimpleResponse {
public String dirName;
@ -38,7 +39,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
service.sendObject(ctx, new ErrorRequestEvent(String.format("Directory %s not found", dirName)));
return;
}
String url = server.config.netty.downloadURL.replace("%dirname%", dirName);
String url = server.config.netty.downloadURL.replace("%dirname%", IOHelper.urlEncode(dirName));
boolean zip = false;
if (server.config.netty.bindings.get(dirName) != null) {
LaunchServer.NettyUpdatesBind bind = server.config.netty.bindings.get(dirName);

View file

@ -1,44 +0,0 @@
package pro.gravit.launchserver.websocket.json;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import pro.gravit.launchserver.websocket.WebSocketService;
public class JsonResponseAdapter implements JsonSerializer<JsonResponseInterface>, JsonDeserializer<JsonResponseInterface> {
private final WebSocketService service;
private static final String PROP_NAME = "type";
public JsonResponseAdapter(WebSocketService service) {
this.service = service;
}
@SuppressWarnings("unchecked")
@Override
public JsonResponseInterface deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<JsonResponseInterface> cls = service.getResponseClass(typename);
return (JsonResponseInterface) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(JsonResponseInterface src, Type typeOfSrc, JsonSerializationContext context) {
// note : won't work, you must delegate this
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = src.getType();
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -3,12 +3,12 @@
import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.LogEvent;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.websockets.RequestInterface;
import pro.gravit.launcher.request.websockets.WebSocketRequest;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.helper.LogHelper;
public class LogListenerCommand extends Command {
public class LogListenerRequest implements RequestInterface {
public class LogListenerRequest implements WebSocketRequest {
@LauncherNetworkAPI
public LogHelper.OutputTypes outputType;

View file

@ -39,7 +39,6 @@
dependencies {
pack project(':LauncherAuthlib')
bundle 'com.github.oshi:oshi-core:3.13.0'
bundle 'com.jfoenix:jfoenix:8.0.8'
bundle 'de.jensd:fontawesomefx:8.9'
bundle 'org.apache.httpcomponents:httpclient:4.5.7'
pack 'io.netty:netty-codec-http:4.1.36.Final'

View file

@ -16,6 +16,12 @@ var config = {
autoEnterDefault: false, // Should autoEnter be enabled by default?
fullScreenDefault: false, // Should fullScreen be enabled by default?
ramDefault: 1024, // Default RAM amount (0 for auto)
jvm: {
enable: false,
jvmMustdie32Dir: "jre-8u202-win32",
jvmMustdie64Dir: "jre-8u202-win64",
}
};
DirBridge.dir = DirBridge.getLauncherDir(config.dir);

View file

@ -136,6 +136,9 @@ function initConsoleScene() {
var appendFunction = function(line) javafx.application.Platform.runLater(function() output.appendText(line));
consoleMenu.lookup("#send").setOnAction(function(){
execCommand(text.getText());
if (text.getText() == "clear") {
output.setText("");
}
text.setText("");
});
FunctionalBridge.addPlainOutput(function(string) {
@ -255,7 +258,7 @@ function verifyLauncher(e) {
var iter = 0;
authTypes = {};
result.list.forEach(function(auth_type, i, arr) {
var serverAuth = new com.jfoenix.controls.JFXComboBox();
var serverAuth = new javafx.scene.control.ComboBox();
serverAuth.getStyleClass().add("authOptions");
authOptions.getItems().add(auth_type.displayName);
authTypes[auth_type.displayName] = auth_type.name;
@ -302,26 +305,51 @@ function doAuth(login, rsaPassword, auth_type) {
function doUpdate(profile, pp, accessToken) {
var digest = profile.isUpdateFastCheck();
overlay.swap(0, update.overlay, function(event) {
update.resetOverlay("Обновление файлов ресурсов");
var assetDirName = profile.getAssetDir();
var assetDir = settings.updatesDir.resolve(assetDirName);
var assetMatcher = profile.getAssetUpdateMatcher();
makeSetProfileRequest(profile, function() {
ClientLauncher.setProfile(profile);
makeUpdateRequest(assetDirName, assetDir, assetMatcher, digest, function(assetHDir) {
settings.putHDir(assetDirName, assetDir, assetHDir.hdir);
update.resetOverlay("Обновление файлов клиента");
var clientDirName = profile.getDir();
var clientDir = settings.updatesDir.resolve(clientDirName);
var clientMatcher = profile.getClientUpdateMatcher();
makeUpdateRequest(clientDirName, clientDir, clientMatcher, digest, function(clientHDir) {
settings.putHDir(clientDirName, clientDir, clientHDir.hdir);
doLaunchClient(assetDir, assetHDir.hdir, clientDir, clientHDir.hdir, profile, pp, accessToken);
if (config.jvm.enable) {
makeSetProfileRequest(profile, function() {
ClientLauncher.setProfile(profile);
var jvmDir = settings.updatesDir.resolve(jvmDirName);
update.resetOverlay("Обновление файлов JVM");
makeUpdateRequest(jvmDirName, jvmDir, null, digest, function(jvmHDir) {
ClientLauncher.setJavaBinPath(jvmDir);
update.resetOverlay("Обновление файлов ресурсов");
var assetDirName = profile.getAssetDir();
var assetDir = settings.updatesDir.resolve(assetDirName);
var assetMatcher = profile.getAssetUpdateMatcher();
makeUpdateRequest(assetDirName, assetDir, assetMatcher, digest, function(assetHDir) {
settings.putHDir(assetDirName, assetDir, assetHDir.hdir);
update.resetOverlay("Обновление файлов клиента");
var clientDirName = profile.getDir();
var clientDir = settings.updatesDir.resolve(clientDirName);
var clientMatcher = profile.getClientUpdateMatcher();
makeUpdateRequest(clientDirName, clientDir, clientMatcher, digest, function(clientHDir) {
settings.putHDir(clientDirName, clientDir, clientHDir.hdir);
doLaunchClient(assetDir, assetHDir.hdir, clientDir, clientHDir.hdir, profile, pp, accessToken);
});
});
});
});
});
} else {
update.resetOverlay("Обновление файлов ресурсов");
var assetDirName = profile.getAssetDir();
var assetDir = settings.updatesDir.resolve(assetDirName);
var assetMatcher = profile.getAssetUpdateMatcher();
makeSetProfileRequest(profile, function() {
ClientLauncher.setProfile(profile);
makeUpdateRequest(assetDirName, assetDir, assetMatcher, digest, function(assetHDir) {
settings.putHDir(assetDirName, assetDir, assetHDir.hdir);
update.resetOverlay("Обновление файлов клиента");
var clientDirName = profile.getDir();
var clientDir = settings.updatesDir.resolve(clientDirName);
var clientMatcher = profile.getClientUpdateMatcher();
makeUpdateRequest(clientDirName, clientDir, clientMatcher, digest, function(clientHDir) {
settings.putHDir(clientDirName, clientDir, clientHDir.hdir);
doLaunchClient(assetDir, assetHDir.hdir, clientDir, clientHDir.hdir, profile, pp, accessToken);
});
});
});
}
});
}

Some files were not shown because too many files have changed in this diff Show more