Merge branch 'release/5.1.0'

This commit is contained in:
Gravit 2020-02-21 11:32:28 +07:00
commit 9e9153b124
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
412 changed files with 6475 additions and 9586 deletions

View file

@ -11,7 +11,7 @@ stages:
- test - test
build: build:
image: frekele/java image: gradle:jdk11
stage: build stage: build
before_script: before_script:
- apt-get -y update - apt-get -y update
@ -30,6 +30,8 @@ build:
- mv LaunchServer.jar ../../../artifacts/LaunchServer.jar - mv LaunchServer.jar ../../../artifacts/LaunchServer.jar
- cd ../../../ServerWrapper/build/libs - cd ../../../ServerWrapper/build/libs
- mv ServerWrapper.jar ../../../artifacts/ServerWrapper.jar - mv ServerWrapper.jar ../../../artifacts/ServerWrapper.jar
- cd ../../../LauncherAuthlib/build/libs
- mv LauncherAuthlib.jar ../../../artifacts/LauncherAuthlib.jar
- cd ../../../ - cd ../../../
- mv modules/*_module/build/libs/*.jar artifacts/modules - mv modules/*_module/build/libs/*.jar artifacts/modules
- mv modules/*_swmodule/build/libs/*.jar artifacts/modules - mv modules/*_swmodule/build/libs/*.jar artifacts/modules
@ -43,7 +45,7 @@ build:
- artifacts - artifacts
test: test:
image: frekele/java image: gradle:jdk11
stage: test stage: test
script: script:
- ./gradlew check - ./gradlew check

View file

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

View file

@ -71,26 +71,26 @@ task cleanjar(type: Jar, dependsOn: jar) {
dependencies { dependencies {
pack project(':LauncherAPI') pack project(':LauncherAPI')
bundle 'org.ow2.asm:asm-commons:7.1' bundle 'org.ow2.asm:asm-commons:7.3.1'
bundle 'mysql:mysql-connector-java:8.0.16' bundle 'mysql:mysql-connector-java:8.0.16'
bundle 'org.postgresql:postgresql:42.2.6' bundle 'org.postgresql:postgresql:42.2.6'
bundle 'org.jline:jline:3.11.0' bundle 'org.jline:jline:3.13.1'
bundle 'org.jline:jline-reader:3.11.0' bundle 'org.jline:jline-reader:3.13.1'
bundle 'org.jline:jline-terminal:3.11.0' bundle 'org.jline:jline-terminal:3.13.1'
bundle 'net.sf.proguard:proguard-base:6.1.0' bundle 'net.sf.proguard:proguard-base:6.2.0'
bundle 'org.fusesource.jansi:jansi:1.18' bundle 'org.fusesource.jansi:jansi:1.18'
bundle 'commons-io:commons-io:2.6' bundle 'commons-io:commons-io:2.6'
bundle 'commons-codec:commons-codec:1.12' bundle 'commons-codec:commons-codec:1.12'
bundle 'org.javassist:javassist:3.25.0-GA' bundle 'org.apache.httpcomponents:httpclient:4.5.10'
bundle 'io.netty:netty-all:4.1.36.Final' bundle 'io.netty:netty-all:4.1.43.Final'
bundle 'org.hibernate:hibernate-core:5.4.4.Final' bundle 'org.hibernate:hibernate-core:5.4.9.Final'
bundle 'org.bouncycastle:bcpkix-jdk15on:1.61' bundle 'org.bouncycastle:bcpkix-jdk15on:1.61'
bundle 'org.slf4j:slf4j-simple:1.7.25' bundle 'org.slf4j:slf4j-simple:1.7.25'
bundle 'org.slf4j:slf4j-api:1.7.25' bundle 'org.slf4j:slf4j-api:1.7.25'
hikari 'io.micrometer:micrometer-core:1.0.6' hikari 'io.micrometer:micrometer-core:1.0.6'
hikari('com.zaxxer:HikariCP:3.2.0') { hikari('com.zaxxer:HikariCP:3.4.1') {
exclude group: 'javassist' exclude group: 'javassist'
exclude group: 'io.micrometer' exclude group: 'io.micrometer'
exclude group: 'org.slf4j' exclude group: 'org.slf4j'

View file

@ -1,38 +1,7 @@
package pro.gravit.launchserver; package pro.gravit.launchserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.CRC32;
import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OperatorCreationException;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.NeedGarbageCollection; import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
@ -41,12 +10,7 @@
import pro.gravit.launcher.modules.events.ClosePhase; import pro.gravit.launcher.modules.events.ClosePhase;
import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.binary.EXEL4JLauncherBinary; import pro.gravit.launchserver.binary.*;
import pro.gravit.launchserver.binary.EXELauncherBinary;
import pro.gravit.launchserver.binary.JARLauncherBinary;
import pro.gravit.launchserver.binary.LauncherBinary;
import pro.gravit.launchserver.binary.ProguardConf;
import pro.gravit.launchserver.binary.SimpleEXELauncherBinary;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.manangers.CertificateManager; import pro.gravit.launchserver.manangers.CertificateManager;
@ -54,7 +18,6 @@
import pro.gravit.launchserver.manangers.ReconfigurableManager; import pro.gravit.launchserver.manangers.ReconfigurableManager;
import pro.gravit.launchserver.manangers.SessionManager; import pro.gravit.launchserver.manangers.SessionManager;
import pro.gravit.launchserver.manangers.hook.AuthHookManager; import pro.gravit.launchserver.manangers.hook.AuthHookManager;
import pro.gravit.launchserver.manangers.hook.BuildHookManager;
import pro.gravit.launchserver.modules.events.LaunchServerFullInitEvent; import pro.gravit.launchserver.modules.events.LaunchServerFullInitEvent;
import pro.gravit.launchserver.modules.events.LaunchServerInitPhase; import pro.gravit.launchserver.modules.events.LaunchServerInitPhase;
import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase; import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase;
@ -69,41 +32,58 @@
import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurable { public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurable {
public enum ReloadType public enum ReloadType {
{
NO_AUTH, NO_AUTH,
NO_COMPONENTS, NO_COMPONENTS,
FULL FULL
} }
public enum LaunchServerEnv
{ public enum LaunchServerEnv {
TEST, TEST,
DEV, DEV,
DEBUG, DEBUG,
PRODUCTION PRODUCTION
} }
public interface LaunchServerConfigManager
{ public interface LaunchServerConfigManager {
LaunchServerConfig readConfig() throws IOException; LaunchServerConfig readConfig() throws IOException;
LaunchServerRuntimeConfig readRuntimeConfig() throws IOException; LaunchServerRuntimeConfig readRuntimeConfig() throws IOException;
void writeConfig(LaunchServerConfig config) throws IOException; void writeConfig(LaunchServerConfig config) throws IOException;
void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException; void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException;
} }
public void reload(ReloadType type) throws Exception { public void reload(ReloadType type) throws Exception {
config.close(type); config.close(type);
AuthProviderPair[] pairs = null; Map<String, AuthProviderPair> pairs = null;
if(type.equals(ReloadType.NO_AUTH)) if (type.equals(ReloadType.NO_AUTH)) {
{
pairs = config.auth; pairs = config.auth;
} }
LogHelper.info("Reading LaunchServer config file"); LogHelper.info("Reading LaunchServer config file");
config = launchServerConfigManager.readConfig(); config = launchServerConfigManager.readConfig();
config.setLaunchServer(this); config.setLaunchServer(this);
if(type.equals(ReloadType.NO_AUTH)) if (type.equals(ReloadType.NO_AUTH)) {
{
config.auth = pairs; config.auth = pairs;
} }
config.verify(); config.verify();
@ -138,13 +118,11 @@ public Map<String, Command> getCommands() {
SubCommand reload = new SubCommand() { SubCommand reload = new SubCommand() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
if(args.length == 0) if (args.length == 0) {
{
reload(ReloadType.FULL); reload(ReloadType.FULL);
return; return;
} }
switch (args[0]) switch (args[0]) {
{
case "full": case "full":
reload(ReloadType.FULL); reload(ReloadType.FULL);
break; break;
@ -155,7 +133,7 @@ public void invoke(String... args) throws Exception {
reload(ReloadType.NO_COMPONENTS); reload(ReloadType.NO_COMPONENTS);
break; break;
default: default:
reload(ReloadType.FULL);; reload(ReloadType.FULL);
break; break;
} }
} }
@ -165,7 +143,7 @@ public void invoke(String... args) throws Exception {
} }
private final class ProfilesFileVisitor extends SimpleFileVisitor<Path> { private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
private final Collection<ClientProfile> result; private final Collection<ClientProfile> result;
private ProfilesFileVisitor(Collection<ClientProfile> result) { private ProfilesFileVisitor(Collection<ClientProfile> result) {
@ -217,17 +195,17 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
// Server config // Server config
public LaunchServerConfig config; public LaunchServerConfig config;
public LaunchServerRuntimeConfig runtime; public final LaunchServerRuntimeConfig runtime;
public final RSAPublicKey publicKey; public final ECPublicKey publicKey;
public final RSAPrivateKey privateKey; public final ECPrivateKey privateKey;
// Launcher binary // Launcher binary
public final JARLauncherBinary launcherBinary; public final JARLauncherBinary launcherBinary;
public Class<? extends LauncherBinary> launcherEXEBinaryClass; public final Class<? extends LauncherBinary> launcherEXEBinaryClass;
public final LauncherBinary launcherEXEBinary; public final LauncherBinary launcherEXEBinary;
// HWID ban + anti-brutforce // HWID ban + anti-brutforce
@ -247,9 +225,6 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
public final CertificateManager certificateManager; public final CertificateManager certificateManager;
public final BuildHookManager buildHookManager;
public final ProguardConf proguardConf; public final ProguardConf proguardConf;
@ -265,21 +240,29 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
public final Timer taskPool; public final Timer taskPool;
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null; public static final Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
public static class LaunchServerDirectories public static class LaunchServerDirectories {
{ public static final String UPDATES_NAME = "updates", PROFILES_NAME = "profiles",
TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries",
LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile";
public Path updatesDir; public Path updatesDir;
public Path profilesDir; public Path profilesDir;
public Path launcherLibrariesDir;
public Path launcherLibrariesCompileDir;
public Path dir; public Path dir;
public void collect() public Path trustStore;
{
if(updatesDir == null) updatesDir = dir.resolve("updates"); public void collect() {
if(profilesDir == null) profilesDir = dir.resolve("profiles"); if (updatesDir == null) updatesDir = dir.resolve(UPDATES_NAME);
if (profilesDir == null) profilesDir = dir.resolve(PROFILES_NAME);
if (trustStore == null) trustStore = dir.resolve(TRUSTSTORE_NAME);
if (launcherLibrariesDir == null) launcherLibrariesDir = dir.resolve(LAUNCHERLIBRARIES_NAME);
if (launcherLibrariesCompileDir == null) launcherLibrariesCompileDir = dir.resolve(LAUNCHERLIBRARIESCOMPILE_NAME);
} }
} }
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, RSAPublicKey publicKey, RSAPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException { public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler, CertificateManager certificateManager) throws IOException {
this.dir = directories.dir; this.dir = directories.dir;
this.env = env; this.env = env;
this.config = config; this.config = config;
@ -291,9 +274,10 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
this.privateKey = privateKey; this.privateKey = privateKey;
this.commandHandler = commandHandler; this.commandHandler = commandHandler;
this.runtime = runtimeConfig; this.runtime = runtimeConfig;
this.certificateManager = certificateManager;
taskPool = new Timer("Timered task worker thread", true); taskPool = new Timer("Timered task worker thread", true);
launcherLibraries = dir.resolve("launcher-libraries"); launcherLibraries = directories.launcherLibrariesDir;
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile"); launcherLibrariesCompile = directories.launcherLibrariesCompileDir;
config.setLaunchServer(this); config.setLaunchServer(this);
@ -306,9 +290,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
modulesManager.invokeEvent(new NewLaunchServerInstanceEvent(this)); modulesManager.invokeEvent(new NewLaunchServerInstanceEvent(this));
// Print keypair fingerprints // Print keypair fingerprints
CRC32 crc = new CRC32();
crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF?
LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue());
// Load class bindings. // Load class bindings.
launcherEXEBinaryClass = defaultLauncherEXEBinaryClass; launcherEXEBinaryClass = defaultLauncherEXEBinaryClass;
@ -325,25 +306,19 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
} }
// build hooks, anti-brutforce and other // build hooks, anti-brutforce and other
buildHookManager = new BuildHookManager();
proguardConf = new ProguardConf(this); proguardConf = new ProguardConf(this);
sessionManager = new SessionManager(); sessionManager = new SessionManager();
mirrorManager = new MirrorManager(); mirrorManager = new MirrorManager();
reconfigurableManager = new ReconfigurableManager(); reconfigurableManager = new ReconfigurableManager();
authHookManager = new AuthHookManager(); authHookManager = new AuthHookManager();
configManager = new ConfigManager(); configManager = new ConfigManager();
certificateManager = new CertificateManager();
//Generate or set new Certificate API //Generate or set new Certificate API
certificateManager.orgName = config.projectName; certificateManager.orgName = config.projectName;
if(config.certificate != null && config.certificate.enabled) if (config.certificate != null && config.certificate.enabled) {
{ if (IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile)) {
if(IOHelper.isFile(caCertFile) && IOHelper.isFile(caKeyFile))
{
certificateManager.ca = certificateManager.readCertificate(caCertFile); certificateManager.ca = certificateManager.readCertificate(caCertFile);
certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile); certificateManager.caKey = certificateManager.readPrivateKey(caKeyFile);
} } else {
else
{
try { try {
certificateManager.generateCA(); certificateManager.generateCA();
certificateManager.writeCertificate(caCertFile, certificateManager.ca); certificateManager.writeCertificate(caCertFile, certificateManager.ca);
@ -352,13 +327,10 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
LogHelper.error(e); LogHelper.error(e);
} }
} }
if(IOHelper.isFile(serverCertFile) && IOHelper.isFile(serverKeyFile)) if (IOHelper.isFile(serverCertFile) && IOHelper.isFile(serverKeyFile)) {
{
certificateManager.server = certificateManager.readCertificate(serverCertFile); certificateManager.server = certificateManager.readCertificate(serverCertFile);
certificateManager.serverKey = certificateManager.readPrivateKey(serverKeyFile); certificateManager.serverKey = certificateManager.readPrivateKey(serverKeyFile);
} } else {
else
{
try { try {
KeyPair pair = certificateManager.generateKeyPair(); KeyPair pair = certificateManager.generateKeyPair();
certificateManager.server = certificateManager.generateCertificate(config.projectName.concat(" Server"), pair.getPublic()); certificateManager.server = certificateManager.generateCertificate(config.projectName.concat(" Server"), pair.getPublic());
@ -405,10 +377,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
Files.createDirectory(profilesDir); Files.createDirectory(profilesDir);
syncProfilesDir(); syncProfilesDir();
if (config.netty != null)
nettyServerSocketHandler = new NettyServerSocketHandler(this); nettyServerSocketHandler = new NettyServerSocketHandler(this);
else
nettyServerSocketHandler = null;
// post init modules // post init modules
modulesManager.invokeEvent(new LaunchServerPostInitPhase(this)); modulesManager.invokeEvent(new LaunchServerPostInitPhase(this));
if (config.components != null) { if (config.components != null) {
@ -424,25 +393,11 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
private LauncherBinary binary() { private LauncherBinary binary() {
if (launcherEXEBinaryClass != null) { if (launcherEXEBinaryClass != null) {
try { try {
return launcherEXEBinaryClass.getConstructor(LaunchServer.class).newInstance(this); return (LauncherBinary) MethodHandles.publicLookup().findConstructor(launcherEXEBinaryClass, MethodType.methodType(void.class, LaunchServer.class)).invoke(this);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException } catch (Throwable e) {
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
LogHelper.error(e); LogHelper.error(e);
} }
} }
if(config.launch4j.alternative != null)
{
switch (config.launch4j.alternative) {
case "simple":
return new SimpleEXELauncherBinary(this);
case "no":
//None
break;
default:
LogHelper.warning("Alternative %s not found", config.launch4j.alternative);
break;
}
}
try { try {
Class.forName("net.sf.launch4j.Builder"); Class.forName("net.sf.launch4j.Builder");
if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this); if (config.launch4j.enabled) return new EXEL4JLauncherBinary(this);
@ -551,7 +506,7 @@ public void syncUpdatesDir(Collection<String> dirs) throws IOException {
// Resolve name and verify is dir // Resolve name and verify is dir
String name = IOHelper.getFileName(updateDir); String name = IOHelper.getFileName(updateDir);
if (!IOHelper.isDir(updateDir)) { if (!IOHelper.isDir(updateDir)) {
if (!IOHelper.isFile(updateDir) && Arrays.asList(".jar", ".exe", ".hash").stream().noneMatch(e -> updateDir.toString().endsWith(e))) if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
LogHelper.warning("Not update dir: '%s'", name); LogHelper.warning("Not update dir: '%s'", name);
continue; continue;
} }

View file

@ -1,14 +1,15 @@
package pro.gravit.launchserver; package pro.gravit.launchserver;
import java.nio.file.Path;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
import pro.gravit.utils.command.CommandHandler; import pro.gravit.utils.command.CommandHandler;
import java.nio.file.Path;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
public class LaunchServerBuilder { public class LaunchServerBuilder {
private LaunchServerConfig config; private LaunchServerConfig config;
private LaunchServerRuntimeConfig runtimeConfig; private LaunchServerRuntimeConfig runtimeConfig;
@ -16,8 +17,9 @@ public class LaunchServerBuilder {
private LaunchServer.LaunchServerEnv env; private LaunchServer.LaunchServerEnv env;
private LaunchServerModulesManager modulesManager; private LaunchServerModulesManager modulesManager;
private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories(); private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
private RSAPublicKey publicKey; private ECPublicKey publicKey;
private RSAPrivateKey privateKey; private ECPrivateKey privateKey;
private CertificateManager certificateManager;
private LaunchServer.LaunchServerConfigManager launchServerConfigManager; private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
public LaunchServerBuilder setConfig(LaunchServerConfig config) { public LaunchServerBuilder setConfig(LaunchServerConfig config) {
@ -55,12 +57,12 @@ public LaunchServerBuilder setDir(Path dir) {
return this; return this;
} }
public LaunchServerBuilder setPublicKey(RSAPublicKey publicKey) { public LaunchServerBuilder setPublicKey(ECPublicKey publicKey) {
this.publicKey = publicKey; this.publicKey = publicKey;
return this; return this;
} }
public LaunchServerBuilder setPrivateKey(RSAPrivateKey privateKey) { public LaunchServerBuilder setPrivateKey(ECPrivateKey privateKey) {
this.privateKey = privateKey; this.privateKey = privateKey;
return this; return this;
} }
@ -70,13 +72,11 @@ public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServe
return this; return this;
} }
public LaunchServer build() throws Exception public LaunchServer build() throws Exception {
{
//if(updatesDir == null) updatesDir = dir.resolve("updates"); //if(updatesDir == null) updatesDir = dir.resolve("updates");
//if(profilesDir == null) profilesDir = dir.resolve("profiles"); //if(profilesDir == null) profilesDir = dir.resolve("profiles");
directories.collect(); directories.collect();
if(launchServerConfigManager == null) if (launchServerConfigManager == null) {
{
launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() { launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() {
@Override @Override
public LaunchServerConfig readConfig() { public LaunchServerConfig readConfig() {
@ -99,6 +99,11 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
} }
}; };
} }
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler); return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler, certificateManager);
}
public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) {
this.certificateManager = certificateManager;
return this;
} }
} }

View file

@ -1,5 +1,33 @@
package pro.gravit.launchserver; package pro.gravit.launchserver;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.hwid.HWIDProvider;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.auth.handler.AuthHandler;
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
import pro.gravit.launchserver.auth.protect.ProtectHandler;
import pro.gravit.launchserver.auth.provider.AuthProvider;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import pro.gravit.launchserver.components.Component;
import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.dao.provider.DaoProvider;
import pro.gravit.launchserver.manangers.CertificateManager;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.utils.Version;
import pro.gravit.utils.command.CommandHandler;
import pro.gravit.utils.command.JLineCommandHandler;
import pro.gravit.utils.command.StdCommandHandler;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.launcher.LauncherTrustManager;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@ -7,35 +35,16 @@
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey; import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey; import java.security.Security;
import java.security.cert.CertificateException;
import pro.gravit.launcher.Launcher; import java.security.interfaces.ECPrivateKey;
import pro.gravit.launcher.hwid.HWIDProvider; import java.security.interfaces.ECPublicKey;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.auth.handler.AuthHandler;
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
import pro.gravit.launchserver.auth.protect.ProtectHandler;
import pro.gravit.launchserver.auth.provider.AuthProvider;
import pro.gravit.launchserver.auth.texture.TextureProvider;
import pro.gravit.launchserver.components.Component;
import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
import pro.gravit.launchserver.dao.provider.DaoProvider;
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
import pro.gravit.launchserver.socket.WebSocketService;
import pro.gravit.utils.command.CommandHandler;
import pro.gravit.utils.command.JLineCommandHandler;
import pro.gravit.utils.command.StdCommandHandler;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
public class LaunchServerStarter { public class LaunchServerStarter {
public static final boolean allowUnsigned = Boolean.getBoolean("launchserver.allowUnsigned");
public static final boolean inDocker = Boolean.getBoolean("launchserver.dockered");
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
JVMHelper.checkStackTrace(LaunchServerStarter.class); JVMHelper.checkStackTrace(LaunchServerStarter.class);
JVMHelper.verifySystemProperties(LaunchServer.class, true); JVMHelper.verifySystemProperties(LaunchServer.class, true);
@ -46,18 +55,30 @@ public static void main(String[] args) throws Exception {
LogHelper.error("StarterAgent is not started!"); LogHelper.error("StarterAgent is not started!");
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`"); LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
} }
Path dir = IOHelper.WORKING_DIR; Path dir = IOHelper.WORKING_DIR;
Path configFile, runtimeConfigFile; Path configFile, runtimeConfigFile;
Path publicKeyFile = dir.resolve("public.key"); Path publicKeyFile = dir.resolve("public.key");
Path privateKeyFile = dir.resolve("private.key"); Path privateKeyFile = dir.resolve("private.key");
RSAPublicKey publicKey; ECPublicKey publicKey;
RSAPrivateKey privateKey; ECPrivateKey privateKey;
Security.addProvider(new BouncyCastleProvider());
CertificateManager certificateManager = new CertificateManager();
try {
certificateManager.readTrustStore(dir.resolve("truststore"));
} catch (CertificateException e) {
throw new IOException(e);
}
{
//LauncherTrustManager.CheckMode mode = (Version.RELEASE == Version.Type.LTS || Version.RELEASE == Version.Type.STABLE) ?
// (allowUnsigned ? LauncherTrustManager.CheckMode.WARN_IN_NOT_SIGNED : LauncherTrustManager.CheckMode.EXCEPTION_IN_NOT_SIGNED) :
// (allowUnsigned ? LauncherTrustManager.CheckMode.NONE_IN_NOT_SIGNED : LauncherTrustManager.CheckMode.WARN_IN_NOT_SIGNED);
certificateManager.checkClass(LaunchServer.class, LauncherTrustManager.CheckMode.NONE_IN_NOT_SIGNED);
}
LaunchServerRuntimeConfig runtimeConfig; LaunchServerRuntimeConfig runtimeConfig;
LaunchServerConfig config; LaunchServerConfig config;
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION; LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config")); LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
modulesManager.autoload(); modulesManager.autoload();
modulesManager.initModules(null); modulesManager.initModules(null);
registerAll(); registerAll();
@ -84,19 +105,17 @@ public static void main(String[] args) throws Exception {
LogHelper.warning("JLine2 isn't in classpath, using std"); LogHelper.warning("JLine2 isn't in classpath, using std");
} }
if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) { if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) {
LogHelper.info("Reading RSA keypair"); LogHelper.info("Reading EC keypair");
publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)); publicKey = SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile));
privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(privateKeyFile)); privateKey = SecurityHelper.toPrivateECKey(IOHelper.read(privateKeyFile));
if (!publicKey.getModulus().equals(privateKey.getModulus()))
throw new IOException("Private and public key modulus mismatch");
} else { } else {
LogHelper.info("Generating RSA keypair"); LogHelper.info("Generating EC keypair");
KeyPair pair = SecurityHelper.genRSAKeyPair(); KeyPair pair = SecurityHelper.genECKeyPair(new SecureRandom());
publicKey = (RSAPublicKey) pair.getPublic(); publicKey = (ECPublicKey) pair.getPublic();
privateKey = (RSAPrivateKey) pair.getPrivate(); privateKey = (ECPrivateKey) pair.getPrivate();
// Write key pair list // Write key pair list
LogHelper.info("Writing RSA keypair list"); LogHelper.info("Writing EC keypair list");
IOHelper.write(publicKeyFile, publicKey.getEncoded()); IOHelper.write(publicKeyFile, publicKey.getEncoded());
IOHelper.write(privateKeyFile, privateKey.getEncoded()); IOHelper.write(privateKeyFile, privateKey.getEncoded());
} }
@ -158,9 +177,15 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOExcept
} }
} }
}; };
LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
directories.dir = dir;
if (inDocker) {
Path parentLibraries = StarterAgent.libraries.toAbsolutePath().normalize().getParent();
directories.launcherLibrariesCompileDir = parentLibraries.resolve(LaunchServer.LaunchServerDirectories.LAUNCHERLIBRARIESCOMPILE_NAME);
directories.launcherLibrariesDir = parentLibraries.resolve(LaunchServer.LaunchServerDirectories.LAUNCHERLIBRARIES_NAME);
}
LaunchServer server = new LaunchServerBuilder() LaunchServer server = new LaunchServerBuilder()
.setDir(dir) .setDirectories(directories)
.setEnv(env) .setEnv(env)
.setCommandHandler(localCommandHandler) .setCommandHandler(localCommandHandler)
.setPrivateKey(privateKey) .setPrivateKey(privateKey)
@ -169,6 +194,7 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOExcept
.setConfig(config) .setConfig(config)
.setModulesManager(modulesManager) .setModulesManager(modulesManager)
.setLaunchServerConfigManager(launchServerConfigManager) .setLaunchServerConfigManager(launchServerConfigManager)
.setCertificateManager(certificateManager)
.build(); .build();
server.run(); server.run();
} }
@ -178,14 +204,12 @@ public static void initGson(LaunchServerModulesManager modulesManager) {
Launcher.gsonManager.initGson(); Launcher.gsonManager.initGson();
} }
public static void registerAll() public static void registerAll() {
{
AuthHandler.registerHandlers(); AuthHandler.registerHandlers();
AuthProvider.registerProviders(); AuthProvider.registerProviders();
TextureProvider.registerProviders(); TextureProvider.registerProviders();
HWIDHandler.registerHandlers(); HWIDHandler.registerHandlers();
PermissionsHandler.registerHandlers();
Component.registerComponents(); Component.registerComponents();
ProtectHandler.registerHandlers(); ProtectHandler.registerHandlers();
WebSocketService.registerResponses(); WebSocketService.registerResponses();

View file

@ -1,15 +1,16 @@
package pro.gravit.launchserver; package pro.gravit.launchserver;
import java.util.Map;
import pro.gravit.utils.command.Command; import pro.gravit.utils.command.Command;
import java.util.Map;
/** /**
* Allows calling commands using the config command * Allows calling commands using the config command
*/ */
public interface Reconfigurable { public interface Reconfigurable {
/** /**
* Gets a list of commands available for this object. * Gets a list of commands available for this object.
*
* @return Key - Command Name * @return Key - Command Name
* Value is a command object * Value is a command object
*/ */

View file

@ -2,18 +2,14 @@
import java.io.IOException; import java.io.IOException;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.nio.file.FileVisitOption; import java.nio.file.*;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermission;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.jar.JarFile; import java.util.jar.JarFile;
@ -64,7 +60,7 @@ public static boolean isAgentStarted() {
public static void premain(String agentArgument, Instrumentation inst) { public static void premain(String agentArgument, Instrumentation inst) {
StarterAgent.inst = inst; StarterAgent.inst = inst;
libraries = Paths.get("libraries"); libraries = Paths.get(Optional.ofNullable(agentArgument).map(e -> e.trim()).filter(e -> !e.isEmpty()).orElse("libraries"));
isStarted = true; isStarted = true;
try { try {
Files.walkFileTree(libraries, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor()); Files.walkFileTree(libraries, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor());

View file

@ -1,5 +1,10 @@
package pro.gravit.launchserver.asm; package pro.gravit.launchserver.asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import pro.gravit.utils.helper.IOHelper;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -8,18 +13,12 @@
import java.util.List; import java.util.List;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import pro.gravit.utils.helper.IOHelper;
/** /**
* Позволяет искать методы внутри незагруженных классов и общие суперклассы для * Позволяет искать методы внутри незагруженных классов и общие суперклассы для
* чего угодно. Работает через поиск class-файлов в classpath. * чего угодно. Работает через поиск class-файлов в classpath.
*/ */
public class ClassMetadataReader implements Closeable { public class ClassMetadataReader implements Closeable {
private class CheckSuperClassVisitor extends ClassVisitor { private static class CheckSuperClassVisitor extends ClassVisitor {
String superClassName; String superClassName;
@ -108,7 +107,7 @@ public ArrayList<String> getSuperClasses(String type) {
@Override @Override
public void close() { public void close() {
cp.stream().forEach(IOHelper::close); cp.forEach(IOHelper::close);
cp.clear(); cp.clear();
} }

View file

@ -0,0 +1,245 @@
package pro.gravit.launchserver.asm;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import pro.gravit.launchserver.binary.BuildContext;
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
import pro.gravit.launcher.LauncherInject;
import pro.gravit.launcher.LauncherInjectionConstructor;
@SuppressWarnings("rawtypes")
public class InjectClassAcceptor implements MainBuildTask.ASMTransformer {
private final Map<String, Object> values;
public InjectClassAcceptor(Map<String, Object> values) {
this.values = values;
}
private static final List<Class<?>> primitiveLDCClasses = Arrays.asList(java.lang.Integer.class, java.lang.Long.class,
java.lang.Float.class, java.lang.Double.class, java.lang.String.class);
private static final String INJECTED_FIELD_DESC = Type.getDescriptor(LauncherInject.class);
private static final String INJECTED_CONSTRUCTOR_DESC = Type.getDescriptor(LauncherInjectionConstructor.class);
private static final List<String> primitiveLDCDescriptors = Arrays.asList(Type.INT_TYPE.getDescriptor(), Type.DOUBLE_TYPE.getDescriptor(),
Type.FLOAT_TYPE.getDescriptor(), Type.LONG_TYPE.getDescriptor(), Type.getDescriptor(String.class));
private static void visit(ClassNode classNode, Map<String, Object> values) {
MethodNode clinitMethod = classNode.methods.stream().filter(methodNode -> "<clinit>".equals(methodNode.name))
.findFirst().orElseGet(() -> {
MethodNode newClinitMethod = new MethodNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
"<clinit>", "()V", null, null);
newClinitMethod.instructions.add(new InsnNode(Opcodes.RETURN));
classNode.methods.add(newClinitMethod);
return newClinitMethod;
});
List<MethodNode> constructors = classNode.methods.stream().filter(method -> "<init>".equals(method.name))
.collect(Collectors.toList());
MethodNode initMethod = constructors.stream().filter(method -> method.invisibleAnnotations != null
&& method.invisibleAnnotations.stream().anyMatch(annotation -> INJECTED_CONSTRUCTOR_DESC.equals(annotation.desc))).findFirst()
.orElseGet(() -> constructors.stream().filter(method -> method.desc.equals("()V")).findFirst().orElse(null));
classNode.fields.forEach(field -> {
// Notice that fields that will be used with this algo should not have default
// value by = ...;
AnnotationNode valueAnnotation = field.invisibleAnnotations != null ? field.invisibleAnnotations.stream()
.filter(annotation -> INJECTED_FIELD_DESC.equals(annotation.desc)).findFirst()
.orElse(null) : null;
if (valueAnnotation == null) {
return;
}
field.invisibleAnnotations.remove(valueAnnotation);
AtomicReference<String> valueName = new AtomicReference<String>(null);
valueAnnotation.accept(new AnnotationVisitor(Opcodes.ASM7) {
@Override
public void visit(final String name, final Object value) {
if ("value".equals(name)) {
if (value.getClass() != String.class)
throw new IllegalArgumentException(
String.format("Invalid annotation with value class %s", field.getClass().getName()));
valueName.set(value.toString());
}
}
});
if (valueName.get() == null) {
throw new IllegalArgumentException("Annotation should always contains 'value' key");
}
if (!values.containsKey(valueName.get())) {
return;
}
Object value = values.get(valueName.get());
if ((field.access & Opcodes.ACC_STATIC) != 0) {
if (primitiveLDCDescriptors.contains(field.desc) && primitiveLDCClasses.contains(value.getClass())) {
field.value = value;
return;
}
List<FieldInsnNode> putStaticNodes = Arrays.stream(clinitMethod.instructions.toArray())
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTSTATIC).map(p -> (FieldInsnNode) p)
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
InsnList setter = serializeValue(value);
if (putStaticNodes.isEmpty()) {
setter.add(new FieldInsnNode(Opcodes.PUTSTATIC, classNode.name, field.name, field.desc));
Arrays.stream(clinitMethod.instructions.toArray()).filter(node -> node.getOpcode() == Opcodes.RETURN)
.forEach(node -> clinitMethod.instructions.insertBefore(node, setter));
} else {
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
for (FieldInsnNode fieldInsnNode : putStaticNodes) {
clinitMethod.instructions.insertBefore(fieldInsnNode, setter);
}
}
} else {
if (initMethod == null) {
throw new IllegalArgumentException(String.format("Not found init in target: %s", classNode.name));
}
List<FieldInsnNode> putFieldNodes = Arrays.stream(initMethod.instructions.toArray())
.filter(node -> node instanceof FieldInsnNode && node.getOpcode() == Opcodes.PUTFIELD).map(p -> (FieldInsnNode) p)
.filter(node -> node.owner.equals(classNode.name) && node.name.equals(field.name) && node.desc.equals(field.desc)).collect(Collectors.toList());
InsnList setter = serializeValue(value);
if (putFieldNodes.isEmpty()) {
setter.insert(new VarInsnNode(Opcodes.ALOAD, 0));
setter.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, field.name, field.desc));
Arrays.stream(initMethod.instructions.toArray())
.filter(node -> node.getOpcode() == Opcodes.RETURN)
.forEach(node -> initMethod.instructions.insertBefore(node, setter));
} else {
setter.insert(new InsnNode(Type.getType(field.desc).getSize() == 1 ? Opcodes.POP : Opcodes.POP2));
for (FieldInsnNode fieldInsnNode : putFieldNodes) {
initMethod.instructions.insertBefore(fieldInsnNode, setter);
}
}
}
});
}
private static final Map<Class<?>, Serializer<?>> serializers;
static {
serializers = new HashMap<>();
serializers.put(List.class, new ListSerializer());
serializers.put(Map.class, new MapSerializer());
serializers.put(byte[].class, new ByteArraySerializer());
serializers.put(Short.class, serializerClass(Opcodes.I2S));
serializers.put(Byte.class, serializerClass(Opcodes.I2B));
serializers.put(Type.class, (Serializer<Type>) e -> { // ow.Type == java.lang.Class in LDC
InsnList ret = new InsnList();
ret.add(new LdcInsnNode(e));
return ret;
});
serializers.put(Boolean.class, (Serializer<Boolean>) e -> {
InsnList ret = new InsnList();
ret.add(new InsnNode(e ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
return ret;
});
serializers.put(Character.class, (Serializer<Character>) e -> {
InsnList ret = new InsnList();
ret.add(NodeUtils.push((int) e));
ret.add(new InsnNode(Opcodes.I2C));
return ret;
});
serializers.put(Enum.class, (Serializer<Enum>) NodeUtils::makeValueEnumGetter);
}
private static Serializer<?> serializerClass(int opcode) {
return new Serializer<Number>() {
@Override
public InsnList serialize(Number value) {
InsnList ret = new InsnList();
ret.add(NodeUtils.push(((Number) value).intValue()));
ret.add(new InsnNode(opcode));
return ret;
}
};
}
@FunctionalInterface
private interface Serializer<T> {
InsnList serialize(T value);
}
@SuppressWarnings("unchecked")
private static InsnList serializeValue(Object value) {
if (value == null) {
InsnList insnList = new InsnList();
insnList.add(new InsnNode(Opcodes.ACONST_NULL));
return insnList;
}
if (primitiveLDCClasses.contains(value.getClass())) {
InsnList insnList = new InsnList();
insnList.add(new LdcInsnNode(value));
return insnList;
}
for (Map.Entry<Class<?>, Serializer<?>> serializerEntry : serializers.entrySet()) {
if (serializerEntry.getKey().isInstance(value)) {
return ((Serializer) serializerEntry.getValue()).serialize(value);
}
}
throw new UnsupportedOperationException(String.format("Serialization of type %s is not supported",
value.getClass()));
}
private static class ListSerializer implements Serializer<List> {
@Override
public InsnList serialize(List value) {
InsnList insnList = new InsnList();
insnList.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(ArrayList.class)));
insnList.add(new InsnNode(Opcodes.DUP));
insnList.add(NodeUtils.push(value.size()));
insnList.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Type.getInternalName(ArrayList.class), "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false));
for (Object object : value) {
insnList.add(new InsnNode(Opcodes.DUP));
insnList.add(serializeValue(object));
insnList.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, Type.getInternalName(List.class), "add",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(Object.class)), true));
insnList.add(new InsnNode(Opcodes.POP));
}
return insnList;
}
}
private static class MapSerializer implements Serializer<Map> {
@Override
public InsnList serialize(Map value) {
InsnList insnList = new InsnList();
insnList.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(value.getClass())));
insnList.add(new InsnNode(Opcodes.DUP));
insnList.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Type.getInternalName(value.getClass()), "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE), false));
for (Object entryObject : value.entrySet()) {
Map.Entry entry = (Map.Entry) entryObject;
insnList.add(new InsnNode(Opcodes.DUP));
insnList.add(serializeValue(entry.getKey()));
insnList.add(serializeValue(entry.getValue()));
insnList.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, Type.getInternalName(Map.class), "put",
Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class), Type.getType(Object.class)),
true));
insnList.add(new InsnNode(Opcodes.POP));
}
return insnList;
}
}
private static class ByteArraySerializer implements Serializer<byte[]> {
@Override
public InsnList serialize(byte[] value) {
InsnList insnList = new InsnList();
insnList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getInternalName(Base64.class),
"getDecoder", Type.getMethodDescriptor(Type.getType(Base64.Decoder.class)), false));
insnList.add(NodeUtils.getSafeStringInsnList(Base64.getEncoder().encodeToString(value)));
insnList.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Base64.Decoder.class),
"decode", Type.getMethodDescriptor(Type.getType(byte[].class), Type.getType(String.class)),
false));
return insnList;
}
}
@Override
public void transform(ClassNode classNode, String className, BuildContext context) {
visit(classNode, values);
}
}

View file

@ -1,29 +1,28 @@
package pro.gravit.launchserver.asm; package pro.gravit.launchserver.asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.JarHelper;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import pro.gravit.utils.helper.IOHelper;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
public final class NodeUtils { public final class NodeUtils {
private NodeUtils() { }
private NodeUtils() {
}
public static ClassNode forClass(Class<?> cls, int flags) { public static ClassNode forClass(Class<?> cls, int flags) {
try (InputStream in = cls.getClassLoader().getResourceAsStream(cls.getName().replace('.', '/') + ".class")) { try (InputStream in = JarHelper.getClassBytesStream(cls)) {
ClassNode ret = new ClassNode(); ClassNode ret = new ClassNode();
new ClassReader(IOHelper.read(in)).accept(ret, flags); new ClassReader(IOHelper.read(in)).accept(ret, flags);
return ret; return ret;
@ -166,4 +165,83 @@ public static int opcodeEmulation(AbstractInsnNode e) {
} }
return stackSize; return stackSize;
} }
public static InsnList getSafeStringInsnList(String string) {
InsnList insnList = new InsnList();
if ((string.length() * 3) < MAX_SAFE_BYTE_COUNT) { // faster check
insnList.add(new LdcInsnNode(string));
return insnList;
}
insnList.add(new TypeInsnNode(NEW, "java/lang/StringBuilder"));
insnList.add(new InsnNode(DUP));
insnList.add(new MethodInsnNode(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false));
String[] chunks = splitUtf8ToChunks(string, MAX_SAFE_BYTE_COUNT);
for (String chunk : chunks) {
insnList.add(new LdcInsnNode(chunk));
insnList.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
}
insnList.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false));
return insnList;
}
public static final int MAX_SAFE_BYTE_COUNT = 65535 - Byte.MAX_VALUE;
public static String[] splitUtf8ToChunks(String text, int maxBytes) {
List<String> parts = new ArrayList<>();
char[] chars = text.toCharArray();
int lastCharIndex = 0;
int currentChunkSize = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
int charSize = getUtf8CharSize(c);
if (currentChunkSize + charSize < maxBytes) {
currentChunkSize += charSize;
} else {
parts.add(text.substring(lastCharIndex, i));
currentChunkSize = 0;
lastCharIndex = i;
}
}
if (currentChunkSize != 0) {
parts.add(text.substring(lastCharIndex));
}
return parts.toArray(new String[0]);
}
public static int getUtf8CharSize(char c) {
if (c >= 0x0001 && c <= 0x007F) {
return 1;
} else if (c <= 0x07FF) {
return 2;
}
return 3;
}
public static InsnList push(final int value) {
InsnList ret = new InsnList();
if (value >= -1 && value <= 5)
ret.add(new InsnNode(Opcodes.ICONST_0 + value));
else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
ret.add(new IntInsnNode(Opcodes.BIPUSH, value));
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
ret.add(new IntInsnNode(Opcodes.SIPUSH, value));
else
ret.add(new LdcInsnNode(value));
return ret;
}
public static InsnList makeValueEnumGetter(@SuppressWarnings("rawtypes") Enum u) {
InsnList ret = new InsnList();
Type e = Type.getType(u.getClass());
ret.add(new FieldInsnNode(Opcodes.GETSTATIC, e.getInternalName(), u.name(), e.getDescriptor()));
return ret;
}
} }

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.asm; package pro.gravit.launchserver.asm;
import java.util.ArrayList;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import java.util.ArrayList;
/** /**
* ClassWriter с другой реализацией метода getCommonSuperClass: при его * ClassWriter с другой реализацией метода getCommonSuperClass: при его
* использовании не происходит загрузки классов. * использовании не происходит загрузки классов.
@ -18,6 +18,7 @@ public SafeClassWriter(ClassMetadataReader classMetadataReader, int flags) {
this.classMetadataReader = classMetadataReader; this.classMetadataReader = classMetadataReader;
} }
public SafeClassWriter(ClassReader classReader, ClassMetadataReader classMetadataReader, int flags) { public SafeClassWriter(ClassReader classReader, ClassMetadataReader classMetadataReader, int flags) {
super(classReader, flags); super(classReader, flags);
this.classMetadataReader = classMetadataReader; this.classMetadataReader = classMetadataReader;

View file

@ -1,30 +1,71 @@
package pro.gravit.launchserver.auth; package pro.gravit.launchserver.auth;
import java.io.IOException;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.handler.AuthHandler; import pro.gravit.launchserver.auth.handler.AuthHandler;
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
import pro.gravit.launchserver.auth.provider.AuthProvider; import pro.gravit.launchserver.auth.provider.AuthProvider;
import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.auth.texture.TextureProvider;
import java.io.IOException;
import java.util.Map;
public class AuthProviderPair { public class AuthProviderPair {
public AuthProvider provider; public AuthProvider provider;
public AuthHandler handler; public AuthHandler handler;
public TextureProvider textureProvider; public TextureProvider textureProvider;
public String name; public HWIDHandler hwid;
public Map<String, String> links;
public transient String name;
public String displayName; public String displayName;
public boolean isDefault = true; public final boolean isDefault = true;
public AuthProviderPair(AuthProvider provider, AuthHandler handler, TextureProvider textureProvider, String name) { public AuthProviderPair(AuthProvider provider, AuthHandler handler, TextureProvider textureProvider, HWIDHandler hwid) {
this.provider = provider; this.provider = provider;
this.handler = handler; this.handler = handler;
this.textureProvider = textureProvider; this.textureProvider = textureProvider;
this.name = name; this.hwid = hwid;
} }
public void init(LaunchServer srv) { public void init(LaunchServer srv, String name) {
this.name = name;
if(links != null) link(srv);
if(provider == null) throw new NullPointerException(String.format("Auth %s provider null", name));
if(handler == null) throw new NullPointerException(String.format("Auth %s handler null", name));
if(textureProvider == null) throw new NullPointerException(String.format("Auth %s textureProvider null", name));
if(hwid == null) throw new NullPointerException(String.format("Auth %s hwid null", name));
provider.init(srv); provider.init(srv);
handler.init(srv); handler.init(srv);
hwid.init();
}
public void link(LaunchServer srv)
{
links.forEach((k,v) -> {
AuthProviderPair pair = srv.config.getAuthProviderPair(v);
if(pair == null)
{
throw new NullPointerException(String.format("Auth %s link failed. Pair %s not found", name, v));
}
if("provider".equals(k))
{
if(pair.provider == null) throw new NullPointerException(String.format("Auth %s link failed. %s.provider is null", name, v));
provider = pair.provider;
}
else if("handler".equals(k))
{
if(pair.handler == null) throw new NullPointerException(String.format("Auth %s link failed. %s.handler is null", name, v));
handler = pair.handler;
}
else if("textureProvider".equals(k))
{
if(pair.textureProvider == null) throw new NullPointerException(String.format("Auth %s link failed. %s.textureProvider is null", name, v));
textureProvider = pair.textureProvider;
}
else if("hwid".equals(k))
{
if(pair.hwid == null) throw new NullPointerException(String.format("Auth %s link failed. %s.hwid is null", name, v));
hwid = pair.hwid;
}
});
} }
public void close() throws IOException { public void close() throws IOException {

View file

@ -1,17 +1,15 @@
package pro.gravit.launchserver.auth; package pro.gravit.launchserver.auth;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mysql.cj.jdbc.MysqlDataSource; import com.mysql.cj.jdbc.MysqlDataSource;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.helper.VerifyHelper;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public final class MySQLSourceConfig implements AutoCloseable { public final class MySQLSourceConfig implements AutoCloseable {
public static final int TIMEOUT = VerifyHelper.verifyInt( public static final int TIMEOUT = VerifyHelper.verifyInt(

View file

@ -1,17 +1,14 @@
package pro.gravit.launchserver.auth; package pro.gravit.launchserver.auth;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.postgresql.ds.PGSimpleDataSource;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import org.postgresql.ds.PGSimpleDataSource;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.helper.VerifyHelper;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public final class PostgreSQLSourceConfig implements AutoCloseable { public final class PostgreSQLSourceConfig implements AutoCloseable {
public static final int TIMEOUT = VerifyHelper.verifyInt( public static final int TIMEOUT = VerifyHelper.verifyInt(
Integer.parseUnsignedInt(System.getProperty("launcher.postgresql.idleTimeout", Integer.toString(5000))), Integer.parseUnsignedInt(System.getProperty("launcher.postgresql.idleTimeout", Integer.toString(5000))),

View file

@ -1,16 +1,16 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.launchserver.auth.provider.AuthProviderResult; import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
import java.io.IOException;
import java.util.UUID;
public abstract class AuthHandler implements AutoCloseable { public abstract class AuthHandler implements AutoCloseable {
public static ProviderMap<AuthHandler> providers = new ProviderMap<>("AuthHandler"); public static final ProviderMap<AuthHandler> providers = new ProviderMap<>("AuthHandler");
private static boolean registredHandl = false; private static boolean registredHandl = false;
@ -35,20 +35,20 @@ public static void registerHandlers() {
/** /**
* Returns the UUID associated with the account * Returns the UUID associated with the account
*
* @param authResult {@link pro.gravit.launchserver.auth.provider.AuthProvider} result * @param authResult {@link pro.gravit.launchserver.auth.provider.AuthProvider} result
* @return User UUID * @return User UUID
* @throws IOException * @throws IOException Internal Script Error
* Internal Script Error
*/ */
public abstract UUID auth(AuthProviderResult authResult) throws IOException; public abstract UUID auth(AuthProviderResult authResult) throws IOException;
/** /**
* Validates serverID * Validates serverID
*
* @param username user name * @param username user name
* @param serverID serverID to check * @param serverID serverID to check
* @return user UUID * @return user UUID
* @throws IOException * @throws IOException Internal Script Error
* Internal Script Error
*/ */
public abstract UUID checkServer(String username, String serverID) throws IOException; public abstract UUID checkServer(String username, String serverID) throws IOException;
@ -58,12 +58,12 @@ public static void registerHandlers() {
/** /**
* Checks assessToken for validity and saves serverID if successful * Checks assessToken for validity and saves serverID if successful
*
* @param username user name * @param username user name
* @param accessToken assessToken to check * @param accessToken assessToken to check
* @param serverID serverID to save * @param serverID serverID to save
* @return true - allow, false - deny * @return true - allow, false - deny
* @throws IOException * @throws IOException Internal Script Error
* Internal Script Error
*/ */
public abstract boolean joinServer(String username, String accessToken, String serverID) throws IOException; public abstract boolean joinServer(String username, String accessToken, String serverID) throws IOException;

View file

@ -1,5 +1,13 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.*;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
@ -9,18 +17,6 @@
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.helper.VerifyHelper;
public abstract class CachedAuthHandler extends AuthHandler implements NeedGarbageCollection, Reconfigurable { public abstract class CachedAuthHandler extends AuthHandler implements NeedGarbageCollection, Reconfigurable {
public static final class Entry { public static final class Entry {
@ -38,7 +34,7 @@ public Entry(UUID uuid, String username, String accessToken, String serverID) {
} }
} }
protected class EntryAndUsername { protected static class EntryAndUsername {
public Map<UUID, CachedAuthHandler.Entry> entryCache; public Map<UUID, CachedAuthHandler.Entry> entryCache;
public Map<String, UUID> usernameCache; public Map<String, UUID> usernameCache;
} }
@ -48,7 +44,7 @@ public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>(); Map<String, Command> commands = new HashMap<>();
commands.put("clear", new SubCommand() { commands.put("clear", new SubCommand() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) {
long entryCacheSize = entryCache.size(); long entryCacheSize = entryCache.size();
long usernamesCacheSize = usernamesCache.size(); long usernamesCacheSize = usernamesCache.size();
entryCache.clear(); entryCache.clear();

View file

@ -1,43 +1,42 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.dao.User;
import java.util.UUID;
public class HibernateAuthHandler extends CachedAuthHandler { public class HibernateAuthHandler extends CachedAuthHandler {
@Override @Override
protected Entry fetchEntry(String username) throws IOException { protected Entry fetchEntry(String username) {
User user = srv.config.dao.userService.findUserByUsername(username); User user = srv.config.dao.userDAO.findByUsername(username);
if (user == null) return null; if (user == null) return null;
return new Entry(user.uuid, username, user.getAccessToken(), user.serverID); return new Entry(user.getUuid(), username, user.getAccessToken(), user.getServerID());
} }
@Override @Override
protected Entry fetchEntry(UUID uuid) throws IOException { protected Entry fetchEntry(UUID uuid) {
User user = srv.config.dao.userService.findUserByUUID(uuid); User user = srv.config.dao.userDAO.findByUUID(uuid);
if (user == null) return null; if (user == null) return null;
return new Entry(user.uuid, user.username, user.getAccessToken(), user.serverID); return new Entry(user.getUuid(), user.getUsername(), user.getAccessToken(), user.getServerID());
} }
@Override @Override
protected boolean updateAuth(UUID uuid, String username, String accessToken) throws IOException { protected boolean updateAuth(UUID uuid, String username, String accessToken) {
User user = srv.config.dao.userService.findUserByUUID(uuid); User user = srv.config.dao.userDAO.findByUUID(uuid);
user.setAccessToken(accessToken); user.setAccessToken(accessToken);
srv.config.dao.userService.updateUser(user); srv.config.dao.userDAO.update(user);
return true; return true;
} }
@Override @Override
protected boolean updateServerID(UUID uuid, String serverID) throws IOException { protected boolean updateServerID(UUID uuid, String serverID) {
User user = srv.config.dao.userService.findUserByUUID(uuid); User user = srv.config.dao.userDAO.findByUUID(uuid);
user.serverID = serverID; user.setServerID(serverID);
srv.config.dao.userService.updateUser(user); srv.config.dao.userDAO.update(user);
return true; return true;
} }
@Override @Override
public void close() throws IOException { public void close() {
} }
} }

View file

@ -1,37 +1,37 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.HTTPRequest;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.UUID; import java.util.UUID;
import pro.gravit.launcher.Launcher;
import pro.gravit.utils.HTTPRequest;
public class JsonAuthHandler extends CachedAuthHandler { public class JsonAuthHandler extends CachedAuthHandler {
public URL getUrl; public URL getUrl;
public URL updateAuthUrl; public URL updateAuthUrl;
public URL updateServerIdUrl; public URL updateServerIdUrl;
public class EntryRequestByUsername { public static class EntryRequestByUsername {
public String username; public final String username;
public EntryRequestByUsername(String username) { public EntryRequestByUsername(String username) {
this.username = username; this.username = username;
} }
} }
public class EntryRequestByUUID { public static class EntryRequestByUUID {
public UUID uuid; public final UUID uuid;
public EntryRequestByUUID(UUID uuid) { public EntryRequestByUUID(UUID uuid) {
this.uuid = uuid; this.uuid = uuid;
} }
} }
public class UpdateAuthRequest { public static class UpdateAuthRequest {
public UUID uuid; public final UUID uuid;
public String username; public final String username;
public String accessToken; public final String accessToken;
public UpdateAuthRequest(UUID uuid, String username, String accessToken) { public UpdateAuthRequest(UUID uuid, String username, String accessToken) {
this.uuid = uuid; this.uuid = uuid;
@ -40,9 +40,9 @@ public UpdateAuthRequest(UUID uuid, String username, String accessToken) {
} }
} }
public class UpdateServerIDRequest { public static class UpdateServerIDRequest {
public UUID uuid; public final UUID uuid;
public String serverID; public final String serverID;
public UpdateServerIDRequest(UUID uuid, String serverID) { public UpdateServerIDRequest(UUID uuid, String serverID) {
this.uuid = uuid; this.uuid = uuid;
@ -50,7 +50,7 @@ public UpdateServerIDRequest(UUID uuid, String serverID) {
} }
} }
public class SuccessResponse { public static class SuccessResponse {
public boolean success; public boolean success;
} }

View file

@ -1,12 +1,12 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.VerifyHelper;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.VerifyHelper;
public final class MemoryAuthHandler extends CachedAuthHandler { public final class MemoryAuthHandler extends CachedAuthHandler {
private static String toUsername(UUID uuid) { private static String toUsername(UUID uuid) {
byte[] bytes = ByteBuffer.allocate(16). byte[] bytes = ByteBuffer.allocate(16).

View file

@ -1,5 +1,9 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException; import java.io.IOException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -7,10 +11,6 @@
import java.sql.SQLException; import java.sql.SQLException;
import java.util.UUID; import java.util.UUID;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.utils.helper.LogHelper;
public final class MySQLAuthHandler extends CachedAuthHandler { public final class MySQLAuthHandler extends CachedAuthHandler {
private MySQLSourceConfig mySQLHolder; private MySQLSourceConfig mySQLHolder;
private String uuidColumn; private String uuidColumn;

View file

@ -1,12 +1,12 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.utils.helper.VerifyHelper;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import pro.gravit.launchserver.auth.provider.AuthProviderResult;
import pro.gravit.utils.helper.VerifyHelper;
public final class NullAuthHandler extends AuthHandler { public final class NullAuthHandler extends AuthHandler {
private volatile AuthHandler handler; private volatile AuthHandler handler;

View file

@ -1,5 +1,8 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import org.postgresql.util.PGobject;
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
import java.io.IOException; import java.io.IOException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -7,10 +10,6 @@
import java.sql.SQLException; import java.sql.SQLException;
import java.util.UUID; import java.util.UUID;
import org.postgresql.util.PGobject;
import pro.gravit.launchserver.auth.PostgreSQLSourceConfig;
public final class PostgreSQLAuthHandler extends CachedAuthHandler { public final class PostgreSQLAuthHandler extends CachedAuthHandler {
private PostgreSQLSourceConfig postgreSQLHolder; private PostgreSQLSourceConfig postgreSQLHolder;
private String uuidColumn; private String uuidColumn;

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.auth.handler; package pro.gravit.launchserver.auth.handler;
import java.io.IOException;
import java.net.URL;
import java.util.UUID;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.net.URL;
import java.util.UUID;
public final class RequestAuthHandler extends CachedAuthHandler { public final class RequestAuthHandler extends CachedAuthHandler {
private String usernameFetch; private String usernameFetch;
private String uuidFetch; private String uuidFetch;
@ -16,8 +16,8 @@ public final class RequestAuthHandler extends CachedAuthHandler {
private String updateAuth; private String updateAuth;
private String updateServerID; private String updateServerID;
private String splitSymbol = ":"; private final String splitSymbol = ":";
private String goodResponse = "OK"; private final String goodResponse = "OK";
@Override @Override
public void init(LaunchServer srv) { public void init(LaunchServer srv) {

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import pro.gravit.launcher.hwid.HWID;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import pro.gravit.launcher.hwid.HWID;
public class AcceptHWIDHandler extends HWIDHandler { public class AcceptHWIDHandler extends HWIDHandler {
@Override @Override

View file

@ -1,9 +1,5 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import pro.gravit.launcher.hwid.HWID; import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
@ -11,8 +7,12 @@
import pro.gravit.utils.command.SubCommand; import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class HWIDHandler implements AutoCloseable, Reconfigurable { public abstract class HWIDHandler implements AutoCloseable, Reconfigurable {
public static ProviderMap<HWIDHandler> providers = new ProviderMap<>("HWIDHandler"); public static final ProviderMap<HWIDHandler> providers = new ProviderMap<>("HWIDHandler");
private static boolean registredHandl = false; private static boolean registredHandl = false;
@ -48,8 +48,7 @@ public void invoke(String... args) throws Exception {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
List<HWID> target = getHwid(args[0]); List<HWID> target = getHwid(args[0]);
for(HWID hwid : target) for (HWID hwid : target) {
{
if (hwid == null) { if (hwid == null) {
LogHelper.error("[%s] HWID: null", args[0]); LogHelper.error("[%s] HWID: null", args[0]);
continue; continue;

View file

@ -1,5 +1,11 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
@ -10,16 +16,9 @@
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class JsonFileHWIDHandler extends HWIDHandler { public class JsonFileHWIDHandler extends HWIDHandler {
public class Entry { public static class Entry {
public HWID hwid; public final HWID hwid;
public String username; public String username;
public boolean isBanned = false; public boolean isBanned = false;
@ -41,15 +40,18 @@ public int hashCode() {
} }
} }
public String filename = "hwids.json"; public final String filename = "hwids.json";
public transient LinkedList<Entry> list = new LinkedList<>(); public transient LinkedList<Entry> list = new LinkedList<>();
public String banMessage = "You banned"; public final String banMessage = "You banned";
@Override @Override
public void ban(List<HWID> hwid) { public void ban(List<HWID> hwid) {
for (Entry e : list) { for (Entry e : list) {
for (HWID banHWID : hwid) { for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = true; if (e.hwid.equals(banHWID)) {
e.isBanned = true;
break;
}
} }
} }
} }
@ -101,7 +103,10 @@ public List<HWID> getHwid(String username) {
public void unban(List<HWID> hwid) { public void unban(List<HWID> hwid) {
for (Entry e : list) { for (Entry e : list) {
for (HWID banHWID : hwid) { for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = false; if (e.hwid.equals(banHWID)) {
e.isBanned = false;
break;
}
} }
} }
} }

View file

@ -1,19 +1,18 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launcher.HTTPRequest;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.utils.HTTPRequest;
import pro.gravit.utils.helper.LogHelper;
public final class JsonHWIDHandler extends HWIDHandler { public final class JsonHWIDHandler extends HWIDHandler {
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
@ -23,12 +22,12 @@ public final class JsonHWIDHandler extends HWIDHandler {
private URL urlGet; private URL urlGet;
private String apiKey; private String apiKey;
public class banRequest { public static class banRequest {
public banRequest(OshiHWID hwid) { public banRequest(OshiHWID hwid) {
this.hwid = hwid; this.hwid = hwid;
} }
OshiHWID hwid; final OshiHWID hwid;
String apiKey; String apiKey;
public banRequest(OshiHWID hwid, String apiKey) { public banRequest(OshiHWID hwid, String apiKey) {
@ -37,14 +36,14 @@ public banRequest(OshiHWID hwid, String apiKey) {
} }
} }
public class checkRequest { public static class checkRequest {
public checkRequest(String username, OshiHWID hwid) { public checkRequest(String username, OshiHWID hwid) {
this.username = username; this.username = username;
this.hwid = hwid; this.hwid = hwid;
} }
String username; final String username;
OshiHWID hwid; final OshiHWID hwid;
String apiKey; String apiKey;
public checkRequest(String username, OshiHWID hwid, String apiKey) { public checkRequest(String username, OshiHWID hwid, String apiKey) {
@ -54,21 +53,21 @@ public checkRequest(String username, OshiHWID hwid, String apiKey) {
} }
} }
public class Result { public static class Result {
String error; String error;
} }
public class BannedResult { public static class BannedResult {
boolean isBanned; boolean isBanned;
String error; String error;
} }
public class HWIDRequest { public static class HWIDRequest {
public HWIDRequest(String username) { public HWIDRequest(String username) {
this.username = username; this.username = username;
} }
String username; final String username;
String apiKey; String apiKey;
public HWIDRequest(String username, String apiKey) { public HWIDRequest(String username, String apiKey) {

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import pro.gravit.launcher.hwid.HWID;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import pro.gravit.launcher.hwid.HWID;
public class MemoryHWIDHandler extends HWIDHandler { public class MemoryHWIDHandler extends HWIDHandler {
public class Entry { public static class Entry {
public HWID hwid; public final HWID hwid;
public String username; public String username;
public boolean isBanned = false; public boolean isBanned = false;
@ -30,14 +30,17 @@ public int hashCode() {
} }
} }
public transient LinkedList<Entry> list = new LinkedList<>(); public final transient LinkedList<Entry> list = new LinkedList<>();
public String banMessage = "You banned"; public final String banMessage = "You banned";
@Override @Override
public void ban(List<HWID> hwid) { public void ban(List<HWID> hwid) {
for (Entry e : list) { for (Entry e : list) {
for (HWID banHWID : hwid) { for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = true; if (e.hwid.equals(banHWID)) {
e.isBanned = true;
break;
}
} }
} }
} }
@ -79,7 +82,10 @@ public List<HWID> getHwid(String username) {
public void unban(List<HWID> hwid) { public void unban(List<HWID> hwid) {
for (Entry e : list) { for (Entry e : list) {
for (HWID banHWID : hwid) { for (HWID banHWID : hwid) {
if (e.hwid.equals(banHWID)) e.isBanned = false; if (e.hwid.equals(banHWID)) {
e.isBanned = false;
break;
}
} }
} }
} }

View file

@ -1,5 +1,11 @@
package pro.gravit.launchserver.auth.hwid; package pro.gravit.launchserver.auth.hwid;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -7,12 +13,6 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import pro.gravit.launcher.hwid.HWID;
import pro.gravit.launcher.hwid.OshiHWID;
import pro.gravit.launchserver.auth.MySQLSourceConfig;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;
public class MysqlHWIDHandler extends HWIDHandler { public class MysqlHWIDHandler extends HWIDHandler {
private MySQLSourceConfig mySQLHolder; private MySQLSourceConfig mySQLHolder;
@ -151,10 +151,10 @@ public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWI
db_hwid.serialNumber = set.getString(hwidFieldSerialNumber); db_hwid.serialNumber = set.getString(hwidFieldSerialNumber);
db_hwid.processorID = set.getString(hwidFieldProcessorID); db_hwid.processorID = set.getString(hwidFieldProcessorID);
db_hwid.HWDiskSerial = set.getString(hwidFieldHWDiskSerial); db_hwid.HWDiskSerial = set.getString(hwidFieldHWDiskSerial);
db_hwid.totalMemory = Long.valueOf(set.getString(hwidFieldTotalMemory)); db_hwid.totalMemory = Long.parseLong(set.getString(hwidFieldTotalMemory));
db_hwid.macAddr = set.getString(hwidFieldMAC); db_hwid.macAddr = set.getString(hwidFieldMAC);
if (LogHelper.isDevEnabled()) { if (LogHelper.isDevEnabled()) {
LogHelper.dev("Compare HWID: %s vs %s", hwid.getSerializeString(), db_hwid.getSerializeString()); LogHelper.dev("Compare HWID: %s vs %s", hwid.toString(), db_hwid.toString());
} }
int compare_point = hwid.compare(db_hwid); int compare_point = hwid.compare(db_hwid);
if (compare_point < compare) continue; if (compare_point < compare) continue;
@ -238,7 +238,7 @@ public List<HWID> getHwid(String username) {
ResultSet rs = s.executeQuery(); ResultSet rs = s.executeQuery();
if (rs.next()) { if (rs.next()) {
OshiHWID oshiHWID = new OshiHWID(); OshiHWID oshiHWID = new OshiHWID();
oshiHWID.totalMemory = Long.valueOf(rs.getString(hwidFieldTotalMemory)); oshiHWID.totalMemory = Long.parseLong(rs.getString(hwidFieldTotalMemory));
oshiHWID.serialNumber = rs.getString(hwidFieldSerialNumber); oshiHWID.serialNumber = rs.getString(hwidFieldSerialNumber);
oshiHWID.HWDiskSerial = rs.getString(hwidFieldHWDiskSerial); oshiHWID.HWDiskSerial = rs.getString(hwidFieldHWDiskSerial);
oshiHWID.processorID = rs.getString(hwidFieldProcessorID); oshiHWID.processorID = rs.getString(hwidFieldProcessorID);

View file

@ -1,26 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
import pro.gravit.launcher.ClientPermissions;
public class ConfigPermissionsHandler extends PermissionsHandler {
public boolean isAdmin = false;
public boolean isServer = false;
@Override
public ClientPermissions getPermissions(String username) {
ClientPermissions permissions = new ClientPermissions();
permissions.canServer = isServer;
permissions.canAdmin = isAdmin;
return permissions;
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
//Unsupported
}
@Override
public void close() {
}
}

View file

@ -1,21 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
import pro.gravit.launcher.ClientPermissions;
public class DefaultPermissionsHandler extends PermissionsHandler {
@Override
public ClientPermissions getPermissions(String username) {
return ClientPermissions.DEFAULT;
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
//Unsupported
}
@Override
public void close() {
}
}

View file

@ -1,27 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.dao.User;
public class HibernatePermissionsHandler extends PermissionsHandler {
@Override
public ClientPermissions getPermissions(String username) {
User user = srv.config.dao.userService.findUserByUsername(username);
if(user == null) return ClientPermissions.DEFAULT;
return user.getPermissions();
}
@Override
public void setPermissions(String username, ClientPermissions permissions) {
User user = srv.config.dao.userService.findUserByUsername(username);
if(user == null) return;
user.setPermissions(permissions);
srv.config.dao.userService.updateUser(user);
}
@Override
public void close() throws Exception {
}
}

View file

@ -1,110 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
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.HashMap;
import java.util.Map;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class JsonFilePermissionsHandler extends PermissionsHandler implements Reconfigurable {
public String filename = "permissions.json";
public static Map<String, ClientPermissions> map;
public void reload() {
map.clear();
Path path = Paths.get(filename);
Type type = new TypeToken<Map<String, ClientPermissions>>() {
}.getType();
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public void close() {
}
@Override
public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>();
SubCommand reload = new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
reload();
}
};
commands.put("reload", reload);
commands.put("save", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
Path path = Paths.get(filename);
if (!IOHelper.exists(path)) {
try (Writer writer = IOHelper.newWriter(path)) {
Launcher.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
}
});
return commands;
}
public static class Enity {
public String username;
public ClientPermissions permissions;
}
@Override
public void init(LaunchServer server) {
super.init(server);
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.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
try (Reader reader = IOHelper.newReader(path)) {
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

@ -1,111 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
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.HashMap;
import java.util.Map;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.utils.command.Command;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class JsonLongFilePermissionsHandler extends PermissionsHandler implements Reconfigurable {
public String filename = "permissions.json";
public long defaultPerms = 0L;
public static Map<String, Long> map;
public void reload() {
map.clear();
Path path = Paths.get(filename);
Type type = new TypeToken<Map<String, Long>>() {
}.getType();
try (Reader reader = IOHelper.newReader(path)) {
map = Launcher.gsonManager.gson.fromJson(reader, type);
} catch (IOException e) {
LogHelper.error(e);
}
}
@Override
public void close() {
}
@Override
public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>();
SubCommand reload = new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
reload();
}
};
commands.put("reload", reload);
commands.put("save", new SubCommand() {
@Override
public void invoke(String... args) throws Exception {
Path path = Paths.get(filename);
if (!IOHelper.exists(path)) {
try (Writer writer = IOHelper.newWriter(path)) {
Launcher.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
}
});
return commands;
}
public static class Enity {
public String username;
public ClientPermissions permissions;
}
@Override
public void init(LaunchServer server) {
super.init(server);
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.gsonManager.gson.toJson(map, writer);
} catch (IOException e) {
LogHelper.error(e);
}
}
try (Reader reader = IOHelper.newReader(path)) {
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,31 +0,0 @@
package pro.gravit.launchserver.auth.permissions;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.ProviderMap;
public abstract class PermissionsHandler implements AutoCloseable {
public static ProviderMap<PermissionsHandler> providers = new ProviderMap<>("PermissionsHandler");
protected transient LaunchServer srv;
private static boolean registredHandl = false;
public static void registerHandlers() {
if (!registredHandl) {
providers.register("json", JsonFilePermissionsHandler.class);
providers.register("json-long", JsonLongFilePermissionsHandler.class);
providers.register("config", ConfigPermissionsHandler.class);
providers.register("default", DefaultPermissionsHandler.class);
providers.register("hibernate", HibernatePermissionsHandler.class);
registredHandl = true;
}
}
public void init(LaunchServer server)
{
this.srv = server;
}
public abstract ClientPermissions getPermissions(String username);
public abstract void setPermissions(String username, ClientPermissions permissions);
}

View file

@ -4,7 +4,7 @@
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
public abstract class ProtectHandler { public abstract class ProtectHandler {
public static ProviderMap<ProtectHandler> providers = new ProviderMap<>("ProtectHandler"); public static final ProviderMap<ProtectHandler> providers = new ProviderMap<>("ProtectHandler");
private static boolean registredHandl = false; private static boolean registredHandl = false;

View file

@ -4,7 +4,8 @@
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
public class StdProtectHandler extends ProtectHandler { public class StdProtectHandler extends ProtectHandler {
public boolean checkSecure = true; public final boolean checkSecure = true;
@Override @Override
public String generateSecureToken(AuthResponse.AuthContext context) { public String generateSecureToken(AuthResponse.AuthContext context) {
return SecurityHelper.randomStringToken(); return SecurityHelper.randomStringToken();

View file

@ -1,5 +1,6 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
@ -7,7 +8,7 @@ public final class AcceptAuthProvider extends AuthProvider {
@Override @Override
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) { public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) {
return new AuthProviderResult(login, SecurityHelper.randomStringToken(), srv); // Same as login return new AuthProviderResult(login, SecurityHelper.randomStringToken(), ClientPermissions.DEFAULT); // Same as login
} }
@Override @Override

View file

@ -1,16 +1,25 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.io.IOException; import pro.gravit.launcher.events.request.GetAvailabilityAuthRequestEvent;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
import java.io.IOException;
public abstract class AuthProvider implements AutoCloseable { public abstract class AuthProvider implements AutoCloseable {
public static ProviderMap<AuthProvider> providers = new ProviderMap<>("AuthProvider"); public static final ProviderMap<AuthProvider> providers = new ProviderMap<>("AuthProvider");
private static boolean registredProv = false; private static boolean registredProv = false;
protected transient LaunchServer srv = null; protected transient LaunchServer srv = null;
public GetAvailabilityAuthRequestEvent.AuthAvailability.AuthType getFirstAuthType() {
return GetAvailabilityAuthRequestEvent.AuthAvailability.AuthType.PASSWORD;
}
public GetAvailabilityAuthRequestEvent.AuthAvailability.AuthType getSecondAuthType() {
return GetAvailabilityAuthRequestEvent.AuthAvailability.AuthType.NONE;
}
public static AuthProviderResult authError(String message) throws AuthException { public static AuthProviderResult authError(String message) throws AuthException {
throw new AuthException(message); throw new AuthException(message);
} }
@ -32,17 +41,17 @@ public static void registerProviders() {
/** /**
* Verifies the username and password * Verifies the username and password
*
* @param login user login * @param login user login
* @param password user password * @param password user password
* @param ip user ip * @param ip user ip
* @return player privileges, effective username and authorization token * @return player privileges, effective username and authorization token
* @throws Exception * @throws Exception Throws an exception {@link AuthException} {@link pro.gravit.utils.HookException} if the verification script returned a meaningful error
* Throws an exception {@link AuthException} {@link pro.gravit.utils.HookException} if the verification script returned a meaningful error
* In other cases, throwing an exception indicates a serious error * In other cases, throwing an exception indicates a serious error
*/ */
public abstract AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception; public abstract AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception;
public void preAuth(String login, AuthRequest.AuthPasswordInterface password, String customText, String ip) { public void preAuth(String login, AuthRequest.AuthPasswordInterface password, String ip) {
} }
@Override @Override

View file

@ -1,7 +1,6 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.LaunchServer;
public class AuthProviderResult { public class AuthProviderResult {
@ -9,10 +8,10 @@ public class AuthProviderResult {
public final String accessToken; public final String accessToken;
public final ClientPermissions permissions; public final ClientPermissions permissions;
public AuthProviderResult(String username, String accessToken, LaunchServer server) { public AuthProviderResult(String username, String accessToken) {
this.username = username; this.username = username;
this.accessToken = accessToken; this.accessToken = accessToken;
permissions = server.config.permissionsHandler.getPermissions(username); permissions = ClientPermissions.DEFAULT;
} }
public AuthProviderResult(String username, String accessToken, ClientPermissions permissions) { public AuthProviderResult(String username, String accessToken, ClientPermissions permissions) {

View file

@ -1,7 +1,5 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.io.IOException;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
@ -11,32 +9,28 @@
public class HibernateAuthProvider extends AuthProvider { public class HibernateAuthProvider extends AuthProvider {
public boolean autoReg; public boolean autoReg;
@Override @Override
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception { public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws Exception {
if (!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported"); if (!(password instanceof AuthPlainPassword)) throw new AuthException("This password type not supported");
User user = srv.config.dao.userService.findUserByUsername(login); User user = srv.config.dao.userDAO.findByUsername(login);
if(user == null && autoReg) if (user == null && autoReg) {
{
AuthHookManager.RegContext context = new AuthHookManager.RegContext(login, ((AuthPlainPassword) password).password, ip, false); AuthHookManager.RegContext context = new AuthHookManager.RegContext(login, ((AuthPlainPassword) password).password, ip, false);
if(srv.authHookManager.registraion.hook(context)) if (srv.authHookManager.registraion.hook(context)) {
{ //user = srv.config.dao.userService.registerNewUser(login, ((AuthPlainPassword) password).password); //TODO: FIX
user = srv.config.dao.userService.registerNewUser(login, ((AuthPlainPassword) password).password); } else {
}
else
{
throw new AuthException("Registration canceled. Try again later"); throw new AuthException("Registration canceled. Try again later");
} }
} }
if(user == null || !user.verifyPassword(((AuthPlainPassword) password).password)) if (user == null || !user.verifyPassword(((AuthPlainPassword) password).password)) {
{
if (user == null) throw new AuthException("Username incorrect"); if (user == null) throw new AuthException("Username incorrect");
else throw new AuthException("Username or password incorrect"); else throw new AuthException("Username or password incorrect");
} }
return new AuthProviderResult(login, SecurityHelper.randomStringToken(), srv); return new AuthProviderResult(login, SecurityHelper.randomStringToken(), user.getPermissions());
} }
@Override @Override
public void close() throws IOException { public void close() {
} }
} }

View file

@ -1,30 +1,29 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.io.IOException;
import java.net.URL;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
import pro.gravit.utils.HTTPRequest; import pro.gravit.launcher.HTTPRequest;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.net.URL;
public final class JsonAuthProvider extends AuthProvider { public final class JsonAuthProvider extends AuthProvider {
private static Gson gson = new Gson(); private static final Gson gson = new Gson();
private URL url; private URL url;
private String apiKey; private String apiKey;
public class authResult { public static class authResult {
String username; String username;
String error; String error;
long permissions; long permissions;
} }
public class authRequest { public static class authRequest {
public authRequest(String username, String password, String ip) { public authRequest(String username, String password, String ip) {
this.username = username; this.username = username;
this.password = password; this.password = password;
@ -38,9 +37,9 @@ public authRequest(String username, String password, String ip, String apiKey) {
this.apiKey = apiKey; this.apiKey = apiKey;
} }
String username; final String username;
String password; final String password;
String ip; final String ip;
String apiKey; String apiKey;
} }

View file

@ -1,10 +1,5 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
@ -15,12 +10,16 @@
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public final class MySQLAuthProvider extends AuthProvider { public final class MySQLAuthProvider extends AuthProvider {
private MySQLSourceConfig mySQLHolder; private MySQLSourceConfig mySQLHolder;
private String query; private String query;
private String message; private String message;
private String[] queryParams; private String[] queryParams;
private boolean usePermission;
@Override @Override
public void init(LaunchServer srv) { public void init(LaunchServer srv) {
@ -42,7 +41,7 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Execute SQL query // Execute SQL query
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT); s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
try (ResultSet set = s.executeQuery()) { try (ResultSet set = s.executeQuery()) {
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(set.getLong(2)) : srv.config.permissionsHandler.getPermissions(set.getString(1))) : authError(message); return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(set.getLong(2))) : authError(message);
} }
} }

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.io.IOException;
import java.util.Objects;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.helper.VerifyHelper;
import java.io.IOException;
import java.util.Objects;
public final class NullAuthProvider extends AuthProvider { public final class NullAuthProvider extends AuthProvider {
private volatile AuthProvider provider; private volatile AuthProvider provider;

View file

@ -1,11 +1,6 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
@ -14,12 +9,16 @@
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public final class PostgreSQLAuthProvider extends AuthProvider { public final class PostgreSQLAuthProvider extends AuthProvider {
private PostgreSQLSourceConfig postgreSQLHolder; private PostgreSQLSourceConfig postgreSQLHolder;
private String query; private String query;
private String message; private String message;
private String[] queryParams; private String[] queryParams;
private boolean usePermission;
@Override @Override
public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException { public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface password, String ip) throws SQLException, AuthException {
@ -33,7 +32,7 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Execute SQL query // Execute SQL query
s.setQueryTimeout(PostgreSQLSourceConfig.TIMEOUT); s.setQueryTimeout(PostgreSQLSourceConfig.TIMEOUT);
try (ResultSet set = s.executeQuery()) { try (ResultSet set = s.executeQuery()) {
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(set.getLong(2)) : srv.config.permissionsHandler.getPermissions(set.getString(1))) : authError(message); return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), new ClientPermissions(set.getLong(2))) : authError(message);
} }
} }
} }

View file

@ -1,9 +1,6 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.util.ArrayList; import pro.gravit.launcher.ClientPermissions;
import java.util.HashMap;
import java.util.Map;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.Reconfigurable; import pro.gravit.launchserver.Reconfigurable;
import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthException;
@ -12,6 +9,10 @@
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public final class RejectAuthProvider extends AuthProvider implements Reconfigurable { public final class RejectAuthProvider extends AuthProvider implements Reconfigurable {
public RejectAuthProvider() { public RejectAuthProvider() {
} }
@ -28,7 +29,7 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
if (whitelist != null) { if (whitelist != null) {
for (String username : whitelist) { for (String username : whitelist) {
if (login.equals(username)) { if (login.equals(username)) {
return new AuthProviderResult(login, SecurityHelper.randomStringToken(), srv); return new AuthProviderResult(login, SecurityHelper.randomStringToken(), ClientPermissions.DEFAULT);
} }
} }
} }
@ -45,7 +46,7 @@ public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>(); Map<String, Command> commands = new HashMap<>();
commands.put("message", new SubCommand() { commands.put("message", new SubCommand() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) {
message = args[0]; message = args[0];
LogHelper.info("New reject message: %s", message); LogHelper.info("New reject message: %s", message);
} }

View file

@ -1,10 +1,5 @@
package pro.gravit.launchserver.auth.provider; package pro.gravit.launchserver.auth.provider;
import java.io.IOException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import pro.gravit.launcher.ClientPermissions; import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
@ -15,11 +10,15 @@
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class RequestAuthProvider extends AuthProvider { public final class RequestAuthProvider extends AuthProvider {
private String url; private String url;
private transient Pattern pattern; private transient Pattern pattern;
private String response; private String response;
private boolean usePermission;
@Override @Override
public void init(LaunchServer srv) { public void init(LaunchServer srv) {
@ -37,7 +36,7 @@ public AuthProviderResult auth(String login, AuthRequest.AuthPasswordInterface p
// Match username // Match username
Matcher matcher = pattern.matcher(currentResponse); Matcher matcher = pattern.matcher(currentResponse);
return matcher.matches() && matcher.groupCount() >= 1 ? return matcher.matches() && matcher.groupCount() >= 1 ?
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(Long.parseLong(matcher.group("permission"))) : srv.config.permissionsHandler.getPermissions(login)) : new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), new ClientPermissions(Long.parseLong(matcher.group("permission")))) :
authError(currentResponse); authError(currentResponse);
} }

View file

@ -1,12 +1,12 @@
package pro.gravit.launchserver.auth.texture; package pro.gravit.launchserver.auth.texture;
import pro.gravit.launcher.profiles.Texture;
import pro.gravit.utils.helper.VerifyHelper;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import pro.gravit.launcher.profiles.Texture;
import pro.gravit.utils.helper.VerifyHelper;
public final class NullTextureProvider extends TextureProvider { public final class NullTextureProvider extends TextureProvider {
private volatile TextureProvider provider; private volatile TextureProvider provider;

View file

@ -1,15 +1,15 @@
package pro.gravit.launchserver.auth.texture; package pro.gravit.launchserver.auth.texture;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.profiles.Texture; import pro.gravit.launcher.profiles.Texture;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;
public final class RequestTextureProvider extends TextureProvider { public final class RequestTextureProvider extends TextureProvider {
public RequestTextureProvider() { public RequestTextureProvider() {
} }

View file

@ -1,13 +1,13 @@
package pro.gravit.launchserver.auth.texture; package pro.gravit.launchserver.auth.texture;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launcher.profiles.Texture; import pro.gravit.launcher.profiles.Texture;
import pro.gravit.utils.ProviderMap; import pro.gravit.utils.ProviderMap;
import java.io.IOException;
import java.util.UUID;
public abstract class TextureProvider implements AutoCloseable { public abstract class TextureProvider implements AutoCloseable {
public static ProviderMap<TextureProvider> providers = new ProviderMap<>("TextureProvider"); public static final ProviderMap<TextureProvider> providers = new ProviderMap<>("TextureProvider");
private static boolean registredProv = false; private static boolean registredProv = false;
public static void registerProviders() { public static void registerProviders() {

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.auth.texture; package pro.gravit.launchserver.auth.texture;
import java.util.UUID;
import pro.gravit.launcher.profiles.Texture; import pro.gravit.launcher.profiles.Texture;
import java.util.UUID;
public final class VoidTextureProvider extends TextureProvider { public final class VoidTextureProvider extends TextureProvider {
@Override @Override

View file

@ -0,0 +1,112 @@
package pro.gravit.launchserver.binary;
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class BinaryPipeline {
public final List<LauncherBuildTask> tasks = new ArrayList<>();
public final AtomicLong count = new AtomicLong(0);
public final Path buildDir;
public final String nameFormat;
public BinaryPipeline(Path buildDir, String nameFormat) {
this.buildDir = buildDir;
this.nameFormat = nameFormat;
}
public void addCounted(int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
List<LauncherBuildTask> indexes = new ArrayList<>();
tasks.stream().filter(pred).forEach(indexes::add);
indexes.forEach(e -> tasks.add(tasks.indexOf(e) + count, taskAdd));
}
public void replaceCounted(int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
List<LauncherBuildTask> indexes = new ArrayList<>();
tasks.stream().filter(pred).forEach(indexes::add);
indexes.forEach(e -> tasks.set(tasks.indexOf(e) + count, taskRep));
}
public void addPre(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(-1, pred, taskAdd);
}
public void add(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(0, pred, taskAdd);
}
public void addAfter(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(1, pred, taskAdd);
}
public void replacePre(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted(-1, pred, taskRep);
}
public void replace(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted( 0, pred, taskRep);
}
public void replaceAfter(Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted(1, pred, taskRep);
}
public <T extends LauncherBuildTask> List<T> getTasksByClass(Class<T> taskClass) {
return tasks.stream().filter(taskClass::isInstance).map(taskClass::cast).collect(Collectors.toList());
}
public <T extends LauncherBuildTask> Optional<T> getTaskByClass(Class<T> taskClass) {
return tasks.stream().filter(taskClass::isInstance).map(taskClass::cast).findFirst();
}
public void build(Path target, boolean deleteTempFiles) throws IOException {
LogHelper.info("Building launcher binary file");
count.set(0); // set jar number
Path thisPath = null;
boolean isNeedDelete = false;
long time_start = System.currentTimeMillis();
long time_this = time_start;
for (LauncherBuildTask task : tasks) {
LogHelper.subInfo("Task %s", task.getName());
Path oldPath = thisPath;
thisPath = task.process(oldPath);
long time_task_end = System.currentTimeMillis();
long time_task = time_task_end - time_this;
time_this = time_task_end;
if (isNeedDelete && deleteTempFiles) Files.deleteIfExists(oldPath);
isNeedDelete = task.allowDelete();
LogHelper.subInfo("Task %s processed from %d millis", task.getName(), time_task);
}
long time_end = System.currentTimeMillis();
if (isNeedDelete && deleteTempFiles) IOHelper.move(thisPath, target);
else IOHelper.copy(thisPath, target);
LogHelper.info("Build successful from %d millis", time_end - time_start);
}
public String nextName(String taskName) {
return String.format(nameFormat, taskName, count.getAndIncrement());
}
public Path nextPath(String taskName) {
return buildDir.resolve(nextName(taskName));
}
public Path nextPath(LauncherBuildTask task) {
return nextPath(task.getName());
}
public Path nextLowerPath(LauncherBuildTask task) {
return nextPath(CommonHelper.low(task.getName()));
}
}

View file

@ -1,37 +1,125 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.StreamObject;
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import pro.gravit.launchserver.binary.tasks.MainBuildTask; import static pro.gravit.utils.helper.IOHelper.UNICODE_CHARSET;
import pro.gravit.utils.helper.IOHelper; import static pro.gravit.utils.helper.IOHelper.newZipEntry;
public class BuildContext { public class BuildContext {
public final ZipOutputStream output; public final ZipOutputStream output;
public final LauncherConfigurator config; public final List<JarFile> readerClassPath;
public final MainBuildTask data; public final MainBuildTask task;
public final HashSet<String> fileList; public final HashSet<String> fileList;
public final HashSet<String> clientModules;
private final static class RuntimeDirVisitor extends SimpleFileVisitor<Path> {
private final ZipOutputStream output;
private final Map<String, byte[]> hashs;
private final Path sourceDir;
private final String targetDir;
public BuildContext(ZipOutputStream output, LauncherConfigurator config, MainBuildTask data) { private RuntimeDirVisitor(ZipOutputStream output, Map<String, byte[]> hashs, Path sourceDir, String targetDir) {
this.output = output; this.output = output;
this.config = config; this.hashs = hashs;
this.data = data; this.sourceDir = sourceDir;
this.targetDir = targetDir;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
String dirName = IOHelper.toString(sourceDir.relativize(dir));
output.putNextEntry(newEntry(dirName + '/'));
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = IOHelper.toString(sourceDir.relativize(file));
if(hashs != null)
hashs.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file));
// Create zip entry and transfer contents
output.putNextEntry(newEntry(fileName));
IOHelper.transfer(file, output);
// Return result
return super.visitFile(file, attrs);
}
private ZipEntry newEntry(String fileName) {
return newZipEntry( targetDir + IOHelper.CROSS_SEPARATOR + fileName);
}
}
public BuildContext(ZipOutputStream output, List<JarFile> readerClassPath, MainBuildTask task) {
this.output = output;
this.readerClassPath = readerClassPath;
this.task = task;
fileList = new HashSet<>(1024); fileList = new HashSet<>(1024);
clientModules = new HashSet<>();
} }
public void pushFile(String filename, InputStream inputStream) throws IOException { public void pushFile(String filename, InputStream inputStream) throws IOException {
ZipEntry zip = IOHelper.newZipEntry(filename); ZipEntry zip = IOHelper.newZipEntry(filename);
output.putNextEntry(zip); output.putNextEntry(zip);
IOHelper.transfer(inputStream, output); IOHelper.transfer(inputStream, output);
output.closeEntry();
fileList.add(filename); fileList.add(filename);
} }
public void pushFile(String filename, StreamObject object) throws IOException
{
ZipEntry zip = IOHelper.newZipEntry(filename);
output.putNextEntry(zip);
object.write(new HOutput(output));
output.closeEntry();
fileList.add(filename);
}
public void pushFile(String filename, Object object, Type type) throws IOException
{
String bytes = Launcher.gsonManager.gson.toJson(object, type);
pushBytes(filename, bytes.getBytes(UNICODE_CHARSET));
}
public void pushDir(Path dir, String targetDir, Map<String, byte[]> hashMap, boolean hidden) throws IOException
{
IOHelper.walk(dir, new RuntimeDirVisitor(output, hashMap, dir, targetDir), hidden);
}
public void pushBytes(String filename, byte[] bytes) throws IOException {
ZipEntry zip = IOHelper.newZipEntry(filename);
output.putNextEntry(zip);
output.write(bytes);
output.closeEntry();
fileList.add(filename);
}
@Deprecated
public void pushJarFile(ZipInputStream input) throws IOException { public void pushJarFile(ZipInputStream input) throws IOException {
ZipEntry e = input.getNextEntry(); ZipEntry e = input.getNextEntry();
while (e != null) { while (e != null) {
@ -45,7 +133,7 @@ public void pushJarFile(ZipInputStream input) throws IOException {
e = input.getNextEntry(); e = input.getNextEntry();
} }
} }
@Deprecated
public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOException { public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOException {
ZipEntry e = input.getNextEntry(); ZipEntry e = input.getNextEntry();
while (e != null) { while (e != null) {
@ -59,4 +147,47 @@ public void pushJarFile(ZipInputStream input, Set<String> blacklist) throws IOEx
e = input.getNextEntry(); e = input.getNextEntry();
} }
} }
public void pushJarFile(Path jarfile, Predicate<ZipEntry> filter, Predicate<String> needTransform) throws IOException
{
pushJarFile(jarfile.toUri().toURL(), filter, needTransform);
}
public void pushJarFile(URL jarfile, Predicate<ZipEntry> filter, Predicate<String> needTransform) throws IOException
{
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(jarfile))) {
ZipEntry e = input.getNextEntry();
while(e != null)
{
String filename = e.getName();
if(e.isDirectory() || fileList.contains(filename) || filter.test(e))
{
e = input.getNextEntry();
continue;
}
try {
output.putNextEntry(IOHelper.newZipEntry(e));
} catch (ZipException ex) {
LogHelper.warning("Write %s failed: %s", filename, ex.getMessage() == null ? "null" : ex.getMessage());
e = input.getNextEntry();
continue;
}
if (filename.endsWith(".class")) {
String classname = filename.replace('/', '.').substring(0,
filename.length() - ".class".length());
if(!needTransform.test(classname))
{
IOHelper.transfer(input, output);
}
else
{
byte[] bytes = IOHelper.read(input);
bytes = task.transformClass(bytes, classname, this);
output.write(bytes);
}
} else
IOHelper.transfer(input, output);
fileList.add(filename);
e = input.getNextEntry();
}
}
}
} }

View file

@ -1,123 +1,17 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import java.io.IOException;
import java.nio.file.Path;
import net.sf.launch4j.Builder;
import net.sf.launch4j.Log;
import net.sf.launch4j.config.Config;
import net.sf.launch4j.config.ConfigPersister;
import net.sf.launch4j.config.Jre;
import net.sf.launch4j.config.LanguageID;
import net.sf.launch4j.config.VersionInfo;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.Version; import pro.gravit.launchserver.binary.tasks.exe.Launch4JTask;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public final class EXEL4JLauncherBinary extends LauncherBinary { public final class EXEL4JLauncherBinary extends LauncherBinary {
private final static class Launch4JLog extends Log {
private static final Launch4JLog INSTANCE = new Launch4JLog();
@Override
public void append(String s) {
LogHelper.subInfo(s);
}
@Override
public void clear() {
// Do nothing
}
}
// URL constants
private static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle
// JRE 8
// File constants
private final Path faviconFile;
public EXEL4JLauncherBinary(LaunchServer server) { public EXEL4JLauncherBinary(LaunchServer server) {
super(server, LauncherBinary.resolve(server, ".exe")); super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe");
faviconFile = server.dir.resolve("favicon.ico");
} }
@Override @Override
public void build() throws IOException { public void init() {
LogHelper.info("Building launcher EXE binary file (Using Launch4J)"); tasks.add(new Launch4JTask(server));
setConfig();
// Set favicon path
Config config = ConfigPersister.getInstance().getConfig();
if (IOHelper.isFile(faviconFile))
config.setIcon(faviconFile.toFile());
else {
config.setIcon(null);
LogHelper.warning("Missing favicon.ico file");
}
// Start building
Builder builder = new Builder(Launch4JLog.INSTANCE);
try {
builder.build();
} catch (Throwable e) {
throw new IOException(e);
}
}
private void setConfig() {
Config config = new Config();
// Set file options
config.setChdir(".");
config.setErrTitle("JVM Error");
config.setDownloadUrl(DOWNLOAD_URL);
// Set boolean options
config.setPriorityIndex(0);
config.setHeaderType(Config.GUI_HEADER);
config.setStayAlive(false);
config.setRestartOnCrash(false);
// Prepare JRE
Jre jre = new Jre();
jre.setMinVersion("1.8.0");
if (server.config.launch4j.setMaxVersion)
jre.setMaxVersion(server.config.launch4j.maxVersion);
jre.setRuntimeBits(Jre.RUNTIME_BITS_64_AND_32);
jre.setJdkPreference(Jre.JDK_PREFERENCE_PREFER_JRE);
config.setJre(jre);
// Prepare version info (product)
VersionInfo info = new VersionInfo();
info.setProductName(server.config.launch4j.productName);
info.setProductVersion(formatVars(server.config.launch4j.productVer));
info.setFileDescription(server.config.launch4j.fileDesc);
info.setFileVersion(formatVars(server.config.launch4j.fileVer));
info.setCopyright(server.config.launch4j.copyright);
info.setTrademarks(server.config.launch4j.trademarks);
info.setInternalName(formatVars(server.config.launch4j.internalName));
// Prepare version info (file)
info.setTxtFileVersion(formatVars(server.config.launch4j.txtFileVersion));
info.setTxtProductVersion(formatVars(server.config.launch4j.txtProductVersion));
// Prepare version info (misc)
info.setOriginalFilename(syncBinaryFile.getFileName().toString());
info.setLanguage(LanguageID.RUSSIAN);
config.setVersionInfo(info);
// Set JAR wrapping options
config.setDontWrapJar(false);
config.setJar(server.launcherBinary.syncBinaryFile.toFile());
config.setOutfile(syncBinaryFile.toFile());
// Return prepared config
ConfigPersister.getInstance().setAntConfig(config, null);
}
private static String VERSION = Version.getVersion().getVersionString();
private static int BUILD = Version.getVersion().build;
public static String formatVars(String mask) {
return String.format(mask, VERSION, BUILD);
} }
} }

View file

@ -1,16 +1,16 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import java.io.IOException;
import java.nio.file.Files;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.nio.file.Files;
public class EXELauncherBinary extends LauncherBinary { public class EXELauncherBinary extends LauncherBinary {
public EXELauncherBinary(LaunchServer server) { public EXELauncherBinary(LaunchServer server) {
super(server, LauncherBinary.resolve(server, ".exe")); super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s-%d.exe");
} }
@Override @Override

View file

@ -1,5 +1,9 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.tasks.*;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -7,35 +11,20 @@
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.tasks.AdditionalFixesApplyTask;
import pro.gravit.launchserver.binary.tasks.AttachJarsTask;
import pro.gravit.launchserver.binary.tasks.CompressBuildTask;
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
import pro.gravit.launchserver.binary.tasks.PrepareBuildTask;
import pro.gravit.launchserver.binary.tasks.ProGuardBuildTask;
import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public final class JARLauncherBinary extends LauncherBinary { public final class JARLauncherBinary extends LauncherBinary {
public final AtomicLong count; public final AtomicLong count;
public final Path runtimeDir; public final Path runtimeDir;
public final Path guardDir; public final Path guardDir;
public final Path buildDir; public final Path buildDir;
public List<LauncherBuildTask> tasks; public final List<Path> coreLibs;
public List<Path> coreLibs; public final List<Path> addonLibs;
public List<Path> addonLibs;
public JARLauncherBinary(LaunchServer server) throws IOException { public JARLauncherBinary(LaunchServer server) throws IOException {
super(server, resolve(server, ".jar")); super(server, resolve(server, ".jar"), "Launcher-%s-%d.jar");
count = new AtomicLong(0); count = new AtomicLong(0);
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR); runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
guardDir = server.dir.resolve(Launcher.GUARD_DIR); guardDir = server.dir.resolve(Launcher.GUARD_DIR);
buildDir = server.dir.resolve("build"); buildDir = server.dir.resolve("build");
tasks = new ArrayList<>();
coreLibs = new ArrayList<>(); coreLibs = new ArrayList<>();
addonLibs = new ArrayList<>(); addonLibs = new ArrayList<>();
if (!Files.isDirectory(buildDir)) { if (!Files.isDirectory(buildDir)) {
@ -47,52 +36,13 @@ public JARLauncherBinary(LaunchServer server) throws IOException {
@Override @Override
public void init() { public void init() {
tasks.add(new PrepareBuildTask(server)); tasks.add(new PrepareBuildTask(server));
if(!server.config.sign.enabled) tasks.add(new CertificateAutogenTask(server));
tasks.add(new MainBuildTask(server)); tasks.add(new MainBuildTask(server));
if (server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); if (server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server));
tasks.add(new ProGuardBuildTask(server)); tasks.add(new ProGuardBuildTask(server));
tasks.add(new AdditionalFixesApplyTask(server)); tasks.add(new AdditionalFixesApplyTask(server));
if (!server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); if (!server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server));
if (server.config.launcher.compress) tasks.add(new CompressBuildTask(server)); if (server.config.launcher.compress) tasks.add(new CompressBuildTask(server));
} tasks.add(new SignJarTask(server.config.sign, server));
@Override
public void build() throws IOException {
LogHelper.info("Building launcher binary file");
count.set(0); // set jar number
Path thisPath = null;
boolean isNeedDelete = false;
long time_start = System.currentTimeMillis();
long time_this = time_start;
for (LauncherBuildTask task : tasks) {
LogHelper.subInfo("Task %s", task.getName());
Path oldPath = thisPath;
thisPath = task.process(oldPath);
long time_task_end = System.currentTimeMillis();
long time_task = time_task_end - time_this;
time_this = time_task_end;
if (isNeedDelete && server.config.launcher.deleteTempFiles) Files.deleteIfExists(oldPath);
isNeedDelete = task.allowDelete();
LogHelper.subInfo("Task %s processed from %d millis", task.getName(), time_task);
}
long time_end = System.currentTimeMillis();
if (isNeedDelete && server.config.launcher.deleteTempFiles) IOHelper.move(thisPath, syncBinaryFile);
else IOHelper.copy(thisPath, syncBinaryFile);
LogHelper.info("Build successful from %d millis", time_end - time_start);
}
public String nextName(String taskName) {
return String.format("Launcher-%s-%d.jar", taskName, count.getAndIncrement());
}
public Path nextPath(String taskName) {
return buildDir.resolve(nextName(taskName));
}
public Path nextPath(LauncherBuildTask task) {
return nextPath(task.getName());
}
public Path nextLowerPath(LauncherBuildTask task) {
return nextPath(CommonHelper.low(task.getName()));
} }
} }

View file

@ -1,24 +1,28 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import java.io.IOException;
import java.nio.file.Path;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
public abstract class LauncherBinary { import java.io.IOException;
import java.nio.file.Path;
public abstract class LauncherBinary extends BinaryPipeline {
public final LaunchServer server; public final LaunchServer server;
public final Path syncBinaryFile; public final Path syncBinaryFile;
private volatile byte[] digest; private volatile byte[] digest;
private volatile byte[] sign; private volatile byte[] sign;
protected LauncherBinary(LaunchServer server, Path binaryFile) { protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat) {
super(server.dir.resolve("build"), nameFormat);
this.server = server; this.server = server;
syncBinaryFile = binaryFile; syncBinaryFile = binaryFile;
} }
public abstract void build() throws IOException; public void build() throws IOException
{
build(syncBinaryFile, server.config.launcher.deleteTempFiles);
}
public final boolean exists() { public final boolean exists() {

View file

@ -1,177 +0,0 @@
package pro.gravit.launchserver.binary;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import pro.gravit.launcher.AutogenConfig;
import pro.gravit.launcher.LauncherConfig;
import pro.gravit.launcher.modules.LauncherModule;
import pro.gravit.launchserver.asm.ClassMetadataReader;
import pro.gravit.launchserver.asm.SafeClassWriter;
public class LauncherConfigurator {
private static final String modulesManagerName = "pro/gravit/launcher/modules/LauncherModulesManager";
private static final String launcherName = "pro/gravit/launcher/LauncherEngine";
private static final String modulesManagerDesc = "Lpro/gravit/launcher/client/ClientModuleManager;";
private static final String registerModDesc = Type.getMethodDescriptor(Type.getType(LauncherModule.class), Type.getType(LauncherModule.class));
private static final String autoGenConfigName = Type.getInternalName(AutogenConfig.class);
private static final String stringDesc = Type.getDescriptor(String.class);
private final ClassNode configclass;
private final MethodNode constructor;
private final MethodNode initModuleMethod;
public LauncherConfigurator(ClassNode configclass) {
this.configclass = configclass;
constructor = configclass.methods.stream().filter(e -> "<init>".equals(e.name)).findFirst().get();
constructor.instructions = new InsnList();
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V"));
initModuleMethod = configclass.methods.stream().filter(e -> "initModules".equals(e.name)).findFirst().get();
initModuleMethod.instructions = new InsnList();
}
public void addModuleClass(String fullName) {
initModuleMethod.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, launcherName, "modulesManager", modulesManagerDesc));
initModuleMethod.instructions.add(new TypeInsnNode(Opcodes.NEW, fullName.replace('.', '/')));
initModuleMethod.instructions.add(new InsnNode(Opcodes.DUP));
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, fullName.replace('.', '/'), "<init>", "()V"));
initModuleMethod.instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, modulesManagerName, "loadModule", registerModDesc));
}
public byte[] getBytecode(ClassMetadataReader reader) {
constructor.instructions.add(new InsnNode(Opcodes.RETURN));
initModuleMethod.instructions.add(new InsnNode(Opcodes.RETURN));
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
configclass.accept(cw);
return cw.toByteArray();
}
public String getZipEntryPath() {
return configclass.name.concat(".class");
}
public void setAddress(String address) {
setStringField("address", address);
}
public void setProjectName(String name) {
setStringField("projectname", name);
}
public void setSecretKey(String key) {
setStringField("secretKeyClient", key);
}
public void setOemUnlockKey(String key) {
setStringField("oemUnlockKey", key);
}
private void setStringField(String name, String value)
{
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new LdcInsnNode(value));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, name, stringDesc));
}
public void setGuardType(String key) {
setStringField("guardType", key);
}
public void setSecureCheck(String hash, String salt) {
setStringField("secureCheckHash", hash);
setStringField("secureCheckSalt", salt);
}
private void push(final int value) {
if (value >= -1 && value <= 5)
constructor.instructions.add(new InsnNode(Opcodes.ICONST_0 + value));
else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
constructor.instructions.add(new IntInsnNode(Opcodes.BIPUSH, value));
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
constructor.instructions.add(new IntInsnNode(Opcodes.SIPUSH, value));
else
constructor.instructions.add(new LdcInsnNode(value));
}
public void setEnv(LauncherConfig.LauncherEnvironment env) {
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
int i = 2;
switch (env) {
case DEV:
i = 0;
break;
case DEBUG:
i = 1;
break;
case STD:
i = 2;
break;
case PROD:
i = 3;
break;
}
push(i);
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "env", Type.INT_TYPE.getInternalName()));
}
public void setClientPort(int port) {
setIntegerField("clientPort", port);
}
public void setIntegerField(String name, int value)
{
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
push(value);
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, name, Type.INT_TYPE.getInternalName()));
}
public void setWarningMissArchJava(boolean b) {
setBooleanField("isWarningMissArchJava", b);
}
private void setBooleanField(String name, boolean b)
{
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new InsnNode(b ? Opcodes.ICONST_1 : Opcodes.ICONST_0));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, name, Type.BOOLEAN_TYPE.getInternalName()));
}
public void setGuardLicense(String name, String key, String encryptKey) {
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new LdcInsnNode(name));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc));
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new LdcInsnNode(key));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc));
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new LdcInsnNode(encryptKey));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc));
}
public void nullGuardLicense() {
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc));
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc));
constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL));
constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc));
}
}

View file

@ -1,5 +1,9 @@
package pro.gravit.launchserver.binary; package pro.gravit.launchserver.binary;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.asm.NodeUtils;
import pro.gravit.utils.helper.*;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -7,24 +11,28 @@
import java.nio.file.Path; import java.nio.file.Path;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.helper.UnpackHelper;
public class ProguardConf { public class ProguardConf {
private static final String chars = "1aAbBcC2dDeEfF3gGhHiI4jJkKl5mMnNoO6pPqQrR7sStT8uUvV9wWxX0yYzZ"; private static final char[] chars = "1aAbBcC2dDeEfF3gGhHiI4jJkKl5mMnNoO6pPqQrR7sStT8uUvV9wWxX0yYzZ".toCharArray();
public static final String[] JAVA9_OPTS = new String[] {
"-libraryjars '<java.home>/jmods/'"
};
public static final String[] JAVA8_OPTS = new String[] {
"-libraryjars '<java.home>/lib/rt.jar'",
"-libraryjars '<java.home>/lib/jce.jar'",
"-libraryjars '<java.home>/lib/ext/nashorn.jar'",
"-libraryjars '<java.home>/lib/ext/jfxrt.jar'"
};
private static String generateString(SecureRandom rand, String lowString, String upString, int il) { private static String generateString(SecureRandom rand, String lowString, String upString, int il) {
StringBuilder sb = new StringBuilder(Math.max(il, lowString.length())); StringBuilder sb = new StringBuilder(Math.max(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)); sb.append(rand.nextBoolean() ? lowString.charAt(i) : upString.charAt(i));
} }
int toI = il - lowString.length(); int toI = il - lowString.length();
for (int i = 0; i < toI; i++) sb.append(chars.charAt(rand.nextInt(chars.length()))); for (int i = 0; i < toI; i++) sb.append(chars[rand.nextInt(chars.length)]);
return sb.toString(); return sb.toString();
} }
@ -45,18 +53,21 @@ public ProguardConf(LaunchServer srv) {
public String[] buildConfig(Path inputJar, Path outputJar) { public String[] buildConfig(Path inputJar, Path outputJar) {
List<String> confStrs = new ArrayList<>(); List<String> confStrs = new ArrayList<>();
prepare(false); prepare(false);
if (srv.config.launcher.proguardGenMappings) confStrs.add("-printmapping \'" + mappings.toFile().getName() + "\'"); if (srv.config.launcher.proguardGenMappings)
confStrs.add("-printmapping \'" + mappings.toFile().getName() + "\'");
confStrs.add("-obfuscationdictionary \'" + words.toFile().getName() + "\'"); confStrs.add("-obfuscationdictionary \'" + words.toFile().getName() + "\'");
confStrs.add("-injar \'" + inputJar.toAbsolutePath() + "\'"); confStrs.add("-injar \'" + inputJar.toAbsolutePath() + "\'");
confStrs.add("-outjar \'" + outputJar.toAbsolutePath() + "\'"); confStrs.add("-outjar \'" + outputJar.toAbsolutePath() + "\'");
Collections.addAll(confStrs, JVMHelper.JVM_VERSION >= 9 ? JAVA9_OPTS : JAVA8_OPTS);
srv.launcherBinary.coreLibs.stream() srv.launcherBinary.coreLibs.stream()
.map(e -> "-libraryjars \'" + e.toAbsolutePath().toString() + "\'") .map(e -> "-libraryjars \'" + e.toAbsolutePath().toString() + "\'")
.forEach(confStrs::add); .forEach(confStrs::add);
srv.launcherBinary.addonLibs.stream() srv.launcherBinary.addonLibs.stream()
.map(e -> "-libraryjars \'" + e.toAbsolutePath().toString() + "\'") .map(e -> "-libraryjars \'" + e.toAbsolutePath().toString() + "\'")
.forEach(confStrs::add); .forEach(confStrs::add);
confStrs.add("-classobfuscationdictionary \'" + words.toFile().getName() + "\'"); confStrs.add("-classobfuscationdictionary \'" + words.toFile().getName() + "\'");
confStrs.add(readConf()); confStrs.add("@".concat(config.toFile().getName()));
return confStrs.toArray(new String[0]); return confStrs.toArray(new String[0]);
} }
@ -88,8 +99,4 @@ public void prepare(boolean force) {
LogHelper.error(e); LogHelper.error(e);
} }
} }
private String readConf() {
return "@".concat(config.toFile().getName());
}
} }

View file

@ -0,0 +1,289 @@
package pro.gravit.launchserver.binary;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import pro.gravit.launchserver.helper.SignHelper;
import pro.gravit.utils.helper.IOHelper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* Generator of signed Jars. It stores some data in memory therefore it is not suited for creation of large files. The
* usage:
* <pre>
* KeyStore keystore = KeyStore.getInstance("JKS");
* keyStore.load(keystoreStream, "keystorePassword");
* SignerJar jar = new SignerJar(out, keyStore, "keyAlias", "keyPassword");
* signedJar.addManifestAttribute("Main-Class", "com.example.MainClass");
* signedJar.addManifestAttribute("Application-Name", "Example");
* signedJar.addManifestAttribute("Permissions", "all-permissions");
* signedJar.addManifestAttribute("Codebase", "*");
* signedJar.addFileContents("com/example/MainClass.class", clsData);
* signedJar.addFileContents("JNLP-INF/APPLICATION.JNLP", generateJnlpContents());
* signedJar.close();
* </pre>
*/
public class SignerJar implements AutoCloseable {
private static final String MANIFEST_FN = "META-INF/MANIFEST.MF";
private final String SIG_FN;
private final String SIG_KEY_FN;
private static final String DIGEST_HASH = SignHelper.hashFunctionName + "-Digest";
private final ZipOutputStream zos;
private final Map<String, String> manifestAttributes;
private String manifestHash;
private String manifestMainHash;
private final Map<String, String> fileDigests;
private final Map<String, String> sectionDigests;
private final Supplier<CMSSignedDataGenerator> gen;
public SignerJar(ZipOutputStream out, Supplier<CMSSignedDataGenerator> gen, String sig_fn, String sig_key_fn) {
zos = out;
this.gen = gen;
manifestAttributes = new LinkedHashMap<>();
fileDigests = new LinkedHashMap<>();
sectionDigests = new LinkedHashMap<>();
SIG_FN = "META-INF/".concat(sig_fn);
SIG_KEY_FN = "META-INF/".concat(sig_key_fn);
}
/**
* Adds a file to the JAR. The file is immediately added to the zipped output stream. This method cannot be called once
* the stream is closed.
*
* @param filename name of the file to add (use forward slash as a path separator)
* @param contents contents of the file
* @throws IOException
* @throws NullPointerException if any of the arguments is {@code null}
*/
public void addFileContents(String filename, byte[] contents) throws IOException {
addFileContents(filename, new ByteArrayInputStream(contents));
}
/**
* Adds a file to the JAR. The file is immediately added to the zipped output stream. This method cannot be called once
* the stream is closed.
*
* @param filename name of the file to add (use forward slash as a path separator)
* @param contents contents of the file
* @throws IOException
* @throws NullPointerException if any of the arguments is {@code null}
*/
public void addFileContents(String filename, InputStream contents) throws IOException {
addFileContents(IOHelper.newZipEntry(filename), contents);
}
/**
* Adds a file to the JAR. The file is immediately added to the zipped output stream. This method cannot be called once
* the stream is closed.
*
* @param entry name of the file to add (use forward slash as a path separator)
* @param contents contents of the file
* @throws IOException
* @throws NullPointerException if any of the arguments is {@code null}
*/
public void addFileContents(ZipEntry entry, byte[] contents) throws IOException {
addFileContents(entry, new ByteArrayInputStream(contents));
}
/**
* Adds a file to the JAR. The file is immediately added to the zipped output stream. This method cannot be called once
* the stream is closed.
*
* @param entry name of the file to add (use forward slash as a path separator)
* @param contents contents of the file
* @throws IOException
* @throws NullPointerException if any of the arguments is {@code null}
*/
public void addFileContents(ZipEntry entry, InputStream contents) throws IOException {
zos.putNextEntry(entry);
SignHelper.HashingOutputStream out = new SignHelper.HashingNonClosingOutputStream(zos, SignHelper.hasher());
IOHelper.transfer(contents, out);
zos.closeEntry();
fileDigests.put(entry.getName(), Base64.getEncoder().encodeToString(out.digest()));
}
/**
* Adds a header to the manifest of the JAR.
*
* @param name name of the attribute, it is placed into the main section of the manifest file
* @param value value of the attribute
*/
public void addManifestAttribute(String name, String value) {
manifestAttributes.put(name, value);
}
/**
* Closes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It closes the
* underlying stream.
*
* @throws IOException
* @throws RuntimeException if the signing goes wrong
*/
@Override
public void close() throws IOException {
finish();
zos.close();
}
/**
* Finishes the JAR file by writing the manifest and signature data to it and finishing the ZIP entries. It leaves the
* underlying stream open.
*
* @throws IOException
* @throws RuntimeException if the signing goes wrong
*/
public void finish() throws IOException {
writeManifest();
byte[] sig = writeSigFile();
writeSignature(sig);
zos.finish();
}
public ZipOutputStream getZos() {
return zos;
}
/**
* Helper for {@link #writeManifest()} that creates the digest of one entry.
*/
private String hashEntrySection(String name, Attributes attributes) throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
ByteArrayOutputStream o = new ByteArrayOutputStream();
manifest.write(o);
int emptyLen = o.toByteArray().length;
manifest.getEntries().put(name, attributes);
manifest.write(o);
byte[] ob = o.toByteArray();
ob = Arrays.copyOfRange(ob, emptyLen, ob.length);
return Base64.getEncoder().encodeToString(SignHelper.hasher().digest(ob));
}
/**
* Helper for {@link #writeManifest()} that creates the digest of the main section.
*/
private String hashMainSection(Attributes attributes) throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().putAll(attributes);
SignHelper.HashingOutputStream o = new SignHelper.HashingNonClosingOutputStream(SignHelper.NULL, SignHelper.hasher());
manifest.write(o);
return Base64.getEncoder().encodeToString(o.digest());
}
/**
* Returns the CMS signed data.
*/
private byte[] signSigFile(byte[] sigContents) throws Exception {
CMSSignedDataGenerator gen = this.gen.get();
CMSTypedData cmsData = new CMSProcessableByteArray(sigContents);
CMSSignedData signedData = gen.generate(cmsData, false);
return signedData.getEncoded();
}
/**
* Writes the manifest to the JAR. It also calculates the digests that are required to be placed in the the signature
* file.
*
* @throws IOException
*/
private void writeManifest() throws IOException {
zos.putNextEntry(IOHelper.newZipEntry(MANIFEST_FN));
Manifest man = new Manifest();
// main section
Attributes mainAttributes = man.getMainAttributes();
mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
for (Map.Entry<String, String> entry : manifestAttributes.entrySet())
mainAttributes.put(new Attributes.Name(entry.getKey()), entry.getValue());
// individual files sections
Attributes.Name digestAttr = new Attributes.Name(DIGEST_HASH);
for (Map.Entry<String, String> entry : fileDigests.entrySet()) {
Attributes attributes = new Attributes();
man.getEntries().put(entry.getKey(), attributes);
attributes.put(digestAttr, entry.getValue());
sectionDigests.put(entry.getKey(), hashEntrySection(entry.getKey(), attributes));
}
SignHelper.HashingOutputStream out = new SignHelper.HashingNonClosingOutputStream(zos, SignHelper.hasher());
man.write(out);
zos.closeEntry();
manifestHash = Base64.getEncoder().encodeToString(out.digest());
manifestMainHash = hashMainSection(man.getMainAttributes());
}
/**
* Writes the .SIG file to the JAR.
*
* @return the contents of the file as bytes
*/
private byte[] writeSigFile() throws IOException {
zos.putNextEntry(IOHelper.newZipEntry(SIG_FN));
Manifest man = new Manifest();
// main section
Attributes mainAttributes = man.getMainAttributes();
mainAttributes.put(Attributes.Name.SIGNATURE_VERSION, "1.0");
mainAttributes.put(new Attributes.Name(DIGEST_HASH + "-Manifest"), manifestHash);
mainAttributes.put(new Attributes.Name(DIGEST_HASH + "-Manifest-Main-Attributes"), manifestMainHash);
// individual files sections
Attributes.Name digestAttr = new Attributes.Name(DIGEST_HASH);
for (Map.Entry<String, String> entry : sectionDigests.entrySet()) {
Attributes attributes = new Attributes();
man.getEntries().put(entry.getKey(), attributes);
attributes.put(digestAttr, entry.getValue());
}
man.write(zos);
zos.closeEntry();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
man.write(baos);
return baos.toByteArray();
}
/**
* Signs the .SIG file and writes the signature (.RSA file) to the JAR.
*
* @throws IOException
* @throws RuntimeException if the signing failed
*/
private void writeSignature(byte[] sigFile) throws IOException {
zos.putNextEntry(IOHelper.newZipEntry(SIG_KEY_FN));
try {
byte[] signature = signSigFile(sigFile);
zos.write(signature);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Signing failed.", e);
}
zos.closeEntry();
}
}

View file

@ -1,31 +0,0 @@
package pro.gravit.launchserver.binary;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class SimpleEXELauncherBinary extends LauncherBinary {
public Path exeTemplate;
public SimpleEXELauncherBinary(LaunchServer server) {
super(server, LauncherBinary.resolve(server, ".exe"));
exeTemplate = server.dir.resolve("SimpleTemplate.exe");
}
@Override
public void build() throws IOException {
if(!IOHelper.isFile(exeTemplate))
{
LogHelper.warning("[SimpleEXEBinary] File %s not found. %s not created", exeTemplate.toString(), syncBinaryFile.toString());
return;
}
try(OutputStream output = IOHelper.newOutput(syncBinaryFile))
{
IOHelper.transfer(exeTemplate, output);
IOHelper.transfer(server.launcherBinary.syncBinaryFile, output);
}
}
}

View file

@ -1,25 +1,21 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
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;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.asm.ClassMetadataReader; import pro.gravit.launchserver.asm.ClassMetadataReader;
import pro.gravit.launchserver.asm.SafeClassWriter; import pro.gravit.launchserver.asm.SafeClassWriter;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.function.Predicate;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class AdditionalFixesApplyTask implements LauncherBuildTask { public class AdditionalFixesApplyTask implements LauncherBuildTask {
private final LaunchServer server; private final LaunchServer server;
@ -37,28 +33,14 @@ public String getName() {
public Path process(Path inputFile) throws IOException { public Path process(Path inputFile) throws IOException {
Path out = server.launcherBinary.nextPath("post-fixed"); Path out = server.launcherBinary.nextPath("post-fixed");
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) { try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(out))) {
apply(inputFile, inputFile, output, server, (e) -> false); apply(inputFile, inputFile, output, server, (e) -> false, true);
} }
return out; return out;
} }
public static void apply(Path inputFile, Path addFile, ZipOutputStream output, LaunchServer srv, Predicate<ZipEntry> excluder) throws IOException { public static void apply(Path inputFile, Path addFile, ZipOutputStream output, LaunchServer srv, Predicate<ZipEntry> excluder, boolean needFixes) throws IOException {
try (ClassMetadataReader reader = new ClassMetadataReader()) { try (ClassMetadataReader reader = new ClassMetadataReader()) {
reader.getCp().add(new JarFile(inputFile.toFile())); reader.getCp().add(new JarFile(inputFile.toFile()));
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)) { try (ZipInputStream input = IOHelper.newZipInput(addFile)) {
ZipEntry e = input.getNextEntry(); ZipEntry e = input.getNextEntry();
while (e != null) { while (e != null) {
@ -70,16 +52,12 @@ public static void apply(Path inputFile, Path addFile, ZipOutputStream output, L
output.putNextEntry(IOHelper.newZipEntry(e)); output.putNextEntry(IOHelper.newZipEntry(e));
if (filename.endsWith(".class")) { if (filename.endsWith(".class")) {
byte[] bytes; byte[] bytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048)) { if(needFixes) {
IOHelper.transfer(input, outputStream); bytes = classFix(input, reader, srv.config.launcher.stripLineNumbers);
bytes = outputStream.toByteArray();
}
try {
bytes = classFix(bytes, reader, srv.config.launcher.stripLineNumbers);
} catch (Throwable t) {
LogHelper.error(t);
}
output.write(bytes); output.write(bytes);
}
else
IOHelper.transfer(input, output);
} else } else
IOHelper.transfer(input, output); IOHelper.transfer(input, output);
e = input.getNextEntry(); e = input.getNextEntry();
@ -88,8 +66,8 @@ public static void apply(Path inputFile, Path addFile, ZipOutputStream output, L
} }
} }
private static byte[] classFix(byte[] bytes, ClassMetadataReader reader, boolean stripNumbers) { private static byte[] classFix(InputStream input, ClassMetadataReader reader, boolean stripNumbers) throws IOException {
ClassReader cr = new ClassReader(bytes); ClassReader cr = new ClassReader(input);
ClassNode cn = new ClassNode(); ClassNode cn = new ClassNode();
cr.accept(cn, stripNumbers ? (ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) : ClassReader.SKIP_FRAMES); cr.accept(cn, stripNumbers ? (ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) : ClassReader.SKIP_FRAMES);
ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

View file

@ -1,5 +1,9 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
@ -8,10 +12,6 @@
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class AttachJarsTask implements LauncherBuildTask { public class AttachJarsTask implements LauncherBuildTask {
private final LaunchServer srv; private final LaunchServer srv;
private final List<Path> jars; private final List<Path> jars;
@ -56,7 +56,7 @@ public Path process(Path inputFile) throws IOException {
private void attach(ZipOutputStream output, Path inputFile, List<Path> lst) throws IOException { private void attach(ZipOutputStream output, Path inputFile, List<Path> lst) throws IOException {
for (Path p : lst) { for (Path p : lst) {
LogHelper.debug("Attaching: " + p); LogHelper.debug("Attaching: " + p);
AdditionalFixesApplyTask.apply(inputFile, p, output, srv, (e) -> exclusions.stream().anyMatch(e.getName()::startsWith)); AdditionalFixesApplyTask.apply(inputFile, p, output, srv, (e) -> exclusions.stream().anyMatch(e.getName()::startsWith), false);
} }
} }

View file

@ -0,0 +1,81 @@
package pro.gravit.launchserver.binary.tasks;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.helper.SignHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Path;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
public class CertificateAutogenTask implements LauncherBuildTask {
private LaunchServer server;
public CertificateAutogenTask(LaunchServer server) {
this.server = server;
}
@Override
public String getName() {
return "CertificateAutogen";
}
public X509Certificate certificate;
public X509CertificateHolder bcCertificate;
public CMSSignedDataGenerator signedDataGenerator;
@Override
public Path process(Path inputFile) throws IOException {
if(signedDataGenerator != null) return inputFile;
try {
X500NameBuilder subject = new X500NameBuilder();
subject.addRDN(BCStyle.CN, server.config.projectName.concat(" Autogenerated"));
subject.addRDN(BCStyle.O, server.config.projectName);
LocalDateTime startDate = LocalDate.now().atStartOfDay();
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(
subject.build(),
new BigInteger("0"),
Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()),
Date.from(startDate.plusDays(3650).atZone(ZoneId.systemDefault()).toInstant()),
new X500Name("CN=ca"),
SubjectPublicKeyInfo.getInstance(server.publicKey.getEncoded()));
builder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(KeyPurposeId.id_kp_codeSigning));
//builder.addExtension(Extension.keyUsage, false, new KeyUsage(1));
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256WITHECDSA");
ContentSigner signer = csBuilder.build(server.privateKey);
bcCertificate = builder.build(signer);
certificate = new JcaX509CertificateConverter().setProvider( "BC" )
.getCertificate( bcCertificate );
ArrayList<Certificate> chain = new ArrayList<>();
chain.add(certificate);
signedDataGenerator = SignHelper.createSignedDataGenerator(server.privateKey, certificate, chain, "SHA256WITHECDSA");
} catch (OperatorCreationException | CMSException | CertificateException e) {
LogHelper.error(e);
}
return inputFile;
}
@Override
public boolean allowDelete() {
return false;
}
}

View file

@ -1,5 +1,8 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -7,9 +10,6 @@
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
public class CompressBuildTask implements LauncherBuildTask { public class CompressBuildTask implements LauncherBuildTask {
public transient final LaunchServer server; public transient final LaunchServer server;
@ -25,12 +25,10 @@ public String getName() {
@Override @Override
public Path process(Path inputFile) throws IOException { public Path process(Path inputFile) throws IOException {
Path output = server.launcherBinary.nextPath(this); Path output = server.launcherBinary.nextPath(this);
try(ZipOutputStream outputStream = new ZipOutputStream(IOHelper.newOutput(output))) try (ZipOutputStream outputStream = new ZipOutputStream(IOHelper.newOutput(output))) {
{
outputStream.setMethod(ZipOutputStream.DEFLATED); outputStream.setMethod(ZipOutputStream.DEFLATED);
outputStream.setLevel(Deflater.BEST_COMPRESSION); outputStream.setLevel(Deflater.BEST_COMPRESSION);
try(ZipInputStream input = IOHelper.newZipInput(inputFile)) try (ZipInputStream input = IOHelper.newZipInput(inputFile)) {
{
ZipEntry e = input.getNextEntry(); ZipEntry e = input.getNextEntry();
while (e != null) { while (e != null) {
if (e.isDirectory()) { if (e.isDirectory()) {

View file

@ -1,112 +1,127 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import static pro.gravit.utils.helper.IOHelper.newZipEntry;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import pro.gravit.launcher.AutogenConfig;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.LauncherConfig;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.asm.ClassMetadataReader; import pro.gravit.launchserver.asm.ClassMetadataReader;
import pro.gravit.launchserver.asm.InjectClassAcceptor;
import pro.gravit.launchserver.asm.SafeClassWriter;
import pro.gravit.launchserver.binary.BuildContext; import pro.gravit.launchserver.binary.BuildContext;
import pro.gravit.launchserver.binary.LauncherConfigurator; import pro.gravit.utils.HookException;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.nio.file.Path;
import java.security.cert.CertificateEncodingException;
import java.util.*;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;
public class MainBuildTask implements LauncherBuildTask { public class MainBuildTask implements LauncherBuildTask {
private final LaunchServer server; private final LaunchServer server;
public final ClassMetadataReader reader; public final ClassMetadataReader reader;
@FunctionalInterface
public interface Transformer {
byte[] transform(byte[] input, String classname, BuildContext context);
}
public static class IOHookSet<R> {
public final Set<IOHook<R>> list = new HashSet<>();
private final class RuntimeDirVisitor extends SimpleFileVisitor<Path> { @FunctionalInterface
private final ZipOutputStream output; public interface IOHook<R> {
private final Map<String, byte[]> runtime; /**
* @param context custom param
* False to continue processing hook
* @throws HookException The hook may return the error text throwing this exception
*/
void hook(R context) throws HookException, IOException;
}
private RuntimeDirVisitor(ZipOutputStream output, Map<String, byte[]> runtime) { public void registerHook(IOHook<R> hook) {
this.output = output; list.add(hook);
this.runtime = runtime; }
public boolean unregisterHook(IOHook<R> hook) {
return list.remove(hook);
}
/**
* @param context custom param
* False to continue
* @throws HookException The hook may return the error text throwing this exception
*/
public void hook(R context) throws HookException, IOException {
for (IOHook<R> hook : list) {
hook.hook(context);
}
}
}
public interface ASMTransformer extends Transformer {
default byte[] transform(byte[] input, String classname, BuildContext context)
{
ClassReader reader = new ClassReader(input);
ClassNode cn = new ClassNode();
reader.accept(cn, 0);
transform(cn, classname, context);
SafeClassWriter writer = new SafeClassWriter(context.task.reader,ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(writer);
return writer.toByteArray();
}
void transform(ClassNode cn, String classname, BuildContext context);
}
public abstract static class ASMAnnotationFieldProcessor implements ASMTransformer
{
private final String desc;
protected ASMAnnotationFieldProcessor(String desc) {
this.desc = desc;
} }
@Override @Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { public void transform(ClassNode cn, String classname, BuildContext context) {
String dirName = IOHelper.toString(server.launcherBinary.runtimeDir.relativize(dir)); for(FieldNode fn : cn.fields)
output.putNextEntry(newEntry(dirName + '/')); {
return super.preVisitDirectory(dir, attrs); if(fn.invisibleAnnotations == null || fn.invisibleAnnotations.isEmpty()) continue;
} AnnotationNode found = null;
for(AnnotationNode an : fn.invisibleAnnotations)
@Override {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if(an == null) continue;
String fileName = IOHelper.toString(server.launcherBinary.runtimeDir.relativize(file)); if(desc.equals(an.desc))
runtime.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file)); {
found = an;
// Create zip entry and transfer contents break;
output.putNextEntry(newEntry(fileName));
IOHelper.transfer(file, output);
// Return result
return super.visitFile(file, attrs);
} }
} }
if(found != null)
private final class GuardDirVisitor extends SimpleFileVisitor<Path> { {
private final ZipOutputStream output; transformField(found, fn, cn, classname, context);
private final Map<String, byte[]> guard;
private GuardDirVisitor(ZipOutputStream output, Map<String, byte[]> guard) {
this.output = output;
this.guard = guard;
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
String dirName = IOHelper.toString(server.launcherBinary.guardDir.relativize(dir));
output.putNextEntry(newGuardEntry(dirName + '/'));
return super.preVisitDirectory(dir, attrs);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fileName = IOHelper.toString(server.launcherBinary.guardDir.relativize(file));
guard.put(fileName, SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, file));
// Create zip entry and transfer contents
output.putNextEntry(newGuardEntry(fileName));
IOHelper.transfer(file, output);
// Return result
return super.visitFile(file, attrs);
} }
} }
private static ZipEntry newEntry(String fileName) {
return newZipEntry(Launcher.RUNTIME_DIR + IOHelper.CROSS_SEPARATOR + fileName);
} }
abstract public void transformField(AnnotationNode an, FieldNode fn, ClassNode cn, String classname, BuildContext context);
private static ZipEntry newGuardEntry(String fileName) {
return newZipEntry(Launcher.GUARD_DIR + IOHelper.CROSS_SEPARATOR + fileName);
} }
public Set<String> blacklist = new HashSet<>();
public List<Transformer> transformers = new ArrayList<>();
public IOHookSet<BuildContext> preBuildHook = new IOHookSet<>();
public IOHookSet<BuildContext> postBuildHook = new IOHookSet<>();
public Map<String, Object> properties = new HashMap<>();
public MainBuildTask(LaunchServer srv) { public MainBuildTask(LaunchServer srv) {
server = srv; server = srv;
reader = new ClassMetadataReader(); reader = new ClassMetadataReader();
InjectClassAcceptor injectClassAcceptor = new InjectClassAcceptor(properties);
transformers.add(injectClassAcceptor);
} }
@Override @Override
@ -118,30 +133,11 @@ public String getName() {
public Path process(Path inputJar) throws IOException { public Path process(Path inputJar) throws IOException {
Path outputJar = server.launcherBinary.nextPath("main"); Path outputJar = server.launcherBinary.nextPath("main");
try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) { try (ZipOutputStream output = new ZipOutputStream(IOHelper.newOutput(outputJar))) {
ClassNode cn = new ClassNode(); BuildContext context = new BuildContext(output, reader.getCp(), this);
new ClassReader(IOHelper.getResourceBytes(AutogenConfig.class.getName().replace('.', '/').concat(".class"))).accept(cn, 0); initProps();
LauncherConfigurator launcherConfigurator = new LauncherConfigurator(cn); preBuildHook.hook(context);
BuildContext context = new BuildContext(output, launcherConfigurator, this); properties.put("launcher.modules", context.clientModules.stream().map(e -> Type.getObjectType(e.replace('.', '/'))).collect(Collectors.toList()));
server.buildHookManager.hook(context); postInitProps();
launcherConfigurator.setAddress(server.config.netty.address);
if (server.config.guardLicense != null)
launcherConfigurator.setGuardLicense(server.config.guardLicense.name, server.config.guardLicense.key, server.config.guardLicense.encryptKey);
else
launcherConfigurator.nullGuardLicense();
launcherConfigurator.setProjectName(server.config.projectName);
launcherConfigurator.setSecretKey(SecurityHelper.randomStringAESKey());
launcherConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512));
launcherConfigurator.setGuardType(server.config.launcher.guardType);
launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava);
launcherConfigurator.setEnv(server.config.env);
String launcherSalt = SecurityHelper.randomStringToken();
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt));
launcherConfigurator.setSecureCheck(Base64.getEncoder().encodeToString(launcherSecureHash), launcherSalt);
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
launcherConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey);
server.buildHookManager.registerAllClientModuleClass(launcherConfigurator);
reader.getCp().add(new JarFile(inputJar.toFile())); reader.getCp().add(new JarFile(inputJar.toFile()));
server.launcherBinary.coreLibs.forEach(e -> { server.launcherBinary.coreLibs.forEach(e -> {
try { try {
@ -150,71 +146,107 @@ public Path process(Path inputJar) throws IOException {
LogHelper.error(e1); LogHelper.error(e1);
} }
}); });
String zPath = launcherConfigurator.getZipEntryPath(); context.pushJarFile(inputJar, (e) -> blacklist.contains(e.getName()), (e) -> true);
try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputJar))) {
ZipEntry e = input.getNextEntry();
while (e != null) {
String filename = e.getName();
if (server.buildHookManager.isContainsBlacklist(filename) || e.isDirectory() || zPath.equals(filename)) {
e = input.getNextEntry();
continue;
}
try {
output.putNextEntry(IOHelper.newZipEntry(e));
} catch (ZipException ex) {
LogHelper.error(ex);
e = input.getNextEntry();
continue;
}
if (filename.endsWith(".class")) {
String classname = filename.replace('/', '.').substring(0,
filename.length() - ".class".length());
byte[] bytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048)) {
IOHelper.transfer(input, outputStream);
bytes = outputStream.toByteArray();
}
bytes = server.buildHookManager.classTransform(bytes, classname, this);
output.write(bytes);
} else
IOHelper.transfer(input, output);
context.fileList.add(filename);
e = input.getNextEntry();
}
}
// write additional classes
for (Map.Entry<String, byte[]> ent : server.buildHookManager.getIncludeClass().entrySet()) {
output.putNextEntry(newZipEntry(ent.getKey().replace('.', '/').concat(".class")));
output.write(server.buildHookManager.classTransform(ent.getValue(), ent.getKey(), this));
}
// map for guard // map for guard
Map<String, byte[]> runtime = new HashMap<>(256); Map<String, byte[]> runtime = new HashMap<>(256);
if (server.buildHookManager.buildRuntime()) {
// Write launcher guard dir // Write launcher guard dir
IOHelper.walk(server.launcherBinary.runtimeDir, new RuntimeDirVisitor(output, runtime), false); context.pushDir(server.launcherBinary.runtimeDir, Launcher.RUNTIME_DIR, runtime, false);
IOHelper.walk(server.launcherBinary.guardDir, new GuardDirVisitor(output, runtime), false); context.pushDir(server.launcherBinary.guardDir, Launcher.GUARD_DIR, runtime, false);
}
// Create launcher config file
byte[] launcherConfigBytes;
try (ByteArrayOutputStream configArray = IOHelper.newByteArrayOutput()) {
try (HOutput configOutput = new HOutput(configArray)) {
new LauncherConfig(server.config.netty.address, server.publicKey, runtime)
.write(configOutput);
}
launcherConfigBytes = configArray.toByteArray();
}
// Write launcher config file LauncherConfig launcherConfig = new LauncherConfig(server.config.netty.address, server.publicKey, runtime, server.config.projectName);
output.putNextEntry(newZipEntry(Launcher.CONFIG_FILE)); context.pushFile(Launcher.CONFIG_FILE, launcherConfig);
output.write(launcherConfigBytes); postBuildHook.hook(context);
ZipEntry e = newZipEntry(zPath);
output.putNextEntry(e);
output.write(launcherConfigurator.getBytecode(reader));
} }
reader.close(); reader.close();
return outputJar; return outputJar;
} }
protected void postInitProps() {
List<byte[]> certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> {
try {
return e.getEncoded();
} catch (CertificateEncodingException e2) {
LogHelper.error(e2);
return new byte[0];
}
}).collect(Collectors.toList());
if(!server.config.sign.enabled)
{
CertificateAutogenTask task = server.launcherBinary.getTaskByClass(CertificateAutogenTask.class).get();
try {
certificates.add(task.certificate.getEncoded());
} catch (CertificateEncodingException e) {
throw new InternalError(e);
}
}
properties.put("launchercore.certificates", certificates);
}
protected void initProps() {
properties.clear();
properties.put("launcher.address", server.config.netty.address);
properties.put("launcher.projectName", server.config.projectName);
properties.put("runtimeconfig.secretKeyClient", SecurityHelper.randomStringAESKey());
properties.put("launcher.port", 32148 + SecurityHelper.newRandom().nextInt(512));
properties.put("launcher.guardType", server.config.launcher.guardType);
properties.put("launcher.isWarningMissArchJava", server.config.launcher.warningMissArchJava);
properties.put("launchercore.env", server.config.env);
properties.put("runtimeconfig.passwordEncryptKey", server.runtime.passwordEncryptKey);
String launcherSalt = SecurityHelper.randomStringToken();
byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
server.runtime.clientCheckSecret.concat(".").concat(launcherSalt));
properties.put("runtimeconfig.secureCheckHash", Base64.getEncoder().encodeToString(launcherSecureHash));
properties.put("runtimeconfig.secureCheckSalt", launcherSalt);
//LogHelper.debug("[checkSecure] %s: %s", launcherSalt, Arrays.toString(launcherSecureHash));
if (server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken();
properties.put("runtimeconfig.oemUnlockKey", server.runtime.oemUnlockKey);
}
public byte[] transformClass(byte[] bytes, String classname, BuildContext context)
{
byte[] result = bytes;
ClassReader cr = null;
ClassWriter writer = null;
ClassNode cn = null;
for(Transformer t : transformers)
{
if(t instanceof ASMTransformer)
{
ASMTransformer asmTransformer = (ASMTransformer) t;
if(cn == null)
{
cr = new ClassReader(result);
cn = new ClassNode();
cr.accept(cn, 0);
}
asmTransformer.transform(cn, classname, context);
continue;
}
else if(cn != null)
{
writer = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(writer);
result = writer.toByteArray();
}
byte[] old_result = result;
result = t.transform(result, classname, context);
if(old_result != result)
{
cr = null;
cn = null;
}
}
if(cn != null)
{
writer = new SafeClassWriter(reader,ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(writer);
result = writer.toByteArray();
}
return result;
}
@Override @Override
public boolean allowDelete() { public boolean allowDelete() {
return true; return true;

View file

@ -1,5 +1,10 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.UnpackHelper;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
@ -8,11 +13,6 @@
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.UnpackHelper;
public class PrepareBuildTask implements LauncherBuildTask { public class PrepareBuildTask implements LauncherBuildTask {
private final LaunchServer server; private final LaunchServer server;
private final Path result; private final Path result;

View file

@ -1,8 +1,5 @@
package pro.gravit.launchserver.binary.tasks; package pro.gravit.launchserver.binary.tasks;
import java.io.IOException;
import java.nio.file.Path;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
@ -11,6 +8,9 @@
import proguard.ParseException; import proguard.ParseException;
import proguard.ProGuard; import proguard.ProGuard;
import java.io.IOException;
import java.nio.file.Path;
public class ProGuardBuildTask implements LauncherBuildTask { public class ProGuardBuildTask implements LauncherBuildTask {
private final LaunchServer server; private final LaunchServer server;

View file

@ -0,0 +1,109 @@
package pro.gravit.launchserver.binary.tasks;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.operator.OperatorCreationException;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.SignerJar;
import pro.gravit.launchserver.config.LaunchServerConfig;
import pro.gravit.launchserver.helper.SignHelper;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateEncodingException;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class SignJarTask implements LauncherBuildTask {
private final LaunchServerConfig.JarSignerConf config;
private final LaunchServer srv;
public SignJarTask(LaunchServerConfig.JarSignerConf config, LaunchServer srv) {
this.config = config;
this.srv = srv;
}
@Override
public String getName() {
return "SignJar";
}
@Override
public Path process(Path inputFile) throws IOException {
Path toRet = srv.launcherBinary.nextPath("signed");
sign(config, inputFile, toRet);
return toRet;
}
public void sign(LaunchServerConfig.JarSignerConf config, Path inputFile, Path signedFile) throws IOException {
if(config.enabled) stdSign(config, inputFile, signedFile);
else autoSign(inputFile, signedFile);
}
private void stdSign(LaunchServerConfig.JarSignerConf config, Path inputFile, Path signedFile) throws IOException {
KeyStore c = SignHelper.getStore(new File(config.keyStore).toPath(), config.keyStorePass, config.keyStoreType);
try (SignerJar output = new SignerJar(new ZipOutputStream(IOHelper.newOutput(signedFile)), () -> SignJarTask.gen(config, c),
config.metaInfSfName, config.metaInfKeyName);
ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputFile))) {
//input.getManifest().getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString())); // may not work such as after Radon.
ZipEntry e = input.getNextEntry();
while (e != null) {
if ("META-INF/MANIFEST.MF".equals(e.getName()) || "/META-INF/MANIFEST.MF".equals(e.getName())) {
Manifest m = new Manifest(input);
m.getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString()));
e = input.getNextEntry();
continue;
}
output.addFileContents(IOHelper.newZipEntry(e), input);
e = input.getNextEntry();
}
}
}
private void autoSign(Path inputFile, Path signedFile) throws IOException {
try (SignerJar output = new SignerJar(new ZipOutputStream(IOHelper.newOutput(signedFile)), () -> {
CertificateAutogenTask task = srv.launcherBinary.getTaskByClass(CertificateAutogenTask.class).get();
return task.signedDataGenerator;
},
"AUTOGEN.SF", "AUTOGEN.EC");
ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputFile))) {
//input.getManifest().getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString())); // may not work such as after Radon.
ZipEntry e = input.getNextEntry();
while (e != null) {
if ("META-INF/MANIFEST.MF".equals(e.getName()) || "/META-INF/MANIFEST.MF".equals(e.getName())) {
Manifest m = new Manifest(input);
m.getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString()));
e = input.getNextEntry();
continue;
}
output.addFileContents(IOHelper.newZipEntry(e), input);
e = input.getNextEntry();
}
}
}
@Override
public boolean allowDelete() {
return true;
}
public static CMSSignedDataGenerator gen(LaunchServerConfig.JarSignerConf config, KeyStore c) {
try {
return SignHelper.createSignedDataGenerator(c,
config.keyAlias, config.signAlgo, config.keyPass);
} catch (CertificateEncodingException | UnrecoverableKeyException | KeyStoreException
| OperatorCreationException | NoSuchAlgorithmException | CMSException e) {
LogHelper.error(e);
return null;
}
}
}

View file

@ -1,51 +0,0 @@
package pro.gravit.launchserver.binary.tasks;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public final class TaskUtil {
public static void addCounted(List<LauncherBuildTask> tasks, int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
List<LauncherBuildTask> indexes = new ArrayList<>();
tasks.stream().filter(pred).forEach(indexes::add);
indexes.forEach(e -> tasks.add(tasks.indexOf(e) + count, taskAdd));
}
public static void replaceCounted(List<LauncherBuildTask> tasks, int count, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
List<LauncherBuildTask> indexes = new ArrayList<>();
tasks.stream().filter(pred).forEach(indexes::add);
indexes.forEach(e -> tasks.set(tasks.indexOf(e) + count, taskRep));
}
public static void addPre(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(tasks, -1, pred, taskAdd);
}
public static void add(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(tasks, 0, pred, taskAdd);
}
public static void addAfter(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskAdd) {
addCounted(tasks, 1, pred, taskAdd);
}
public static void replacePre(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted(tasks, -1, pred, taskRep);
}
public static void replace(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted(tasks, 0, pred, taskRep);
}
public static void replaceAfter(List<LauncherBuildTask> tasks, Predicate<LauncherBuildTask> pred, LauncherBuildTask taskRep) {
replaceCounted(tasks, 1, pred, taskRep);
}
public static <T extends LauncherBuildTask> List<T> getTaskByClass(List<LauncherBuildTask> tasks, Class<T> taskClass) {
return tasks.stream().filter(taskClass::isInstance).map(taskClass::cast).collect(Collectors.toList());
}
private TaskUtil() {
}
}

View file

@ -0,0 +1,129 @@
package pro.gravit.launchserver.binary.tasks.exe;
import net.sf.launch4j.Builder;
import net.sf.launch4j.Log;
import net.sf.launch4j.config.*;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
import pro.gravit.utils.Version;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.nio.file.Path;
public class Launch4JTask implements LauncherBuildTask {
private final static class Launch4JLog extends Log {
private static final Launch4JLog INSTANCE = new Launch4JLog();
@Override
public void append(String s) {
LogHelper.subInfo(s);
}
@Override
public void clear() {
// Do nothing
}
}
public static final String DOWNLOAD_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"; // Oracle
private final Path faviconFile;
private final LaunchServer server;
public Launch4JTask(LaunchServer launchServer) {
this.server = launchServer;
faviconFile = launchServer.dir.resolve("favicon.ico");
}
@Override
public String getName() {
return "launch4j";
}
@Override
public Path process(Path inputFile) throws IOException {
LogHelper.info("Building launcher EXE binary file (Using Launch4J)");
Path output = setConfig();
// Set favicon path
Config config = ConfigPersister.getInstance().getConfig();
if (IOHelper.isFile(faviconFile))
config.setIcon(faviconFile.toFile());
else {
config.setIcon(null);
LogHelper.warning("Missing favicon.ico file");
}
// Start building
Builder builder = new Builder(Launch4JLog.INSTANCE);
try {
builder.build();
} catch (Throwable e) {
throw new IOException(e);
}
return output;
}
@Override
public boolean allowDelete() {
return true;
}
private Path setConfig() {
Path path = server.launcherEXEBinary.nextPath(getName());
Config config = new Config();
// Set file options
config.setChdir(".");
config.setErrTitle("JVM Error");
config.setDownloadUrl(server.config.launch4j.downloadUrl);
if (server.config.launch4j.supportURL != null) config.setSupportUrl(server.config.launch4j.supportURL);
// Set boolean options
config.setPriorityIndex(0);
config.setHeaderType(Config.GUI_HEADER);
config.setStayAlive(false);
config.setRestartOnCrash(false);
// Prepare JRE
Jre jre = new Jre();
jre.setMinVersion(server.config.launch4j.minVersion);
if (server.config.launch4j.setMaxVersion)
jre.setMaxVersion(server.config.launch4j.maxVersion);
jre.setRuntimeBits(Jre.RUNTIME_BITS_64_AND_32);
jre.setJdkPreference(Jre.JDK_PREFERENCE_PREFER_JRE);
config.setJre(jre);
// Prepare version info (product)
VersionInfo info = new VersionInfo();
info.setProductName(server.config.launch4j.productName);
info.setProductVersion(formatVars(server.config.launch4j.productVer));
info.setFileDescription(server.config.launch4j.fileDesc);
info.setFileVersion(formatVars(server.config.launch4j.fileVer));
info.setCopyright(server.config.launch4j.copyright);
info.setTrademarks(server.config.launch4j.trademarks);
info.setInternalName(formatVars(server.config.launch4j.internalName));
// Prepare version info (file)
info.setTxtFileVersion(formatVars(server.config.launch4j.txtFileVersion));
info.setTxtProductVersion(formatVars(server.config.launch4j.txtProductVersion));
// Prepare version info (misc)
info.setOriginalFilename(path.getFileName().toString());
info.setLanguage(LanguageID.RUSSIAN);
config.setVersionInfo(info);
// Set JAR wrapping options
config.setDontWrapJar(false);
config.setJar(server.launcherBinary.syncBinaryFile.toFile());
config.setOutfile(path.toFile());
// Return prepared config
ConfigPersister.getInstance().setAntConfig(config, null);
return path;
}
private static final String VERSION = Version.getVersion().getVersionString();
private static final int BUILD = Version.getVersion().build;
public static String formatVars(String mask) {
return String.format(mask, VERSION, BUILD);
}
}

View file

@ -1,9 +1,9 @@
package pro.gravit.launchserver.command; package pro.gravit.launchserver.command;
import java.util.Map;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import java.util.Map;
public abstract class Command extends pro.gravit.utils.command.Command { public abstract class Command extends pro.gravit.utils.command.Command {

View file

@ -1,7 +1,5 @@
package pro.gravit.launchserver.command.auth; package pro.gravit.launchserver.command.auth;
import java.util.UUID;
import pro.gravit.launcher.request.auth.password.AuthPlainPassword; import pro.gravit.launcher.request.auth.password.AuthPlainPassword;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
@ -10,6 +8,8 @@
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.util.UUID;
public final class AuthCommand extends Command { public final class AuthCommand extends Command {
public AuthCommand(LaunchServer server) { public AuthCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.command.auth; package pro.gravit.launchserver.command.auth;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException; import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.UUID;
public final class UUIDToUsernameCommand extends Command { public final class UUIDToUsernameCommand extends Command {
public UUIDToUsernameCommand(LaunchServer server) { public UUIDToUsernameCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.command.auth; package pro.gravit.launchserver.command.auth;
import java.io.IOException;
import java.util.UUID;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException; import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.UUID;
public final class UsernameToUUIDCommand extends Command { public final class UsernameToUUIDCommand extends Command {
public UsernameToUUIDCommand(LaunchServer server) { public UsernameToUUIDCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.command.basic; package pro.gravit.launchserver.command.basic;
import java.io.IOException;
import java.nio.file.Files;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import java.io.IOException;
import java.nio.file.Files;
public class ProguardCleanCommand extends Command { public class ProguardCleanCommand extends Command {
public ProguardCleanCommand(LaunchServer server) { public ProguardCleanCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,10 +1,10 @@
package pro.gravit.launchserver.command.basic; package pro.gravit.launchserver.command.basic;
import java.io.IOException;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import java.io.IOException;
public class RegenProguardDictCommand extends Command { public class RegenProguardDictCommand extends Command {
public RegenProguardDictCommand(LaunchServer server) { public RegenProguardDictCommand(LaunchServer server) {

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.command.basic; package pro.gravit.launchserver.command.basic;
import java.io.IOException;
import java.nio.file.Files;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import java.io.IOException;
import java.nio.file.Files;
public class RemoveMappingsProguardCommand extends Command { public class RemoveMappingsProguardCommand extends Command {
public RemoveMappingsProguardCommand(LaunchServer server) { public RemoveMappingsProguardCommand(LaunchServer server) {

View file

@ -1,14 +1,15 @@
package pro.gravit.launchserver.command.basic; package pro.gravit.launchserver.command.basic;
import java.nio.file.Paths;
import java.security.KeyPair;
import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509CertificateHolder;
import pro.gravit.launcher.hwid.HWIDCheckHelper;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler; import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
import pro.gravit.utils.helper.LogHelper;
import java.nio.file.Paths;
import java.security.KeyPair;
public class TestCommand extends Command { public class TestCommand extends Command {
public TestCommand(LaunchServer server) { public TestCommand(LaunchServer server) {
@ -55,5 +56,8 @@ public void invoke(String... args) throws Exception {
server.certificateManager.writePrivateKey(Paths.get(name.concat(".key")), pair.getPrivate()); server.certificateManager.writePrivateKey(Paths.get(name.concat(".key")), pair.getPrivate());
server.certificateManager.writeCertificate(Paths.get(name.concat(".crt")), cert); server.certificateManager.writeCertificate(Paths.get(name.concat(".crt")), cert);
} }
if (args[0].equals("hwidcheck")) {
LogHelper.info("HWID String %s bad rating %d", args[1], HWIDCheckHelper.checkString(args[1]));
}
} }
} }

View file

@ -21,11 +21,10 @@ public String getUsageDescription() {
} }
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) {
int count = 0; int count = 0;
for(User user : server.config.dao.userService.findAllUsers()) for (User user : server.config.dao.userDAO.findAll()) {
{ LogHelper.subInfo("[%s] UUID: %s", user.getUsername(), user.getUuid().toString());
LogHelper.subInfo("[%s] UUID: %s", user.username, user.uuid.toString());
count++; count++;
} }
LogHelper.info("Print %d users", count); LogHelper.info("Print %d users", count);

View file

@ -23,13 +23,12 @@ public String getUsageDescription() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
verifyArgs(args, 1); verifyArgs(args, 1);
User user = server.config.dao.userService.findUserByUsername(args[0]); User user = server.config.dao.userDAO.findByUsername(args[0]);
if(user == null) if (user == null) {
{
LogHelper.error("User %s not found", args[0]); LogHelper.error("User %s not found", args[0]);
return; return;
} }
LogHelper.info("[%s] UUID: %s", user.username, user.uuid.toString()); LogHelper.info("[%s] UUID: %s", user.getUsername(), user.getUuid().toString());
//for(UserHWID hwid : user.hwids) //for(UserHWID hwid : user.hwids)
//{ //{
// LogHelper.info("[%s] HWID: memory: %d | serial %s | hwdiskserial: %s | processorID %s | macAddr %s", user.username, hwid.totalMemory, hwid.serialNumber, hwid.HWDiskSerial, hwid.processorID, hwid.macAddr); // LogHelper.info("[%s] HWID: memory: %d | serial %s | hwdiskserial: %s | processorID %s | macAddr %s", user.username, hwid.totalMemory, hwid.serialNumber, hwid.HWDiskSerial, hwid.processorID, hwid.macAddr);

View file

@ -1,12 +1,12 @@
package pro.gravit.launchserver.command.dao; package pro.gravit.launchserver.command.dao;
import java.util.UUID;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.dao.User; import pro.gravit.launchserver.dao.impl.UserHibernateImpl;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.util.UUID;
public class RegisterCommand extends Command { public class RegisterCommand extends Command {
public RegisterCommand(LaunchServer server) { public RegisterCommand(LaunchServer server) {
super(server); super(server);
@ -25,11 +25,11 @@ public String getUsageDescription() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
verifyArgs(args, 2); verifyArgs(args, 2);
User user = new User(); UserHibernateImpl user = new UserHibernateImpl();
user.username = args[0]; user.username = args[0];
user.setPassword(args[1]); user.setPassword(args[1]);
user.uuid = UUID.randomUUID(); user.uuid = UUID.randomUUID();
server.config.dao.userService.saveUser(user); server.config.dao.userDAO.save(user);
LogHelper.info("User %s registered. UUID: %s", user.username, user.uuid.toString()); LogHelper.info("User %s registered. UUID: %s", user.username, user.uuid.toString());
} }
} }

View file

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

View file

@ -1,5 +1,14 @@
package pro.gravit.launchserver.command.dump; package pro.gravit.launchserver.command.dump;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -8,16 +17,6 @@
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.google.gson.reflect.TypeToken;
import pro.gravit.launcher.Launcher;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.launchserver.socket.Client;
import pro.gravit.utils.command.SubCommand;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public class DumpSessionsCommand extends Command { public class DumpSessionsCommand extends Command {
public DumpSessionsCommand(LaunchServer server) { public DumpSessionsCommand(LaunchServer server) {
super(server); super(server);

View file

@ -4,37 +4,18 @@
import pro.gravit.launchserver.command.auth.AuthCommand; import pro.gravit.launchserver.command.auth.AuthCommand;
import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand; import pro.gravit.launchserver.command.auth.UUIDToUsernameCommand;
import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand; import pro.gravit.launchserver.command.auth.UsernameToUUIDCommand;
import pro.gravit.launchserver.command.basic.BuildCommand; import pro.gravit.launchserver.command.basic.*;
import pro.gravit.launchserver.command.basic.ProguardCleanCommand;
import pro.gravit.launchserver.command.basic.RegenProguardDictCommand;
import pro.gravit.launchserver.command.basic.RemoveMappingsProguardCommand;
import pro.gravit.launchserver.command.basic.RestartCommand;
import pro.gravit.launchserver.command.basic.StopCommand;
import pro.gravit.launchserver.command.basic.TestCommand;
import pro.gravit.launchserver.command.basic.VersionCommand;
import pro.gravit.launchserver.command.dao.GetAllUsersCommand; import pro.gravit.launchserver.command.dao.GetAllUsersCommand;
import pro.gravit.launchserver.command.dao.GetUserCommand; import pro.gravit.launchserver.command.dao.GetUserCommand;
import pro.gravit.launchserver.command.dao.RegisterCommand; import pro.gravit.launchserver.command.dao.RegisterCommand;
import pro.gravit.launchserver.command.dao.SetUserPasswordCommand; import pro.gravit.launchserver.command.dao.SetUserPasswordCommand;
import pro.gravit.launchserver.command.dump.DumpSessionsCommand; import pro.gravit.launchserver.command.dump.DumpSessionsCommand;
import pro.gravit.launchserver.command.hash.DownloadAssetCommand; import pro.gravit.launchserver.command.hash.*;
import pro.gravit.launchserver.command.hash.DownloadClientCommand;
import pro.gravit.launchserver.command.hash.IndexAssetCommand;
import pro.gravit.launchserver.command.hash.SyncBinariesCommand;
import pro.gravit.launchserver.command.hash.SyncProfilesCommand;
import pro.gravit.launchserver.command.hash.SyncUpdatesCommand;
import pro.gravit.launchserver.command.hash.UnindexAssetCommand;
import pro.gravit.launchserver.command.install.CheckInstallCommand; import pro.gravit.launchserver.command.install.CheckInstallCommand;
import pro.gravit.launchserver.command.install.MultiCommand; import pro.gravit.launchserver.command.install.MultiCommand;
import pro.gravit.launchserver.command.modules.LoadModuleCommand; import pro.gravit.launchserver.command.modules.LoadModuleCommand;
import pro.gravit.launchserver.command.modules.ModulesCommand; import pro.gravit.launchserver.command.modules.ModulesCommand;
import pro.gravit.launchserver.command.service.ClientsCommand; import pro.gravit.launchserver.command.service.*;
import pro.gravit.launchserver.command.service.ComponentCommand;
import pro.gravit.launchserver.command.service.ConfigCommand;
import pro.gravit.launchserver.command.service.GetModulusCommand;
import pro.gravit.launchserver.command.service.GetPermissionsCommand;
import pro.gravit.launchserver.command.service.GivePermissionsCommand;
import pro.gravit.launchserver.command.service.ServerStatusCommand;
import pro.gravit.utils.command.BaseCommandCategory; import pro.gravit.utils.command.BaseCommandCategory;
import pro.gravit.utils.command.basic.ClearCommand; import pro.gravit.utils.command.basic.ClearCommand;
import pro.gravit.utils.command.basic.DebugCommand; import pro.gravit.utils.command.basic.DebugCommand;
@ -103,11 +84,11 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
service.registerCommand("serverStatus", new ServerStatusCommand(server)); service.registerCommand("serverStatus", new ServerStatusCommand(server));
service.registerCommand("checkInstall", new CheckInstallCommand(server)); service.registerCommand("checkInstall", new CheckInstallCommand(server));
service.registerCommand("multi", new MultiCommand(server)); service.registerCommand("multi", new MultiCommand(server));
service.registerCommand("getModulus", new GetModulusCommand(server)); service.registerCommand("notify", new NotifyCommand(server));
service.registerCommand("component", new ComponentCommand(server)); service.registerCommand("component", new ComponentCommand(server));
service.registerCommand("givePermission", new GivePermissionsCommand(server));
service.registerCommand("getPermissions", new GetPermissionsCommand(server));
service.registerCommand("clients", new ClientsCommand(server)); service.registerCommand("clients", new ClientsCommand(server));
service.registerCommand("signJar", new SignJarCommand(server));
service.registerCommand("signDir", new SignDirCommand(server));
Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components"); Category serviceCategory = new Category(service, "service", "Managing LaunchServer Components");
handler.registerCategory(serviceCategory); handler.registerCategory(serviceCategory);
} }

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
public final class DownloadAssetCommand extends Command { public final class DownloadAssetCommand extends Command {
public DownloadAssetCommand(LaunchServer server) { public DownloadAssetCommand(LaunchServer server) {

View file

@ -1,12 +1,5 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.ClientProfile;
@ -16,6 +9,14 @@
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.UUID;
public final class DownloadClientCommand extends Command { public final class DownloadClientCommand extends Command {
public DownloadClientCommand(LaunchServer server) { public DownloadClientCommand(LaunchServer server) {
@ -55,13 +56,13 @@ public void invoke(String... args) throws IOException, CommandException {
String profilePath = String.format("pro/gravit/launchserver/defaults/profile%s.cfg", versionName); String profilePath = String.format("pro/gravit/launchserver/defaults/profile%s.cfg", versionName);
try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) { try (BufferedReader reader = IOHelper.newReader(IOHelper.getResourceURL(profilePath))) {
client = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class); client = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class);
} catch (IOException e) } catch (IOException e) {
{
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName); JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
client = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class); client = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
} }
client.setTitle(dirName); client.setTitle(dirName);
client.setDir(dirName); client.setDir(dirName);
client.setUUID(UUID.randomUUID());
try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir, try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir,
dirName, "json"))) { dirName, "json"))) {
Launcher.gsonManager.configGson.toJson(client, writer); Launcher.gsonManager.configGson.toJson(client, writer);

View file

@ -1,5 +1,15 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.helper.SecurityHelper.DigestAlgorithm;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
@ -9,29 +19,18 @@
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections; import java.util.Collections;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.helper.SecurityHelper.DigestAlgorithm;
public final class IndexAssetCommand extends Command { public final class IndexAssetCommand extends Command {
private static Gson gson = new Gson(); private static final Gson gson = new Gson();
public static class IndexObject { public static class IndexObject {
long size; final long size;
public IndexObject(long size, String hash) { public IndexObject(long size, String hash) {
this.size = size; this.size = size;
this.hash = hash; this.hash = hash;
} }
String hash; final String hash;
} }
private static final class IndexAssetVisitor extends SimpleFileVisitor<Path> { private static final class IndexAssetVisitor extends SimpleFileVisitor<Path> {

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import java.io.IOException;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
public final class SyncBinariesCommand extends Command { public final class SyncBinariesCommand extends Command {
public SyncBinariesCommand(LaunchServer server) { public SyncBinariesCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import java.io.IOException;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
public final class SyncProfilesCommand extends Command { public final class SyncProfilesCommand extends Command {
public SyncProfilesCommand(LaunchServer server) { public SyncProfilesCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,14 +1,14 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;
public final class SyncUpdatesCommand extends Command { public final class SyncUpdatesCommand extends Command {
public SyncUpdatesCommand(LaunchServer server) { public SyncUpdatesCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,23 +1,22 @@
package pro.gravit.launchserver.command.hash; package pro.gravit.launchserver.command.hash;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.command.CommandException;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper;
public final class UnindexAssetCommand extends Command { public final class UnindexAssetCommand extends Command {
private static JsonParser parser = new JsonParser(); private static final JsonParser parser = new JsonParser();
public UnindexAssetCommand(LaunchServer server) { public UnindexAssetCommand(LaunchServer server) {
super(server); super(server);

View file

@ -21,7 +21,7 @@ public String getUsageDescription() {
} }
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) {
LogHelper.info("Check install success"); LogHelper.info("Check install success");
JVMHelper.RUNTIME.exit(0); JVMHelper.RUNTIME.exit(0);
} }

View file

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

View file

@ -1,11 +1,11 @@
package pro.gravit.launchserver.command.modules; package pro.gravit.launchserver.command.modules;
import java.nio.file.Path;
import java.nio.file.Paths;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command; import pro.gravit.launchserver.command.Command;
import java.nio.file.Path;
import java.nio.file.Paths;
public class LoadModuleCommand extends Command { public class LoadModuleCommand extends Command {
public LoadModuleCommand(LaunchServer server) { public LoadModuleCommand(LaunchServer server) {
super(server); super(server);

View file

@ -24,17 +24,16 @@ public String getUsageDescription() {
} }
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) {
WebSocketService service = server.nettyServerSocketHandler.nettyServer.service; WebSocketService service = server.nettyServerSocketHandler.nettyServer.service;
service.channels.forEach((channel -> { service.channels.forEach((channel -> {
WebSocketFrameHandler frameHandler = channel.pipeline().get(WebSocketFrameHandler.class); WebSocketFrameHandler frameHandler = channel.pipeline().get(WebSocketFrameHandler.class);
Client client = frameHandler.getClient(); Client client = frameHandler.getClient();
String ip = IOHelper.getIP(channel.remoteAddress()); String ip = IOHelper.getIP(channel.remoteAddress());
if (!client.isAuth) if (!client.isAuth)
LogHelper.info("Channel %s | checkSign %s", ip, client.checkSign ? "true" : "false"); LogHelper.info("Channel %s | connectUUID %s | checkSign %s", ip, frameHandler.getConnectUUID(), client.checkSign ? "true" : "false");
else else {
{ LogHelper.info("Client name %s | ip %s | connectUUID %s", client.username == null ? "null" : client.username, ip, frameHandler.getConnectUUID());
LogHelper.info("Client name %s | ip %s", client.username == null ? "null" : client.username, ip);
LogHelper.subInfo("Data: checkSign %s | isSecure %s | auth_id %s", client.checkSign ? "true" : "false", client.isSecure ? "true" : "false", LogHelper.subInfo("Data: checkSign %s | isSecure %s | auth_id %s", client.checkSign ? "true" : "false", client.isSecure ? "true" : "false",
client.auth_id); client.auth_id);
LogHelper.subInfo("Permissions: %s (long %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.toLong()); LogHelper.subInfo("Permissions: %s (long %d)", client.permissions == null ? "null" : client.permissions.toString(), client.permissions == null ? 0 : client.permissions.toLong());

View file

@ -1,8 +1,5 @@
package pro.gravit.launchserver.command.service; package pro.gravit.launchserver.command.service;
import java.io.Reader;
import java.nio.file.Paths;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.NeedGarbageCollection; import pro.gravit.launcher.NeedGarbageCollection;
import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.LaunchServer;
@ -11,6 +8,9 @@
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.io.Reader;
import java.nio.file.Paths;
public class ComponentCommand extends Command { public class ComponentCommand extends Command {
public ComponentCommand(LaunchServer server) { public ComponentCommand(LaunchServer server) {
super(server); super(server);

View file

@ -1,26 +0,0 @@
package pro.gravit.launchserver.command.service;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.gravit.utils.helper.LogHelper;
public class GetModulusCommand extends Command {
public GetModulusCommand(LaunchServer server) {
super(server);
}
@Override
public String getArgsDescription() {
return null;
}
@Override
public String getUsageDescription() {
return null;
}
@Override
public void invoke(String... args) throws Exception {
LogHelper.info("You publickey modulus: %s", server.publicKey.getModulus().toString(16));
}
}

View file

@ -1,30 +0,0 @@
package pro.gravit.launchserver.command.service;
import pro.gravit.launcher.ClientPermissions;
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.launchserver.command.Command;
import pro.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());
}
}

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