mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-06-28 20:18:10 +03:00
[FEATURE][EXPERIMENTAL] Refactor ProfilesProvider
This commit is contained in:
parent
88fa3ca1a0
commit
88a70bf47b
48 changed files with 925 additions and 1298 deletions
|
@ -106,7 +106,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
||||||
public final ConfigManager configManager;
|
public final ConfigManager configManager;
|
||||||
public final FeaturesManager featuresManager;
|
public final FeaturesManager featuresManager;
|
||||||
public final KeyAgreementManager keyAgreementManager;
|
public final KeyAgreementManager keyAgreementManager;
|
||||||
public final UpdatesManager updatesManager;
|
|
||||||
// HWID ban + anti-brutforce
|
// HWID ban + anti-brutforce
|
||||||
public final CertificateManager certificateManager;
|
public final CertificateManager certificateManager;
|
||||||
// Server
|
// Server
|
||||||
|
@ -162,7 +161,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
configManager = new ConfigManager();
|
configManager = new ConfigManager();
|
||||||
featuresManager = new FeaturesManager(this);
|
featuresManager = new FeaturesManager(this);
|
||||||
authManager = new AuthManager(this);
|
authManager = new AuthManager(this);
|
||||||
updatesManager = new UpdatesManager(this);
|
|
||||||
RestoreResponse.registerProviders(this);
|
RestoreResponse.registerProviders(this);
|
||||||
|
|
||||||
config.init(ReloadType.FULL);
|
config.init(ReloadType.FULL);
|
||||||
|
@ -179,7 +177,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
|
|
||||||
launcherBinary.init();
|
launcherBinary.init();
|
||||||
launcherEXEBinary.init();
|
launcherEXEBinary.init();
|
||||||
syncLauncherBinaries();
|
|
||||||
launcherModuleLoader = new LauncherModuleLoader(this);
|
launcherModuleLoader = new LauncherModuleLoader(this);
|
||||||
if (config.components != null) {
|
if (config.components != null) {
|
||||||
logger.debug("Init components");
|
logger.debug("Init components");
|
||||||
|
@ -339,11 +336,6 @@ public void close() throws Exception {
|
||||||
logger.info("LaunchServer stopped");
|
logger.info("LaunchServer stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
|
||||||
return config.profileProvider.getProfiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setProfiles(Set<ClientProfile> profilesList) {
|
public void setProfiles(Set<ClientProfile> profilesList) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
@ -370,21 +362,6 @@ public void run() {
|
||||||
}));
|
}));
|
||||||
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
CommonHelper.newThread("Command Thread", true, commandHandler).start();
|
||||||
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
CommonHelper.newThread("Socket Command Thread", true, socketCommandServer).start();
|
||||||
// Sync updates dir
|
|
||||||
CommonHelper.newThread("Profiles and updates sync", true, () -> {
|
|
||||||
try {
|
|
||||||
// Sync profiles dir
|
|
||||||
syncProfilesDir();
|
|
||||||
|
|
||||||
// Sync updates dir
|
|
||||||
config.updatesProvider.syncInitially();
|
|
||||||
|
|
||||||
|
|
||||||
modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this));
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("Updates/Profiles not synced", e);
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
if (config.netty != null)
|
if (config.netty != null)
|
||||||
rebindNettyServerSocket();
|
rebindNettyServerSocket();
|
||||||
|
@ -398,47 +375,6 @@ public void run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncLauncherBinaries() throws IOException {
|
|
||||||
logger.info("Syncing launcher binaries");
|
|
||||||
|
|
||||||
// Syncing launcher binary
|
|
||||||
logger.info("Syncing launcher binary file");
|
|
||||||
if (!launcherBinary.sync()) logger.warn("Missing launcher binary file");
|
|
||||||
|
|
||||||
// Syncing launcher EXE binary
|
|
||||||
logger.info("Syncing launcher EXE binary file");
|
|
||||||
if (!launcherEXEBinary.sync())
|
|
||||||
logger.warn("Missing launcher EXE binary file");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void syncProfilesDir() throws IOException {
|
|
||||||
logger.info("Syncing profiles dir");
|
|
||||||
config.profileProvider.sync();
|
|
||||||
if (config.netty.sendProfileUpdatesEvent) {
|
|
||||||
sendUpdateProfilesEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendUpdateProfilesEvent() {
|
|
||||||
if (nettyServerSocketHandler == null || nettyServerSocketHandler.nettyServer == null || nettyServerSocketHandler.nettyServer.service == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nettyServerSocketHandler.nettyServer.service.forEachActiveChannels((ch, handler) -> {
|
|
||||||
Client client = handler.getClient();
|
|
||||||
if (client == null || !client.isAuth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProfilesRequestEvent event = new ProfilesRequestEvent(config.profileProvider.getProfiles(client));
|
|
||||||
event.requestUUID = RequestEvent.eventUUID;
|
|
||||||
handler.service.sendObject(ch, event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
|
||||||
updatesManager.syncUpdatesDir(dirs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerObject(String name, Object object) {
|
public void registerObject(String name, Object object) {
|
||||||
if (object instanceof Reconfigurable) {
|
if (object instanceof Reconfigurable) {
|
||||||
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
reconfigurableManager.registerReconfigurable(name, (Reconfigurable) object);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
|
@ -179,7 +179,7 @@ public static void registerAll() {
|
||||||
OptionalAction.registerProviders();
|
OptionalAction.registerProviders();
|
||||||
OptionalTrigger.registerProviders();
|
OptionalTrigger.registerProviders();
|
||||||
MixProvider.registerProviders();
|
MixProvider.registerProviders();
|
||||||
ProfileProvider.registerProviders();
|
ProfilesProvider.registerProviders();
|
||||||
UpdatesProvider.registerProviders();
|
UpdatesProvider.registerProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.Launcher;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class LocalProfileProvider extends ProfileProvider {
|
|
||||||
public String profilesDir = "profiles";
|
|
||||||
private transient volatile Map<Path, ClientProfile> profilesMap;
|
|
||||||
private transient volatile Set<ClientProfile> profilesList; // Cache
|
|
||||||
@Override
|
|
||||||
public void sync() throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
if (!IOHelper.isDir(profilesDirPath))
|
|
||||||
Files.createDirectory(profilesDirPath);
|
|
||||||
Map<Path, ClientProfile> newProfiles = new HashMap<>();
|
|
||||||
IOHelper.walk(profilesDirPath, new ProfilesFileVisitor(newProfiles), false);
|
|
||||||
Set<ClientProfile> newProfilesList = new HashSet<>(newProfiles.values());
|
|
||||||
profilesMap = newProfiles;
|
|
||||||
profilesList = newProfilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<ClientProfile> getProfiles() {
|
|
||||||
return profilesList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addProfile(ClientProfile profile) throws IOException {
|
|
||||||
Path profilesDirPath = Path.of(profilesDir);
|
|
||||||
ClientProfile oldProfile;
|
|
||||||
Path target = null;
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
target = e.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(target == null) {
|
|
||||||
target = profilesDirPath.resolve(profile.getTitle()+".json");
|
|
||||||
oldProfile = profilesMap.get(target);
|
|
||||||
if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) {
|
|
||||||
throw new FileAlreadyExistsException(target.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try (BufferedWriter writer = IOHelper.newWriter(target)) {
|
|
||||||
Launcher.gsonManager.configGson.toJson(profile, writer);
|
|
||||||
}
|
|
||||||
addProfile(target, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteProfile(ClientProfile profile) throws IOException {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
Files.deleteIfExists(e.getKey());
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addProfile(Path path, ClientProfile profile) {
|
|
||||||
for(var e : profilesMap.entrySet()) {
|
|
||||||
if(e.getValue().getUUID().equals(profile.getUUID())) {
|
|
||||||
profilesMap.remove(e.getKey());
|
|
||||||
profilesList.remove(e.getValue());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profilesMap.put(path, profile);
|
|
||||||
profilesList.add(profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
|
||||||
private final Map<Path, ClientProfile> result;
|
|
||||||
private final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
private ProfilesFileVisitor(Map<Path, ClientProfile> result) {
|
|
||||||
this.result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
|
||||||
|
|
||||||
// Read profile
|
|
||||||
ClientProfile profile;
|
|
||||||
try (BufferedReader reader = IOHelper.newReader(file)) {
|
|
||||||
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
|
||||||
}
|
|
||||||
profile.verify();
|
|
||||||
|
|
||||||
// Add SIGNED profile to result list
|
|
||||||
result.put(file.toAbsolutePath(), profile);
|
|
||||||
return super.visitFile(file, attrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,427 @@
|
||||||
|
package pro.gravit.launchserver.auth.profiles;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.base.Launcher;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||||
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launcher.core.serialize.HInput;
|
||||||
|
import pro.gravit.launcher.core.serialize.HOutput;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.Reconfigurable;
|
||||||
|
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.utils.command.Command;
|
||||||
|
import pro.gravit.utils.command.SubCommand;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class LocalProfilesProvider extends ProfilesProvider implements Reconfigurable {
|
||||||
|
private final transient Logger logger = LogManager.getLogger();
|
||||||
|
public String profilesDir = "profiles";
|
||||||
|
public String cacheFile = ".updates-cache";
|
||||||
|
public String updatesDir = "updates";
|
||||||
|
public boolean cacheUpdates = true;
|
||||||
|
private transient volatile Map<String, HashedDir> updatesDirMap;
|
||||||
|
private transient volatile Map<UUID, LocalProfile> profilesMap;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UncompletedProfile create(String name, String description, CompletedProfile reference) {
|
||||||
|
LocalProfile ref = (LocalProfile) reference;
|
||||||
|
LocalProfile profile;
|
||||||
|
if(ref != null) {
|
||||||
|
ClientProfile newClientProfile = new ClientProfileBuilder(ref.profile)
|
||||||
|
.setTitle(name)
|
||||||
|
.setInfo(description)
|
||||||
|
.setDir(name)
|
||||||
|
.createClientProfile();
|
||||||
|
profile = new LocalProfile(newClientProfile, ref.clientDir, ref.assetDir);
|
||||||
|
Path updatesDirPath = Path.of(updatesDir);
|
||||||
|
try {
|
||||||
|
IOHelper.copy(updatesDirPath.resolve(ref.profile.getDir()), updatesDirPath.resolve(profile.profile.getDir()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
profile = new LocalProfile(new ClientProfileBuilder()
|
||||||
|
.setUuid(UUID.randomUUID())
|
||||||
|
.setTitle(name)
|
||||||
|
.setInfo(description)
|
||||||
|
.setDir(name)
|
||||||
|
.setAssetDir("assets")
|
||||||
|
.createClientProfile(), null, getUpdatesDir("assets"));
|
||||||
|
}
|
||||||
|
profilesMap.put(profile.getUuid(), profile);
|
||||||
|
try(Writer writer = IOHelper.newWriter(profile.getConfigPath())) {
|
||||||
|
Launcher.gsonManager.configGson.toJson(profile.profile, writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(UncompletedProfile profile) {
|
||||||
|
LocalProfile p = (LocalProfile) profile;
|
||||||
|
profilesMap.remove(p.getUuid());
|
||||||
|
try {
|
||||||
|
Path updatesDirPath = Path.of(updatesDir);
|
||||||
|
IOHelper.deleteDir(updatesDirPath.resolve(p.profile.getDir()), true);
|
||||||
|
Files.delete(p.getConfigPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UncompletedProfile> getProfiles(Client client) {
|
||||||
|
return new HashSet<>(profilesMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletedProfile pushUpdate(UncompletedProfile profile, String tag, ClientProfile clientProfile, List<ProfileAction> assetActions, List<ProfileAction> clientActions, List<UpdateFlag> flags) throws IOException {
|
||||||
|
Path updatesDirPath = Path.of(updatesDir);
|
||||||
|
LocalProfile localProfile = (LocalProfile) profile;
|
||||||
|
localProfile = new LocalProfile(clientProfile, localProfile.clientDir, localProfile.assetDir);
|
||||||
|
localProfile.profile = clientProfile;
|
||||||
|
if(assetActions != null && !assetActions.isEmpty()) {
|
||||||
|
Path assetDir = updatesDirPath.resolve(clientProfile.getAssetDir());
|
||||||
|
execute(localProfile.assetDir, assetDir, assetActions);
|
||||||
|
localProfile.assetDir = new HashedDir(assetDir, null, true, true);
|
||||||
|
}
|
||||||
|
if(clientActions != null && !clientActions.isEmpty()) {
|
||||||
|
Path clientDir = updatesDirPath.resolve(clientProfile.getDir());
|
||||||
|
execute(localProfile.clientDir, clientDir, clientActions);
|
||||||
|
localProfile.clientDir = new HashedDir(clientDir, null, true, true);
|
||||||
|
}
|
||||||
|
profilesMap.put(localProfile.getUuid(), localProfile);
|
||||||
|
return localProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void download(CompletedProfile profile, Map<String, Path> files, boolean assets) throws IOException {
|
||||||
|
Path sourceDir = Path.of(updatesDir).resolve(assets ? profile.getProfile().getAssetDir() : profile.getProfile().getDir());
|
||||||
|
for(var e : files.entrySet()) {
|
||||||
|
var source = sourceDir.resolve(e.getKey());
|
||||||
|
var target = e.getValue();
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.copy(source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedDir getUnconnectedDirectory(String name) {
|
||||||
|
return getUpdatesDir(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletedProfile get(UUID uuid, String tag) {
|
||||||
|
return profilesMap.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletedProfile get(String name, String tag) {
|
||||||
|
for(var p : profilesMap.values()) {
|
||||||
|
if(p.getName() != null && p.getName().equals(name)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeCache(Path file) throws IOException {
|
||||||
|
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
||||||
|
output.writeLength(updatesDirMap.size(), 0);
|
||||||
|
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
||||||
|
output.writeString(entry.getKey(), 0);
|
||||||
|
entry.getValue().write(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readCache(Path file) throws IOException {
|
||||||
|
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
||||||
|
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
||||||
|
int size = input.readLength(0);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
String name = input.readString(0);
|
||||||
|
HashedDir dir = new HashedDir(input);
|
||||||
|
updatesDirMap.put(name, dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
||||||
|
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readProfilesDir() throws IOException {
|
||||||
|
Path profilesDirPath = Path.of(profilesDir);
|
||||||
|
Map<UUID, LocalProfile> newProfiles = new HashMap<>();
|
||||||
|
IOHelper.walk(profilesDirPath, new ProfilesFileVisitor(newProfiles), false);
|
||||||
|
profilesMap = newProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readUpdatesDir() throws IOException {
|
||||||
|
var cacheFilePath = Path.of(cacheFile);
|
||||||
|
if (cacheUpdates) {
|
||||||
|
if (Files.exists(cacheFilePath)) {
|
||||||
|
try {
|
||||||
|
readCache(cacheFilePath);
|
||||||
|
return;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Read updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sync(Collection<String> dirs) throws IOException {
|
||||||
|
logger.info("Syncing updates dir");
|
||||||
|
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
||||||
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(Path.of(updatesDir))) {
|
||||||
|
for (final Path updateDir : dirStream) {
|
||||||
|
if (Files.isHidden(updateDir))
|
||||||
|
continue; // Skip hidden
|
||||||
|
|
||||||
|
// Resolve name and verify is dir
|
||||||
|
String name = IOHelper.getFileName(updateDir);
|
||||||
|
if (!IOHelper.isDir(updateDir)) {
|
||||||
|
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
||||||
|
logger.warn("Not update dir: '{}'", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add from previous map (it's guaranteed to be non-null)
|
||||||
|
if (dirs != null && !dirs.contains(name)) {
|
||||||
|
HashedDir hdir = updatesDirMap.get(name);
|
||||||
|
if (hdir != null) {
|
||||||
|
newUpdatesDirMap.put(name, hdir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync and sign update dir
|
||||||
|
logger.info("Syncing '{}' update dir", name);
|
||||||
|
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||||
|
newUpdatesDirMap.put(name, updateHDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||||
|
if (cacheUpdates) {
|
||||||
|
try {
|
||||||
|
writeCache(Path.of(cacheFile));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
logger.error("Write updates cache failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashedDir getUpdatesDir(String updateName) {
|
||||||
|
if(updateName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return updatesDirMap.get(updateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
super.init(server);
|
||||||
|
try {
|
||||||
|
if (!IOHelper.isDir(Path.of(updatesDir)))
|
||||||
|
Files.createDirectory(Path.of(updatesDir));
|
||||||
|
readUpdatesDir();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Updates not synced", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Path profilesDirPath = Path.of(profilesDir);
|
||||||
|
if (!IOHelper.isDir(profilesDirPath))
|
||||||
|
Files.createDirectory(profilesDirPath);
|
||||||
|
readProfilesDir();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Profiles not synced", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(HashedDir dir, Path updatesDirPath, List<ProfileAction> actions) throws IOException {
|
||||||
|
for(var action : actions) {
|
||||||
|
execute(dir, updatesDirPath, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(HashedDir dir, Path updatesDirPath, ProfileAction action) throws IOException {
|
||||||
|
switch (action.type()) {
|
||||||
|
case UPLOAD -> {
|
||||||
|
Path target = updatesDirPath.resolve(action.target());
|
||||||
|
if(action.source() == null) {
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.transfer(action.input().get(), target);
|
||||||
|
} else {
|
||||||
|
Path source = Path.of(action.source());
|
||||||
|
if(source.toAbsolutePath().equals(target.toAbsolutePath())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(action.deleteSource()) {
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.move(source, target);
|
||||||
|
} else {
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.copy(source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case COPY -> {
|
||||||
|
Path source = updatesDirPath.resolve(action.source());
|
||||||
|
Path target = updatesDirPath.resolve(action.target());
|
||||||
|
if(source.toAbsolutePath().equals(target.toAbsolutePath())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.copy(source, target);
|
||||||
|
}
|
||||||
|
case MOVE -> {
|
||||||
|
Path source = updatesDirPath.resolve(action.source());
|
||||||
|
Path target = updatesDirPath.resolve(action.target());
|
||||||
|
if(source.toAbsolutePath().equals(target.toAbsolutePath())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IOHelper.createParentDirs(target);
|
||||||
|
IOHelper.move(source, target);
|
||||||
|
}
|
||||||
|
case DELETE -> {
|
||||||
|
Path target = updatesDirPath.resolve(action.target());
|
||||||
|
if(Files.isDirectory(target)) {
|
||||||
|
IOHelper.deleteDir(target, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Command> getCommands() {
|
||||||
|
return Map.of( "sync",
|
||||||
|
new SubCommand("[]", "sync all") {
|
||||||
|
@Override
|
||||||
|
public void invoke(String... args) throws Exception {
|
||||||
|
try {
|
||||||
|
if (!IOHelper.isDir(Path.of(updatesDir)))
|
||||||
|
Files.createDirectory(Path.of(updatesDir));
|
||||||
|
readUpdatesDir();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Updates not synced", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Path profilesDirPath = Path.of(profilesDir);
|
||||||
|
if (!IOHelper.isDir(profilesDirPath))
|
||||||
|
Files.createDirectory(profilesDirPath);
|
||||||
|
readProfilesDir();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Profiles not synced", e);
|
||||||
|
}
|
||||||
|
logger.info("Profiles and updates synced");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocalProfile implements CompletedProfile {
|
||||||
|
private ClientProfile profile;
|
||||||
|
private HashedDir clientDir;
|
||||||
|
private HashedDir assetDir;
|
||||||
|
private Path configPath;
|
||||||
|
|
||||||
|
public LocalProfile(ClientProfile profile, HashedDir clientDir, HashedDir assetDir) {
|
||||||
|
this.profile = profile;
|
||||||
|
this.clientDir = clientDir;
|
||||||
|
this.assetDir = assetDir;
|
||||||
|
this.configPath = Path.of(profilesDir).resolve(profile.getDir());
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalProfile(ClientProfile profile, HashedDir clientDir, HashedDir assetDir, Path configPath) {
|
||||||
|
this.profile = profile;
|
||||||
|
this.clientDir = clientDir;
|
||||||
|
this.assetDir = assetDir;
|
||||||
|
this.configPath = configPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientProfile getProfile() {
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedDir getClientDir() {
|
||||||
|
return clientDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashedDir getAssetDir() {
|
||||||
|
return assetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUuid() {
|
||||||
|
return profile.getUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return profile.getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return profile.getInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultTag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getConfigPath() {
|
||||||
|
return configPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ProfilesFileVisitor extends SimpleFileVisitor<Path> {
|
||||||
|
private final Map<UUID, LocalProfile> result;
|
||||||
|
private final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
|
private ProfilesFileVisitor(Map<UUID, LocalProfile> result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
logger.info("Syncing '{}' profile", IOHelper.getFileName(file));
|
||||||
|
|
||||||
|
// Read profile
|
||||||
|
ClientProfile profile;
|
||||||
|
try (BufferedReader reader = IOHelper.newReader(file)) {
|
||||||
|
profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class);
|
||||||
|
}
|
||||||
|
profile.verify();
|
||||||
|
|
||||||
|
LocalProfile localProfile = new LocalProfile(profile, getUpdatesDir(profile.getDir()), getUpdatesDir(profile.getAssetDir()), file);
|
||||||
|
result.put(localProfile.getUuid(), localProfile);
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,76 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.profiles;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.utils.ProviderMap;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class ProfileProvider {
|
|
||||||
public static final ProviderMap<ProfileProvider> providers = new ProviderMap<>("ProfileProvider");
|
|
||||||
private static boolean registredProviders = false;
|
|
||||||
protected transient LaunchServer server;
|
|
||||||
|
|
||||||
public static void registerProviders() {
|
|
||||||
if (!registredProviders) {
|
|
||||||
providers.register("local", LocalProfileProvider.class);
|
|
||||||
registredProviders = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(LaunchServer server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void sync() throws IOException;
|
|
||||||
|
|
||||||
public abstract Set<ClientProfile> getProfiles();
|
|
||||||
|
|
||||||
public abstract void addProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public abstract void deleteProfile(ClientProfile profile) throws IOException;
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(UUID uuid) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getUUID().equals(uuid)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClientProfile getProfile(String title) {
|
|
||||||
for(var e : getProfiles()) {
|
|
||||||
if(e.getTitle().equals(title)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ClientProfile> getProfiles(Client client) {
|
|
||||||
List<ClientProfile> profileList;
|
|
||||||
Set<ClientProfile> serverProfiles = getProfiles();
|
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) {
|
|
||||||
profileList = new ArrayList<>(4);
|
|
||||||
for (ClientProfile profile : serverProfiles) {
|
|
||||||
if (protectHandler.canGetProfile(profile, client)) {
|
|
||||||
profileList.add(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
profileList = List.copyOf(serverProfiles);
|
|
||||||
}
|
|
||||||
return profileList;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package pro.gravit.launchserver.auth.profiles;
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.socket.Client;
|
||||||
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public abstract class ProfilesProvider {
|
||||||
|
public static final ProviderMap<ProfilesProvider> providers = new ProviderMap<>("ProfileProvider");
|
||||||
|
private static boolean registredProviders = false;
|
||||||
|
protected transient LaunchServer server;
|
||||||
|
|
||||||
|
public static void registerProviders() {
|
||||||
|
if (!registredProviders) {
|
||||||
|
providers.register("local", LocalProfilesProvider.class);
|
||||||
|
registredProviders = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(LaunchServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract UncompletedProfile create(String name, String description, CompletedProfile basic);
|
||||||
|
public abstract void delete(UncompletedProfile profile);
|
||||||
|
public abstract Set<UncompletedProfile> getProfiles(Client client);
|
||||||
|
public abstract CompletedProfile pushUpdate(UncompletedProfile profile,
|
||||||
|
String tag,
|
||||||
|
ClientProfile clientProfile,
|
||||||
|
List<ProfileAction> assetActions,
|
||||||
|
List<ProfileAction> clientActions,
|
||||||
|
List<UpdateFlag> flags) throws IOException;
|
||||||
|
public abstract void download(CompletedProfile profile, Map<String, Path> files, boolean assets) throws IOException;
|
||||||
|
public abstract HashedDir getUnconnectedDirectory(String name);
|
||||||
|
public abstract CompletedProfile get(UUID uuid, String tag);
|
||||||
|
public abstract CompletedProfile get(String name, String tag);
|
||||||
|
public CompletedProfile get(UncompletedProfile profile) {
|
||||||
|
if(profile == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return get(profile.getUuid(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface UncompletedProfile {
|
||||||
|
UUID getUuid();
|
||||||
|
String getName();
|
||||||
|
String getDescription();
|
||||||
|
String getDefaultTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface CompletedProfile extends UncompletedProfile {
|
||||||
|
String getTag();
|
||||||
|
ClientProfile getProfile();
|
||||||
|
HashedDir getClientDir();
|
||||||
|
HashedDir getAssetDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ProfileAction(ProfileActionType type, String source, String target, Supplier<InputStream> input, Consumer<OutputStream> output, boolean deleteSource) {
|
||||||
|
public enum ProfileActionType {
|
||||||
|
UPLOAD, COPY, MOVE, DELETE
|
||||||
|
}
|
||||||
|
public static ProfileAction upload(Path source, String target, boolean deleteSource) {
|
||||||
|
return new ProfileAction(ProfileActionType.UPLOAD, source.toString(), target, null, null, deleteSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfileAction upload(Supplier<InputStream> input, String target) {
|
||||||
|
return new ProfileAction(ProfileActionType.UPLOAD, null, target, input, null, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UpdateFlag {
|
||||||
|
USE_DEFAULT_ASSETS, DELETE_SOURCE_FILES
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,18 +2,11 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
|
||||||
import java.util.*;
|
public class StdProtectHandler extends ProtectHandler {
|
||||||
|
|
||||||
public class StdProtectHandler extends ProtectHandler implements ProfilesProtectHandler {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
public Map<String, List<String>> profileWhitelist = new HashMap<>();
|
|
||||||
public List<String> allowUpdates = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
||||||
|
@ -22,38 +15,6 @@ public boolean allowGetAccessToken(AuthResponse.AuthContext context) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(LaunchServer server) {
|
public void init(LaunchServer server) {
|
||||||
if (profileWhitelist != null && !profileWhitelist.isEmpty()) {
|
|
||||||
logger.warn("profileWhitelist deprecated. Please use permission 'launchserver.profile.PROFILE_UUID.show' and 'launchserver.profile.PROFILE_UUID.enter'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canGetProfile(ClientProfile profile, Client client) {
|
|
||||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.show", profile, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canChangeProfile(ClientProfile profile, Client client) {
|
|
||||||
return (client.isAuth && !profile.isLimited()) || isWhitelisted("launchserver.profile.%s.enter", profile, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canGetUpdates(String updatesDirName, Client client) {
|
|
||||||
return client.profile != null && (client.profile.getDir().equals(updatesDirName) || client.profile.getAssetDir().equals(updatesDirName) || allowUpdates.contains(updatesDirName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWhitelisted(String property, ClientProfile profile, Client client) {
|
|
||||||
if (client.permissions != null) {
|
|
||||||
String permByUUID = property.formatted(profile.getUUID());
|
|
||||||
if (client.permissions.hasPerm(permByUUID)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
String permByTitle = property.formatted(profile.getTitle().toLowerCase(Locale.ROOT));
|
|
||||||
if (client.permissions.hasPerm(permByTitle)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<String> allowedUsername = profileWhitelist.get(profile.getTitle());
|
|
||||||
return allowedUsername != null && allowedUsername.contains(client.username);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package pro.gravit.launchserver.auth.protect.interfaces;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
|
||||||
|
|
||||||
public interface ProfilesProtectHandler {
|
|
||||||
default boolean canGetProfiles(Client client) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean canGetProfile(ClientProfile profile, Client client) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean canChangeProfile(ClientProfile profile, Client client) {
|
|
||||||
return client.isAuth;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean canGetUpdates(String updatesDirName, Client client) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,226 +2,81 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launcher.core.serialize.HInput;
|
|
||||||
import pro.gravit.launcher.core.serialize.HOutput;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.IOException;
|
||||||
import java.nio.file.DirectoryStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.util.Arrays;
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
import java.util.stream.Stream;
|
import java.util.Map;
|
||||||
|
|
||||||
public class LocalUpdatesProvider extends UpdatesProvider {
|
public class LocalUpdatesProvider extends UpdatesProvider {
|
||||||
private final transient Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
public String cacheFile = ".updates-cache";
|
|
||||||
public String updatesDir = "updates";
|
public String updatesDir = "updates";
|
||||||
public boolean cacheUpdates = true;
|
public String binaryName = "Launcher";
|
||||||
private volatile transient Map<String, HashedDir> updatesDirMap;
|
public Map<UpdateVariant, String> urls = new HashMap<>(Map.of(
|
||||||
|
UpdateVariant.JAR, "http://localhost:9274/Launcher.jar",
|
||||||
private void writeCache(Path file) throws IOException {
|
UpdateVariant.EXE, "http://localhost:9274/Launcher.exe"
|
||||||
try (HOutput output = new HOutput(IOHelper.newOutput(file))) {
|
));
|
||||||
output.writeLength(updatesDirMap.size(), 0);
|
private final transient Map<UpdateVariant, byte[]> hashMap = new HashMap<>();
|
||||||
for (Map.Entry<String, HashedDir> entry : updatesDirMap.entrySet()) {
|
|
||||||
output.writeString(entry.getKey(), 0);
|
|
||||||
entry.getValue().write(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Saved {} updates to cache", updatesDirMap.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readCache(Path file) throws IOException {
|
|
||||||
Map<String, HashedDir> updatesDirMap = new HashMap<>(16);
|
|
||||||
try (HInput input = new HInput(IOHelper.newInput(file))) {
|
|
||||||
int size = input.readLength(0);
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
String name = input.readString(0);
|
|
||||||
HashedDir dir = new HashedDir(input);
|
|
||||||
updatesDirMap.put(name, dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.debug("Found {} updates from cache", updatesDirMap.size());
|
|
||||||
this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readUpdatesFromCache() throws IOException {
|
|
||||||
readCache(Path.of(cacheFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readUpdatesDir() throws IOException {
|
|
||||||
var cacheFilePath = Path.of(cacheFile);
|
|
||||||
if (cacheUpdates) {
|
|
||||||
if (Files.exists(cacheFilePath)) {
|
|
||||||
try {
|
|
||||||
readCache(cacheFilePath);
|
|
||||||
return;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
logger.error("Read updates cache failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sync(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(LaunchServer server) {
|
public void init(LaunchServer server) {
|
||||||
super.init(server);
|
super.init(server);
|
||||||
try {
|
try {
|
||||||
if (!IOHelper.isDir(Path.of(updatesDir)))
|
sync(UpdateVariant.JAR);
|
||||||
Files.createDirectory(Path.of(updatesDir));
|
sync(UpdateVariant.EXE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Updates not synced", e);
|
logger.error("Error when syncing binaries", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncInitially() throws IOException {
|
public void pushUpdate(Map<UpdateVariant, Path> files) throws IOException {
|
||||||
readUpdatesDir();
|
for(var e : files.entrySet()) {
|
||||||
|
IOHelper.copy(e.getValue(), getUpdate(e.getKey()));
|
||||||
|
sync(e.getKey());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sync(Collection<String> dirs) throws IOException {
|
public void sync(UpdateVariant variant) throws IOException {
|
||||||
logger.info("Syncing updates dir");
|
var source = getUpdate(variant);
|
||||||
Map<String, HashedDir> newUpdatesDirMap = new HashMap<>(16);
|
if(!Files.exists(source)) {
|
||||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(Path.of(updatesDir))) {
|
logger.warn("Dont exist {} binary", variant);
|
||||||
for (final Path updateDir : dirStream) {
|
return;
|
||||||
if (Files.isHidden(updateDir))
|
}
|
||||||
continue; // Skip hidden
|
byte[] hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, source);
|
||||||
|
hashMap.put(variant, hash);
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve name and verify is dir
|
public Path getUpdate(UpdateVariant variant) {
|
||||||
String name = IOHelper.getFileName(updateDir);
|
String fileName;
|
||||||
if (!IOHelper.isDir(updateDir)) {
|
switch (variant) {
|
||||||
if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e)))
|
case JAR -> {
|
||||||
logger.warn("Not update dir: '{}'", name);
|
fileName = binaryName.concat(".jar");
|
||||||
continue;
|
}
|
||||||
}
|
case EXE -> {
|
||||||
|
fileName = binaryName.concat(".exe");
|
||||||
// Add from previous map (it's guaranteed to be non-null)
|
}
|
||||||
if (dirs != null && !dirs.contains(name)) {
|
default -> {
|
||||||
HashedDir hdir = updatesDirMap.get(name);
|
fileName = binaryName;
|
||||||
if (hdir != null) {
|
|
||||||
newUpdatesDirMap.put(name, hdir);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync and sign update dir
|
|
||||||
logger.info("Syncing '{}' update dir", name);
|
|
||||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
|
||||||
newUpdatesDirMap.put(name, updateHDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
return Path.of(updatesDir).resolve(fileName);
|
||||||
if (cacheUpdates) {
|
}
|
||||||
try {
|
|
||||||
writeCache(Path.of(cacheFile));
|
@Override
|
||||||
} catch (Throwable e) {
|
public UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest) {
|
||||||
logger.error("Write updates cache failed", e);
|
byte[] hash = hashMap.get(variant);
|
||||||
}
|
if (hash == null) {
|
||||||
|
return null; // We dont have this file
|
||||||
}
|
}
|
||||||
server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server));
|
if(Arrays.equals(digest, hash)) {
|
||||||
}
|
return null; // Launcher already updated
|
||||||
|
|
||||||
@Override
|
|
||||||
public HashedDir getUpdatesDir(String updateName) {
|
|
||||||
return updatesDirMap.get(updateName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path resolveUpdateName(String updateName) {
|
|
||||||
if(updateName == null) {
|
|
||||||
return Path.of(updatesDir);
|
|
||||||
}
|
}
|
||||||
return Path.of(updatesDir).resolve(updateName);
|
return new UpdateInfo(urls.get(variant));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
for(var e : files.entrySet()) {
|
|
||||||
var target = path.resolve(e.getKey());
|
|
||||||
var source = e.getValue();
|
|
||||||
IOHelper.createParentDirs(target);
|
|
||||||
if(deleteAfterUpload) {
|
|
||||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
} else {
|
|
||||||
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OutputStream upload(String updateName, String file) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
var target = path.resolve(file);
|
|
||||||
IOHelper.createParentDirs(target);
|
|
||||||
return new FileOutputStream(target.toFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Path> download(String updateName, List<String> files) {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
Map<String, Path> map = new HashMap<>();
|
|
||||||
for(var e : files) {
|
|
||||||
map.put(e, path.resolve(e));
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void download(String updateName, Map<String, Path> files) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
for(var e : files.entrySet()) {
|
|
||||||
var source = path.resolve(e.getKey());
|
|
||||||
var target = e.getValue();
|
|
||||||
IOHelper.copy(source, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream download(String updateName, String path) throws IOException {
|
|
||||||
return new FileInputStream(resolveUpdateName(updateName).resolve(path).toFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void move(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException {
|
|
||||||
for(var e : files.entrySet()) {
|
|
||||||
var source = resolveUpdateName(e.getKey().updateName()).resolve(e.getKey().path());
|
|
||||||
var target = resolveUpdateName(e.getValue().updateName()).resolve(e.getValue().path());
|
|
||||||
IOHelper.move(source, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void copy(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException {
|
|
||||||
for(var e : files.entrySet()) {
|
|
||||||
var source = resolveUpdateName(e.getKey().updateName()).resolve(e.getKey().path());
|
|
||||||
var target = resolveUpdateName(e.getValue().updateName()).resolve(e.getValue().path());
|
|
||||||
IOHelper.copy(source, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String updateName, List<String> files) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
for(var e : files) {
|
|
||||||
var target = path.resolve(e);
|
|
||||||
Files.delete(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(String updateName) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
IOHelper.deleteDir(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(String updateName) throws IOException {
|
|
||||||
var path = resolveUpdateName(updateName);
|
|
||||||
Files.createDirectories(path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,15 @@
|
||||||
package pro.gravit.launchserver.auth.updates;
|
package pro.gravit.launchserver.auth.updates;
|
||||||
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedEntry;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.utils.ProviderMap;
|
import pro.gravit.utils.ProviderMap;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.net.URL;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.file.FileVisitResult;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class UpdatesProvider {
|
public abstract class UpdatesProvider {
|
||||||
|
|
||||||
public static final ProviderMap<UpdatesProvider> providers = new ProviderMap<>("UpdatesProvider");
|
public static final ProviderMap<UpdatesProvider> providers = new ProviderMap<>("UpdatesProvider");
|
||||||
private static boolean registredProviders = false;
|
private static boolean registredProviders = false;
|
||||||
protected transient LaunchServer server;
|
protected transient LaunchServer server;
|
||||||
|
@ -36,81 +25,17 @@ public void init(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sync() throws IOException {
|
public abstract void pushUpdate(Map<UpdateVariant, Path> files) throws IOException;
|
||||||
sync(null);
|
public abstract UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest);
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void syncInitially() throws IOException;
|
|
||||||
|
|
||||||
public abstract void sync(Collection<String> updateNames) throws IOException;
|
|
||||||
|
|
||||||
public abstract HashedDir getUpdatesDir(String updateName);
|
|
||||||
|
|
||||||
public abstract void upload(String updateName, Map<String, Path> files, boolean deleteAfterUpload) throws IOException;
|
|
||||||
|
|
||||||
public abstract OutputStream upload(String updateName, String file) throws IOException;
|
|
||||||
|
|
||||||
public void upload(String updateName, Path dir, boolean deleteAfterUpload) throws IOException {
|
|
||||||
if(!Files.isDirectory(dir)) {
|
|
||||||
throw new UnsupportedEncodingException(String.format("%s is not a directory", dir));
|
|
||||||
}
|
|
||||||
Map<String, Path> map = new HashMap<>();
|
|
||||||
IOHelper.walk(dir, new SimpleFileVisitor<>() {
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
map.put(dir.relativize(file).toString(), file);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
upload(updateName, map, deleteAfterUpload);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Map<String, Path> download(String updateName, List<String> files) throws IOException;
|
|
||||||
|
|
||||||
public abstract void download(String updateName, Map<String, Path> files) throws IOException;
|
|
||||||
|
|
||||||
public abstract InputStream download(String updateName, String path) throws IOException;
|
|
||||||
|
|
||||||
public abstract void move(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException;
|
|
||||||
|
|
||||||
public void move(String updateName, String newUpdateName) throws IOException {
|
|
||||||
create(newUpdateName);
|
|
||||||
var updatesDir = getUpdatesDir(updateName);
|
|
||||||
Map<UpdateNameAndFile, UpdateNameAndFile> map = new HashMap<>();
|
|
||||||
updatesDir.walk("/", (path, name, entry) -> {
|
|
||||||
map.put(UpdateNameAndFile.of(updateName, path), UpdateNameAndFile.of(newUpdateName, path));
|
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
|
||||||
});
|
|
||||||
move(map);
|
|
||||||
delete(updateName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void copy(Map<UpdateNameAndFile, UpdateNameAndFile> files) throws IOException;
|
|
||||||
|
|
||||||
public void copy(String updateName, String newUpdateName) throws IOException {
|
|
||||||
create(newUpdateName);
|
|
||||||
var updatesDir = getUpdatesDir(updateName);
|
|
||||||
Map<UpdateNameAndFile, UpdateNameAndFile> map = new HashMap<>();
|
|
||||||
updatesDir.walk("/", (path, name, entry) -> {
|
|
||||||
map.put(UpdateNameAndFile.of(updateName, path), UpdateNameAndFile.of(newUpdateName, path));
|
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
|
||||||
});
|
|
||||||
copy(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void delete(String updateName, List<String> files) throws IOException;
|
|
||||||
|
|
||||||
public abstract void delete(String updateName) throws IOException;
|
|
||||||
|
|
||||||
public abstract void create(String updateName) throws IOException;
|
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record UpdateNameAndFile(String updateName, String path) {
|
public enum UpdateVariant {
|
||||||
public static UpdateNameAndFile of(String updateName, String path) {
|
JAR, EXE
|
||||||
return new UpdateNameAndFile(updateName, path);
|
}
|
||||||
}
|
|
||||||
|
public record UpdateInfo(String url) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launchserver.binary;
|
package pro.gravit.launchserver.binary;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -9,14 +10,16 @@
|
||||||
public class EXELauncherBinary extends LauncherBinary {
|
public class EXELauncherBinary extends LauncherBinary {
|
||||||
|
|
||||||
public EXELauncherBinary(LaunchServer server) {
|
public EXELauncherBinary(LaunchServer server) {
|
||||||
super(server, LauncherBinary.resolve(server, ".exe"), "Launcher-%s.exe");
|
super(server, "Launcher-%s.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpdatesProvider.UpdateVariant getVariant() {
|
||||||
|
return UpdatesProvider.UpdateVariant.EXE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build() throws IOException {
|
public void build() throws IOException {
|
||||||
if (IOHelper.isFile(syncBinaryFile)) {
|
|
||||||
Files.delete(syncBinaryFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import pro.gravit.launcher.base.Launcher;
|
import pro.gravit.launcher.base.Launcher;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.binary.tasks.*;
|
import pro.gravit.launchserver.binary.tasks.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -23,7 +24,7 @@ public final class JARLauncherBinary extends LauncherBinary {
|
||||||
public final Map<String, Path> files;
|
public final Map<String, Path> files;
|
||||||
|
|
||||||
public JARLauncherBinary(LaunchServer server) throws IOException {
|
public JARLauncherBinary(LaunchServer server) throws IOException {
|
||||||
super(server, resolve(server, ".jar"), "Launcher-%s.jar");
|
super(server, "Launcher-%s.jar");
|
||||||
count = new AtomicLong(0);
|
count = new AtomicLong(0);
|
||||||
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
|
runtimeDir = server.dir.resolve(Launcher.RUNTIME_DIR);
|
||||||
buildDir = server.dir.resolve("build");
|
buildDir = server.dir.resolve("build");
|
||||||
|
@ -36,6 +37,11 @@ public JARLauncherBinary(LaunchServer server) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UpdatesProvider.UpdateVariant getVariant() {
|
||||||
|
return UpdatesProvider.UpdateVariant.JAR;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
tasks.add(new PrepareBuildTask(server));
|
tasks.add(new PrepareBuildTask(server));
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launchserver.binary;
|
package pro.gravit.launchserver.binary;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
import pro.gravit.launchserver.binary.tasks.LauncherBuildTask;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
@ -12,13 +13,10 @@
|
||||||
|
|
||||||
public abstract class LauncherBinary extends BinaryPipeline {
|
public abstract class LauncherBinary extends BinaryPipeline {
|
||||||
public final LaunchServer server;
|
public final LaunchServer server;
|
||||||
public final Path syncBinaryFile;
|
|
||||||
private volatile byte[] digest;
|
|
||||||
|
|
||||||
protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat) {
|
protected LauncherBinary(LaunchServer server, String nameFormat) {
|
||||||
super(server.tmpDir.resolve("build"), nameFormat);
|
super(server.tmpDir.resolve("build"), nameFormat);
|
||||||
this.server = server;
|
this.server = server;
|
||||||
syncBinaryFile = binaryFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path resolve(LaunchServer server, String ext) {
|
public static Path resolve(LaunchServer server, String ext) {
|
||||||
|
@ -40,30 +38,17 @@ public void build() throws IOException {
|
||||||
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
logger.info("Task {} processed from {} millis", task.getName(), time_task);
|
||||||
}
|
}
|
||||||
long time_end = System.currentTimeMillis();
|
long time_end = System.currentTimeMillis();
|
||||||
server.config.updatesProvider.upload(null, Map.of(syncBinaryFile.toString(), thisPath), true);
|
if(thisPath != null) {
|
||||||
|
server.config.updatesProvider.pushUpdate(Map.of(getVariant(), thisPath));
|
||||||
|
} else {
|
||||||
|
logger.warn("Missing {} binary file", getVariant());
|
||||||
|
}
|
||||||
IOHelper.deleteDir(buildDir, false);
|
IOHelper.deleteDir(buildDir, false);
|
||||||
logger.info("Build successful from {} millis", time_end - time_start);
|
logger.info("Build successful from {} millis", time_end - time_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean exists() {
|
public abstract UpdatesProvider.UpdateVariant getVariant();
|
||||||
return syncBinaryFile != null && IOHelper.isFile(syncBinaryFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final byte[] getDigest() {
|
|
||||||
return digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean sync() {
|
|
||||||
try {
|
|
||||||
var target = syncBinaryFile.toString();
|
|
||||||
var path = server.config.updatesProvider.download(null, List.of(target)).get(target);
|
|
||||||
digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(path));
|
|
||||||
return true;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ protected boolean showApplyDialog(String text) throws IOException {
|
||||||
return response.equals("y");
|
return response.equals("y");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Downloader downloadWithProgressBar(String taskName, List<Downloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
protected static Downloader downloadWithProgressBar(String taskName, List<Downloader.SizedFile> list, String baseUrl, Path targetDir) throws Exception {
|
||||||
long total = 0;
|
long total = 0;
|
||||||
for (Downloader.SizedFile file : list) {
|
for (Downloader.SizedFile file : list) {
|
||||||
if(file.size < 0) {
|
if(file.size < 0) {
|
||||||
|
|
|
@ -21,6 +21,5 @@ public String getUsageDescription() {
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
server.buildLauncherBinaries();
|
server.buildLauncherBinaries();
|
||||||
server.syncLauncherBinaries();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,8 @@ public static void registerCommands(pro.gravit.utils.command.CommandHandler hand
|
||||||
|
|
||||||
// Register sync commands
|
// Register sync commands
|
||||||
BaseCommandCategory updates = new BaseCommandCategory();
|
BaseCommandCategory updates = new BaseCommandCategory();
|
||||||
updates.registerCommand("indexAsset", new IndexAssetCommand(server));
|
//updates.registerCommand("indexAsset", new IndexAssetCommand(server));
|
||||||
updates.registerCommand("unindexAsset", new UnindexAssetCommand(server));
|
//updates.registerCommand("unindexAsset", new UnindexAssetCommand(server));
|
||||||
updates.registerCommand("downloadAsset", new DownloadAssetCommand(server));
|
|
||||||
updates.registerCommand("downloadClient", new DownloadClientCommand(server));
|
|
||||||
updates.registerCommand("sync", new SyncCommand(server));
|
updates.registerCommand("sync", new SyncCommand(server));
|
||||||
updates.registerCommand("profile", new ProfilesCommand(server));
|
updates.registerCommand("profile", new ProfilesCommand(server));
|
||||||
Category updatesCategory = new Category(updates, "updates", "Update and Sync Management");
|
Category updatesCategory = new Category(updates, "updates", "Update and Sync Management");
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.hash;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.Launcher;
|
|
||||||
import pro.gravit.launcher.base.Downloader;
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launchserver.HttpRequester;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class DownloadAssetCommand extends Command {
|
|
||||||
private static final String MINECRAFT_VERSIONS_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
|
||||||
private static final String RESOURCES_DOWNLOAD_URL = "https://resources.download.minecraft.net/";
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public DownloadAssetCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[version] [dir] (mojang/mirror)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Download asset dir";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
//Version version = Version.byName(args[0]);
|
|
||||||
String versionName = args[0];
|
|
||||||
String dirName = IOHelper.verifyFileName(args.length > 1 ? args[1] : "assets");
|
|
||||||
String type = args.length > 2 ? args[2] : "mojang";
|
|
||||||
Path assetDir = server.createTempDirectory("assets");
|
|
||||||
var updatesDir = server.config.updatesProvider.getUpdatesDir(dirName);
|
|
||||||
if(updatesDir == null) {
|
|
||||||
updatesDir = new HashedDir();
|
|
||||||
server.config.updatesProvider.create(dirName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create asset dir
|
|
||||||
if (Files.notExists(assetDir)) {
|
|
||||||
logger.info("Creating asset dir: '{}'", dirName);
|
|
||||||
Files.createDirectory(assetDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.equals("mojang")) {
|
|
||||||
HttpRequester requester = new HttpRequester();
|
|
||||||
logger.info("Fetch versions from {}", MINECRAFT_VERSIONS_URL);
|
|
||||||
var versions = requester.send(requester.get(MINECRAFT_VERSIONS_URL, null), MinecraftVersions.class).getOrThrow();
|
|
||||||
String profileUrl = null;
|
|
||||||
for (var e : versions.versions) {
|
|
||||||
if (e.id.equals(versionName)) {
|
|
||||||
profileUrl = e.url;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (profileUrl == null) {
|
|
||||||
logger.error("Version {} not found", versionName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("Fetch profile {} from {}", versionName, profileUrl);
|
|
||||||
var profileInfo = requester.send(requester.get(profileUrl, null), MiniVersion.class).getOrThrow();
|
|
||||||
String assetsIndexUrl = profileInfo.assetIndex.url;
|
|
||||||
String assetIndex = profileInfo.assetIndex.id;
|
|
||||||
Path indexPath = assetDir.resolve("indexes").resolve(assetIndex + ".json");
|
|
||||||
logger.info("Fetch asset index {} from {}", assetIndex, assetsIndexUrl);
|
|
||||||
JsonObject assets = requester.send(requester.get(assetsIndexUrl, null), JsonObject.class).getOrThrow();
|
|
||||||
JsonObject objects = assets.get("objects").getAsJsonObject();
|
|
||||||
try (Writer writer = IOHelper.newWriter(indexPath)) {
|
|
||||||
logger.info("Save {}", indexPath);
|
|
||||||
Launcher.gsonManager.configGson.toJson(assets, writer);
|
|
||||||
}
|
|
||||||
if (!assetIndex.equals(versionName)) {
|
|
||||||
Path targetPath = assetDir.resolve("indexes").resolve(versionName + ".json");
|
|
||||||
logger.info("Copy {} into {}", indexPath, targetPath);
|
|
||||||
Files.copy(indexPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
List<Downloader.SizedFile> toDownload = new ArrayList<>(128);
|
|
||||||
for (var e : objects.entrySet()) {
|
|
||||||
var value = e.getValue().getAsJsonObject();
|
|
||||||
var hash = value.get("hash").getAsString();
|
|
||||||
hash = hash.substring(0, 2) + "/" + hash;
|
|
||||||
var size = value.get("size").getAsLong();
|
|
||||||
var path = "objects/" + hash;
|
|
||||||
if (updatesDir.tryFindRecursive(path).isFound()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
toDownload.add(new Downloader.SizedFile(hash, path, size));
|
|
||||||
}
|
|
||||||
logger.info("Download {} files", toDownload.size());
|
|
||||||
Downloader downloader = downloadWithProgressBar(dirName, toDownload, RESOURCES_DOWNLOAD_URL, assetDir);
|
|
||||||
downloader.getFuture().get();
|
|
||||||
} else {
|
|
||||||
// Download required asset
|
|
||||||
logger.info("Downloading asset, it may take some time");
|
|
||||||
//HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getAssetsURL(version.name), assetDir);
|
|
||||||
server.mirrorManager.downloadZip(assetDir, "assets/%s.zip", versionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
server.config.updatesProvider.upload(dirName, assetDir, true);
|
|
||||||
|
|
||||||
// Finished
|
|
||||||
server.syncUpdatesDir(Collections.singleton(dirName));
|
|
||||||
logger.info("Asset successfully downloaded: '{}'", dirName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public record MiniVersionInfo(String id, String url) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public record MinecraftVersions(List<MiniVersionInfo> versions) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public record MinecraftAssetIndexInfo(String id, String url) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public record MiniVersion(MinecraftAssetIndexInfo assetIndex) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.hash;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.Launcher;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
|
||||||
import pro.gravit.utils.command.CommandException;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public final class DownloadClientCommand extends Command {
|
|
||||||
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public DownloadClientCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[version] [dir] (mirror/generate)";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Download client dir";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws IOException, CommandException {
|
|
||||||
verifyArgs(args, 2);
|
|
||||||
//Version version = Version.byName(args[0]);
|
|
||||||
String versionName = args[0];
|
|
||||||
String dirName = IOHelper.verifyFileName(args[1] != null ? args[1] : args[0]);
|
|
||||||
Path clientDir = server.createTempDirectory("client");
|
|
||||||
server.config.updatesProvider.create(dirName);
|
|
||||||
|
|
||||||
boolean isMirrorClientDownload = false;
|
|
||||||
if (args.length > 2) {
|
|
||||||
isMirrorClientDownload = args[2].equals("mirror");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download required client
|
|
||||||
logger.info("Downloading client, it may take some time");
|
|
||||||
//HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getClientsURL(version.name), clientDir);
|
|
||||||
server.mirrorManager.downloadZip(clientDir, "clients/%s.zip", versionName);
|
|
||||||
|
|
||||||
// Create profile file
|
|
||||||
logger.info("Creaing profile file: '{}'", dirName);
|
|
||||||
ClientProfile clientProfile = null;
|
|
||||||
if (isMirrorClientDownload) {
|
|
||||||
try {
|
|
||||||
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
|
|
||||||
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
|
|
||||||
var builder = new ClientProfileBuilder(clientProfile);
|
|
||||||
builder.setTitle(dirName);
|
|
||||||
builder.setDir(dirName);
|
|
||||||
builder.setUuid(UUID.randomUUID());
|
|
||||||
clientProfile = builder.createClientProfile();
|
|
||||||
if (clientProfile.getServers() != null) {
|
|
||||||
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
|
|
||||||
if (serverProfile != null) {
|
|
||||||
serverProfile.name = dirName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Filed download clientProfile from mirror: '{}' Generation through MakeProfileHelper", versionName);
|
|
||||||
isMirrorClientDownload = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isMirrorClientDownload) {
|
|
||||||
try {
|
|
||||||
String internalVersion = versionName;
|
|
||||||
if (internalVersion.contains("-")) {
|
|
||||||
internalVersion = internalVersion.substring(0, versionName.indexOf('-'));
|
|
||||||
}
|
|
||||||
ClientProfile.Version version = ClientProfile.Version.of(internalVersion);
|
|
||||||
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) <= 0) {
|
|
||||||
logger.warn("Minecraft 1.7.9 and below not supported. Use at your own risk");
|
|
||||||
}
|
|
||||||
MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(clientDir, version);
|
|
||||||
for (MakeProfileHelper.MakeProfileOption option : options) {
|
|
||||||
logger.debug("Detected option {}", option.getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
clientProfile = MakeProfileHelper.makeProfile(version, dirName, options);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
isMirrorClientDownload = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
server.config.profileProvider.addProfile(clientProfile);
|
|
||||||
server.config.updatesProvider.upload(dirName, clientDir, true);
|
|
||||||
|
|
||||||
// Finished
|
|
||||||
server.syncProfilesDir();
|
|
||||||
server.syncUpdatesDir(Collections.singleton(dirName));
|
|
||||||
logger.info("Client successfully downloaded: '{}'", dirName);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,7 +52,7 @@ public String getUsageDescription() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 3);
|
/*verifyArgs(args, 3);
|
||||||
String inputAssetDirName = IOHelper.verifyFileName(args[0]);
|
String inputAssetDirName = IOHelper.verifyFileName(args[0]);
|
||||||
String indexFileName = IOHelper.verifyFileName(args[1]);
|
String indexFileName = IOHelper.verifyFileName(args[1]);
|
||||||
String outputAssetDirName = IOHelper.verifyFileName(args[2]);
|
String outputAssetDirName = IOHelper.verifyFileName(args[2]);
|
||||||
|
@ -78,7 +78,7 @@ public void invoke(String... args) throws Exception {
|
||||||
|
|
||||||
// Finished
|
// Finished
|
||||||
server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
|
server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
|
||||||
logger.info("Asset successfully indexed: '{}'", inputAssetDirName);
|
logger.info("Asset successfully indexed: '{}'", inputAssetDirName);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class IndexObject {
|
public static class IndexObject {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public String getUsageDescription() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) throws Exception {
|
public void invoke(String... args) throws Exception {
|
||||||
verifyArgs(args, 3);
|
/*verifyArgs(args, 3);
|
||||||
String inputAssetDirName = IOHelper.verifyFileName(args[0]);
|
String inputAssetDirName = IOHelper.verifyFileName(args[0]);
|
||||||
String indexFileName = IOHelper.verifyFileName(args[1]);
|
String indexFileName = IOHelper.verifyFileName(args[1]);
|
||||||
String outputAssetDirName = IOHelper.verifyFileName(args[2]);
|
String outputAssetDirName = IOHelper.verifyFileName(args[2]);
|
||||||
|
@ -73,6 +73,6 @@ public void invoke(String... args) throws Exception {
|
||||||
|
|
||||||
// Finished
|
// Finished
|
||||||
server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
|
server.syncUpdatesDir(Collections.singleton(outputAssetDirName));
|
||||||
logger.info("Asset successfully unindexed: '{}'", outputAssetDir.toAbsolutePath().toString());
|
logger.info("Asset successfully unindexed: '{}'", outputAssetDir.toAbsolutePath().toString());*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
@ -34,26 +35,14 @@ 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);
|
||||||
ClientProfile profile;
|
ProfilesProvider.CompletedProfile profile;
|
||||||
try {
|
try {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
UUID uuid = UUID.fromString(args[0]);
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
profile = server.config.profilesProvider.get(uuid, null);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
profile = server.config.profilesProvider.get(args[0], null);
|
||||||
}
|
}
|
||||||
var builder = new ClientProfileBuilder(profile);
|
server.config.profilesProvider.create(args[1], "Description", profile);
|
||||||
builder.setTitle(args[1]);
|
|
||||||
builder.setUuid(UUID.randomUUID());
|
|
||||||
if(profile.getServers().size() == 1) {
|
|
||||||
profile.getServers().getFirst().name = args[1];
|
|
||||||
}
|
|
||||||
logger.info("Copy {} to {}", profile.getDir(), args[1]);
|
|
||||||
server.config.updatesProvider.copy(profile.getDir(), args[1]);
|
|
||||||
builder.setDir(args[1]);
|
|
||||||
profile = builder.createClientProfile();
|
|
||||||
server.config.profileProvider.addProfile(profile);
|
|
||||||
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
logger.info("Profile {} cloned from {}", args[1], args[0]);
|
||||||
server.syncProfilesDir();
|
|
||||||
server.syncUpdatesDir(List.of(args[1]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
package pro.gravit.launchserver.command.profiles;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.base.Downloader;
|
||||||
|
import pro.gravit.launcher.base.Launcher;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfileVersions;
|
||||||
|
import pro.gravit.launchserver.HttpRequester;
|
||||||
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
import pro.gravit.launchserver.helper.AssetsDirHelper;
|
||||||
|
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CreateProfileCommand extends Command {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
|
public CreateProfileCommand(LaunchServer server) {
|
||||||
|
super(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getArgsDescription() {
|
||||||
|
return "[version] [dir] (mirror/generate)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsageDescription() {
|
||||||
|
return "Download client";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(String... args) throws Exception {
|
||||||
|
verifyArgs(args, 2);
|
||||||
|
//Version version = Version.byName(args[0]);
|
||||||
|
String versionName = args[0];
|
||||||
|
String dirName = args[1];
|
||||||
|
Path clientDir = server.createTempDirectory("client");
|
||||||
|
|
||||||
|
boolean isMirrorProfileDownload = false;
|
||||||
|
if (args.length > 2) {
|
||||||
|
isMirrorProfileDownload = args[2].equals("mirror");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download required client
|
||||||
|
logger.info("Downloading client, it may take some time");
|
||||||
|
//HttpDownloader.downloadZip(server.mirrorManager.getDefaultMirror().getClientsURL(version.name), clientDir);
|
||||||
|
server.mirrorManager.downloadZip(clientDir, "clients/%s.zip", versionName);
|
||||||
|
|
||||||
|
// Create profile file
|
||||||
|
logger.info("Creaing profile file: '{}'", dirName);
|
||||||
|
ClientProfile clientProfile = null;
|
||||||
|
try {
|
||||||
|
JsonElement clientJson = server.mirrorManager.jsonRequest(null, "GET", "clients/%s.json", versionName);
|
||||||
|
clientProfile = Launcher.gsonManager.configGson.fromJson(clientJson, ClientProfile.class);
|
||||||
|
var builder = new ClientProfileBuilder(clientProfile);
|
||||||
|
builder.setTitle(dirName);
|
||||||
|
builder.setDir(dirName);
|
||||||
|
builder.setUuid(UUID.randomUUID());
|
||||||
|
clientProfile = builder.createClientProfile();
|
||||||
|
if (clientProfile.getServers() != null) {
|
||||||
|
ClientProfile.ServerProfile serverProfile = clientProfile.getDefaultServerProfile();
|
||||||
|
if (serverProfile != null) {
|
||||||
|
serverProfile.name = dirName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Filed download clientProfile from mirror: '{}' Generation through MakeProfileHelper", versionName);
|
||||||
|
isMirrorProfileDownload = false;
|
||||||
|
}
|
||||||
|
if (!isMirrorProfileDownload) {
|
||||||
|
try {
|
||||||
|
String internalVersion = versionName;
|
||||||
|
if (internalVersion.contains("-")) {
|
||||||
|
internalVersion = internalVersion.substring(0, versionName.indexOf('-'));
|
||||||
|
}
|
||||||
|
ClientProfile.Version version = ClientProfile.Version.of(internalVersion);
|
||||||
|
if (version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) <= 0) {
|
||||||
|
logger.warn("Minecraft 1.7.9 and below not supported. Use at your own risk");
|
||||||
|
}
|
||||||
|
MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(clientDir, version);
|
||||||
|
for (MakeProfileHelper.MakeProfileOption option : options) {
|
||||||
|
logger.debug("Detected option {}", option.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
clientProfile = MakeProfileHelper.makeProfile(version, dirName, options);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
isMirrorProfileDownload = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushClientAndDownloadAssets(server, clientProfile, clientDir);
|
||||||
|
|
||||||
|
// Finished
|
||||||
|
logger.info("Client successfully downloaded: '{}'", dirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProfilesProvider.CompletedProfile pushClientAndDownloadAssets(LaunchServer server, ClientProfile clientProfile, Path clientDir) throws Exception {
|
||||||
|
var uncompleted = server.config.profilesProvider.create(clientProfile.getTitle(), "Description", null);
|
||||||
|
var completed = server.config.profilesProvider.pushUpdate(uncompleted, null, clientProfile, null, List.of(
|
||||||
|
ProfilesProvider.ProfileAction.upload(clientDir, "", true)
|
||||||
|
), List.of(ProfilesProvider.UpdateFlag.USE_DEFAULT_ASSETS));
|
||||||
|
{
|
||||||
|
String assetIndexPath = String.format("indexes/%s.json", completed.getProfile().getAssetIndex());
|
||||||
|
if (!completed.getAssetDir().tryFindRecursive(assetIndexPath).isFound()) {
|
||||||
|
Path assetDir = server.createTempDirectory("assets");
|
||||||
|
HttpRequester requester = new HttpRequester();
|
||||||
|
var assetInfo = AssetsDirHelper.getAssetInfo(requester, completed.getProfile().getAssetIndex());
|
||||||
|
var toDownload = AssetsDirHelper.makeToDownloadFiles(assetInfo, completed.getAssetDir());
|
||||||
|
logger.info("Download assets {}", completed.getProfile().getAssetIndex());
|
||||||
|
Downloader downloader = downloadWithProgressBar(completed.getProfile().getAssetIndex(),
|
||||||
|
toDownload, AssetsDirHelper.RESOURCES_DOWNLOAD_URL, assetDir);
|
||||||
|
downloader.getFuture().get();
|
||||||
|
byte[] assetIndexBytes = Launcher.gsonManager.configGson.toJson(assetInfo.assets()).getBytes(StandardCharsets.UTF_8);
|
||||||
|
completed = server.config.profilesProvider.pushUpdate(uncompleted, null, clientProfile, List.of(
|
||||||
|
ProfilesProvider.ProfileAction.upload(() -> {
|
||||||
|
return new ByteArrayInputStream(assetIndexBytes);
|
||||||
|
}, assetIndexPath),
|
||||||
|
ProfilesProvider.ProfileAction.upload(assetDir, "", true)
|
||||||
|
), List.of(
|
||||||
|
ProfilesProvider.ProfileAction.upload(clientDir, "", true)
|
||||||
|
), List.of(ProfilesProvider.UpdateFlag.USE_DEFAULT_ASSETS));
|
||||||
|
} else {
|
||||||
|
completed = server.config.profilesProvider.pushUpdate(uncompleted, null, clientProfile, null, List.of(
|
||||||
|
ProfilesProvider.ProfileAction.upload(clientDir, "", true)
|
||||||
|
), List.of(ProfilesProvider.UpdateFlag.USE_DEFAULT_ASSETS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -27,24 +28,18 @@ 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);
|
||||||
ClientProfile profile;
|
ProfilesProvider.CompletedProfile profile;
|
||||||
try {
|
try {
|
||||||
UUID uuid = UUID.fromString(args[0]);
|
UUID uuid = UUID.fromString(args[0]);
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
profile = server.config.profilesProvider.get(uuid, null);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
profile = server.config.profileProvider.getProfile(args[0]);
|
profile = server.config.profilesProvider.get(args[0], null);
|
||||||
}
|
}
|
||||||
if(profile == null) {
|
if(profile == null) {
|
||||||
logger.error("Profile {} not found", args[0]);
|
logger.error("Profile {} not found", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", profile.getDir());
|
logger.info("Delete {}", args[0]);
|
||||||
if(!showApplyDialog("Continue?")) {
|
server.config.profilesProvider.delete(profile);
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID());
|
|
||||||
server.config.profileProvider.deleteProfile(profile);
|
|
||||||
logger.info("Delete {}", profile.getDir());
|
|
||||||
server.config.updatesProvider.delete(profile.getDir());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ public String getUsageDescription() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(String... args) {
|
public void invoke(String... args) {
|
||||||
for(var profile : server.getProfiles()) {
|
for(var profile : server.config.profilesProvider.getProfiles(null)) {
|
||||||
logger.info("{} ({}) {}", profile.getTitle(), profile.getVersion().toString(), profile.isLimited() ? "limited" : "");
|
logger.info("{} ({})", profile.getName(), profile.getUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.profiles;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
import pro.gravit.launchserver.helper.MakeProfileHelper;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class MakeProfileCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public MakeProfileCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[name] [minecraft version] [dir]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "make profile for any minecraft versions";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 3);
|
|
||||||
ClientProfile.Version version = parseClientVersion(args[1]);
|
|
||||||
MakeProfileHelper.MakeProfileOption[] options = MakeProfileHelper.getMakeProfileOptionsFromDir(Path.of(args[2]), version);
|
|
||||||
for (MakeProfileHelper.MakeProfileOption option : options) {
|
|
||||||
logger.info("Detected option {}", option);
|
|
||||||
}
|
|
||||||
ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options);
|
|
||||||
server.config.profileProvider.addProfile(profile);
|
|
||||||
logger.info("Profile {} created", args[0]);
|
|
||||||
server.syncProfilesDir();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,8 +6,7 @@
|
||||||
public class ProfilesCommand extends Command {
|
public class ProfilesCommand extends Command {
|
||||||
public ProfilesCommand(LaunchServer server) {
|
public ProfilesCommand(LaunchServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
this.childCommands.put("make", new MakeProfileCommand(server));
|
this.childCommands.put("create", new CreateProfileCommand(server));
|
||||||
this.childCommands.put("save", new SaveProfilesCommand(server));
|
|
||||||
this.childCommands.put("clone", new CloneProfileCommand(server));
|
this.childCommands.put("clone", new CloneProfileCommand(server));
|
||||||
this.childCommands.put("list", new ListProfilesCommand(server));
|
this.childCommands.put("list", new ListProfilesCommand(server));
|
||||||
this.childCommands.put("delete", new DeleteProfileCommand(server));
|
this.childCommands.put("delete", new DeleteProfileCommand(server));
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.profiles;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class SaveProfilesCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public SaveProfilesCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[profile names...]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "load and save profile";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
verifyArgs(args, 1);
|
|
||||||
if (args.length > 0) {
|
|
||||||
for (String profileName : args) {
|
|
||||||
ClientProfile profile;
|
|
||||||
try {
|
|
||||||
UUID uuid = UUID.fromString(profileName);
|
|
||||||
profile = server.config.profileProvider.getProfile(uuid);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
profile = server.config.profileProvider.getProfile(profileName);
|
|
||||||
}
|
|
||||||
server.config.profileProvider.addProfile(profile);
|
|
||||||
}
|
|
||||||
server.syncProfilesDir();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -149,8 +149,8 @@ public void invoke(String... args) {
|
||||||
case PROD -> printCheckResult("env", "", true);
|
case PROD -> printCheckResult("env", "", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Profiles
|
//Profiles TODO: Implement
|
||||||
for (ClientProfile profile : server.getProfiles()) {
|
/*for (ClientProfile profile : server.config.profilesProvider.getProfiles(null)) {
|
||||||
boolean bad = false;
|
boolean bad = false;
|
||||||
String profileModuleName = "profiles.%s".formatted(profile.getTitle());
|
String profileModuleName = "profiles.%s".formatted(profile.getTitle());
|
||||||
for (String exc : profile.getUpdateExclusions()) {
|
for (String exc : profile.getUpdateExclusions()) {
|
||||||
|
@ -177,7 +177,7 @@ public void invoke(String... args) {
|
||||||
}
|
}
|
||||||
if (!bad)
|
if (!bad)
|
||||||
printCheckResult(profileModuleName, "", true);
|
printCheckResult(profileModuleName, "", true);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//Linux permissions check
|
//Linux permissions check
|
||||||
if (JVMHelper.OS_TYPE == JVMHelper.OS.LINUX) {
|
if (JVMHelper.OS_TYPE == JVMHelper.OS.LINUX) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
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.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.utils.command.SubCommand;
|
import pro.gravit.utils.command.SubCommand;
|
||||||
|
|
||||||
|
@ -28,9 +29,9 @@ public void invoke(String... args) throws Exception {
|
||||||
public void invoke(String... args) {
|
public void invoke(String... args) {
|
||||||
AuthProviderPair pair = args.length > 1 ? server.config.getAuthProviderPair(args[1]) : server.config.getAuthProviderPair();
|
AuthProviderPair pair = args.length > 1 ? server.config.getAuthProviderPair(args[1]) : server.config.getAuthProviderPair();
|
||||||
boolean publicOnly = args.length <= 2 || Boolean.parseBoolean(args[2]);
|
boolean publicOnly = args.length <= 2 || Boolean.parseBoolean(args[2]);
|
||||||
ClientProfile profile = null;
|
ProfilesProvider.UncompletedProfile profile = null;
|
||||||
for (ClientProfile p : server.getProfiles()) {
|
for (var p : server.config.profilesProvider.getProfiles(null)) {
|
||||||
if (p.getTitle().equals(args[0]) || p.getUUID().toString().equals(args[0])) {
|
if (p.getName().equals(args[0]) || p.getUuid().toString().equals(args[0])) {
|
||||||
profile = p;
|
profile = p;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,7 @@ public void invoke(String... args) {
|
||||||
logger.error("AuthId {} not found", args[1]);
|
logger.error("AuthId {} not found", args[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String token = server.authManager.newCheckServerToken(profile != null ? profile.getUUID().toString() : args[0], pair.name, publicOnly);
|
String token = server.authManager.newCheckServerToken(profile != null ? profile.getUuid().toString() : args[0], pair.name, publicOnly);
|
||||||
logger.info("Server token {} authId {}: {}", args[0], pair.name, token);
|
logger.info("Server token {} authId {}: {}", args[0], pair.name, token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.sync;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public final class SyncBinariesCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public SyncBinariesCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Resync launcher binaries";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws IOException {
|
|
||||||
server.syncLauncherBinaries();
|
|
||||||
logger.info("Binaries successfully resynced");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,12 +6,7 @@
|
||||||
public class SyncCommand extends Command {
|
public class SyncCommand extends Command {
|
||||||
public SyncCommand(LaunchServer server) {
|
public SyncCommand(LaunchServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
this.childCommands.put("profiles", new SyncProfilesCommand(server));
|
|
||||||
this.childCommands.put("binaries", new SyncBinariesCommand(server));
|
|
||||||
this.childCommands.put("updates", new SyncUpdatesCommand(server));
|
|
||||||
this.childCommands.put("up", new SyncUPCommand(server));
|
|
||||||
this.childCommands.put("launchermodules", new SyncLauncherModulesCommand(server));
|
this.childCommands.put("launchermodules", new SyncLauncherModulesCommand(server));
|
||||||
this.childCommands.put("updatescache", new SyncUpdatesCacheCommand(server));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.sync;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public final class SyncProfilesCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public SyncProfilesCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Resync profiles dir";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws IOException {
|
|
||||||
server.syncProfilesDir();
|
|
||||||
logger.info("Profiles successfully resynced");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.sync;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public final class SyncUPCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public SyncUPCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Resync profiles & updates dirs";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws IOException {
|
|
||||||
server.syncProfilesDir();
|
|
||||||
logger.info("Profiles successfully resynced");
|
|
||||||
|
|
||||||
server.syncUpdatesDir(null);
|
|
||||||
logger.info("Updates dir successfully resynced");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.sync;
|
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
public class SyncUpdatesCacheCommand extends Command {
|
|
||||||
public SyncUpdatesCacheCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "sync updates cache";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws Exception {
|
|
||||||
server.updatesManager.readUpdatesFromCache();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package pro.gravit.launchserver.command.sync;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
import pro.gravit.launchserver.command.Command;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public final class SyncUpdatesCommand extends Command {
|
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
|
||||||
|
|
||||||
public SyncUpdatesCommand(LaunchServer server) {
|
|
||||||
super(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getArgsDescription() {
|
|
||||||
return "[subdirs...]";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsageDescription() {
|
|
||||||
return "Resync updates dir";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(String... args) throws IOException {
|
|
||||||
Set<String> dirs = null;
|
|
||||||
if (args.length > 0) { // Hash all updates dirs
|
|
||||||
dirs = new HashSet<>(args.length);
|
|
||||||
Collections.addAll(dirs, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash updates dir
|
|
||||||
server.syncUpdatesDir(dirs);
|
|
||||||
logger.info("Updates dir successfully resynced");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,8 +8,8 @@
|
||||||
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.auth.core.RejectAuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.profiles.LocalProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.LocalProfilesProvider;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
import pro.gravit.launchserver.auth.protect.StdProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
import pro.gravit.launchserver.auth.texture.RequestTextureProvider;
|
||||||
|
@ -39,7 +39,7 @@ public final class LaunchServerConfig {
|
||||||
// Handlers & Providers
|
// Handlers & Providers
|
||||||
public ProtectHandler protectHandler;
|
public ProtectHandler protectHandler;
|
||||||
public Map<String, Component> components;
|
public Map<String, Component> components;
|
||||||
public ProfileProvider profileProvider = new LocalProfileProvider();
|
public ProfilesProvider profilesProvider = new LocalProfilesProvider();
|
||||||
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
public UpdatesProvider updatesProvider = new LocalUpdatesProvider();
|
||||||
public NettyConfig netty;
|
public NettyConfig netty;
|
||||||
public LauncherConf launcher;
|
public LauncherConf launcher;
|
||||||
|
@ -85,7 +85,8 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) {
|
||||||
newConfig.components.put("authLimiter", authLimiterComponent);
|
newConfig.components.put("authLimiter", authLimiterComponent);
|
||||||
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
ProGuardComponent proGuardComponent = new ProGuardComponent();
|
||||||
newConfig.components.put("proguard", proGuardComponent);
|
newConfig.components.put("proguard", proGuardComponent);
|
||||||
newConfig.profileProvider = new LocalProfileProvider();
|
newConfig.profilesProvider = new LocalProfilesProvider();
|
||||||
|
newConfig.updatesProvider = new LocalUpdatesProvider();
|
||||||
return newConfig;
|
return newConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +168,9 @@ public void init(LaunchServer.ReloadType type) {
|
||||||
server.registerObject("protectHandler", protectHandler);
|
server.registerObject("protectHandler", protectHandler);
|
||||||
protectHandler.init(server);
|
protectHandler.init(server);
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
if(profilesProvider != null) {
|
||||||
server.registerObject("profileProvider", profileProvider);
|
server.registerObject("profileProvider", profilesProvider);
|
||||||
profileProvider.init(server);
|
profilesProvider.init(server);
|
||||||
}
|
}
|
||||||
if(updatesProvider != null) {
|
if(updatesProvider != null) {
|
||||||
server.registerObject("updatesProvider", updatesProvider);
|
server.registerObject("updatesProvider", updatesProvider);
|
||||||
|
@ -215,9 +216,9 @@ public void close(LaunchServer.ReloadType type) {
|
||||||
server.unregisterObject("protectHandler", protectHandler);
|
server.unregisterObject("protectHandler", protectHandler);
|
||||||
protectHandler.close();
|
protectHandler.close();
|
||||||
}
|
}
|
||||||
if(profileProvider != null) {
|
if(profilesProvider != null) {
|
||||||
server.unregisterObject("profileProvider", profileProvider);
|
server.unregisterObject("profilesProvider", profilesProvider);
|
||||||
profileProvider.close();
|
profilesProvider.close();
|
||||||
}
|
}
|
||||||
if(updatesProvider != null) {
|
if(updatesProvider != null) {
|
||||||
server.unregisterObject("updatesProvider", updatesProvider);
|
server.unregisterObject("updatesProvider", updatesProvider);
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package pro.gravit.launchserver.helper;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import pro.gravit.launcher.base.Downloader;
|
||||||
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
|
import pro.gravit.launchserver.HttpRequester;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AssetsDirHelper {
|
||||||
|
public static final String MINECRAFT_VERSIONS_URL = "https://launchermeta.mojang.com/mc/game/version_manifest.json";
|
||||||
|
public static final String RESOURCES_DOWNLOAD_URL = "https://resources.download.minecraft.net/";
|
||||||
|
|
||||||
|
public static List<Downloader.SizedFile> makeToDownloadFiles(AssetInfo assetInfo, HashedDir updatesDir) {
|
||||||
|
List<Downloader.SizedFile> toDownload = new ArrayList<>(128);
|
||||||
|
for (var e : assetInfo.assets.entrySet()) {
|
||||||
|
var value = e.getValue().getAsJsonObject();
|
||||||
|
var hash = value.get("hash").getAsString();
|
||||||
|
hash = hash.substring(0, 2) + "/" + hash;
|
||||||
|
var size = value.get("size").getAsLong();
|
||||||
|
var path = "objects/" + hash;
|
||||||
|
if (updatesDir.tryFindRecursive(path).isFound()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
toDownload.add(new Downloader.SizedFile(hash, path, size));
|
||||||
|
}
|
||||||
|
return toDownload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssetInfo getAssetInfo(HttpRequester requester, String versionName) throws IOException {
|
||||||
|
var versions = requester.send(requester.get(MINECRAFT_VERSIONS_URL, null), MinecraftVersions.class).getOrThrow();
|
||||||
|
String profileUrl = null;
|
||||||
|
for (var e : versions.versions) {
|
||||||
|
if (e.id.equals(versionName)) {
|
||||||
|
profileUrl = e.url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var profileInfo = requester.send(requester.get(profileUrl, null), MiniVersion.class).getOrThrow();
|
||||||
|
String assetsIndexUrl = profileInfo.assetIndex.url;
|
||||||
|
String assetIndex = profileInfo.assetIndex.id;
|
||||||
|
JsonObject assets = requester.send(requester.get(assetsIndexUrl, null), JsonObject.class).getOrThrow();
|
||||||
|
return new AssetInfo(assetIndex, assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record AssetInfo(String assetIndex, JsonObject assets) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record MiniVersionInfo(String id, String url) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record MinecraftVersions(List<MiniVersionInfo> versions) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record MinecraftAssetIndexInfo(String id, String url) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record MiniVersion(MinecraftAssetIndexInfo assetIndex) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -191,7 +191,7 @@ public PlayerProfile getPlayerProfile(Client client) {
|
||||||
playerProfile = getPlayerProfile(client.auth, user);
|
playerProfile = getPlayerProfile(client.auth, user);
|
||||||
if (playerProfile != null) return playerProfile;
|
if (playerProfile != null) return playerProfile;
|
||||||
if (client.auth.textureProvider != null) {
|
if (client.auth.textureProvider != null) {
|
||||||
return getPlayerProfile(client.uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider, new HashMap<>());
|
return getPlayerProfile(client.uuid, client.username, client.profile == null ? null : client.profile.getName(), client.auth.textureProvider, new HashMap<>());
|
||||||
}
|
}
|
||||||
// Return combined profile
|
// Return combined profile
|
||||||
return new PlayerProfile(client.uuid, client.username, new HashMap<>(), new HashMap<>());
|
return new PlayerProfile(client.uuid, client.username, new HashMap<>(), new HashMap<>());
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||||
import pro.gravit.launchserver.auth.mix.MixProvider;
|
import pro.gravit.launchserver.auth.mix.MixProvider;
|
||||||
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
import pro.gravit.launchserver.auth.password.PasswordVerifier;
|
||||||
import pro.gravit.launchserver.auth.profiles.ProfileProvider;
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
import pro.gravit.launchserver.auth.protect.ProtectHandler;
|
||||||
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
import pro.gravit.launchserver.auth.texture.TextureProvider;
|
||||||
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
import pro.gravit.launchserver.auth.updates.UpdatesProvider;
|
||||||
|
@ -48,7 +48,7 @@ public void registerAdapters(GsonBuilder builder) {
|
||||||
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
|
||||||
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers));
|
||||||
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers));
|
||||||
builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers));
|
builder.registerTypeAdapter(ProfilesProvider.class, new UniversalJsonAdapter<>(ProfilesProvider.providers));
|
||||||
builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers));
|
builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers));
|
||||||
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
modulesManager.invokeEvent(new PreGsonPhase(builder));
|
||||||
//ClientWebSocketService.appendTypeAdapters(builder);
|
//ClientWebSocketService.appendTypeAdapters(builder);
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class UpdatesManager {
|
|
||||||
private final LaunchServer server;
|
|
||||||
|
|
||||||
public UpdatesManager(LaunchServer server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void readUpdatesFromCache() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void readUpdatesDir() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
|
||||||
server.config.updatesProvider.sync(dirs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public HashSet<String> getUpdatesList() {
|
|
||||||
return new HashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public HashedDir getUpdate(String name) {
|
|
||||||
return server.config.updatesProvider.getUpdatesDir(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void addUpdate(String name, HashedDir dir) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@
|
||||||
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.auth.core.interfaces.UserHardware;
|
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||||
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -19,7 +20,7 @@ public class Client {
|
||||||
public String auth_id;
|
public String auth_id;
|
||||||
public long timestamp;
|
public long timestamp;
|
||||||
public AuthResponse.ConnectTypes type;
|
public AuthResponse.ConnectTypes type;
|
||||||
public ClientProfile profile;
|
public ProfilesProvider.CompletedProfile profile;
|
||||||
public boolean isAuth;
|
public boolean isAuth;
|
||||||
public boolean checkSign;
|
public boolean checkSign;
|
||||||
public ClientPermissions permissions;
|
public ClientPermissions permissions;
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
|
import pro.gravit.launcher.base.events.request.ProfilesRequestEvent;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
import pro.gravit.launcher.base.profiles.ClientProfile;
|
||||||
|
import pro.gravit.launcher.base.profiles.ClientProfileBuilder;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
import pro.gravit.launchserver.auth.profiles.ProfilesProvider;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
|
||||||
|
@ -13,21 +14,22 @@
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProfilesResponse extends SimpleResponse {
|
public class ProfilesResponse extends SimpleResponse {
|
||||||
@Deprecated
|
|
||||||
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
public static List<ClientProfile> getListVisibleProfiles(LaunchServer server, Client client) {
|
||||||
List<ClientProfile> profileList;
|
Set<ProfilesProvider.UncompletedProfile> serverProfiles = server.config.profilesProvider.getProfiles(client);
|
||||||
Set<ClientProfile> serverProfiles = server.getProfiles();
|
List<ClientProfile> profiles = new ArrayList<>();
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) {
|
for(var uncompleted : serverProfiles) {
|
||||||
profileList = new ArrayList<>(4);
|
if(uncompleted instanceof ProfilesProvider.CompletedProfile completed) {
|
||||||
for (ClientProfile profile : serverProfiles) {
|
profiles.add(completed.getProfile());
|
||||||
if (protectHandler.canGetProfile(profile, client)) {
|
} else {
|
||||||
profileList.add(profile);
|
profiles.add(new ClientProfileBuilder()
|
||||||
}
|
.setUuid(uncompleted.getUuid())
|
||||||
|
.setTitle(uncompleted.getName())
|
||||||
|
.setInfo(uncompleted.getDescription())
|
||||||
|
.createClientProfile());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
profileList = List.copyOf(serverProfiles);
|
|
||||||
}
|
}
|
||||||
return profileList;
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -37,10 +39,6 @@ public String getType() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler profilesProtectHandler && !profilesProtectHandler.canGetProfiles(client)) {
|
sendResult(new ProfilesRequestEvent(getListVisibleProfiles(server, client)));
|
||||||
sendError("Access denied");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendResult(new ProfilesRequestEvent(server.config.profileProvider.getProfiles(client)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,15 @@
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import pro.gravit.launcher.base.events.request.SetProfileRequestEvent;
|
import pro.gravit.launcher.base.events.request.SetProfileRequestEvent;
|
||||||
import pro.gravit.launcher.base.profiles.ClientProfile;
|
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
import pro.gravit.utils.HookException;
|
import pro.gravit.utils.HookException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class SetProfileResponse extends SimpleResponse {
|
public class SetProfileResponse extends SimpleResponse {
|
||||||
public String client;
|
public UUID uuid;
|
||||||
|
public String tag;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
|
@ -25,20 +24,13 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
} catch (HookException e) {
|
} catch (HookException e) {
|
||||||
sendError(e.getMessage());
|
sendError(e.getMessage());
|
||||||
}
|
}
|
||||||
Collection<ClientProfile> profiles = server.getProfiles();
|
var profile = server.config.profilesProvider.get(uuid, tag);
|
||||||
for (ClientProfile p : profiles) {
|
if(profile == null) {
|
||||||
if (p.getTitle().equals(this.client)) {
|
sendError("Profile not found");
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler profilesProtectHandler &&
|
return;
|
||||||
!profilesProtectHandler.canChangeProfile(p, client)) {
|
|
||||||
sendError("Access denied");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.profile = p;
|
|
||||||
sendResult(new SetProfileRequestEvent(p));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sendError("Profile not found");
|
client.profile = profile;
|
||||||
|
sendResult(new SetProfileRequestEvent(profile.getProfile(), profile.getTag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import pro.gravit.launcher.base.events.request.LauncherRequestEvent;
|
import pro.gravit.launcher.base.events.request.LauncherRequestEvent;
|
||||||
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.auth.updates.UpdatesProvider;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||||
|
@ -43,28 +44,21 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
bytes = Base64.getDecoder().decode(hash);
|
bytes = Base64.getDecoder().decode(hash);
|
||||||
else
|
else
|
||||||
bytes = digest;
|
bytes = digest;
|
||||||
if (launcher_type == 1) // JAR
|
UpdatesProvider.UpdateVariant variant = UpdatesProvider.UpdateVariant.JAR;
|
||||||
{
|
if(launcher_type == 2) {
|
||||||
byte[] hash = server.launcherBinary.getDigest();
|
variant = UpdatesProvider.UpdateVariant.EXE;
|
||||||
if (hash == null)
|
}
|
||||||
service.sendObjectAndClose(ctx, new LauncherRequestEvent(true, server.config.netty.launcherURL));
|
byte[] hashToCheck = bytes;
|
||||||
if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) {
|
if(!checkSecure(secureHash, secureSalt)) {
|
||||||
client.checkSign = true;
|
hashToCheck = null; // Always need update
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
}
|
||||||
} else {
|
UpdatesProvider.UpdateInfo info = server.config.updatesProvider.checkUpdates(variant, hashToCheck);
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, null, 0));
|
if (info != null) {
|
||||||
}
|
sendResult(new LauncherRequestEvent(true, info.url()));
|
||||||
} else if (launcher_type == 2) //EXE
|
} else {
|
||||||
{
|
client.checkSign = true;
|
||||||
byte[] hash = server.launcherEXEBinary.getDigest();
|
sendResult(new LauncherRequestEvent(false, null, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
||||||
if (hash == null) sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL));
|
}
|
||||||
if (Arrays.equals(bytes, hash) && checkSecure(secureHash, secureSalt)) {
|
|
||||||
client.checkSign = true;
|
|
||||||
sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000));
|
|
||||||
} else {
|
|
||||||
sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, null, 0));
|
|
||||||
}
|
|
||||||
} else sendError("Request launcher type error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String createLauncherExtendedToken() {
|
public String createLauncherExtendedToken() {
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import pro.gravit.launcher.base.events.request.UpdateRequestEvent;
|
import pro.gravit.launcher.base.events.request.UpdateRequestEvent;
|
||||||
import pro.gravit.launcher.core.hasher.HashedDir;
|
import pro.gravit.launcher.core.hasher.HashedDir;
|
||||||
import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler;
|
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||||
|
@ -19,15 +18,22 @@ public String getType() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
if (server.config.protectHandler instanceof ProfilesProtectHandler profilesProtectHandler && !profilesProtectHandler.canGetUpdates(dirName, client)) {
|
|
||||||
sendError("Access denied");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dirName == null) {
|
if (dirName == null) {
|
||||||
sendError("Invalid request");
|
sendError("Invalid request");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HashedDir dir = server.updatesManager.getUpdate(dirName);
|
if(client.profile == null) {
|
||||||
|
sendError("Profile not setted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashedDir dir = null;
|
||||||
|
if(dirName.equals(client.profile.getProfile().getDir())) {
|
||||||
|
dir = client.profile.getClientDir();
|
||||||
|
} else if(dirName.equals(client.profile.getProfile().getAssetDir())) {
|
||||||
|
dir = client.profile.getAssetDir();
|
||||||
|
} else {
|
||||||
|
dir = server.config.profilesProvider.getUnconnectedDirectory(dirName);
|
||||||
|
}
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
sendError("Directory %s not found".formatted(dirName));
|
sendError("Directory %s not found".formatted(dirName));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,9 +12,17 @@ public class SetProfileRequestEvent extends RequestEvent {
|
||||||
private static final UUID uuid = UUID.fromString("08c0de9e-4364-4152-9066-8354a3a48541");
|
private static final UUID uuid = UUID.fromString("08c0de9e-4364-4152-9066-8354a3a48541");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public final ClientProfile newProfile;
|
public final ClientProfile newProfile;
|
||||||
|
@LauncherNetworkAPI
|
||||||
|
public final String tag;
|
||||||
|
|
||||||
public SetProfileRequestEvent(ClientProfile newProfile) {
|
public SetProfileRequestEvent(ClientProfile newProfile) {
|
||||||
this.newProfile = newProfile;
|
this.newProfile = newProfile;
|
||||||
|
this.tag = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetProfileRequestEvent(ClientProfile newProfile, String tag) {
|
||||||
|
this.newProfile = newProfile;
|
||||||
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,12 +6,21 @@
|
||||||
import pro.gravit.launcher.base.request.Request;
|
import pro.gravit.launcher.base.request.Request;
|
||||||
import pro.gravit.launcher.base.request.websockets.WebSocketRequest;
|
import pro.gravit.launcher.base.request.websockets.WebSocketRequest;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class SetProfileRequest extends Request<SetProfileRequestEvent> implements WebSocketRequest {
|
public class SetProfileRequest extends Request<SetProfileRequestEvent> implements WebSocketRequest {
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public final String client;
|
public final UUID uuid;
|
||||||
|
public final String tag;
|
||||||
|
|
||||||
|
public SetProfileRequest(UUID uuid, String tag) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
public SetProfileRequest(ClientProfile profile) {
|
public SetProfileRequest(ClientProfile profile) {
|
||||||
this.client = profile.getTitle();
|
this.uuid = profile.getUUID();
|
||||||
|
this.tag = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 38788df61f8efc5453fe9c05017b629648b5fe6f
|
Subproject commit 6f699fae50f98cec19279092d9d5fac1ac451914
|
Loading…
Reference in a new issue