Merge branch 'release/5.0.0'

This commit is contained in:
Gravit 2019-04-27 17:33:15 +07:00
commit 36e1fd45f5
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
316 changed files with 6124 additions and 5484 deletions

View file

@ -1,4 +1,3 @@
# project is java
language: java
# Use https (public access) instead of git for git-submodules. This modifies only Travis-CI behavior!
# disable the default submodule logic
@ -17,7 +16,4 @@ cache:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
script:
- ./gradlew assemble build
# not working artifacts
addons:
artifacts: false
- ./gradlew build

View file

@ -1,6 +1,8 @@
def mainClassName = "ru.gravit.launchserver.LaunchServer"
def mainAgentName = "ru.gravit.launchserver.StarterAgent"
evaluationDependsOn(':Launcher')
repositories {
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
@ -28,7 +30,8 @@
jar {
dependsOn parent.childProjects.Launcher.tasks.build
from { configurations.pack.collect { it.isDirectory() ? it : zipTree(it) } }
from(parent.childProjects.Launcher.tasks.jar.archivePath, parent.childProjects.Launcher.tasks.genRuntimeJS.archivePath)
from(parent.childProjects.Launcher.tasks.shadowJar.archivePath)
from(parent.childProjects.Launcher.tasks.genRuntimeJS.archivePath)
manifest.attributes("Main-Class": mainClassName,
"Premain-Class": mainAgentName,
"Can-Redefine-Classes": "true",
@ -75,6 +78,7 @@ bundle project(':Radon')
}
compileOnlyA 'com.google.guava:guava:26.0-jre'
compileOnlyA 'log4j:log4j:1.2.17' // Do not update (laggy dep).
compileOnlyA 'org.apache.logging.log4j:log4j-core:2.11.2'
}

View file

@ -1,47 +1,47 @@
package ru.gravit.launchserver;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.LauncherConfig;
import ru.gravit.launcher.NeedGarbageCollection;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.managers.ConfigManager;
import ru.gravit.launcher.managers.GarbageManager;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.auth.protect.NoProtectHandler;
import ru.gravit.launchserver.auth.protect.ProtectHandler;
import ru.gravit.launchserver.components.AuthLimiterComponent;
import ru.gravit.launchserver.auth.handler.AuthHandler;
import ru.gravit.launchserver.auth.handler.MemoryAuthHandler;
import ru.gravit.launchserver.auth.hwid.AcceptHWIDHandler;
import ru.gravit.launchserver.auth.hwid.HWIDHandler;
import ru.gravit.launchserver.auth.permissions.DefaultPermissionsHandler;
import ru.gravit.launchserver.auth.permissions.JsonFilePermissionsHandler;
import ru.gravit.launchserver.auth.permissions.PermissionsHandler;
import ru.gravit.launchserver.auth.protect.NoProtectHandler;
import ru.gravit.launchserver.auth.protect.ProtectHandler;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.auth.provider.RejectAuthProvider;
import ru.gravit.launchserver.auth.texture.RequestTextureProvider;
import ru.gravit.launchserver.auth.texture.TextureProvider;
import ru.gravit.launchserver.binary.*;
import ru.gravit.launchserver.components.AuthLimiterComponent;
import ru.gravit.launchserver.components.Component;
import ru.gravit.utils.command.CommandHandler;
import ru.gravit.utils.command.JLineCommandHandler;
import ru.gravit.utils.command.StdCommandHandler;
import ru.gravit.launchserver.config.*;
import ru.gravit.launchserver.config.LaunchServerRuntimeConfig;
import ru.gravit.launchserver.legacy.Response;
import ru.gravit.launchserver.manangers.*;
import ru.gravit.launchserver.manangers.hook.AuthHookManager;
import ru.gravit.launchserver.manangers.hook.BuildHookManager;
import ru.gravit.launchserver.manangers.hook.SocketHookManager;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.NettyServerSocketHandler;
import ru.gravit.launchserver.socket.ServerSocketHandler;
import ru.gravit.launchserver.texture.RequestTextureProvider;
import ru.gravit.launchserver.texture.TextureProvider;
import ru.gravit.launchserver.websocket.NettyServerSocketHandler;
import ru.gravit.utils.command.CommandHandler;
import ru.gravit.utils.command.JLineCommandHandler;
import ru.gravit.utils.command.StdCommandHandler;
import ru.gravit.utils.config.JsonConfigurable;
import ru.gravit.utils.helper.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.lang.ProcessBuilder.Redirect;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.file.*;
@ -61,21 +61,18 @@ public void reload() throws Exception {
config.close();
LogHelper.info("Reading LaunchServer config file");
try (BufferedReader reader = IOHelper.newReader(configFile)) {
config = Launcher.gson.fromJson(reader, Config.class);
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
}
config.verify();
Launcher.applyLauncherEnv(config.env);
for (AuthProviderPair auth : config.auth) {
auth.init();
}
config.init();
}
public static final class Config {
public int port;
public int legacyPort;
private String address;
private String legacyAddress;
private String bindAddress;
private String legacyBindAddress;
public String projectName;
@ -91,25 +88,21 @@ public static final class Config {
private transient AuthProviderPair authDefault;
public AuthProviderPair getAuthProviderPair(String name)
{
for(AuthProviderPair pair : auth)
{
public AuthProviderPair getAuthProviderPair(String name) {
for (AuthProviderPair pair : auth) {
if (pair.name.equals(name)) return pair;
}
return null;
}
public ProtectHandler protectHandler;
public PermissionsHandler permissionsHandler;
public AuthProviderPair getAuthProviderPair()
{
public AuthProviderPair getAuthProviderPair() {
if (authDefault != null) return authDefault;
for(AuthProviderPair pair : auth)
{
if(pair.isDefault)
{
for (AuthProviderPair pair : auth) {
if (pair.isDefault) {
authDefault = pair;
return pair;
}
@ -130,30 +123,26 @@ public AuthProviderPair getAuthProviderPair()
public NettyConfig netty;
public GuardLicenseConf guardLicense;
public boolean compress;
public String whitelistRejectString;
public boolean genMappings;
public boolean isUsingWrapper;
public boolean isDownloadJava;
public LauncherConf launcher;
public boolean isWarningMissArchJava;
public boolean enabledProGuard;
public boolean enabledRadon;
public boolean stripLineNumbers;
public boolean deleteTempFiles;
public boolean enableRcon;
public String startScript;
public String getAddress() {
return address;
public String getLegacyAddress() {
return legacyAddress;
}
public String getBindAddress() {
return bindAddress;
public String getLegacyBindAddress() {
return legacyBindAddress;
}
public void setProjectName(String projectName) {
@ -170,17 +159,17 @@ public void setEnv(LauncherConfig.LauncherEnvironment env) {
public SocketAddress getSocketAddress() {
return new InetSocketAddress(bindAddress, port);
return new InetSocketAddress(legacyBindAddress, legacyPort);
}
public void setAddress(String address) {
this.address = address;
public void setLegacyAddress(String legacyAddress) {
this.legacyAddress = legacyAddress;
}
public void verify() {
VerifyHelper.verify(getAddress(), VerifyHelper.NOT_EMPTY, "LaunchServer address can't be empty");
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");
}
@ -191,12 +180,10 @@ public void verify() {
break;
}
}
if(protectHandler == null)
{
if (protectHandler == null) {
throw new NullPointerException("ProtectHandler must not be null");
}
if(!isOneDefault)
{
if (!isOneDefault) {
throw new IllegalStateException("No auth pairs declared by default.");
}
if (permissionsHandler == null) {
@ -205,13 +192,45 @@ public void verify() {
if (env == null) {
throw new NullPointerException("Env must not be null");
}
if(netty == null)
{
if (netty == null) {
throw new NullPointerException("Netty must not be null");
}
}
public void close()
public void init()
{
Launcher.applyLauncherEnv(env);
for (AuthProviderPair provider : auth) {
provider.init();
}
permissionsHandler.init();
hwidHandler.init();
if (protectHandler != null) {
protectHandler.checkLaunchServerLicense();
}
LaunchServer.server.registerObject("permissionsHandler", permissionsHandler);
for (int i = 0; i < auth.length; ++i) {
AuthProviderPair pair = auth[i];
LaunchServer.server.registerObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
LaunchServer.server.registerObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
LaunchServer.server.registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
}
Arrays.stream(mirrors).forEach(LaunchServer.server.mirrorManager::addMirror);
}
public void close() {
try {
LaunchServer.server.unregisterObject("permissionsHandler", permissionsHandler);
for (int i = 0; i < auth.length; ++i) {
AuthProviderPair pair = auth[i];
LaunchServer.server.unregisterObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
LaunchServer.server.unregisterObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
LaunchServer.server.unregisterObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
}
} catch (Exception e)
{
LogHelper.error(e);
}
try {
for (AuthProviderPair p : auth) p.close();
} catch (IOException e) {
@ -243,17 +262,40 @@ public static class ExeConf {
public String txtFileVersion;
public String txtProductVersion;
}
public class NettyConfig
public class LauncherConf
{
public String bindAddress;
public int port;
public String guardType;
}
public class NettyConfig {
public boolean clientEnabled;
public boolean sendExceptionEnabled;
public String launcherURL;
public String downloadURL;
public String launcherEXEURL;
public String address;
public Map<String, String> bindings = new HashMap<>();
public NettyPerformanceConfig performance;
public NettyBindAddress[] binds;
}
public class GuardLicenseConf
public class NettyPerformanceConfig
{
public int bossThread;
public int workerThread;
}
public class NettyBindAddress
{
public String address;
public int port;
public NettyBindAddress(String address, int port) {
this.address = address;
this.port = port;
}
}
public class GuardLicenseConf {
public String name;
public String key;
public String encryptKey;
@ -273,7 +315,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
// Read profile
ClientProfile profile;
try (BufferedReader reader = IOHelper.newReader(file)) {
profile = Launcher.gson.fromJson(reader, ClientProfile.class);
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
}
profile.verify();
@ -294,7 +336,7 @@ public static void main(String... args) throws Throwable {
long startTime = System.currentTimeMillis();
try {
@SuppressWarnings("resource")
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, args);
LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, false, args);
if (args.length == 0) launchserver.run();
else { //Обработка команды
launchserver.commandHandler.eval(args, false);
@ -311,6 +353,8 @@ public static void main(String... args) throws Throwable {
public final Path dir;
public final boolean testEnv;
public final Path launcherLibraries;
public final Path launcherLibrariesCompile;
@ -318,6 +362,7 @@ public static void main(String... args) throws Throwable {
public final List<String> args;
public final Path configFile;
public final Path runtimeConfigFile;
public final Path publicKeyFile;
@ -331,6 +376,7 @@ public static void main(String... args) throws Throwable {
// Server config
public Config config;
public LaunchServerRuntimeConfig runtime;
public final RSAPublicKey publicKey;
@ -340,6 +386,8 @@ public static void main(String... args) throws Throwable {
public final JARLauncherBinary launcherBinary;
public Class<? extends LauncherBinary> launcherEXEBinaryClass;
public final LauncherBinary launcherEXEBinary;
// HWID ban + anti-brutforce
@ -358,6 +406,8 @@ public static void main(String... args) throws Throwable {
public final ReconfigurableManager reconfigurableManager;
public final ConfigManager configManager;
public final BuildHookManager buildHookManager;
@ -378,16 +428,17 @@ public static void main(String... args) throws Throwable {
public final Timer taskPool;
public static Gson gson;
public static GsonBuilder gsonBuilder;
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecException {
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
this.dir = dir;
this.testEnv = testEnv;
taskPool = new Timer("Timered task worker thread", true);
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");
publicKeyFile = dir.resolve("public.key");
privateKeyFile = dir.resolve("private.key");
updatesDir = dir.resolve("updates");
@ -406,6 +457,9 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
// Set command handler
CommandHandler localCommandHandler;
if (testEnv)
localCommandHandler = new StdCommandHandler(false);
else
try {
Class.forName("jline.Terminal");
@ -443,6 +497,9 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF?
LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
// Load class bindings.
launcherEXEBinaryClass = defaultLauncherEXEBinaryClass;
// pre init modules
modulesManager = new ModulesManager(this);
modulesManager.autoload(dir.resolve("modules"));
@ -450,22 +507,36 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
initGson();
// Read LaunchServer config
generateConfigIfNotExists();
generateConfigIfNotExists(testEnv);
LogHelper.info("Reading LaunchServer config file");
try (BufferedReader reader = IOHelper.newReader(configFile)) {
config = Launcher.gson.fromJson(reader, Config.class);
config = Launcher.gsonManager.gson.fromJson(reader, Config.class);
}
if(!Files.exists(runtimeConfigFile))
{
LogHelper.info("Reset LaunchServer runtime config file");
runtime = new LaunchServerRuntimeConfig();
runtime.reset();
}
else
{
LogHelper.info("Reading LaunchServer runtime config file");
try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) {
runtime = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class);
}
}
runtime.verify();
config.verify();
Launcher.applyLauncherEnv(config.env);
for (AuthProviderPair provider : config.auth) {
provider.init();
}
if(config.protectHandler != null)
{
config.permissionsHandler.init();
config.hwidHandler.init();
if (config.protectHandler != null) {
config.protectHandler.checkLaunchServerLicense();
}
if(config.components != null)
{
if (config.components != null) {
LogHelper.debug("PreInit components");
config.components.forEach((k, v) -> {
LogHelper.subDebug("PreInit component %s", k);
@ -483,43 +554,26 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
reconfigurableManager = new ReconfigurableManager();
socketHookManager = new SocketHookManager();
authHookManager = new AuthHookManager();
configManager = new ConfigManager();
GarbageManager.registerNeedGC(sessionManager);
reloadManager.registerReloadable("launchServer", this);
if (config.permissionsHandler instanceof Reloadable)
reloadManager.registerReloadable("permissionsHandler", (Reloadable) config.permissionsHandler);
registerObject("permissionsHandler", config.permissionsHandler);
for (int i = 0; i < config.auth.length; ++i) {
AuthProviderPair pair = config.auth[i];
if (pair.provider instanceof Reloadable)
reloadManager.registerReloadable("auth.".concat(pair.name).concat(".provider"), (Reloadable) pair.provider);
if (pair.handler instanceof Reloadable)
reloadManager.registerReloadable("auth.".concat(pair.name).concat(".handler"), (Reloadable) pair.handler);
if (pair.textureProvider instanceof Reloadable)
reloadManager.registerReloadable("auth.".concat(pair.name).concat(".texture"), (Reloadable) pair.textureProvider);
}
Arrays.stream(config.mirrors).forEach(mirrorManager::addMirror);
if (config.permissionsHandler instanceof Reconfigurable)
reconfigurableManager.registerReconfigurable("permissionsHandler", (Reconfigurable) config.permissionsHandler);
for (int i = 0; i < config.auth.length; ++i) {
AuthProviderPair pair = config.auth[i];
if (pair.provider instanceof Reconfigurable)
reconfigurableManager.registerReconfigurable("auth.".concat(pair.name).concat(".provider"), (Reconfigurable) pair.provider);
if (pair.handler instanceof Reconfigurable)
reconfigurableManager.registerReconfigurable("auth.".concat(pair.name).concat(".handler"), (Reconfigurable) pair.handler);
if (pair.textureProvider instanceof Reconfigurable)
reconfigurableManager.registerReconfigurable("auth.".concat(pair.name).concat(".texture"), (Reconfigurable) pair.textureProvider);
registerObject("auth.".concat(pair.name).concat(".provider"), pair.provider);
registerObject("auth.".concat(pair.name).concat(".handler"), pair.handler);
registerObject("auth.".concat(pair.name).concat(".texture"), pair.textureProvider);
}
Arrays.stream(config.mirrors).forEach(mirrorManager::addMirror);
// init modules
modulesManager.initModules();
if(config.components != null)
{
if (config.components != null) {
LogHelper.debug("Init components");
config.components.forEach((k, v) -> {
LogHelper.subDebug("Init component %s", k);
registerObject("component.".concat(k), v);
v.init(this);
});
LogHelper.debug("Init components successful");
@ -549,8 +603,7 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
// post init modules
modulesManager.postInitModules();
if(config.components != null)
{
if (config.components != null) {
LogHelper.debug("PostInit components");
config.components.forEach((k, v) -> {
LogHelper.subDebug("PostInit component %s", k);
@ -566,31 +619,19 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
}
public static void initGson() {
if (Launcher.gson != null) return;
Launcher.gsonBuilder = new GsonBuilder();
Launcher.gsonBuilder.registerTypeAdapter(AuthProvider.class, new AuthProviderAdapter());
Launcher.gsonBuilder.registerTypeAdapter(TextureProvider.class, new TextureProviderAdapter());
Launcher.gsonBuilder.registerTypeAdapter(AuthHandler.class, new AuthHandlerAdapter());
Launcher.gsonBuilder.registerTypeAdapter(PermissionsHandler.class, new PermissionsHandlerAdapter());
Launcher.gsonBuilder.registerTypeAdapter(HWIDHandler.class, new HWIDHandlerAdapter());
Launcher.gsonBuilder.registerTypeAdapter(Component.class, new ComponentAdapter());
Launcher.gsonBuilder.registerTypeAdapter(ProtectHandler.class, new ProtectHandlerAdapter());
Launcher.gson = Launcher.gsonBuilder.create();
//Human readable
LaunchServer.gsonBuilder = new GsonBuilder();
LaunchServer.gsonBuilder.setPrettyPrinting();
LaunchServer.gsonBuilder.registerTypeAdapter(AuthProvider.class, new AuthProviderAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(TextureProvider.class, new TextureProviderAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(AuthHandler.class, new AuthHandlerAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(PermissionsHandler.class, new PermissionsHandlerAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(HWIDHandler.class, new HWIDHandlerAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(Component.class, new ComponentAdapter());
LaunchServer.gsonBuilder.registerTypeAdapter(ProtectHandler.class, new ProtectHandlerAdapter());
LaunchServer.gson = LaunchServer.gsonBuilder.create();
Launcher.gsonManager = new LaunchServerGsonManager();
Launcher.gsonManager.initGson();
}
private LauncherBinary binary() {
if (launcherEXEBinaryClass != null) {
try {
return launcherEXEBinaryClass.getConstructor(LaunchServer.class).newInstance(this);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
LogHelper.error(e);
}
}
try {
Class.forName("net.sf.launch4j.Builder");
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
@ -612,11 +653,23 @@ public void close() {
// Close handlers & providers
config.close();
modulesManager.close();
LogHelper.info("Save LaunchServer runtime config");
try(Writer writer = IOHelper.newWriter(runtimeConfigFile))
{
if(Launcher.gsonManager.configGson != null)
{
Launcher.gsonManager.configGson.toJson(runtime, writer);
} else {
LogHelper.error("Error writing LaunchServer runtime config file. Gson is null");
}
} catch (IOException e) {
LogHelper.error(e);
}
// Print last message before death :(
LogHelper.info("LaunchServer stopped");
}
private void generateConfigIfNotExists() throws IOException {
private void generateConfigIfNotExists(boolean testEnv) throws IOException {
if (IOHelper.isFile(configFile))
return;
@ -641,17 +694,28 @@ private void generateConfigIfNotExists() throws IOException {
new MemoryAuthHandler(),
new RequestTextureProvider("http://example.com/skins/%username%.png", "http://example.com/cloaks/%username%.png")
, "std")};
newConfig.auth[0].displayName = "Default";
newConfig.protectHandler = new NoProtectHandler();
newConfig.permissionsHandler = new JsonFilePermissionsHandler();
newConfig.port = 7240;
newConfig.bindAddress = "0.0.0.0";
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 = "Вас нет в белом списке";
newConfig.netty = new NettyConfig();
newConfig.netty.address = "ws://localhost:9274/api";
newConfig.netty.downloadURL = "http://localhost:9274/%dirname%/";
newConfig.netty.launcherURL = "http://localhost:9274/Launcher.jar";
newConfig.netty.launcherEXEURL = "http://localhost:9274/Launcher.exe";
newConfig.netty.clientEnabled = false;
newConfig.netty.port = 9274;
newConfig.netty.binds = new NettyBindAddress[]{ new NettyBindAddress("0.0.0.0", 9274) };
newConfig.netty.performance = new NettyPerformanceConfig();
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();
@ -670,22 +734,40 @@ private void generateConfigIfNotExists() throws IOException {
newConfig.components.put("authLimiter", authLimiterComponent);
// Set server address
System.out.println("LaunchServer address: ");
newConfig.setAddress(commandHandler.readLine());
if (testEnv) {
newConfig.setLegacyAddress("localhost");
newConfig.setProjectName("test");
} else {
System.out.println("LaunchServer legacy address(default: localhost): ");
newConfig.setLegacyAddress(commandHandler.readLine());
System.out.println("LaunchServer projectName: ");
newConfig.setProjectName(commandHandler.readLine());
}
if(newConfig.legacyAddress == null)
{
LogHelper.error("Legacy address null. Using localhost");
newConfig.legacyAddress = "localhost";
}
if(newConfig.projectName == null)
{
LogHelper.error("ProjectName null. Using MineCraft");
newConfig.projectName = "MineCraft";
}
// Write LaunchServer config
LogHelper.info("Writing LaunchServer config file");
try (BufferedWriter writer = IOHelper.newWriter(configFile)) {
LaunchServer.gson.toJson(newConfig, writer);
Launcher.gsonManager.configGson.toJson(newConfig, writer);
}
}
public Collection<ClientProfile> getProfiles() {
public List<ClientProfile> getProfiles() {
return profilesList;
}
public void setProfiles(List<ClientProfile> profilesList) {
this.profilesList = Collections.unmodifiableList(profilesList);
}
public SignedObjectHolder<HashedDir> getUpdateDir(String name) {
return updatesDirMap.get(name);
@ -713,8 +795,10 @@ public void run() {
throw new IllegalStateException("LaunchServer has been already started");
// Add shutdown hook, then start LaunchServer
if (!this.testEnv) {
JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close));
CommonHelper.newThread("Command Thread", true, commandHandler).start();
}
rebindServerSocket();
if (config.netty != null)
rebindNettyServerSocket();
@ -796,6 +880,35 @@ public void restart() {
}
}
public void registerObject(String name, Object object) {
if (object instanceof Reloadable) {
reloadManager.registerReloadable(name, (Reloadable) object);
}
if (object instanceof Reconfigurable) {
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
}
if (object instanceof NeedGarbageCollection) {
GarbageManager.registerNeedGC((NeedGarbageCollection) object);
}
if (object instanceof JsonConfigurable) {
}
}
public void unregisterObject(String name, Object object) {
if (object instanceof Reloadable) {
reloadManager.unregisterReloadable(name);
}
if (object instanceof Reconfigurable) {
reconfigurableManager.unregisterReconfigurable(name);
}
if (object instanceof NeedGarbageCollection) {
GarbageManager.unregisterNeedGC((NeedGarbageCollection) object);
}
if (object instanceof JsonConfigurable) {
}
}
public void fullyRestart() {
restart();
JVMHelper.RUNTIME.exit(0);

View file

@ -2,7 +2,7 @@
import ru.gravit.launchserver.auth.handler.AuthHandler;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.texture.TextureProvider;
import ru.gravit.launchserver.auth.texture.TextureProvider;
import java.io.IOException;
@ -11,6 +11,7 @@ public class AuthProviderPair {
public AuthHandler handler;
public TextureProvider textureProvider;
public String name;
public String displayName;
public boolean isDefault = true;
public AuthProviderPair(AuthProvider provider, AuthHandler handler, TextureProvider textureProvider, String name) {
@ -20,8 +21,7 @@ public AuthProviderPair(AuthProvider provider, AuthHandler handler, TextureProvi
this.name = name;
}
public void init()
{
public void init() {
provider.init();
handler.init();
}

View file

@ -80,8 +80,7 @@ public synchronized Connection getConnection() throws SQLException {
hikari = false;
// Try using HikariCP
source = mysqlSource;
if(enableHikari)
{
if (enableHikari) {
try {
Class.forName("com.zaxxer.hikari.HikariDataSource");
hikari = true; // Used for shutdown. Not instanceof because of possible classpath error

View file

@ -2,16 +2,13 @@
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.auth.provider.AuthProviderResult;
import ru.gravit.utils.helper.VerifyHelper;
import ru.gravit.utils.ProviderMap;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AuthHandler implements AutoCloseable {
private static final Map<String, Class<? extends AuthHandler>> AUTH_HANDLERS = new ConcurrentHashMap<>(4);
public static ProviderMap<AuthHandler> providers = new ProviderMap<>("AuthHandler");
private static boolean registredHandl = false;
@ -19,29 +16,13 @@ public static UUID authError(String message) throws AuthException {
throw new AuthException(message);
}
public static void registerHandler(String name, Class<? extends AuthHandler> adapter) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(AUTH_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Auth handler has been already registered: '%s'", name));
}
public static Class<? extends AuthHandler> getHandlerClass(String name) {
return AUTH_HANDLERS.get(name);
}
public static String getHandlerName(Class<AuthHandler> clazz) {
for (Map.Entry<String, Class<? extends AuthHandler>> e : AUTH_HANDLERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
public static void registerHandlers() {
if (!registredHandl) {
registerHandler("null", NullAuthHandler.class);
registerHandler("memory", MemoryAuthHandler.class);
registerHandler("mysql", MySQLAuthHandler.class);
providers.register("null", NullAuthHandler.class);
providers.register("json", JsonAuthHandler.class);
providers.register("memory", MemoryAuthHandler.class);
providers.register("mysql", MySQLAuthHandler.class);
providers.register("request", RequestAuthHandler.class);
registredHandl = true;
}
}

View file

@ -0,0 +1,80 @@
package ru.gravit.launchserver.auth.handler;
import ru.gravit.launcher.Launcher;
import ru.gravit.utils.HTTPRequest;
import java.io.IOException;
import java.net.URL;
import java.util.UUID;
public class JsonAuthHandler extends CachedAuthHandler {
public URL getUrl;
public URL updateAuthUrl;
public URL updateServerIdUrl;
public class EntryRequestByUsername
{
public String username;
public EntryRequestByUsername(String username) {
this.username = username;
}
}
public class EntryRequestByUUID
{
public UUID uuid;
public EntryRequestByUUID(UUID uuid) {
this.uuid = uuid;
}
}
public class UpdateAuthRequest
{
public UUID uuid;
public String username;
public String accessToken;
public UpdateAuthRequest(UUID uuid, String username, String accessToken) {
this.uuid = uuid;
this.username = username;
this.accessToken = accessToken;
}
}
public class UpdateServerIDRequest
{
public UUID uuid;
public String serverID;
public UpdateServerIDRequest(UUID uuid, String serverID) {
this.uuid = uuid;
this.serverID = serverID;
}
}
public class SuccessResponse
{
public boolean success;
}
@Override
protected Entry fetchEntry(String username) throws IOException {
return Launcher.gsonManager.configGson.fromJson(HTTPRequest.jsonRequest(Launcher.gsonManager.configGson.toJsonTree(new EntryRequestByUsername(username)), getUrl), Entry.class);
}
@Override
protected Entry fetchEntry(UUID uuid) throws IOException {
return Launcher.gsonManager.configGson.fromJson(HTTPRequest.jsonRequest(Launcher.gsonManager.configGson.toJsonTree(new EntryRequestByUUID(uuid)), getUrl), Entry.class);
}
@Override
protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
return Launcher.gsonManager.configGson.fromJson(HTTPRequest.jsonRequest(Launcher.gsonManager.configGson.toJsonTree(new UpdateAuthRequest(uuid, username, accessToken)), updateAuthUrl), SuccessResponse.class).success;
}
@Override
protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
return Launcher.gsonManager.configGson.fromJson(HTTPRequest.jsonRequest(Launcher.gsonManager.configGson.toJsonTree(new UpdateServerIDRequest(uuid, serverID)), updateServerIdUrl), SuccessResponse.class).success;
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,89 @@
package ru.gravit.launchserver.auth.handler;
import ru.gravit.utils.helper.CommonHelper;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.net.URL;
import java.util.UUID;
public final class RequestAuthHandler extends CachedAuthHandler {
private String usernameFetch;
private String uuidFetch;
private String updateAuth;
private String updateServerID;
private String splitSymbol = ":";
private String goodResponse = "OK";
@Override
public void init() {
if (usernameFetch == null)
LogHelper.error("[Verify][AuthHandler] usernameFetch cannot be null");
if (uuidFetch == null)
LogHelper.error("[Verify][AuthHandler] uuidFetch cannot be null");
if (updateAuth == null)
LogHelper.error("[Verify][AuthHandler] updateAuth cannot be null");
if (updateServerID == null)
LogHelper.error("[Verify][AuthHandler] updateServerID cannot be null");
}
@Override
protected Entry fetchEntry(UUID uuid) throws IOException {
String response = IOHelper.request(new URL(CommonHelper.replace(uuidFetch, "uuid", IOHelper.urlEncode(uuid.toString()))));
String[] parts = response.split(splitSymbol);
String username = parts[0];
String accessToken = parts[1];
String serverID = parts[2];
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Got username: " + username);
LogHelper.debug("[AuthHandler] Got accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Got serverID: " + serverID);
LogHelper.debug("[AuthHandler] Got UUID: " + uuid);
}
return new Entry(uuid, username, accessToken, serverID);
}
@Override
protected Entry fetchEntry(String username) throws IOException {
String response = IOHelper.request(new URL(CommonHelper.replace(usernameFetch, "user", IOHelper.urlEncode(username))));
String[] parts = response.split(splitSymbol);
UUID uuid = UUID.fromString(parts[0]);
String accessToken = parts[1];
String serverID = parts[2];
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Got username: " + username);
LogHelper.debug("[AuthHandler] Got accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Got serverID: " + serverID);
LogHelper.debug("[AuthHandler] Got UUID: " + uuid);
}
return new Entry(uuid, username, accessToken, serverID);
}
@Override
protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException {
String response = IOHelper.request(new URL(CommonHelper.replace(updateAuth, "user", IOHelper.urlEncode(username), "uuid", IOHelper.urlEncode(uuid.toString()), "token", IOHelper.urlEncode(accessToken))));
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Set accessToken: " + accessToken);
LogHelper.debug("[AuthHandler] Set UUID: " + uuid);
LogHelper.debug("[AuthHandler] For this username: " + username);
}
return goodResponse.equals(response);
}
@Override
protected boolean updateServerID(UUID uuid, String serverID) throws IOException {
String response = IOHelper.request(new URL(CommonHelper.replace(updateAuth, "serverid", IOHelper.urlEncode(serverID), "uuid", IOHelper.urlEncode(uuid.toString()))));
if (LogHelper.isDebugEnabled()) {
LogHelper.debug("[AuthHandler] Set serverID: " + serverID);
LogHelper.debug("[AuthHandler] For this UUID: " + uuid);
}
return goodResponse.equals(response);
}
@Override
public void close() {
}
}

View file

@ -22,6 +22,11 @@ public void close() {
//SKIP
}
@Override
public void init() {
}
@Override
public List<HWID> getHwid(String username) {
return new ArrayList<>();

View file

@ -1,29 +1,21 @@
package ru.gravit.launchserver.auth.hwid;
import ru.gravit.launcher.HWID;
import ru.gravit.utils.helper.VerifyHelper;
import ru.gravit.utils.ProviderMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public abstract class HWIDHandler implements AutoCloseable {
private static final Map<String, Class<? extends HWIDHandler>> HW_HANDLERS = new ConcurrentHashMap<>(4);
public static ProviderMap<HWIDHandler> providers = new ProviderMap<>("HWIDHandler");
private static boolean registredHandl = false;
public static void registerHandler(String name, Class<? extends HWIDHandler> adapter) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(HW_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("HWID handler has been already registered: '%s'", name));
}
public static void registerHandlers() {
if (!registredHandl) {
registerHandler("accept", AcceptHWIDHandler.class);
registerHandler("mysql", MysqlHWIDHandler.class);
registerHandler("json", JsonHWIDHandler.class);
providers.register("accept", AcceptHWIDHandler.class);
providers.register("mysql", MysqlHWIDHandler.class);
providers.register("json", JsonHWIDHandler.class);
providers.register("memory", MemoryHWIDHandler.class);
registredHandl = true;
}
}
@ -40,18 +32,9 @@ public void check(HWID hwid, String username) throws HWIDException {
@Override
public abstract void close() throws Exception;
public abstract void init();
public abstract List<HWID> getHwid(String username) throws HWIDException;
public abstract void unban(List<HWID> hwid) throws HWIDException;
public static Class<? extends HWIDHandler> getHandlerClass(String name) {
return HW_HANDLERS.get(name);
}
public static String getHandlerName(Class<? extends HWIDHandler> clazz) {
for (Map.Entry<String, Class<? extends HWIDHandler>> e : HW_HANDLERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
}

View file

@ -0,0 +1,107 @@
package ru.gravit.launchserver.auth.hwid;
import com.google.gson.reflect.TypeToken;
import ru.gravit.launcher.HWID;
import ru.gravit.launcher.Launcher;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public class JsonFileHWIDHandler extends HWIDHandler {
public class Entry {
public HWID hwid;
public String username;
public boolean isBanned = false;
public Entry(HWID hwid) {
this.hwid = hwid;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o;
return Objects.equals(hwid, entry.hwid);
}
@Override
public int hashCode() {
return Objects.hash(hwid);
}
}
public String filename = "hwids.json";
public transient LinkedList<Entry> list = new LinkedList<>();
public String banMessage = "You banned";
@Override
public void ban(List<HWID> hwid) {
for (Entry e : list) {
for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = true;
}
}
}
@Override
public void init() {
Path path = Paths.get(filename);
Type type = new TypeToken<LinkedList<Entry>>() {
}.getType();
try (Reader reader = IOHelper.newReader(path)) {
list = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public void check0(HWID hwid, String username) throws HWIDException {
boolean isOne = false;
for (Entry e : list) {
if (e.hwid.equals(hwid)) {
isOne = true;
if (e.isBanned) throw new HWIDException(banMessage);
}
}
if (!isOne) {
list.add(new Entry(hwid));
}
}
@Override
public void close() throws Exception {
Path path = Paths.get(filename);
try (Writer writer = IOHelper.newWriter(path)) {
Launcher.gsonManager.configGson.toJson(list, writer);
}
}
@Override
public List<HWID> getHwid(String username) {
LinkedList<HWID> hwids = new LinkedList<>();
for (Entry e : list) {
if (e.username.equals(username)) hwids.add(e.hwid);
}
return hwids;
}
@Override
public void unban(List<HWID> hwid) {
for (Entry e : list) {
for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = false;
}
}
}
}

View file

@ -111,6 +111,11 @@ public void close() {
// pass
}
@Override
public void init() {
}
@Override
public List<HWID> getHwid(String username) throws HWIDException {
ArrayList<HWID> hwids = new ArrayList<>();

View file

@ -0,0 +1,86 @@
package ru.gravit.launchserver.auth.hwid;
import ru.gravit.launcher.HWID;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
public class MemoryHWIDHandler extends HWIDHandler {
public class Entry {
public HWID hwid;
public String username;
public boolean isBanned = false;
public Entry(HWID hwid) {
this.hwid = hwid;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o;
return Objects.equals(hwid, entry.hwid);
}
@Override
public int hashCode() {
return Objects.hash(hwid);
}
}
public transient LinkedList<Entry> list = new LinkedList<>();
public String banMessage = "You banned";
@Override
public void ban(List<HWID> hwid) {
for (Entry e : list) {
for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = true;
}
}
}
@Override
public void check0(HWID hwid, String username) throws HWIDException {
boolean isOne = false;
for (Entry e : list) {
if (e.hwid.equals(hwid)) {
isOne = true;
if (e.isBanned) throw new HWIDException(banMessage);
}
}
if (!isOne) {
list.add(new Entry(hwid));
}
}
@Override
public void close() {
}
@Override
public void init() {
}
@Override
public List<HWID> getHwid(String username) {
LinkedList<HWID> hwids = new LinkedList<>();
for (Entry e : list) {
if (e.username.equals(username)) hwids.add(e.hwid);
}
return hwids;
}
@Override
public void unban(List<HWID> hwid) {
for (Entry e : list) {
for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = false;
}
}
}
}

View file

@ -143,8 +143,7 @@ public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWI
boolean isOne = false;
while (set.next()) {
if (!oneCompareMode) isOne = true;
if(compareMode)
{
if (compareMode) {
OshiHWID db_hwid = new OshiHWID();
db_hwid.serialNumber = set.getString(hwidFieldSerialNumber);
db_hwid.processorID = set.getString(hwidFieldProcessorID);
@ -154,8 +153,7 @@ public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWI
LogHelper.dev("Compare HWID: %s vs %s", hwid.getSerializeString(), db_hwid.getSerializeString());
int compare_point = hwid.compare(db_hwid);
if (compare_point < compare) continue;
else
{
else {
LogHelper.debug("User %s hwid check: found compare %d in %d", username, compare_point, set.getInt("id"));
}
}
@ -250,4 +248,9 @@ public List<HWID> getHwid(String username) {
public void close() {
mySQLHolder.close();
}
@Override
public void init() {
}
}

View file

@ -6,6 +6,11 @@ public class ConfigPermissionsHandler extends PermissionsHandler {
public boolean isAdmin = false;
public boolean isServer = false;
@Override
public void init() {
}
@Override
public ClientPermissions getPermissions(String username) {
ClientPermissions permissions = new ClientPermissions();
@ -14,6 +19,11 @@ public ClientPermissions getPermissions(String username) {
return permissions;
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
//Unsupported
}
@Override
public void close() {

View file

@ -3,13 +3,23 @@
import ru.gravit.launcher.ClientPermissions;
public class DefaultPermissionsHandler extends PermissionsHandler {
@Override
public void init() {
}
@Override
public ClientPermissions getPermissions(String username) {
return ClientPermissions.DEFAULT;
}
@Override
public void close() throws Exception {
public void setPermissions(String username, ClientPermissions permissions) {
//Unsupported
}
@Override
public void close() {
}
}

View file

@ -27,14 +27,14 @@ public void reload() {
Type type = new TypeToken<Map<String, ClientPermissions>>() {
}.getType();
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gson.fromJson(reader, type);
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public void close() throws Exception {
public void close() {
}
@ -44,26 +44,36 @@ public static class Enity {
}
@Override
public ClientPermissions getPermissions(String username) {
return map.getOrDefault(username, ClientPermissions.DEFAULT);
}
public JsonFilePermissionsHandler() {
public void init() {
Type type = new TypeToken<Map<String, ClientPermissions>>() {
}.getType();
Path path = Paths.get(filename);
if (!IOHelper.exists(path)) {
map = new HashMap<>();
try (Writer writer = IOHelper.newWriter(path)) {
Launcher.gson.toJson(map, writer);
Launcher.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gson.fromJson(reader, type);
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public ClientPermissions getPermissions(String username) {
return map.getOrDefault(username, ClientPermissions.DEFAULT);
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
map.put(username, permissions);
}
public JsonFilePermissionsHandler() {
}
}

View file

@ -28,14 +28,14 @@ public void reload() {
Type type = new TypeToken<Map<String, Long>>() {
}.getType();
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gson.fromJson(reader, type);
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public void close() throws Exception {
public void close() {
}
@ -45,26 +45,36 @@ public static class Enity {
}
@Override
public ClientPermissions getPermissions(String username) {
return new ClientPermissions(map.getOrDefault(username, defaultPerms));
}
public JsonLongFilePermissionsHandler() {
public void init() {
Type type = new TypeToken<Map<String, ClientPermissions>>() {
}.getType();
Path path = Paths.get(filename);
if (!IOHelper.exists(path)) {
map = new HashMap<>();
try (Writer writer = IOHelper.newWriter(path)) {
Launcher.gson.toJson(map, writer);
Launcher.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gson.fromJson(reader, type);
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public ClientPermissions getPermissions(String username) {
return new ClientPermissions(map.getOrDefault(username, defaultPerms));
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
map.put(username, permissions.toLong());
}
public JsonLongFilePermissionsHandler() {
}
}

View file

@ -1,42 +1,25 @@
package ru.gravit.launchserver.auth.permissions;
import ru.gravit.launcher.ClientPermissions;
import ru.gravit.utils.helper.VerifyHelper;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import ru.gravit.utils.ProviderMap;
public abstract class PermissionsHandler implements AutoCloseable {
private static final Map<String, Class<? extends PermissionsHandler>> PERMISSIONS_HANDLERS = new ConcurrentHashMap<>(4);
public static ProviderMap<PermissionsHandler> providers = new ProviderMap<>("PermissionsHandler");
private static boolean registredHandl = false;
public static void registerHandler(String name, Class<? extends PermissionsHandler> adapter) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(PERMISSIONS_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Auth handler has been already registered: '%s'", name));
}
public static Class<? extends PermissionsHandler> getHandlerClass(String name) {
return PERMISSIONS_HANDLERS.get(name);
}
public static String getHandlerName(Class<? extends PermissionsHandler> clazz) {
for (Map.Entry<String, Class<? extends PermissionsHandler>> e : PERMISSIONS_HANDLERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
public static void registerHandlers() {
if (!registredHandl) {
registerHandler("json", JsonFilePermissionsHandler.class);
registerHandler("json-long", JsonLongFilePermissionsHandler.class);
registerHandler("config", ConfigPermissionsHandler.class);
registerHandler("default", DefaultPermissionsHandler.class);
providers.register("json", JsonFilePermissionsHandler.class);
providers.register("json-long", JsonLongFilePermissionsHandler.class);
providers.register("config", ConfigPermissionsHandler.class);
providers.register("default", DefaultPermissionsHandler.class);
registredHandl = true;
}
}
public abstract void init();
public abstract ClientPermissions getPermissions(String username);
public abstract void setPermissions(String username, ClientPermissions permissions);
}

View file

@ -1,6 +1,6 @@
package ru.gravit.launchserver.auth.protect;
import ru.gravit.launchserver.response.auth.AuthResponse;
import ru.gravit.launchserver.websocket.json.auth.AuthResponse;
import ru.gravit.utils.helper.SecurityHelper;
public class NoProtectHandler extends ProtectHandler {
@ -9,6 +9,21 @@ public String generateSecureToken(AuthResponse.AuthContext context) {
return SecurityHelper.randomStringToken();
}
@Override
public String generateClientSecureToken() {
return SecurityHelper.randomStringToken();
}
@Override
public boolean verifyClientSecureToken(String token, String secureKey) {
return true;
}
@Override
public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
return true;
}
@Override
public void checkLaunchServerLicense() {
// None

View file

@ -1,43 +1,27 @@
package ru.gravit.launchserver.auth.protect;
import ru.gravit.launchserver.response.auth.AuthResponse;
import ru.gravit.utils.helper.VerifyHelper;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import ru.gravit.launchserver.websocket.json.auth.AuthResponse;
import ru.gravit.utils.ProviderMap;
public abstract class ProtectHandler {
private static final Map<String, Class<? extends ProtectHandler>> PROTECT_HANDLERS = new ConcurrentHashMap<>(4);
public static ProviderMap<ProtectHandler> providers = new ProviderMap<>("ProtectHandler");
private static boolean registredHandl = false;
public static void registerHandler(String name, Class<? extends ProtectHandler> adapter) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(PROTECT_HANDLERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Protect handler has been already registered: '%s'", name));
}
public static Class<? extends ProtectHandler> getHandlerClass(String name) {
return PROTECT_HANDLERS.get(name);
}
public static String getHandlerName(Class<ProtectHandler> clazz) {
for (Map.Entry<String, Class<? extends ProtectHandler>> e : PROTECT_HANDLERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
public static void registerHandlers() {
if (!registredHandl) {
registerHandler("none", NoProtectHandler.class);
providers.register("none", NoProtectHandler.class);
registredHandl = true;
}
}
public abstract String generateSecureToken(AuthResponse.AuthContext context); //Генерация токена для передачи его в LauncherGuardInterface
public abstract String generateClientSecureToken();
public abstract boolean verifyClientSecureToken(String token, String secureKey);
public abstract boolean allowGetAccessToken(AuthResponse.AuthContext context);
public abstract void checkLaunchServerLicense(); //Выдает SecurityException при ошибке проверки лицензии
//public abstract
}

View file

@ -1,35 +1,26 @@
package ru.gravit.launchserver.auth.provider;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.utils.helper.VerifyHelper;
import ru.gravit.utils.ProviderMap;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AuthProvider implements AutoCloseable {
private static final Map<String, Class<? extends AuthProvider>> AUTH_PROVIDERS = new ConcurrentHashMap<>(8);
public static ProviderMap<AuthProvider> providers = new ProviderMap<>("AuthProvider");
private static boolean registredProv = false;
public static AuthProviderResult authError(String message) throws AuthException {
throw new AuthException(message);
}
public static void registerProvider(String name, Class<? extends AuthProvider> adapter) {
VerifyHelper.putIfAbsent(AUTH_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Auth provider has been already registered: '%s'", name));
}
public static void registerProviders() {
if (!registredProv) {
registerProvider("null", NullAuthProvider.class);
registerProvider("accept", AcceptAuthProvider.class);
registerProvider("reject", RejectAuthProvider.class);
registerProvider("mysql", MySQLAuthProvider.class);
registerProvider("request", RequestAuthProvider.class);
registerProvider("json", JsonAuthProvider.class);
providers.register("null", NullAuthProvider.class);
providers.register("accept", AcceptAuthProvider.class);
providers.register("reject", RejectAuthProvider.class);
providers.register("mysql", MySQLAuthProvider.class);
providers.register("request", RequestAuthProvider.class);
providers.register("json", JsonAuthProvider.class);
registredProv = true;
}
}
@ -37,25 +28,13 @@ public static void registerProviders() {
public abstract AuthProviderResult auth(String login, String password, String ip) throws Exception;
public void preAuth(String login, String password, String customText, String ip) throws Exception
{
public void preAuth(String login, String password, String customText, String ip) {
return;
}
@Override
public abstract void close() throws IOException;
public static Class<? extends AuthProvider> getProviderClass(String name) {
return AUTH_PROVIDERS.get(name);
}
public static String getProviderName(Class<? extends AuthProvider> clazz) {
for (Map.Entry<String, Class<? extends AuthProvider>> e : AUTH_PROVIDERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
public void init() {
}

View file

@ -29,8 +29,7 @@ public void init() {
@Override
public AuthProviderResult auth(String login, String password, String ip) throws SQLException, AuthException {
try(Connection c = mySQLHolder.getConnection())
{
try (Connection c = mySQLHolder.getConnection()) {
PreparedStatement s = c.prepareStatement(query);
String[] replaceParams = {"login", login, "password", password, "ip", ip};
for (int i = 0; i < queryParams.length; i++)

View file

@ -1,4 +1,4 @@
package ru.gravit.launchserver.texture;
package ru.gravit.launchserver.auth.texture;
import ru.gravit.launcher.profiles.Texture;
import ru.gravit.utils.helper.VerifyHelper;

View file

@ -1,4 +1,4 @@
package ru.gravit.launchserver.texture;
package ru.gravit.launchserver.auth.texture;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.profiles.Texture;

View file

@ -0,0 +1,32 @@
package ru.gravit.launchserver.auth.texture;
import ru.gravit.launcher.profiles.Texture;
import ru.gravit.utils.ProviderMap;
import java.io.IOException;
import java.util.UUID;
public abstract class TextureProvider implements AutoCloseable {
public static ProviderMap<TextureProvider> providers = new ProviderMap<>("TextureProvider");
private static boolean registredProv = false;
public static void registerProviders() {
if (!registredProv) {
providers.register("null", NullTextureProvider.class);
providers.register("void", VoidTextureProvider.class);
// Auth providers that doesn't do nothing :D
providers.register("request", RequestTextureProvider.class);
registredProv = true;
}
}
@Override
public abstract void close() throws IOException;
public abstract Texture getCloakTexture(UUID uuid, String username, String client) throws IOException;
public abstract Texture getSkinTexture(UUID uuid, String username, String client) throws IOException;
}

View file

@ -1,4 +1,4 @@
package ru.gravit.launchserver.texture;
package ru.gravit.launchserver.auth.texture;
import ru.gravit.launcher.profiles.Texture;

View file

@ -70,11 +70,6 @@ public void setAddress(String address) {
body.append(address);
body.append("\";");
}
public void setNettyAddress(String address) {
body.append("this.nettyAddress = \"");
body.append(address);
body.append("\";");
}
public void setProjectName(String name) {
body.append("this.projectname = \"");
@ -88,16 +83,10 @@ public void setSecretKey(String key) {
body.append("\";");
}
public void setPort(int port) {
body.append("this.port = ");
body.append(port);
body.append(";");
}
public void setNettyPort(int port) {
body.append("this.nettyPort = ");
body.append(port);
body.append(";");
public void setGuardType(String key) {
body.append("this.guardType = \"");
body.append(key);
body.append("\";");
}
public void setEnv(LauncherConfig.LauncherEnvironment env) {
@ -128,31 +117,13 @@ public void setClientPort(int port) {
body.append(";");
}
public void setUsingWrapper(boolean b) {
body.append("this.isUsingWrapper = ");
body.append(b ? "true" : "false");
body.append(";");
}
public void setDownloadJava(boolean b) {
body.append("this.isDownloadJava = ");
body.append(b ? "true" : "false");
body.append(";");
}
public void setNettyEnabled(boolean b) {
body.append("this.isNettyEnabled = ");
body.append(b ? "true" : "false");
body.append(";");
}
public void setWarningMissArchJava(boolean b) {
body.append("this.isWarningMissArchJava = ");
body.append(b ? "true" : "false");
body.append(";");
}
public void setGuardLicense(String name, String key, String encryptKey)
{
public void setGuardLicense(String name, String key, String encryptKey) {
body.append("this.guardLicenseName = \"");
body.append(name);
body.append("\";");

View file

@ -6,7 +6,9 @@
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.utils.helper.UnpackHelper;
import java.io.*;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
@ -18,8 +20,7 @@ public class ProguardConf {
private static String generateString(SecureRandom rand, String lowString, String upString, int il) {
StringBuilder sb = new StringBuilder(il + lowString.length());
for(int i = 0;i<lowString.length();++i)
{
for (int i = 0; i < lowString.length(); ++i) {
sb.append(rand.nextBoolean() ? lowString.charAt(i) : upString.charAt(i));
}
for (int i = 0; i < il - 1; i++) sb.append(chars.charAt(rand.nextInt(chars.length())));

View file

@ -11,7 +11,10 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Predicate;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@ -31,13 +34,33 @@ public String getName() {
@Override
public Path process(Path inputFile) throws IOException {
Path out = server.launcherBinary.nextPath("post-fixed");
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) {
apply(inputFile, inputFile, output, server, (e) -> false);
}
return out;
}
public static void apply(Path inputFile, Path addFile, ZipOutputStream output, LaunchServer srv, Predicate<ZipEntry> excluder) throws IOException {
try (ClassMetadataReader reader = new ClassMetadataReader()) {
reader.getCp().add(new JarFile(inputFile.toFile()));
try (ZipInputStream input = IOHelper.newZipInput(inputFile);
ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) {
List<JarFile> libs = srv.launcherBinary.coreLibs.stream().map(e -> {
try {
return new JarFile(e.toFile());
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}).collect(Collectors.toList());
libs.addAll(srv.launcherBinary.addonLibs.stream().map(e -> {
try {
return new JarFile(e.toFile());
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}).collect(Collectors.toList()));
try (ZipInputStream input = IOHelper.newZipInput(addFile)) {
ZipEntry e = input.getNextEntry();
while (e != null) {
if (e.isDirectory()) {
if (e.isDirectory() || excluder.test(e)) {
e = input.getNextEntry();
continue;
}
@ -49,14 +72,13 @@ public Path process(Path inputFile) throws IOException {
IOHelper.transfer(input, outputStream);
bytes = outputStream.toByteArray();
}
output.write(classFix(bytes, reader, server.config.stripLineNumbers));
output.write(classFix(bytes, reader, srv.config.stripLineNumbers));
} else
IOHelper.transfer(input, output);
e = input.getNextEntry();
}
}
}
return out;
}
private static byte[] classFix(byte[] bytes, ClassMetadataReader reader, boolean stripNumbers) {

View file

@ -44,26 +44,16 @@ public Path process(Path inputFile) throws IOException {
IOHelper.transfer(input, output);
e = input.getNextEntry();
}
attach(output, srv.launcherBinary.coreLibs);
attach(output, jars);
attach(output, inputFile, srv.launcherBinary.coreLibs);
attach(output, inputFile, jars);
}
return outputFile;
}
private void attach(ZipOutputStream output, List<Path> lst) throws IOException {
private void attach(ZipOutputStream output, Path inputFile, List<Path> lst) throws IOException {
for (Path p : lst) {
LogHelper.debug("Attaching: " + p);
try (ZipInputStream input = IOHelper.newZipInput(p)) {
ZipEntry e = input.getNextEntry();
while (e != null) {
String filename = e.getName();
if (exclusions.stream().noneMatch(filename::startsWith) && !e.isDirectory()) {
output.putNextEntry(IOHelper.newZipEntry(e));
IOHelper.transfer(input, output);
}
e = input.getNextEntry();
}
}
AdditionalFixesApplyTask.apply(inputFile, p, output, srv, (e) -> exclusions.stream().anyMatch(e.getName()::startsWith));
}
}

View file

@ -128,22 +128,14 @@ public Path process(Path inputJar) throws IOException {
});
BuildContext context = new BuildContext(output, jaConfigurator, this);
server.buildHookManager.hook(context);
jaConfigurator.setAddress(server.config.getAddress());
jaConfigurator.setPort(server.config.port);
jaConfigurator.setNettyEnabled(server.config.netty.clientEnabled);
if(server.config.netty.clientEnabled)
{
jaConfigurator.setNettyPort(server.config.netty.port);
jaConfigurator.setNettyAddress(server.config.netty.address);
}
jaConfigurator.setAddress(server.config.netty.address);
if (server.config.guardLicense != null)
jaConfigurator.setGuardLicense(server.config.guardLicense.name, server.config.guardLicense.key, server.config.guardLicense.encryptKey);
jaConfigurator.setProjectName(server.config.projectName);
jaConfigurator.setSecretKey(SecurityHelper.randomStringAESKey());
jaConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512));
jaConfigurator.setUsingWrapper(server.config.isUsingWrapper);
jaConfigurator.setGuardType(server.config.launcher.guardType);
jaConfigurator.setWarningMissArchJava(server.config.isWarningMissArchJava);
jaConfigurator.setDownloadJava(server.config.isDownloadJava);
jaConfigurator.setEnv(server.config.env);
server.buildHookManager.registerAllClientModuleClass(jaConfigurator);
reader.getCp().add(new JarFile(inputJar.toFile()));
@ -201,7 +193,7 @@ public Path process(Path inputJar) throws IOException {
byte[] launcherConfigBytes;
try (ByteArrayOutputStream configArray = IOHelper.newByteArrayOutput()) {
try (HOutput configOutput = new HOutput(configArray)) {
new LauncherConfig(server.config.getAddress(), server.config.port, server.publicKey, runtime)
new LauncherConfig(server.config.netty.address, server.publicKey, runtime)
.write(configOutput);
}
launcherConfigBytes = configArray.toByteArray();
@ -215,7 +207,7 @@ public Path process(Path inputJar) throws IOException {
jaConfigurator.compile();
output.write(jaConfigurator.getBytecode());
} catch (CannotCompileException | NotFoundException e) {
LogHelper.error(e);
throw new IOException(e);
}
reader.close();
return outputJar;

View file

@ -1,19 +1,19 @@
package ru.gravit.launchserver.binary.tasks;
import me.itzsomebody.radon.Radon;
import me.itzsomebody.radon.SessionInfo;
import me.itzsomebody.radon.config.ConfigurationParser;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.UnpackHelper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import me.itzsomebody.radon.Radon;
import me.itzsomebody.radon.SessionInfo;
import me.itzsomebody.radon.config.ConfigurationParser;
public class RadonBuildTask implements LauncherBuildTask {
private final LaunchServer srv;
public final Path config;
@ -32,8 +32,10 @@ public String getName() {
@Override
public Path process(Path inputFile) throws IOException {
Path outputFile = srv.launcherBinary.nextLowerPath(this);
Files.deleteIfExists(outputFile);
if (srv.config.enabledRadon) {
if (!IOHelper.isFile(config)) UnpackHelper.unpack(IOHelper.getResourceURL("ru/gravit/launchserver/defaults/radon.cfg"), config);
if (!IOHelper.isFile(config))
UnpackHelper.unpack(IOHelper.getResourceURL("ru/gravit/launchserver/defaults/radon.cfg"), config);
ConfigurationParser p = new ConfigurationParser(IOHelper.newInput(config));
SessionInfo info = p.createSessionFromConfig();
info.setInput(inputFile.toFile());

View file

@ -0,0 +1,40 @@
package ru.gravit.launchserver.command.auth;
import ru.gravit.launcher.HWID;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.utils.helper.LogHelper;
import java.util.List;
public class GetHWIDCommand extends Command {
public GetHWIDCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[username]";
}
@Override
public String getUsageDescription() {
return "get HWID from username";
}
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
List<HWID> target = server.config.hwidHandler.getHwid(args[0]);
for(HWID hwid : target)
{
if(hwid == null)
{
LogHelper.error("HWID %s: null", args[0]);
continue;
}
LogHelper.info("HWID %s: %s", args[0], hwid.toString());
}
LogHelper.info("Found %d HWID", target.size());
}
}

View file

@ -1,49 +0,0 @@
package ru.gravit.launchserver.command.basic;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.utils.command.Command;
import ru.gravit.utils.command.CommandException;
import ru.gravit.utils.helper.LogHelper;
import java.util.Map.Entry;
public final class HelpCommand extends ru.gravit.launchserver.command.Command {
private static void printCommand(String name, Command command) {
String args = command.getArgsDescription();
LogHelper.subInfo("%s %s - %s", name, args == null ? "[nothing]" : args, command.getUsageDescription());
}
public HelpCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[command name]";
}
@Override
public String getUsageDescription() {
return "Print command usage";
}
@Override
public void invoke(String... args) throws CommandException {
if (args.length < 1) {
printCommands();
return;
}
// Print command help
printCommand(args[0]);
}
private void printCommand(String name) throws CommandException {
printCommand(name, server.commandHandler.lookup(name));
}
private void printCommands() {
for (Entry<String, Command> entry : server.commandHandler.commandsMap().entrySet())
printCommand(entry.getKey(), entry.getValue());
}
}

View file

@ -2,7 +2,7 @@
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.launchserver.socket.NettyServerSocketHandler;
import ru.gravit.launchserver.websocket.NettyServerSocketHandler;
import ru.gravit.utils.helper.CommonHelper;
public class TestCommand extends Command {

View file

@ -1,5 +1,6 @@
package ru.gravit.launchserver.command.dump;
import ru.gravit.launcher.Launcher;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.auth.handler.CachedAuthHandler;
@ -44,7 +45,7 @@ public void invoke(String... args) throws Exception {
serializable.entryCache = entryCache;
serializable.usernameCache = usernamesCache;
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
LaunchServer.gson.toJson(serializable, writer);
Launcher.gsonManager.configGson.toJson(serializable, writer);
}
LogHelper.subInfo("Write %d entryCache, %d usernameCache", entryCache.size(), usernamesCache.size());
} else if (args[0].equals("load")) {
@ -52,7 +53,7 @@ public void invoke(String... args) throws Exception {
int size_entry = 0;
int size_username = 0;
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
EntryAndUsername entryAndUsername = LaunchServer.gson.fromJson(reader, EntryAndUsername.class);
EntryAndUsername entryAndUsername = Launcher.gsonManager.configGson.fromJson(reader, EntryAndUsername.class);
size_entry = entryAndUsername.entryCache.size();
size_username = entryAndUsername.usernameCache.size();
authHandler.loadEntryCache(entryAndUsername.entryCache);

View file

@ -1,6 +1,7 @@
package ru.gravit.launchserver.command.dump;
import com.google.gson.reflect.TypeToken;
import ru.gravit.launcher.Launcher;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.launchserver.socket.Client;
@ -36,7 +37,7 @@ public void invoke(String... args) throws Exception {
LogHelper.info("Sessions write to %s", args[1]);
Set<Client> clientSet = server.sessionManager.getSessions();
try (Writer writer = IOHelper.newWriter(Paths.get(args[1]))) {
LaunchServer.gson.toJson(clientSet, writer);
Launcher.gsonManager.configGson.toJson(clientSet, writer);
}
LogHelper.subInfo("Write %d sessions", clientSet.size());
} else if (args[0].equals("load")) {
@ -45,7 +46,7 @@ public void invoke(String... args) throws Exception {
try (Reader reader = IOHelper.newReader(Paths.get(args[1]))) {
Type setType = new TypeToken<HashSet<Client>>() {
}.getType();
Set<Client> clientSet = LaunchServer.gson.fromJson(reader, setType);
Set<Client> clientSet = Launcher.gsonManager.configGson.fromJson(reader, setType);
size = clientSet.size();
server.sessionManager.loadSessions(clientSet);
}

View file

@ -11,60 +11,82 @@
import ru.gravit.launchserver.command.modules.LoadModuleCommand;
import ru.gravit.launchserver.command.modules.ModulesCommand;
import ru.gravit.launchserver.command.service.*;
import ru.gravit.utils.command.BaseCommandCategory;
import ru.gravit.utils.command.basic.ClearCommand;
import ru.gravit.utils.command.basic.DebugCommand;
import ru.gravit.utils.command.basic.GCCommand;
import ru.gravit.utils.command.basic.HelpCommand;
public abstract class CommandHandler extends ru.gravit.utils.command.CommandHandler {
public static void registerCommands(ru.gravit.utils.command.CommandHandler handler)
{
public static void registerCommands(ru.gravit.utils.command.CommandHandler handler) {
LaunchServer server = LaunchServer.server;
BaseCommandCategory basic = new BaseCommandCategory();
// Register basic commands
handler.registerCommand("help", new HelpCommand(server));
handler.registerCommand("version", new VersionCommand(server));
handler.registerCommand("build", new BuildCommand(server));
handler.registerCommand("stop", new StopCommand(server));
handler.registerCommand("restart", new RestartCommand(server));
handler.registerCommand("rebind", new RebindCommand(server));
handler.registerCommand("debug", new DebugCommand(server));
handler.registerCommand("clear", new ClearCommand(server));
handler.registerCommand("gc", new GCCommand(server));
handler.registerCommand("proguardClean", new ProguardCleanCommand(server));
handler.registerCommand("proguardDictRegen", new RegenProguardDictCommand(server));
handler.registerCommand("proguardMappingsRemove", new RemoveMappingsProguardCommand(server));
handler.registerCommand("logConnections", new LogConnectionsCommand(server));
handler.registerCommand("loadModule", new LoadModuleCommand(server));
handler.registerCommand("modules", new ModulesCommand(server));
handler.registerCommand("test", new TestCommand(server));
basic.registerCommand("help", new HelpCommand(handler));
basic.registerCommand("version", new VersionCommand(server));
basic.registerCommand("build", new BuildCommand(server));
basic.registerCommand("stop", new StopCommand(server));
basic.registerCommand("restart", new RestartCommand(server));
basic.registerCommand("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));
Category basicCategory = new Category(basic,"basic", "Base LaunchServer commands");
handler.registerCategory(basicCategory);
// Register sync commands
handler.registerCommand("indexAsset", new IndexAssetCommand(server));
handler.registerCommand("unindexAsset", new UnindexAssetCommand(server));
handler.registerCommand("downloadAsset", new DownloadAssetCommand(server));
handler.registerCommand("downloadClient", new DownloadClientCommand(server));
handler.registerCommand("syncBinaries", new SyncBinariesCommand(server));
handler.registerCommand("syncUpdates", new SyncUpdatesCommand(server));
handler.registerCommand("syncProfiles", new SyncProfilesCommand(server));
BaseCommandCategory updates = new BaseCommandCategory();
updates.registerCommand("indexAsset", new IndexAssetCommand(server));
updates.registerCommand("unindexAsset", new UnindexAssetCommand(server));
updates.registerCommand("downloadAsset", new DownloadAssetCommand(server));
updates.registerCommand("downloadClient", new DownloadClientCommand(server));
updates.registerCommand("syncBinaries", new SyncBinariesCommand(server));
updates.registerCommand("syncUpdates", new SyncUpdatesCommand(server));
updates.registerCommand("syncProfiles", new SyncProfilesCommand(server));
Category updatesCategory = new Category(updates,"updates", "Update and Sync Management");
handler.registerCategory(updatesCategory);
// Register auth commands
handler.registerCommand("auth", new AuthCommand(server));
handler.registerCommand("usernameToUUID", new UsernameToUUIDCommand(server));
handler.registerCommand("uuidToUsername", new UUIDToUsernameCommand(server));
handler.registerCommand("ban", new BanCommand(server));
handler.registerCommand("unban", new UnbanCommand(server));
BaseCommandCategory auth = new BaseCommandCategory();
auth.registerCommand("auth", new AuthCommand(server));
auth.registerCommand("usernameToUUID", new UsernameToUUIDCommand(server));
auth.registerCommand("uuidToUsername", new UUIDToUsernameCommand(server));
auth.registerCommand("ban", new BanCommand(server));
auth.registerCommand("unban", new UnbanCommand(server));
auth.registerCommand("getHWID", new GetHWIDCommand(server));
Category authCategory = new Category(auth,"auth", "User Management");
handler.registerCategory(authCategory);
//Register dump commands
handler.registerCommand("dumpSessions", new DumpSessionsCommand(server));
handler.registerCommand("dumpEntryCache", new DumpEntryCacheCommand(server));
BaseCommandCategory dump = new BaseCommandCategory();
dump.registerCommand("dumpSessions", new DumpSessionsCommand(server));
dump.registerCommand("dumpEntryCache", new DumpEntryCacheCommand(server));
Category dumpCategory = new Category(dump,"dump", "Dump runtime data");
handler.registerCategory(dumpCategory);
//Register service commands
handler.registerCommand("reload", new ReloadCommand(server));
handler.registerCommand("reloadAll", new ReloadAllCommand(server));
handler.registerCommand("reloadList", new ReloadListCommand(server));
handler.registerCommand("config", new ConfigCommand(server));
handler.registerCommand("configHelp", new ConfigHelpCommand(server));
handler.registerCommand("configList", new ConfigListCommand(server));
handler.registerCommand("serverStatus", new ServerStatusCommand(server));
handler.registerCommand("checkInstall", new CheckInstallCommand(server));
handler.registerCommand("multi", new MultiCommand(server));
handler.registerCommand("getModulus", new GetModulusCommand(server));
handler.registerCommand("component", new ComponentCommand(server));
BaseCommandCategory service = new BaseCommandCategory();
service.registerCommand("reload", new ReloadCommand(server));
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));
service.registerCommand("getModulus", new GetModulusCommand(server));
service.registerCommand("component", new ComponentCommand(server));
service.registerCommand("givePermission", new GivePermissionsCommand(server));
service.registerCommand("getPermissions", new GetPermissionsCommand(server));
Category serviceCategory = new Category(service,"service", "Managing LaunchServer Components");
handler.registerCategory(serviceCategory);
}
}

View file

@ -19,7 +19,7 @@ public DownloadAssetCommand(LaunchServer server) {
@Override
public String getArgsDescription() {
return "<version> <dir>";
return "[version] [dir]";
}
@Override

View file

@ -1,11 +1,12 @@
package ru.gravit.launchserver.command.hash;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.profiles.ClientProfile.Version;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.utils.command.CommandException;
import ru.gravit.utils.HttpDownloader;
import ru.gravit.utils.command.CommandException;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
@ -24,7 +25,7 @@ public DownloadClientCommand(LaunchServer server) {
@Override
public String getArgsDescription() {
return "<version> <dir>";
return "[version] [dir]";
}
@Override
@ -52,13 +53,13 @@ public void invoke(String... args) throws IOException, CommandException {
ClientProfile client;
String profilePath = String.format("ru/gravit/launchserver/defaults/profile%s.cfg", version.name);
try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) {
client = LaunchServer.gson.fromJson(reader, ClientProfile.class);
client = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class);
}
client.setTitle(dirName);
client.setDir(dirName);
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
dirName, "cfg"))) {
LaunchServer.gson.toJson(client, writer);
Launcher.gsonManager.configGson.toJson(client, writer);
}
// Finished

View file

@ -81,7 +81,7 @@ public IndexAssetCommand(LaunchServer server) {
@Override
public String getArgsDescription() {
return "<dir> <index> <output-dir>";
return "[dir] [index] [output-dir]";
}
@Override

View file

@ -24,7 +24,7 @@ public UnindexAssetCommand(LaunchServer server) {
@Override
public String getArgsDescription() {
return "<dir> <index> <output-dir>";
return "[dir] [index] [output-dir]";
}
@Override

View file

@ -20,8 +20,7 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
for(String arg : args)
{
for (String arg : args) {
server.commandHandler.eval(arg, false);
}
}

View file

@ -1,5 +1,6 @@
package ru.gravit.launchserver.command.service;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.NeedGarbageCollection;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
@ -25,8 +26,7 @@ public String getUsageDescription() {
return "component manager";
}
public void printHelp()
{
public void printHelp() {
LogHelper.info("Print help for component:");
LogHelper.subInfo("component unload [componentName]");
LogHelper.subInfo("component load [componentName] [filename]");
@ -38,66 +38,53 @@ public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
String componentName = null;
if (args.length > 1) componentName = args[1];
switch(args[0])
{
case "unload":
{
switch (args[0]) {
case "unload": {
if (componentName == null) throw new IllegalArgumentException("Must set componentName");
Component component = server.config.components.get(componentName);
if (component == null) {
LogHelper.error("Component %s not found", componentName);
return;
}
if(component instanceof AutoCloseable)
{
if (component instanceof AutoCloseable) {
((AutoCloseable) component).close();
}
else
{
} else {
LogHelper.error("Component %s unload not supported", componentName);
return;
}
break;
}
case "gc":
{
case "gc": {
if (componentName == null) throw new IllegalArgumentException("Must set componentName");
Component component = server.config.components.get(componentName);
if (component == null) {
LogHelper.error("Component %s not found", componentName);
return;
}
if(component instanceof NeedGarbageCollection)
{
if (component instanceof NeedGarbageCollection) {
((NeedGarbageCollection) component).garbageCollection();
}
else
{
} else {
LogHelper.error("Component %s gc not supported", componentName);
return;
}
break;
}
case "load":
{
case "load": {
if (componentName == null) throw new IllegalArgumentException("Must set componentName");
if (args.length <= 2) throw new IllegalArgumentException("Must set file");
String fileName = args[2];
try(Reader reader = IOHelper.newReader(Paths.get(fileName)))
{
Component component = LaunchServer.gson.fromJson(reader, Component.class);
try (Reader reader = IOHelper.newReader(Paths.get(fileName))) {
Component component = Launcher.gsonManager.configGson.fromJson(reader, Component.class);
component.preInit(server);
component.init(server);
component.postInit(server);
LogHelper.info("Component %s(%s) loaded", componentName, component.getClass().getName());
}
}
case "help":
{
case "help": {
printHelp();
}
default:
{
default: {
printHelp();
}
}

View file

@ -0,0 +1,30 @@
package ru.gravit.launchserver.command.service;
import ru.gravit.launcher.ClientPermissions;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.utils.helper.LogHelper;
public class GetPermissionsCommand extends Command {
public GetPermissionsCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[username]";
}
@Override
public String getUsageDescription() {
return "print username permissions";
}
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
String username = args[0];
ClientPermissions permissions = server.config.permissionsHandler.getPermissions(username);
LogHelper.info("Permissions %s: %s (long: %d)", username, permissions.toString(), permissions.toLong());
}
}

View file

@ -0,0 +1,51 @@
package ru.gravit.launchserver.command.service;
import ru.gravit.launcher.ClientPermissions;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.command.Command;
import ru.gravit.utils.helper.LogHelper;
public class GivePermissionsCommand extends Command {
public GivePermissionsCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return "[username] [permission] [true/false]";
}
@Override
public String getUsageDescription() {
return "give permissions";
}
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 3);
String username = args[0];
ClientPermissions permissions = server.config.permissionsHandler.getPermissions(username);
String permission = args[1];
boolean isEnabled = Boolean.valueOf(args[2]);
switch (permission) {
case "admin": {
permissions.canAdmin = isEnabled;
break;
}
case "server": {
permissions.canServer = isEnabled;
break;
}
case "bot": {
permissions.canBot = isEnabled;
break;
}
default: {
LogHelper.error("Unknown permission: %s", permission);
return;
}
}
LogHelper.info("Write new permissions for %s", username);
server.config.permissionsHandler.setPermissions(username, permissions);
}
}

View file

@ -21,7 +21,6 @@ public String getUsageDescription() {
@Override
public void invoke(String... args) throws Exception {
verifyArgs(args, 1);
LogHelper.info("Reload all config");
server.reloadManager.reloadAll();
}

View file

@ -4,6 +4,7 @@
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.auth.handler.CachedAuthHandler;
import ru.gravit.launchserver.command.Command;
import ru.gravit.utils.command.CommandHandler;
import ru.gravit.utils.helper.JVMHelper;
import ru.gravit.utils.helper.LogHelper;
@ -33,9 +34,13 @@ public void invoke(String... args) {
long days = (uptime / 60 / 60 / 24);
LogHelper.info("Uptime: %d days %d hours %d minutes %d seconds", days, hour, min, second);
LogHelper.info("Uptime (double): %f", (double) JVMHelper.RUNTIME_MXBEAN.getUptime() / 1000);
LogHelper.info("Sessions: %d | Modules: %d | Commands: %d", server.sessionManager.getSessions().size(), server.modulesManager.modules.size(), server.commandHandler.commandsMap().size());
for(AuthProviderPair pair : server.config.auth)
int commands = server.commandHandler.getBaseCategory().commandsMap().size();
for(CommandHandler.Category category : server.commandHandler.getCategories())
{
commands += category.category.commandsMap().size();
}
LogHelper.info("Sessions: %d | Modules: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), server.modulesManager.modules.size(), commands, server.commandHandler.getCategories().size() + 1);
for (AuthProviderPair pair : server.config.auth) {
if (pair.handler instanceof CachedAuthHandler) {
LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size());
}

View file

@ -4,9 +4,8 @@
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.components.Component;
import ru.gravit.launchserver.response.auth.AuthResponse;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.websocket.json.auth.AuthResponse;
import java.util.ArrayList;
import java.util.HashMap;
@ -26,9 +25,9 @@ public void init(LaunchServer launchServer) {
public void postInit(LaunchServer launchServer) {
}
public void preAuthHook(AuthResponse.AuthContext context, Client client) throws AuthException {
if(isLimit(context.ip))
{
if (isLimit(context.ip)) {
AuthProvider.authError(message);
}
}

View file

@ -0,0 +1,38 @@
package ru.gravit.launchserver.components;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.utils.command.Command;
import java.util.HashMap;
import java.util.Map;
public class CommandRemoverComponent extends Component implements AutoCloseable {
public String[] removeList = new String[]{};
public transient Map<String, Command> commandsList = new HashMap<>();
@Override
public void preInit(LaunchServer launchServer) {
}
@Override
public void init(LaunchServer launchServer) {
}
@Override
public void postInit(LaunchServer launchServer) {
for (String cmd : removeList) {
Command removedCmd = launchServer.commandHandler.unregisterCommand(cmd);
if (removedCmd != null)
commandsList.put(cmd, removedCmd);
}
}
@Override
public void close() {
for (Map.Entry<String, Command> e : commandsList.entrySet()) {
LaunchServer.server.commandHandler.registerCommand(e.getKey(), e.getValue());
}
}
}

View file

@ -1,40 +1,23 @@
package ru.gravit.launchserver.components;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.utils.helper.VerifyHelper;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import ru.gravit.utils.ProviderMap;
public abstract class Component {
private static final Map<String, Class<? extends Component>> COMPONENTS = new ConcurrentHashMap<>(4);
public static ProviderMap<Component> providers = new ProviderMap<>();
private static boolean registredComp = false;
public static void registerComponent(String name, Class<? extends Component> adapter) {
VerifyHelper.verifyIDName(name);
VerifyHelper.putIfAbsent(COMPONENTS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Auth handler has been already registered: '%s'", name));
}
public static Class<? extends Component> getComponentClass(String name) {
return COMPONENTS.get(name);
}
public static String getComponentName(Class<Component> clazz) {
for (Map.Entry<String, Class<? extends Component>> e : COMPONENTS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
public static void registerComponents() {
if (!registredComp) {
registerComponent("authLimiter", AuthLimiterComponent.class);
providers.register("authLimiter", AuthLimiterComponent.class);
providers.register("commandRemover", CommandRemoverComponent.class);
registredComp = true;
}
}
public abstract void preInit(LaunchServer launchServer);
public abstract void init(LaunchServer launchServer);
public abstract void postInit(LaunchServer launchServer);
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.auth.handler.AuthHandler;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class AuthHandlerAdapter implements JsonSerializer<AuthHandler>, JsonDeserializer<AuthHandler> {
private static final String PROP_NAME = "type";
@Override
public AuthHandler deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends AuthHandler> cls = AuthHandler.getHandlerClass(typename);
if(cls == null)
{
LogHelper.error("AuthHandler %s not found", typename);
return null;
}
return (AuthHandler) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(AuthHandler src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
@SuppressWarnings("unchecked")
String classPath = AuthHandler.getHandlerName((Class<AuthHandler>) src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class AuthProviderAdapter implements JsonSerializer<AuthProvider>, JsonDeserializer<AuthProvider> {
private static final String PROP_NAME = "type";
@Override
public AuthProvider deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends AuthProvider> cls = AuthProvider.getProviderClass(typename);
if(cls == null)
{
LogHelper.error("AuthProvider %s not found", typename);
return null;
}
return (AuthProvider) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(AuthProvider src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = AuthProvider.getProviderName(src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.components.Component;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class ComponentAdapter implements JsonSerializer<Component>, JsonDeserializer<Component> {
private static final String PROP_NAME = "component";
@Override
public Component deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends Component> cls = Component.getComponentClass(typename);
if(cls == null)
{
LogHelper.error("Component %s not found", typename);
return null;
}
return (Component) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(Component src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
@SuppressWarnings("unchecked")
String classPath = Component.getComponentName((Class<Component>) src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.auth.hwid.HWIDHandler;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class HWIDHandlerAdapter implements JsonSerializer<HWIDHandler>, JsonDeserializer<HWIDHandler> {
private static final String PROP_NAME = "type";
@Override
public HWIDHandler deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends HWIDHandler> cls = HWIDHandler.getHandlerClass(typename);
if(cls == null)
{
LogHelper.error("HWIDHandler %s not found", typename);
return null;
}
return (HWIDHandler) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(HWIDHandler src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = HWIDHandler.getHandlerName(src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -0,0 +1,16 @@
package ru.gravit.launchserver.config;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
public class LaunchServerRuntimeConfig {
public String clientToken;
public void verify()
{
if(clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null");
}
public void reset()
{
clientToken = SecurityHelper.randomStringToken();
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.auth.permissions.PermissionsHandler;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class PermissionsHandlerAdapter implements JsonSerializer<PermissionsHandler>, JsonDeserializer<PermissionsHandler> {
private static final String PROP_NAME = "type";
@Override
public PermissionsHandler deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends PermissionsHandler> cls = PermissionsHandler.getHandlerClass(typename);
if(cls == null)
{
LogHelper.error("PermissionsHandler %s not found", typename);
return null;
}
return (PermissionsHandler) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(PermissionsHandler src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = PermissionsHandler.getHandlerName(src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.auth.protect.ProtectHandler;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class ProtectHandlerAdapter implements JsonSerializer<ProtectHandler>, JsonDeserializer<ProtectHandler> {
private static final String PROP_NAME = "type";
@Override
public ProtectHandler deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends ProtectHandler> cls = ProtectHandler.getHandlerClass(typename);
if(cls == null)
{
LogHelper.error("ProtectHandler %s not found", typename);
return null;
}
return (ProtectHandler) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(ProtectHandler src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
@SuppressWarnings("unchecked")
String classPath = ProtectHandler.getHandlerName((Class<ProtectHandler>) src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.config;
import com.google.gson.*;
import ru.gravit.launchserver.texture.TextureProvider;
import ru.gravit.utils.helper.LogHelper;
import java.lang.reflect.Type;
public class TextureProviderAdapter implements JsonSerializer<TextureProvider>, JsonDeserializer<TextureProvider> {
private static final String PROP_NAME = "type";
@Override
public TextureProvider deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String typename = json.getAsJsonObject().getAsJsonPrimitive(PROP_NAME).getAsString();
Class<? extends TextureProvider> cls = TextureProvider.getProviderClass(typename);
if(cls == null)
{
LogHelper.error("TextureProvider %s not found", typename);
return null;
}
return (TextureProvider) context.deserialize(json, cls);
}
@Override
public JsonElement serialize(TextureProvider src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jo = context.serialize(src).getAsJsonObject();
String classPath = TextureProvider.getProviderName(src.getClass());
jo.add(PROP_NAME, new JsonPrimitive(classPath));
return jo;
}
}

View file

@ -1,4 +1,4 @@
package ru.gravit.launchserver.response;
package ru.gravit.launchserver.legacy;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;

View file

@ -1,16 +1,12 @@
package ru.gravit.launchserver.response;
package ru.gravit.launchserver.legacy;
import ru.gravit.launcher.request.RequestException;
import ru.gravit.launcher.request.RequestType;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.admin.ExecCommandResponse;
import ru.gravit.launchserver.response.auth.*;
import ru.gravit.launchserver.response.profile.BatchProfileByUsernameResponse;
import ru.gravit.launchserver.response.profile.ProfileByUUIDResponse;
import ru.gravit.launchserver.response.profile.ProfileByUsernameResponse;
import ru.gravit.launchserver.response.update.*;
import ru.gravit.launchserver.legacy.update.LauncherResponse;
import ru.gravit.launchserver.legacy.update.LegacyLauncherResponse;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.LogHelper;
@ -37,23 +33,8 @@ public static void registerResponse(int type, Factory<?> factory) {
public static void registerResponses() {
registerResponse(RequestType.PING.getNumber(), PingResponse::new);
registerResponse(RequestType.AUTH.getNumber(), AuthResponse::new);
registerResponse(RequestType.CHECK_SERVER.getNumber(), CheckServerResponse::new);
registerResponse(RequestType.JOIN_SERVER.getNumber(), JoinServerResponse::new);
registerResponse(RequestType.BATCH_PROFILE_BY_USERNAME.getNumber(), BatchProfileByUsernameResponse::new);
registerResponse(RequestType.PROFILE_BY_USERNAME.getNumber(), ProfileByUsernameResponse::new);
registerResponse(RequestType.PROFILE_BY_UUID.getNumber(), ProfileByUUIDResponse::new);
registerResponse(RequestType.LEGACYLAUNCHER.getNumber(), LegacyLauncherResponse::new);
registerResponse(RequestType.LAUNCHER.getNumber(), LauncherResponse::new);
registerResponse(RequestType.UPDATE_LIST.getNumber(), UpdateListResponse::new);
registerResponse(RequestType.UPDATE.getNumber(), UpdateResponse::new);
registerResponse(RequestType.PROFILES.getNumber(), ProfilesResponse::new);
registerResponse(RequestType.SERVERAUTH.getNumber(), AuthServerResponse::new);
registerResponse(RequestType.SETPROFILE.getNumber(), SetProfileResponse::new);
registerResponse(RequestType.CHANGESERVER.getNumber(), ChangeServerResponse::new);
registerResponse(RequestType.EXECCOMMAND.getNumber(), ExecCommandResponse::new);
}

View file

@ -1,11 +1,11 @@
package ru.gravit.launchserver.response.update;
package ru.gravit.launchserver.legacy.update;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launcher.serialize.signed.DigestBytesHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.legacy.Response;
import ru.gravit.launchserver.socket.Client;
import java.io.IOException;

View file

@ -1,10 +1,10 @@
package ru.gravit.launchserver.response.update;
package ru.gravit.launchserver.legacy.update;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.binary.LauncherBinary;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.legacy.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.SecurityHelper;

View file

@ -0,0 +1,26 @@
package ru.gravit.launchserver.manangers;
import com.google.gson.GsonBuilder;
import ru.gravit.launcher.managers.GsonManager;
import ru.gravit.launchserver.auth.handler.AuthHandler;
import ru.gravit.launchserver.auth.hwid.HWIDHandler;
import ru.gravit.launchserver.auth.permissions.PermissionsHandler;
import ru.gravit.launchserver.auth.protect.ProtectHandler;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.auth.texture.TextureProvider;
import ru.gravit.launchserver.components.Component;
import ru.gravit.utils.UniversalJsonAdapter;
public class LaunchServerGsonManager extends GsonManager {
@Override
public void registerAdapters(GsonBuilder builder) {
super.registerAdapters(builder);
builder.registerTypeAdapter(AuthProvider.class, new UniversalJsonAdapter<>(AuthProvider.providers));
builder.registerTypeAdapter(TextureProvider.class, new UniversalJsonAdapter<>(TextureProvider.providers));
builder.registerTypeAdapter(AuthHandler.class, new UniversalJsonAdapter<>(AuthHandler.providers));
builder.registerTypeAdapter(PermissionsHandler.class, new UniversalJsonAdapter<>(PermissionsHandler.providers));
builder.registerTypeAdapter(HWIDHandler.class, new UniversalJsonAdapter<>(HWIDHandler.providers));
builder.registerTypeAdapter(Component.class, new UniversalJsonAdapter<>(Component.providers));
builder.registerTypeAdapter(ProtectHandler.class, new UniversalJsonAdapter<>(ProtectHandler.providers));
}
}

View file

@ -1,7 +1,7 @@
package ru.gravit.launchserver.manangers;
import ru.gravit.launcher.managers.SimpleModulesConfigManager;
import ru.gravit.launcher.managers.SimpleModuleManager;
import ru.gravit.launcher.managers.SimpleModulesConfigManager;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.modules.CoreModule;
import ru.gravit.launchserver.modules.LaunchServerModuleContext;

View file

@ -11,16 +11,20 @@ public class ReconfigurableManager {
private final HashMap<String, Reconfigurable> RECONFIGURABLE = new HashMap<>();
public void registerReconfigurable(String name, Reconfigurable reconfigurable) {
VerifyHelper.putIfAbsent(RECONFIGURABLE, name, Objects.requireNonNull(reconfigurable, "adapter"),
VerifyHelper.putIfAbsent(RECONFIGURABLE, name.toLowerCase(), Objects.requireNonNull(reconfigurable, "adapter"),
String.format("Reloadable has been already registered: '%s'", name));
}
public Reconfigurable unregisterReconfigurable(String name)
{
return RECONFIGURABLE.remove(name);
}
public void printHelp(String name) {
RECONFIGURABLE.get(name).printConfigHelp();
RECONFIGURABLE.get(name.toLowerCase()).printConfigHelp();
}
public void call(String name, String action, String[] args) {
RECONFIGURABLE.get(name).reconfig(action, args);
RECONFIGURABLE.get(name.toLowerCase()).reconfig(action.toLowerCase(), args);
}
public void printReconfigurables() {

View file

@ -11,8 +11,12 @@ public class ReloadManager {
private final HashMap<String, Reloadable> RELOADABLES = new HashMap<>();
public void registerReloadable(String name, Reloadable reloadable) {
VerifyHelper.putIfAbsent(RELOADABLES, name, Objects.requireNonNull(reloadable, "adapter"),
String.format("Reloadable has been already registered: '%s'", name));
VerifyHelper.putIfAbsent(RELOADABLES, name.toLowerCase(), Objects.requireNonNull(reloadable, "adapter"),
String.format("Reloadable has been already registered: '%s'", name.toLowerCase()));
}
public Reloadable unregisterReloadable(String name)
{
return RELOADABLES.remove(name);
}
public void reloadAll() {
@ -26,7 +30,7 @@ public void reloadAll() {
}
public void reload(String name) throws Exception {
RELOADABLES.get(name).reload();
RELOADABLES.get(name.toLowerCase()).reload();
}
public void printReloadables() {

View file

@ -1,8 +1,8 @@
package ru.gravit.launchserver.manangers.hook;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.response.auth.AuthResponse;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.websocket.json.auth.AuthResponse;
import java.util.HashSet;
import java.util.Set;

View file

@ -1,42 +0,0 @@
package ru.gravit.launchserver.response.admin;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
public class ExecCommandResponse extends Response {
public ExecCommandResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws Exception {
Client clientData = server.sessionManager.getClient(session);
if (!clientData.isAuth || !clientData.permissions.canAdmin || !server.config.enableRcon)
requestError("Access denied");
writeNoError(output);
String cmd = input.readString(SerializeLimits.MAX_COMMAND);
LogHelper.OutputEnity loutput = new LogHelper.OutputEnity(message -> {
try {
output.writeBoolean(true);
output.writeString(message, SerializeLimits.MAX_COMMAND);
} catch (IOException e) {
LogHelper.error(e);
}
}, LogHelper.OutputTypes.PLAIN);
LogHelper.addOutput(loutput);
try {
server.commandHandler.eval(cmd, false);
output.writeBoolean(false);
} finally {
LogHelper.removeOutput(loutput);
}
writeNoError(output);
}
}

View file

@ -1,154 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.OshiHWID;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.auth.hwid.HWIDException;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.auth.provider.AuthProviderResult;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.response.profile.ProfileByUUIDResponse;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.utils.helper.VerifyHelper;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
public final class AuthResponse extends Response {
private static String echo(int length) {
char[] chars = new char[length];
Arrays.fill(chars, '*');
return new String(chars);
}
public AuthResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
public static class AuthContext {
public AuthContext(long session, String login, int password_lenght, String customText, String client, String hwid, String ip, boolean isServerAuth) {
this.session = session;
this.login = login;
this.password_lenght = password_lenght;
this.customText = customText;
this.client = client;
this.hwid = hwid;
this.ip = ip;
this.isServerAuth = isServerAuth;
}
public long session;
public String login;
public int password_lenght; //Use AuthProvider for get password
public String client;
public String hwid;
public String customText;
public String ip;
public boolean isServerAuth;
}
@Override
public void reply() throws Exception {
String login = input.readString(SerializeLimits.MAX_LOGIN);
boolean isClient = input.readBoolean();
String client = null;
if (isClient)
client = input.readString(SerializeLimits.MAX_CLIENT);
String auth_id = input.readString(SerializeLimits.MAX_QUEUE_SIZE);
String hwid_str = input.readString(SerializeLimits.MAX_HWID_STR);
byte[] encryptedPassword = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
String customText = input.readString(SerializeLimits.MAX_CUSTOM_TEXT);
// Decrypt password
String password;
try {
password = IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey).
doFinal(encryptedPassword));
} catch (IllegalBlockSizeException | BadPaddingException ignored) {
requestError("Password decryption error");
return;
}
// Authenticate
debug("Login: '%s', Password: '%s'", login, echo(password.length()));
AuthProviderResult result;
AuthProviderPair pair;
if(auth_id.isEmpty()) pair = server.config.getAuthProviderPair();
else pair = server.config.getAuthProviderPair(auth_id);
if(pair == null) requestError("Auth type not found");
AuthProvider provider = pair.provider;
clientData.type = Client.Type.USER;
AuthContext context = new AuthContext(session, login, password.length(), customText, client, hwid_str, ip, false);
try {
server.authHookManager.preHook(context, clientData);
if (!clientData.checkSign) {
throw new AuthException("You must using checkLauncher");
}
provider.preAuth(login,password,customText,ip);
result = provider.auth(login, password, ip);
if (!VerifyHelper.isValidUsername(result.username)) {
AuthProvider.authError(String.format("Illegal result: '%s'", result.username));
return;
}
if (isClient) {
Collection<ClientProfile> profiles = server.getProfiles();
for (ClientProfile p : profiles) {
if (p.getTitle().equals(client)) {
if (!p.isWhitelistContains(login)) {
throw new AuthException(server.config.whitelistRejectString);
}
clientData.profile = p;
}
}
if (clientData.profile == null) {
throw new AuthException("Your profile is not found");
}
}
server.config.hwidHandler.check(OshiHWID.gson.fromJson(hwid_str, OshiHWID.class), result.username);
server.authHookManager.postHook(context, clientData);
} catch (AuthException | HWIDException e) {
if (e.getMessage() == null) LogHelper.error(e);
requestError(e.getMessage());
return;
} catch (Exception e) {
LogHelper.error(e);
requestError("Internal auth provider error");
return;
}
debug("Auth: '%s' -> '%s', '%s'", login, result.username, result.accessToken);
clientData.isAuth = true;
clientData.permissions = result.permissions;
clientData.username = result.username;
clientData.auth_id = auth_id;
clientData.updateAuth();
// Authenticate on server (and get UUID)
UUID uuid;
try {
uuid = pair.handler.auth(result);
} catch (AuthException e) {
requestError(e.getMessage());
return;
} catch (Exception e) {
LogHelper.error(e);
requestError("Internal auth handler error");
return;
}
String protectToken = server.config.protectHandler.generateSecureToken(context);
writeNoError(output);
// Write profile and UUID
ProfileByUUIDResponse.getProfile(server, uuid, result.username, client, clientData.auth.textureProvider).write(output);
output.writeASCII(result.accessToken, -SecurityHelper.TOKEN_STRING_LENGTH);
clientData.permissions.write(output);
output.writeString(protectToken, SerializeLimits.MAX_CUSTOM_TEXT);
}
}

View file

@ -1,98 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.auth.hwid.HWIDException;
import ru.gravit.launchserver.auth.provider.AuthProvider;
import ru.gravit.launchserver.auth.provider.AuthProviderResult;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.utils.helper.VerifyHelper;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.util.Arrays;
import java.util.Collection;
public final class AuthServerResponse extends Response {
private static String echo(int length) {
char[] chars = new char[length];
Arrays.fill(chars, '*');
return new String(chars);
}
public AuthServerResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws Exception {
String login = input.readString(SerializeLimits.MAX_LOGIN);
String client = input.readString(SerializeLimits.MAX_CLIENT);
String auth_id = input.readString(SerializeLimits.MAX_QUEUE_SIZE);
byte[] encryptedPassword = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
// Decrypt password
String password;
try {
password = IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey).
doFinal(encryptedPassword));
} catch (IllegalBlockSizeException | BadPaddingException ignored) {
requestError("ServerPassword decryption error");
return;
}
// Authenticate
debug("ServerLogin: '%s', Password: '%s'", login, echo(password.length()));
AuthProviderResult result;
AuthProviderPair pair;
if(auth_id.isEmpty()) pair = server.config.getAuthProviderPair();
else pair = server.config.getAuthProviderPair(auth_id);
if(pair == null) requestError("Auth type not found");
AuthProvider provider = pair.provider;
AuthResponse.AuthContext context = new AuthResponse.AuthContext(session, login, password.length(), null, client, null, ip, true);
try {
server.authHookManager.preHook(context, clientData);
result = provider.auth(login, password, ip);
if (!VerifyHelper.isValidUsername(result.username)) {
AuthProvider.authError(String.format("Illegal result: '%s'", result.username));
return;
}
Collection<ClientProfile> profiles = server.getProfiles();
for (ClientProfile p : profiles) {
if (p.getTitle().equals(client)) {
clientData.profile = p;
}
}
if (clientData.profile == null) {
throw new AuthException("Your profile is not found");
}
clientData.permissions = server.config.permissionsHandler.getPermissions(login);
if (!clientData.permissions.canServer) {
throw new AuthException("Your account cannot be a server");
}
clientData.type = Client.Type.SERVER;
clientData.username = result.username;
server.authHookManager.postHook(context, clientData);
} catch (AuthException | HWIDException e) {
requestError(e.getMessage());
return;
} catch (Exception e) {
LogHelper.error(e);
requestError("Internal auth provider error");
return;
}
debug("ServerAuth: '%s' -> '%s', '%s'", login, result.username, result.accessToken);
clientData.isAuth = true;
clientData.auth_id = auth_id;
clientData.updateAuth();
writeNoError(output);
clientData.permissions.write(output);
}
}

View file

@ -1,28 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
public class ChangeServerResponse extends Response {
public static boolean needChange = false;
public static String address;
public static int port;
public ChangeServerResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws Exception {
writeNoError(output);
output.writeBoolean(needChange);
//if true
if (needChange) {
output.writeString(address, 255);
output.writeInt(port);
}
}
}

View file

@ -1,53 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.response.profile.ProfileByUUIDResponse;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
import java.util.UUID;
public final class CheckServerResponse extends Response {
public CheckServerResponse(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 {
String username = VerifyHelper.verifyUsername(input.readString(SerializeLimits.MAX_LOGIN));
String serverID = VerifyHelper.verifyServerID(input.readASCII(41)); // With minus sign
String client = input.readString(SerializeLimits.MAX_CLIENT);
debug("Username: %s, Server ID: %s", username, serverID);
if (!clientData.isAuth || clientData.type != Client.Type.SERVER) {
requestError("Access denied");
return;
}
// Try check server with auth handler
UUID uuid;
try {
server.authHookManager.checkServerHook(username, serverID);
uuid = clientData.auth.handler.checkServer(username, serverID);
} catch (AuthException e) {
requestError(e.getMessage());
return;
} catch (Exception e) {
LogHelper.error(e);
requestError("Internal auth handler error");
return;
}
writeNoError(output);
// Write profile and UUID
output.writeBoolean(uuid != null);
if (uuid != null)
ProfileByUUIDResponse.getProfile(server, uuid, username, client, clientData.auth.textureProvider).write(output);
}
}

View file

@ -1,50 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
public final class JoinServerResponse extends Response {
public JoinServerResponse(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 {
String username = VerifyHelper.verifyUsername(input.readString(SerializeLimits.MAX_LOGIN));
String accessToken = SecurityHelper.verifyToken(input.readASCII(-SecurityHelper.TOKEN_STRING_LENGTH));
String serverID = VerifyHelper.verifyServerID(input.readASCII(SerializeLimits.MAX_SERVERID)); // With minus sign
if (!clientData.isAuth || clientData.type != Client.Type.USER) {
requestError("Access denied");
return;
}
// Try join server with auth handler
debug("Username: '%s', Access token: %s, Server ID: %s", username, accessToken, serverID);
boolean success;
try {
server.authHookManager.joinServerHook(username, accessToken, serverID);
success = clientData.auth.handler.joinServer(username, accessToken, serverID);
} catch (AuthException e) {
requestError(e.getMessage());
return;
} catch (Exception e) {
LogHelper.error(e);
requestError("Internal auth handler error");
return;
}
writeNoError(output);
// Write response
output.writeBoolean(success);
}
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.response.auth;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import java.util.Collection;
public class SetProfileResponse extends Response {
public SetProfileResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws Exception {
String client = input.readString(SerializeLimits.MAX_CLIENT);
if (!clientData.isAuth) requestError("You not auth");
Collection<ClientProfile> profiles = server.getProfiles();
for (ClientProfile p : profiles) {
if (p.getTitle().equals(client)) {
if (!p.isWhitelistContains(clientData.username)) {
requestError(server.config.whitelistRejectString);
return;
}
clientData.profile = p;
writeNoError(output);
output.writeBoolean(true);
break;
}
}
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.response.profile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
import java.util.Arrays;
public final class BatchProfileByUsernameResponse extends Response {
public BatchProfileByUsernameResponse(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 {
int length = input.readLength(SerializeLimits.MAX_BATCH_SIZE);
String[] usernames = new String[length];
String[] clients = new String[length];
for (int i = 0; i < usernames.length; i++) {
usernames[i] = VerifyHelper.verifyUsername(input.readString(64));
clients[i] = input.readString(SerializeLimits.MAX_CLIENT);
}
debug("Usernames: " + Arrays.toString(usernames));
// Respond with profiles array
for (int i = 0; i < usernames.length; i++)
ProfileByUsernameResponse.writeProfile(server, output, usernames[i], clients[i], clientData.auth);
}
}

View file

@ -1,62 +0,0 @@
package ru.gravit.launchserver.response.profile;
import ru.gravit.launcher.profiles.PlayerProfile;
import ru.gravit.launcher.profiles.Texture;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.texture.TextureProvider;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.UUID;
public final class ProfileByUUIDResponse extends Response {
public static PlayerProfile getProfile(LaunchServer server, UUID uuid, String username, String client, TextureProvider textureProvider) {
// Get skin texture
Texture skin;
try {
skin = textureProvider.getSkinTexture(uuid, username, client);
} catch (IOException e) {
LogHelper.error(new IOException(String.format("Can't get skin texture: '%s'", username), e));
skin = null;
}
// Get cloak texture
Texture cloak;
try {
cloak = textureProvider.getCloakTexture(uuid, username, client);
} catch (IOException e) {
LogHelper.error(new IOException(String.format("Can't get cloak texture: '%s'", username), e));
cloak = null;
}
// Return combined profile
return new PlayerProfile(uuid, username, skin, cloak);
}
public ProfileByUUIDResponse(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 {
UUID uuid = input.readUUID();
debug("UUID: " + uuid);
String client = input.readString(SerializeLimits.MAX_CLIENT);
// Verify has such profile
String username = clientData.auth.handler.uuidToUsername(uuid);
if (username == null) {
output.writeBoolean(false);
return;
}
// Write profile
output.writeBoolean(true);
getProfile(server, uuid, username, client, clientData.auth.textureProvider).write(output);
}
}

View file

@ -1,41 +0,0 @@
package ru.gravit.launchserver.response.profile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.auth.AuthProviderPair;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
import java.util.UUID;
public final class ProfileByUsernameResponse extends Response {
public static void writeProfile(LaunchServer server, HOutput output, String username, String client, AuthProviderPair pair) throws IOException {
UUID uuid = pair.handler.usernameToUUID(username);
if (uuid == null) {
output.writeBoolean(false);
return;
}
// Write profile
output.writeBoolean(true);
ProfileByUUIDResponse.getProfile(server, uuid, username, client, pair.textureProvider).write(output);
}
public ProfileByUsernameResponse(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 {
String username = VerifyHelper.verifyUsername(input.readString(64));
debug("Username: " + username);
String client = input.readString(SerializeLimits.MAX_CLIENT);
// Write response
writeProfile(server, output, username, client, clientData.auth);
}
}

View file

@ -1,38 +0,0 @@
package ru.gravit.launchserver.response.update;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.Collection;
public final class ProfilesResponse extends Response {
public ProfilesResponse(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
input.readBoolean();
if (clientData.type == Client.Type.USER && !clientData.checkSign) {
LogHelper.warning("User session: %d ip %s try get profiles", session, ip);
requestError("Access denied");
return;
}
writeNoError(output);
Collection<ClientProfile> profiles = server.getProfiles();
output.writeLength(profiles.size(), 0);
for (ClientProfile profile : profiles) {
LogHelper.debug("Writted profile: %s", profile.getTitle());
output.writeString(Launcher.gson.toJson(profile), 0);
}
}
}

View file

@ -1,28 +0,0 @@
package ru.gravit.launchserver.response.update;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import java.util.Map.Entry;
import java.util.Set;
public final class UpdateListResponse extends Response {
public UpdateListResponse(LaunchServer server, long session, HInput input, HOutput output, String ip, Client clientData) {
super(server, session, input, output, ip, clientData);
}
@Override
public void reply() throws Exception {
Set<Entry<String, SignedObjectHolder<HashedDir>>> updateDirs = server.getUpdateDirs();
// Write all update dirs names
output.writeLength(updateDirs.size(), 0);
for (Entry<String, SignedObjectHolder<HashedDir>> entry : updateDirs)
output.writeString(entry.getKey(), 255);
}
}

View file

@ -1,140 +0,0 @@
package ru.gravit.launchserver.response.update;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.hasher.HashedEntry;
import ru.gravit.launcher.hasher.HashedEntry.Type;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.request.UpdateAction;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.SerializeLimits;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.IOHelper;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Deque;
import java.util.LinkedList;
import java.util.zip.DeflaterOutputStream;
public final class UpdateResponse extends Response {
public UpdateResponse(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 {
// Read update dir name
String updateDirName = IOHelper.verifyFileName(input.readString(255));
SignedObjectHolder<HashedDir> hdir = server.getUpdateDir(updateDirName);
if (hdir == null) {
requestError(String.format("Unknown update dir: %s", updateDirName));
return;
}
if (!clientData.isAuth || clientData.type != Client.Type.USER || clientData.profile == null) {
requestError("Access denied");
return;
}
if (!clientData.permissions.canAdmin) {
for (ClientProfile p : server.getProfiles()) {
if (!clientData.profile.getTitle().equals(p.getTitle())) continue;
if (!p.isWhitelistContains(clientData.username)) {
requestError("You don't download this folder");
return;
}
}
}
writeNoError(output);
// Write update hdir
debug("Update dir: '%s'", updateDirName);
hdir.write(output);
output.writeBoolean(server.config.compress);
output.flush();
// Prepare variables for actions queue
Path dir = server.updatesDir.resolve(updateDirName);
Deque<HashedDir> dirStack = new LinkedList<>();
dirStack.add(hdir.object);
// Perform update
// noinspection IOResourceOpenedButNotSafelyClosed
OutputStream fileOutput = server.config.compress ? new DeflaterOutputStream(output.stream, IOHelper.newDeflater(), IOHelper.BUFFER_SIZE, true) : output.stream;
UpdateAction[] actionsSlice = new UpdateAction[SerializeLimits.MAX_QUEUE_SIZE];
loop:
while (true) {
// Read actions slice
int length = input.readLength(actionsSlice.length);
for (int i = 0; i < length; i++)
actionsSlice[i] = new UpdateAction(input);
// Perform actions
for (int i = 0; i < length; i++) {
UpdateAction action = actionsSlice[i];
switch (action.type) {
case CD:
debug("CD '%s'", action.name);
// Get hashed dir (for validation)
HashedEntry hSubdir = dirStack.getLast().getEntry(action.name);
if (hSubdir == null || hSubdir.getType() != Type.DIR)
throw new IOException("Unknown hashed dir: " + action.name);
dirStack.add((HashedDir) hSubdir);
// Resolve dir
dir = dir.resolve(action.name);
break;
case GET:
debug("GET '%s'", action.name);
// Get hashed file (for validation)
HashedEntry hFile = dirStack.getLast().getEntry(action.name);
if (hFile == null || hFile.getType() != Type.FILE)
throw new IOException("Unknown hashed file: " + action.name);
// Resolve and write file
Path file = dir.resolve(action.name);
if (IOHelper.readAttributes(file).size() != hFile.size()) {
fileOutput.write(0x0);
fileOutput.flush();
throw new IOException("Unknown hashed file: " + action.name);
}
fileOutput.write(0xFF);
try (InputStream fileInput = IOHelper.newInput(file)) {
IOHelper.transfer(fileInput, fileOutput);
}
break;
case CD_BACK:
debug("CD ..");
// Remove from hashed dir stack
dirStack.removeLast();
if (dirStack.isEmpty())
throw new IOException("Empty hDir stack");
// Get parent
dir = dir.getParent();
break;
case FINISH:
break loop;
default:
throw new AssertionError(String.format("Unsupported action type: '%s'", action.type.name()));
}
}
// Flush all actions
fileOutput.flush();
}
// So we've updated :)
if (fileOutput instanceof DeflaterOutputStream)
((DeflaterOutputStream) fileOutput).finish();
}
}

View file

@ -14,8 +14,10 @@ public class Client {
public ClientProfile profile;
public boolean isAuth;
public boolean checkSign;
public boolean isSecure;
public ClientPermissions permissions;
public String username;
public String verifyToken;
public LogHelper.OutputEnity logOutput;
public transient AuthProviderPair auth;
@ -34,8 +36,8 @@ public Client(long session) {
public void up() {
timestamp = System.currentTimeMillis();
}
public void updateAuth()
{
public void updateAuth() {
if (!isAuth) return;
if (auth_id.isEmpty()) auth = LaunchServer.server.config.getAuthProviderPair();
else auth = LaunchServer.server.config.getAuthProviderPair(auth_id);

View file

@ -5,9 +5,9 @@
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.legacy.Response;
import ru.gravit.launchserver.manangers.SessionManager;
import ru.gravit.launchserver.manangers.hook.SocketHookManager;
import ru.gravit.launchserver.response.Response;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;

View file

@ -1,82 +0,0 @@
package ru.gravit.launchserver.socket.websocket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static io.netty.handler.codec.rtsp.RtspResponseStatuses.NOT_FOUND;
public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private final String websocketPath;
public WebSocketIndexPageHandler(String websocketPath) {
this.websocketPath = websocketPath;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
// Handle a bad request.
if (!req.decoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the index page
if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, websocketPath);
ByteBuf content = WebSocketServerIndexPage.getContent(webSocketLocation);
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
res.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
HttpUtil.setContentLength(res, content.readableBytes());
sendHttpResponse(ctx, req, res);
} else {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response getStatus code is not OK (200).
if (res.status().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
HttpUtil.setContentLength(res, res.content().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
String protocol = "ws";
if (cp.get(SslHandler.class) != null) {
// SSL in use so use Secure WebSockets
protocol = "wss";
}
return protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path;
}
}

View file

@ -1,61 +0,0 @@
package ru.gravit.launchserver.socket.websocket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
public final class WebSocketServerIndexPage {
private static final String NEWLINE = "\r\n";
public static ByteBuf getContent(String webSocketLocation) {
return Unpooled.copiedBuffer(
"<html><head><title>Web Socket Test</title></head>" + NEWLINE +
"<body>" + NEWLINE +
"<script type=\"text/javascript\">" + NEWLINE +
"var socket;" + NEWLINE +
"if (!window.WebSocket) {" + NEWLINE +
" window.WebSocket = window.MozWebSocket;" + NEWLINE +
'}' + NEWLINE +
"if (window.WebSocket) {" + NEWLINE +
" socket = new WebSocket(\"" + webSocketLocation + "\");" + NEWLINE +
" socket.onmessage = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = ta.value + '\\n' + event.data" + NEWLINE +
" };" + NEWLINE +
" socket.onopen = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = \"Web Socket opened!\";" + NEWLINE +
" };" + NEWLINE +
" socket.onclose = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = ta.value + \"Web Socket closed\"; " + NEWLINE +
" };" + NEWLINE +
"} else {" + NEWLINE +
" alert(\"Your browser does not support Web Socket.\");" + NEWLINE +
'}' + NEWLINE +
NEWLINE +
"function send(message) {" + NEWLINE +
" if (!window.WebSocket) { return; }" + NEWLINE +
" if (socket.readyState == WebSocket.OPEN) {" + NEWLINE +
" socket.send(message);" + NEWLINE +
" } else {" + NEWLINE +
" alert(\"The socket is not open.\");" + NEWLINE +
" }" + NEWLINE +
'}' + NEWLINE +
"</script>" + NEWLINE +
"<form onsubmit=\"return false;\">" + NEWLINE +
"<input type=\"text\" name=\"message\" value=\"Hello, World!\"/>" +
"<input type=\"button\" value=\"Send Web Socket Data\"" + NEWLINE +
" onclick=\"send(this.form.message.value)\" />" + NEWLINE +
"<h3>Output</h3>" + NEWLINE +
"<textarea id=\"responseText\" style=\"width:500px;height:300px;\"></textarea>" + NEWLINE +
"</form>" + NEWLINE +
"</body>" + NEWLINE +
"</html>" + NEWLINE, CharsetUtil.US_ASCII);
}
private WebSocketServerIndexPage() {
// Unused
}
}

View file

@ -1,11 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
public interface JsonResponseInterface {
String getType();
void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception;
}

View file

@ -1,17 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
public class SimpleResponse implements JsonResponseInterface {
@Override
public String getType() {
return null;
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) {
}
}

View file

@ -1,32 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.admin;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.ExecCommandRequestEvent;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
public class ExecCommandResponse implements JsonResponseInterface {
public String cmd;
@Override
public String getType() {
return "cmdExec";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) {
if (!client.isAuth) {
service.sendObject(ctx, new ErrorRequestEvent("Access denied"));
return;
}
if (!client.permissions.canAdmin) {
service.sendObject(ctx, new ErrorRequestEvent("Access denied"));
return;
}
LaunchServer.server.commandHandler.eval(cmd, false);
service.sendObject(ctx, new ExecCommandRequestEvent(true));
}
}

View file

@ -1,38 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.auth;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.JoinServerRequestEvent;
import ru.gravit.launchserver.auth.AuthException;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import ru.gravit.utils.helper.LogHelper;
public class JoinServerResponse implements JsonResponseInterface {
public String serverID;
public String accessToken;
public String username;
@Override
public String getType() {
return "joinServer";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) {
boolean success;
try {
success = client.auth.handler.joinServer(username, accessToken, serverID);
} catch (AuthException e) {
service.sendObject(ctx, new ErrorRequestEvent(e.getMessage()));
return;
} catch (Exception e) {
LogHelper.error(e);
service.sendObject(ctx, new ErrorRequestEvent("Internal authHandler error"));
return;
}
service.sendObject(ctx, new JoinServerRequestEvent(success));
}
}

View file

@ -1,29 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.auth;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.ProfilesRequestEvent;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import java.util.List;
public class ProfilesResponse implements JsonResponseInterface {
@Override
public String getType() {
return "profiles";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception {
if(!client.checkSign)
{
service.sendObject(ctx, new ErrorRequestEvent("Access denied"));
return;
}
service.sendObject(ctx, new ProfilesRequestEvent((List<ClientProfile>) LaunchServer.server.getProfiles()));
}
}

View file

@ -1,42 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.auth;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.SetProfileRequestEvent;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import java.util.Collection;
public class SetProfileResponse implements JsonResponseInterface {
public String client;
@Override
public String getType() {
return "setProfile";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception {
if(!client.isAuth)
{
service.sendObject(ctx, new ErrorRequestEvent("Access denied"));
return;
}
Collection<ClientProfile> profiles = LaunchServer.server.getProfiles();
for (ClientProfile p : profiles) {
if (p.getTitle().equals(this.client)) {
if (!p.isWhitelistContains(client.username)) {
service.sendObject(ctx, new ErrorRequestEvent(LaunchServer.server.config.whitelistRejectString));
return;
}
client.profile = p;
service.sendObject(ctx, new SetProfileRequestEvent(p));
return;
}
}
service.sendObject(ctx, new ErrorRequestEvent("Profile not found"));
}
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.profile;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.BatchProfileByUsernameRequestEvent;
import ru.gravit.launcher.profiles.PlayerProfile;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import java.util.UUID;
public class BatchProfileByUsername implements JsonResponseInterface {
class Entry
{
String username;
String client;
}
Entry[] list;
@Override
public String getType() {
return "batchProfileByUsername";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception {
BatchProfileByUsernameRequestEvent result = new BatchProfileByUsernameRequestEvent();
result.playerProfiles = new PlayerProfile[list.length];
for(int i=0;i<list.length;++i)
{
UUID uuid = client.auth.handler.usernameToUUID(list[i].username);
result.playerProfiles[i] = ProfileByUUIDResponse.getProfile(LaunchServer.server,uuid,list[i].username,list[i].client, client.auth.textureProvider);
}
service.sendObject(ctx, result);
}
}

View file

@ -1,27 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.profile;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import java.util.UUID;
import static ru.gravit.launchserver.socket.websocket.json.profile.ProfileByUUIDResponse.getProfile;
public class ProfileByUsername implements JsonResponseInterface {
String username;
String client;
@Override
public String getType() {
return "profileByUsername";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception {
UUID uuid = client.auth.handler.usernameToUUID(username);
service.sendObject(ctx, new ProfileByUsernameRequestEvent(getProfile(LaunchServer.server,uuid,username,this.client, client.auth.textureProvider)));
}
}

View file

@ -1,35 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.update;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.UpdateListRequestEvent;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
import java.util.HashSet;
import java.util.Map;
public class UpdateListResponse implements JsonResponseInterface {
@Override
public String getType() {
return "updateList";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) {
if (!client.isAuth) {
service.sendObject(ctx, new ErrorRequestEvent("Access denied"));
return;
}
HashSet<String> set = new HashSet<>();
for(Map.Entry<String, SignedObjectHolder<HashedDir>> entry : LaunchServer.server.updatesDirMap.entrySet())
set.add(entry.getKey());
service.sendObject(ctx, new UpdateListRequestEvent(set));
}
}

View file

@ -1,36 +0,0 @@
package ru.gravit.launchserver.socket.websocket.json.update;
import io.netty.channel.ChannelHandlerContext;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.events.request.UpdateRequestEvent;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.launchserver.socket.websocket.WebSocketService;
import ru.gravit.launchserver.socket.websocket.json.JsonResponseInterface;
public class UpdateResponse implements JsonResponseInterface {
public String dir;
@Override
public String getType() {
return "update";
}
@Override
public void execute(WebSocketService service, ChannelHandlerContext ctx, Client client) throws Exception {
if (!client.isAuth || client.type != Client.Type.USER || client.profile == null) {
service.sendObject(ctx,new ErrorRequestEvent("Access denied"));
return;
}
if (!client.permissions.canAdmin) {
for (ClientProfile p : LaunchServer.server.getProfiles()) {
if (!client.profile.getTitle().equals(p.getTitle())) continue;
if (!p.isWhitelistContains(client.username)) {
service.sendObject(ctx,new ErrorRequestEvent("You don't download this folder"));
return;
}
}
}
service.sendObject(ctx,new UpdateRequestEvent(LaunchServer.server.updatesDirMap.get(dir).object));
}
}

View file

@ -1,52 +0,0 @@
package ru.gravit.launchserver.texture;
import ru.gravit.launcher.profiles.Texture;
import ru.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public abstract class TextureProvider implements AutoCloseable {
private static final Map<String, Class<? extends TextureProvider>> TEXTURE_PROVIDERS = new ConcurrentHashMap<>(2);
private static boolean registredProv = false;
public static void registerProvider(String name, Class<? extends TextureProvider> adapter) {
VerifyHelper.putIfAbsent(TEXTURE_PROVIDERS, name, Objects.requireNonNull(adapter, "adapter"),
String.format("Texture provider has been already registered: '%s'", name));
}
public static void registerProviders() {
if (!registredProv) {
registerProvider("null", NullTextureProvider.class);
registerProvider("void", VoidTextureProvider.class);
// Auth providers that doesn't do nothing :D
registerProvider("request", RequestTextureProvider.class);
registredProv = true;
}
}
@Override
public abstract void close() throws IOException;
public abstract Texture getCloakTexture(UUID uuid, String username, String client) throws IOException;
public abstract Texture getSkinTexture(UUID uuid, String username, String client) throws IOException;
public static Class<? extends TextureProvider> getProviderClass(String name) {
return TEXTURE_PROVIDERS.get(name);
}
public static String getProviderName(Class<? extends TextureProvider> clazz) {
for (Map.Entry<String, Class<? extends TextureProvider>> e : TEXTURE_PROVIDERS.entrySet()) {
if (e.getValue().equals(clazz)) return e.getKey();
}
return null;
}
}

View file

@ -0,0 +1,60 @@
package ru.gravit.launchserver.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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.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.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.websocket.fileserver.FileServerHandler;
import java.net.InetSocketAddress;
public class LauncherNettyServer implements AutoCloseable {
public final ServerBootstrap serverBootstrap;
public final EventLoopGroup bossGroup;
public final EventLoopGroup workerGroup;
private static final String WEBSOCKET_PATH = "/api";
public LauncherNettyServer() {
LaunchServer.NettyConfig config = LaunchServer.server.config.netty;
bossGroup = new NioEventLoopGroup(config.performance.bossThread);
workerGroup = new NioEventLoopGroup(config.performance.workerThread);
serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
public void initChannel(NioSocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
//p.addLast(new LoggingHandler(LogLevel.INFO));
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
pipeline.addLast(new FileServerHandler(LaunchServer.server.updatesDir, true));
pipeline.addLast(new WebSocketFrameHandler());
}
});
}
public ChannelFuture bind(InetSocketAddress address)
{
return serverBootstrap.bind(address);
}
@Override
public void close() {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}

View file

@ -1,26 +1,9 @@
package ru.gravit.launchserver.socket;
package ru.gravit.launchserver.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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.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.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import ru.gravit.launcher.ssl.LauncherKeyStore;
import ru.gravit.launcher.ssl.LauncherTrustManager;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.fileserver.FileServerHandler;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.websocket.WebSocketFrameHandler;
import ru.gravit.utils.helper.CommonHelper;
import ru.gravit.launchserver.legacy.Response;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.VerifyHelper;
@ -33,30 +16,24 @@
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.security.*;
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.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@SuppressWarnings({"unused", "rawtypes"})
public final class NettyServerSocketHandler implements Runnable, AutoCloseable {
private static final String WEBSOCKET_PATH = "/api";
private static SSLServerSocketFactory ssf;
private static final ThreadFactory THREAD_FACTORY = r -> CommonHelper.newThread("Network Thread", true, r);
public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
public static LauncherNettyServer nettyServer;
private final AtomicReference<ServerSocket> serverSocket = new AtomicReference<>();
private final ExecutorService threadPool = Executors.newCachedThreadPool(THREAD_FACTORY);
// API
private final Map<String, Response.Factory> customResponses = new ConcurrentHashMap<>(2);
@ -116,45 +93,21 @@ public void run() {
}*/
//System.setProperty( "javax.net.ssl.keyStore","keystore");
//System.setProperty( "javax.net.ssl.keyStorePassword","PSP1000");
try {
/*try {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
} catch (IOException e) {
e.printStackTrace();
}
}*/
LogHelper.info("Starting server socket thread");
//SSLEngine engine = sc.createSSLEngine();
//engine.setUseClientMode(false);
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
WebSocketFrameHandler.server = LaunchServer.server;
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
public void initChannel(NioSocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
//p.addLast(new LoggingHandler(LogLevel.INFO));
System.out.println("P!");
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
pipeline.addLast(new FileServerHandler(LaunchServer.server.updatesDir, true));
pipeline.addLast(new WebSocketFrameHandler());
}
});
ChannelFuture f = b.bind(new InetSocketAddress(LaunchServer.server.config.netty.port)).sync(); //TEST ONLY!
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
nettyServer = new LauncherNettyServer();
for(LaunchServer.NettyBindAddress address : LaunchServer.server.config.netty.binds)
{
nettyServer.bind(new InetSocketAddress(address.address, address.port));
}
/*
try (SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket()) {

View file

@ -1,17 +1,18 @@
package ru.gravit.launchserver.socket.websocket;
package ru.gravit.launchserver.websocket;
import com.google.gson.GsonBuilder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.concurrent.GlobalEventExecutor;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.LogHelper;
import java.util.concurrent.TimeUnit;
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
public static LaunchServer server;
public static GsonBuilder builder = new GsonBuilder();
@ -21,12 +22,19 @@ public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocket
static {
service.registerResponses();
}
public void setClient(Client client)
{
this.client = client;
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
LogHelper.debug("New client %s", IOHelper.getIP(ctx.channel().remoteAddress()));
client = new Client(0);
service.registerClient(ctx.channel());
ctx.executor().schedule(() -> {
ctx.channel().writeAndFlush(new PingWebSocketFrame());
}, 30L, TimeUnit.SECONDS);
}
@Override
@ -35,6 +43,16 @@ protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
if (frame instanceof TextWebSocketFrame) {
service.process(ctx, (TextWebSocketFrame) frame, client);
} else if ((frame instanceof PingWebSocketFrame)) {
frame.content().retain();
ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content()));
//return;
}
else if ((frame instanceof PongWebSocketFrame)) {
LogHelper.dev("WebSocket Client received pong");
}
else if ((frame instanceof CloseWebSocketFrame)) {
ctx.channel().close();
} else {
String message = "unsupported frame type: " + frame.getClass().getName();
throw new UnsupportedOperationException(message);

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