diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57ad678 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/.gradle +example.txt diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..dff5f3a --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: java diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 25b3a36..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 OlympicCode - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 4e77505..e32cfbe 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,27 @@ # vHackOSAPI-Java -## IN-DEV -### The vHackOSAPI is currently being developed, progress below. +## BETA +### The vHackOSAPI is now in a beta stage, meaning it might have some bugs and not all features are implemented, please report any issues. ### Join [Our Discord](https://discord.gg/52MtBDp) to keep updated. -[![Discord](https://img.shields.io/badge/Chat-%20on%20Discord-738bd7.svg?style=flat-square)](https://discord.gg/52MtBDp) [![Downloads](https://img.shields.io/github/downloads/OlympicCode/vHackAPI-Java/total.svg?style=flat-square)]() +[![Discord](https://img.shields.io/badge/Chat-%20on%20Discord-738bd7.svg?style=flat-square)](https://discord.gg/52MtBDp) [![Downloads](https://img.shields.io/github/downloads/OlympicCode/vHackOSAPI-Java/total.svg?style=flat-square)]() [![](https://jitpack.io/v/net.olympiccode/vHackOSAPI-Java.svg?style=flat-square)](https://jitpack.io/#net.olympiccode/vHackOSAPI-Java) # +#### Gradle configuration +``` + repositories { + jcenter() + maven { url "https://jitpack.io" } + } + dependencies { + compile 'net.olympiccode:vHackOSAPI-Java:dev-SNAPSHOT' + } +``` ##### Current API progress: - [x] Base request system - [x] Basic status retrieving - [X] App upgrading & installing -- [ ] Update boosting and finishing -- [ ] Exploiting, remote notepad editing and bruteforcing -- [ ] Logging in and grabbing money +- [X] Update boosting and finishing +- [X] Exploiting, remote notepad editing and bruteforcing +- [X] Logging in and grabbing money - [ ] Mission completing + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7d6160b --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' + id 'com.github.johnrengelman.shadow' version '1.2.4' +} +group 'vHackAPI' +version '1.0-SNAPSHOT' +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile 'com.squareup.okhttp3:okhttp:3.9.1' + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25' + compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.6.1' + compile group: 'org.json', name: 'json', version: '20090211' + compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.1' + compileOnly 'org.projectlombok:lombok:1.16.20' +} + +shadowJar.destinationDir = file("/build/libs") +shadowJar.archiveName = 'vHackOSAPI.jar' diff --git a/src/main/java/examples/BrainStormExample.java b/src/main/java/examples/BrainStormExample.java new file mode 100644 index 0000000..253a5da --- /dev/null +++ b/src/main/java/examples/BrainStormExample.java @@ -0,0 +1,157 @@ +package examples; + +import net.olympiccode.vhackos.api.appstore.App; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.entities.BruteForceState; +import net.olympiccode.vhackos.api.entities.impl.TaskManagerImpl; +import net.olympiccode.vhackos.api.events.Event; +import net.olympiccode.vhackos.api.events.EventListener; +import net.olympiccode.vhackos.api.events.StatsUpdateEvent; +import net.olympiccode.vhackos.api.events.UpdateTaskFinishEvent; +import net.olympiccode.vhackos.api.exceptions.ExploitFailedException; +import net.olympiccode.vhackos.api.network.ExploitedTarget; +import net.olympiccode.vhackos.api.vHackOSAPI; +import net.olympiccode.vhackos.api.vHackOSAPIBuilder; + +import javax.security.auth.login.LoginException; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +public class BrainStormExample implements EventListener { + /* + ATTENTION + + THIS IS THE CLASS I USE TO TEST THE API, I DECIDED TO KEEP IT HERE AS IT HAS MOST API FUNCTIONS AND CAN BE GOOD FOR EXAMPLES + */ + public static void main(String[] args) { + try { + String l = null; + try { + l = Files.readAllLines(Paths.get("example.txt"), Charset.forName("UTF-8")).stream().collect(Collectors.joining()); + } catch (IOException e) { + e.printStackTrace(); + } + if (l == null || !l.contains("#")) { + return; + } + String username = l.split("#")[0]; + String pass = l.split("#")[1]; + System.out.println(username + pass); + // Proxy proxyTest = new Proxy(Proxy.Type.HTTP,new InetSocketAddress("127.0.0.1", 8888)); + //OkHttpClient.Builder builder = new OkHttpClient.Builder().proxy(proxyTest); + vHackOSAPI api = new vHackOSAPIBuilder()/*.setHttpClientBuilder(builder)*/.setUsername(username).setPassword(pass).buildBlocking(); + api.addEventListener(new BrainStormExample()); + // Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> System.out.println(api.getTaskManager().getActiveTasks().stream().map(task -> task.getType() + ": " + task.getLevel() + " (" + task.getId() + ") - " + ((task.getEndTimestamp() - System.currentTimeMillis()) / 1000) ).collect(Collectors.joining("\n"))), 0, 5000, TimeUnit.MILLISECONDS); + // api.getAppManager().getApp(AppType.Spam).getAsUpdateable().fillTasks(); + int lvl = 10000000; + App capp = null; + System.out.println(api.getAppManager().getApps()); + for (App app : api.getAppManager().getApps()) { + if (!app.isInstalled() && app.getRequiredLevel() <= api.getStats().getLevel()) app.getAsInstallable().install(); + if (app.getLevel() != 0 && !app.isOneTime() && app.isInstalled() && app.getLevel() < lvl) { + lvl = app.getLevel(); + capp = app; + } + } + if (capp.getPrice() < api.getStats().getMoney()) { + System.out.println("Starting " + capp.getType().getName()); + if (!capp.getAsUpdateable().fillTasks()) ((TaskManagerImpl) api.getTaskManager()).reloadTasks(); + if (api.getTaskManager().getBoosters() > 0) { + System.out.println("Boosted tasks"); + api.getTaskManager().boostAll(); + } + if (api.getStats().getNetcoins() > 1000) { + System.out.println("Finished tasks with netcoins"); + api.getTaskManager().finishAll(); + } + } + Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> { + System.out.println("Active tasks: " + api.getTaskManager().getActiveTasks().stream().map(task -> task.getId() + " " + task.getType().getName()).collect(Collectors.joining(", "))); + }, 0, 10000, TimeUnit.MILLISECONDS); + Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> { + api.getMiner().start(); + }, 0, 60000 * 60, TimeUnit.MILLISECONDS); + Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> { + final long[] money = {0}; + api.getTaskManager().getActiveBrutes().forEach(bruteForce -> { + if (bruteForce.getState() == BruteForceState.SUCCESS) { + ExploitedTarget etarget = bruteForce.exploit(); + ExploitedTarget.Banking banking = etarget.getBanking(); + + if (banking.isBruteForced()) { + long av = banking.getAvaliableMoney(); + if (av > 0 && banking.withdraw()) System.out.println("Got " + av + " of " + banking.getTotal() + " (" + banking.getSavings() + "/" + banking.getMaxSavings() + ") " + (banking.getSavings() / 2 < banking.getMaxSavings())); else System.out.println("fail" + (banking.getSavings() / 2 < banking.getMaxSavings())); + money[0] = money[0] + av; + if (!(banking.getSavings() / 2 < banking.getMaxSavings()) && banking.getSavings() < 1000000 && !bruteForce.getUsername().toLowerCase().contains("atjon")) bruteForce.remove(); + } else { + banking.startBruteForce(); + } + etarget.setSystemLog("Checkium was here #OlympicCode"); + } + }); + api.getStats().getExploits(); + if (api.getStats().getExploits() > 0) { + int level = api.getAppManager().getApp(AppType.SDK).getLevel(); + api.getNetworkManager().getTargets().forEach(target -> { + if (target.getFirewall() < level && api.getStats().getExploits() > 0) { + try { + ExploitedTarget etarget = target.exploit(); + etarget.getBanking().startBruteForce(); + etarget.setSystemLog("Checkium was here #OlympicCode"); + System.out.println("Started brute @ " + etarget.getIp()); + } catch (ExploitFailedException e) { + System.out.println(target.getIp() + ": " + e.getMessage()); + } + } + }); + } + }, 100, 60000, TimeUnit.MILLISECONDS); + System.out.println(api.getTaskManager().getActiveBrutes().stream().map(bruteForce -> bruteForce.getUsername() + " " + bruteForce.getState()).collect(Collectors.joining(", "))); + } catch (LoginException | InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + public void onEvent(Event event) { + if (event instanceof StatsUpdateEvent) { + StatsUpdateEvent e = (StatsUpdateEvent) event; + System.out.println(e.getStats().getExploits() + " " + e.getStats().getMoney() + " " + e.getStats().getNetcoins() + " (" + e.getAPI().getMiner().isRunning() + ")"); + System.out.println(e.getStats().getLevel() + " - " + e.getStats().getLevelPorcentage()); + } else if (event instanceof UpdateTaskFinishEvent) { + UpdateTaskFinishEvent e = (UpdateTaskFinishEvent) event; + System.out.println(e.getAPI().getTaskManager().getActiveTasks().size() + "Finished " + e.getTask().getType() + " to level " + e.getTask().getLevel()); + if (e.getAPI().getTaskManager().getActiveTasks().size() == 0) { + int lvl = 100; + App capp = null; + for (App app : e.getAPI().getAppManager().getApps()) { + if (app.getLevel() != 0 && !app.isOneTime() && app.isInstalled() && app.getLevel() < lvl) { + lvl = app.getLevel(); + capp = app; + } + } + System.out.println("Starting " + capp.getType().getName() + " (" + capp.getType().getId() + ")"); + boolean a = capp.getAsUpdateable().fillTasks(); + if (!a) { + a = capp.getAsUpdateable().fillTasks(); + } + if (a) { + if (e.getAPI().getTaskManager().getBoosters() > 0) { + System.out.println("Boosted tasks"); + e.getAPI().getTaskManager().boostAll(); + } + if (e.getAPI().getStats().getNetcoins() > 1000) { + System.out.println("Finished tasks with netcoins"); + e.getAPI().getTaskManager().finishAll(); + } + } + } + } + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/App.java b/src/main/java/net/olympiccode/vhackos/api/appstore/App.java new file mode 100644 index 0000000..854ce09 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/App.java @@ -0,0 +1,21 @@ +package net.olympiccode.vhackos.api.appstore; + +import net.olympiccode.vhackos.api.entities.AppType; + +public interface App { + InstallableApp getAsInstallable(); + + UpdateableApp getAsUpdateable(); + + AppType getType(); + + long getPrice(); + + int getLevel(); + + int getRequiredLevel(); + + boolean isOneTime(); + + boolean isInstalled(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/AppManager.java b/src/main/java/net/olympiccode/vhackos/api/appstore/AppManager.java new file mode 100644 index 0000000..1669f57 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/AppManager.java @@ -0,0 +1,10 @@ +package net.olympiccode.vhackos.api.appstore; + +import net.olympiccode.vhackos.api.entities.AppType; + +import java.util.List; + +public interface AppManager { +App getApp(AppType type); +List getApps(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/InstallableApp.java b/src/main/java/net/olympiccode/vhackos/api/appstore/InstallableApp.java new file mode 100644 index 0000000..da22290 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/InstallableApp.java @@ -0,0 +1,6 @@ +package net.olympiccode.vhackos.api.appstore; + +public interface InstallableApp { + boolean hasRequiredLevel(); + boolean install(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/Task.java b/src/main/java/net/olympiccode/vhackos/api/appstore/Task.java new file mode 100644 index 0000000..1f7f3c2 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/Task.java @@ -0,0 +1,12 @@ +package net.olympiccode.vhackos.api.appstore; + +import net.olympiccode.vhackos.api.entities.AppType; + +public interface Task { + boolean isFinished(); + long getLevel(); + AppType getType(); + long getId(); + long getEndTimestamp(); + long getStartTimestamp(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/TaskManager.java b/src/main/java/net/olympiccode/vhackos/api/appstore/TaskManager.java new file mode 100644 index 0000000..7979d29 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/TaskManager.java @@ -0,0 +1,14 @@ +package net.olympiccode.vhackos.api.appstore; + +import net.olympiccode.vhackos.api.entities.impl.BruteForceImpl; + +import java.util.List; + +public interface TaskManager { + List getActiveTasks(); + List getActiveBrutes(); + boolean finishAll(); + boolean boostAll(); + int getFinishAllCost(); + int getBoosters(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/appstore/UpdateableApp.java b/src/main/java/net/olympiccode/vhackos/api/appstore/UpdateableApp.java new file mode 100644 index 0000000..ae6c9e4 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/appstore/UpdateableApp.java @@ -0,0 +1,6 @@ +package net.olympiccode.vhackos.api.appstore; + +public interface UpdateableApp { + boolean update(); + boolean fillTasks(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/AppType.java b/src/main/java/net/olympiccode/vhackos/api/entities/AppType.java new file mode 100644 index 0000000..7ded752 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/AppType.java @@ -0,0 +1,39 @@ +package net.olympiccode.vhackos.api.entities; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.stream.Collectors; + + +public enum AppType { + Notepad("Notepad", 0), + Antivirus ("Antivirus", 1), + Firewall ("Firewall", 2), + Spam ("Spam", 3), + BruteForce ("Bruteforce", 4), + BankingProtection ("Banking Protection", 5), + SDK ("Software Development Kit", 6), + Community ("Community", 7), + Missions ("Missions", 8), + Leaderboards ("Leaderboards", 9), + IPSP ("IP-Spoofing", 10), + NCMiner ("NCMiner", 11), + MalwareKit ("Malware Kit", 12), + Jobs ("Jobs", 13); + + @Getter + private String name; + @Getter + private int id; + + AppType(String name, int id) { + this.name = name; + this.id = id; + } + + public static AppType byId(int id) { + return Arrays.stream(AppType.values()).filter(appType -> appType.getId() == id).collect(Collectors.toList()).get(0); + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/BruteForceState.java b/src/main/java/net/olympiccode/vhackos/api/entities/BruteForceState.java new file mode 100644 index 0000000..8e89589 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/BruteForceState.java @@ -0,0 +1,5 @@ +package net.olympiccode.vhackos.api.entities; + +public enum BruteForceState { + RUNNING, SUCCESS, FAILED +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/Stats.java b/src/main/java/net/olympiccode/vhackos/api/entities/Stats.java new file mode 100644 index 0000000..c5e8f06 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/Stats.java @@ -0,0 +1,21 @@ +package net.olympiccode.vhackos.api.entities; + +public interface Stats { + long getMoney(); + + long getExploits(); + + long getNetcoins(); + + long getLevel(); + + long getExperience(); + + long getRequiredExperience(); + + long getLevelPorcentage(); + + String getIpAddress(); + + String getUsername(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppImpl.java new file mode 100644 index 0000000..e3e6f93 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppImpl.java @@ -0,0 +1,43 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import lombok.Setter; +import net.olympiccode.vhackos.api.appstore.App; +import net.olympiccode.vhackos.api.appstore.InstallableApp; +import net.olympiccode.vhackos.api.appstore.UpdateableApp; +import net.olympiccode.vhackos.api.entities.AppType; + +@Getter +@Setter +public class AppImpl implements App { + private AppType type; + private long price; + private int level; + private int requiredLevel; + private boolean oneTime; + private int maxLevel; + private vHackOSAPIImpl api; + private boolean installed; + + public AppImpl(vHackOSAPIImpl api, AppType type, long price, int level, int requiredLevel, int maxLevel) { + this.type = type; + this.price = price; + this.level = level; + this.requiredLevel = requiredLevel; + this.oneTime = maxLevel < 2; + this.api = api; + this.installed = level > 0; + this.maxLevel = maxLevel; + } + + public InstallableApp getAsInstallable() { + return new InstallableAppImpl(api, type, price, level, requiredLevel, maxLevel); + } + + + public UpdateableApp getAsUpdateable() { + return new UpdateableAppImpl(api, type, price, level, requiredLevel, maxLevel); + } + + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppManagerImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppManagerImpl.java new file mode 100644 index 0000000..16e473c --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/AppManagerImpl.java @@ -0,0 +1,46 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.appstore.App; +import net.olympiccode.vhackos.api.appstore.AppManager; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.requests.Response; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class AppManagerImpl implements AppManager { + private final vHackOSAPIImpl api; + + public AppManagerImpl(vHackOSAPIImpl api) { + this.api = api; + } + + public List getApps() { + Route.CompiledRoute route = Route.AppStore.GET_APPS.compile(api); + Response r = api.getRequester().getResponse(route); + JSONObject object = r.getJSON(); + List l = new ArrayList<>(); + try { + JSONArray array = object.getJSONArray("apps"); + for (AppType type : AppType.values()) { + JSONObject appobj = array.getJSONObject(type.getId()); + int price = appobj.optInt("price", -1); + int level = appobj.optInt("level", 0); + int requiredLevel = appobj.optInt("require", 1); + int maxLevel = appobj.optInt("maxlvl", 1); + l.add(new AppImpl(api, type, price, level, requiredLevel, maxLevel)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return l; + } + public App getApp(AppType type) { + return getApps().get(type.getId()); + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/BruteForceImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/BruteForceImpl.java new file mode 100644 index 0000000..f0b9c44 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/BruteForceImpl.java @@ -0,0 +1,45 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.entities.BruteForceState; +import net.olympiccode.vhackos.api.exceptions.ExploitFailedException; +import net.olympiccode.vhackos.api.network.BruteForce; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONObject; + +@Getter +public class BruteForceImpl implements BruteForce { + private final String username; + private final String ip; + private final vHackOSAPIImpl api; + private long startTimestamp, endTimestamp, id; + private BruteForceState state; + + public BruteForceImpl(vHackOSAPIImpl api, BruteForceState state, String ip, long startTimestamp, long endTimestamp, String username, long id) { + this.state = state; + this.ip = ip; + this.startTimestamp = startTimestamp; + this.endTimestamp = endTimestamp; + this.username = username; + this.id = id; + this.api = api; + } + + public ExploitedTargetImpl exploit() { + try { + return new ExploitedTargetImpl(api, ip); + } catch (ExploitFailedException e) { + return null; + } + } + + public boolean remove() { + JSONObject obj = Route.Tasks.REMOVE_BRUTE.compile(api, "10000", String.valueOf(id)).getResponse().getJSON(); + if (obj.optInt("bruteremoved", 0) == 1) { + api.getTaskManager().activeBrutes.remove(this); + return true; + } + return false; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/ExploitedTargetImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/ExploitedTargetImpl.java new file mode 100644 index 0000000..e1003b5 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/ExploitedTargetImpl.java @@ -0,0 +1,146 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import net.olympiccode.vhackos.api.exceptions.ExploitFailedException; +import net.olympiccode.vhackos.api.network.ExploitedTarget; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public class ExploitedTargetImpl implements ExploitedTarget { + + private long level = -1; + private final vHackOSAPIImpl api; + private final String ip; + private String username = null; + private Banking banking; + private String SystemLog; + public ExploitedTargetImpl(vHackOSAPIImpl api, String ip) throws ExploitFailedException { + JSONObject object = Route.Network.REMOTE.compile(api, ip).getResponse().getJSON(); + this.api = api; + this.ip = ip; + try { + int level = object.getInt("remoteLevel"); + String username = object.getString("remoteUsername"); + this.level = level; + this.username = username; + } catch (JSONException e) { + e.printStackTrace(); + } + this.banking = new BankingImpl(); + if (level == -1 || username == null) { + throw new ExploitFailedException("An error ocurred"); + } + } + + public String getSystemLog() { + if (SystemLog == null) { + JSONObject object = Route.Network.GET_LOG.compile(api, ip).getResponse().getJSON(); + try { + SystemLog = object.getString("logs"); + } catch (JSONException e) { + e.printStackTrace(); + } + } + return SystemLog; + } + + public boolean clearSystemLog() { + return setSystemLog(""); + } + + public boolean setSystemLog(String s) { + JSONObject obj = Route.Network.EDIT_LOG.compile(api, ip, "100", s).getResponse().getJSON(); + return obj.optInt("result", 0) == 2; + } + + @Getter + public class BankingImpl implements Banking { + private boolean bruteForced; + private long avaliableMoney; + private int transactionCount; + private int savings; + private int total; + private int maxSavings; + private List transactions = new ArrayList<>(); + BankingImpl() { + JSONObject object = Route.Network.REMOTE_BANKING.compile(api, ip).getResponse().getJSON(); + try { + this.bruteForced = object.getInt("open") == 1; + this.avaliableMoney = object.optLong("money", 0); + this.transactionCount = object.optInt("transcount", 0); + this.savings = object.optInt("savings", 0); + this.total = object.optInt("total", 0); + this.maxSavings = object.optInt("maxsavings", 0); + if (object.has("transactions")) { + JSONArray array = object.getJSONArray("transactions"); + for (int i = 0; i < array.length(); i++) { + JSONObject trans = array.getJSONObject(i); + transactions.add(new TransactionImpl(trans)); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public boolean startBruteForce() { + JSONObject object = Route.Network.START_BRUTEFORCE.compile(api, ip).getResponse().getJSON(); + try { + int result = object.getInt("result"); + switch (result) { + case 0: + return true; + case 1: + return true; + case 2: + return false; + } + } catch (JSONException e) { + e.printStackTrace(); + } + return false; + } + + public boolean withdraw() { + if (!isBruteForced() && avaliableMoney < 1) return false; + JSONObject object = Route.Network.BANKING_RETRIEVE.compile(api, "100", ip).getResponse().getJSON(); + try { + if (object.has("withdraw") && object.getInt("withdraw") == 1) { + avaliableMoney = 0; + ((StatsImpl) api.getStats()).setMoney(api.getStats().getMoney() + avaliableMoney); + return true; + } + } catch (JSONException e) { + e.printStackTrace(); + } + return false; + } + + @Getter + class TransactionImpl implements Transaction { + long time; + String from_ip; + String to_ip; + long amount; + + + TransactionImpl(JSONObject object) { + try { + time = object.getLong("time") * 1000; + from_ip = object.getString("from_ip"); + to_ip = object.getString("to_ip"); + amount = object.getLong("amount"); + } catch (JSONException e) { + e.printStackTrace(); + } + + } + } + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/InstallableAppImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/InstallableAppImpl.java new file mode 100644 index 0000000..b305dad --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/InstallableAppImpl.java @@ -0,0 +1,33 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.appstore.InstallableApp; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.requests.Response; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONObject; + +public class InstallableAppImpl extends AppImpl implements InstallableApp { + + private vHackOSAPIImpl api; + private AppType type; + public InstallableAppImpl(vHackOSAPIImpl api, AppType type, long price, int level, int requiredLevel, int maxLevel) { + super(api, type, price, level, requiredLevel, maxLevel); + this.api = api; + this.type = type; + if (level > 0) { + throw new RuntimeException("Tried to get installable app of already installed app"); + } + } + + public boolean hasRequiredLevel() { + return api.getStats().getLevel() >= getRequiredLevel(); + } + + public boolean install() { + Route.CompiledRoute route = Route.AppStore.APP_ACTION.compile(api, "200", String.valueOf(type.getId())); + Response r = api.getRequester().getResponse(route); + JSONObject object = r.getJSON(); + return Integer.valueOf(object.optString("installed", "1")) == 0; + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/MinerImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/MinerImpl.java new file mode 100644 index 0000000..d49ee1b --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/MinerImpl.java @@ -0,0 +1,59 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.misc.Miner; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONObject; + +public class MinerImpl implements Miner { + + private final vHackOSAPIImpl api; + private Boolean installed; + public MinerImpl(vHackOSAPIImpl api) { + this.api = api; + } + + private boolean checkInstall() { + if (installed != null) return installed; + installed = api.getAppManager().getApp(AppType.NCMiner).isInstalled(); + return installed; + } + public boolean isRunning() { + if (!checkInstall()) return false; + JSONObject obj = Route.Misc.MINER.compile(api).getResponse().getJSON(); + return obj.optInt("running", 0) == 1; + } + + public boolean isDone() { + if (!checkInstall()) return false; + JSONObject obj = Route.Misc.MINER.compile(api).getResponse().getJSON(); + return obj.optInt("running", 0) == 2; + } + + public boolean claim() { + if (!checkInstall()) return false; + if (isDone()) { + JSONObject obj = Route.Misc.MINER_ACT.compile(api, "200").getResponse().getJSON(); + if(obj.optInt("claimed", 0) == 1) { + ((StatsImpl)api.getStats()).setNetcoins(api.getStats().getNetcoins() + 100); + return true; + } + } + return false; + } + + public boolean start() { + if (!checkInstall()) return false; + if (isDone()) { + claim(); + } + if (!isRunning() && !isDone()) { + JSONObject obj = Route.Misc.MINER_ACT.compile(api, "100").getResponse().getJSON(); + if(obj.optInt("started", 0) == 1) { + ((StatsImpl)api.getStats()).setNetcoins(api.getStats().getNetcoins() + 100); + return true; + } + } + return false; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/NetworkManagerImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/NetworkManagerImpl.java new file mode 100644 index 0000000..f611571 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/NetworkManagerImpl.java @@ -0,0 +1,46 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.network.NetworkManager; +import net.olympiccode.vhackos.api.network.Target; +import net.olympiccode.vhackos.api.requests.Response; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +public class NetworkManagerImpl implements NetworkManager { + + private vHackOSAPIImpl api; + + public NetworkManagerImpl(vHackOSAPIImpl api) { + this.api = api; + } + + + public List getTargets() { + Response r = Route.Network.TARGET_LIST.compile(api).getResponse(); + JSONObject object = r.getJSON(); + List targets = new ArrayList<>(); + try { + JSONArray array = object.getJSONArray("ips"); + for (int i = 0; i < array.length(); i++) { + JSONObject t = array.getJSONObject(i); + String ip = t.getString("ip"); + int level = t.getInt("level"); + int fw = t.getInt("fw"); + boolean open = t.getInt("open") == 1; + targets.add(new TargetImpl(api, ip, level, fw, open)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return targets; + } + + public vHackOSAPIImpl getApi() { + return api; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/StatsImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/StatsImpl.java new file mode 100644 index 0000000..e37d801 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/StatsImpl.java @@ -0,0 +1,20 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import lombok.Setter; +import net.olympiccode.vhackos.api.entities.Stats; + +@Setter +@Getter +public class StatsImpl implements Stats { + private final vHackOSAPIImpl api; + private long money, exploits, netcoins, level, experience, requiredExperience, levelPorcentage; + private String ipAddress, username; + + public StatsImpl(vHackOSAPIImpl api) { + this.api = api; + } + + + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/TargetImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TargetImpl.java new file mode 100644 index 0000000..60d36e4 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TargetImpl.java @@ -0,0 +1,64 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import net.olympiccode.vhackos.api.exceptions.ExploitFailedException; +import net.olympiccode.vhackos.api.network.Target; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Class containing a network target + *
Used to exploit them + */ +@Getter +public class TargetImpl implements Target { + + private final int firewall; + private final int level; + private final String ip; + private final boolean open; + private final vHackOSAPIImpl api; + + public TargetImpl(vHackOSAPIImpl api, String ip, int level, int firewall, boolean open) { + this.api = api; + this.ip = ip; + this.level = level; + this.firewall = firewall; + this.open = open; + } + + /** + * Exploits the target + * + * @return ExploitedTargetImpl The exploited target instance + * @throws net.olympiccode.vhackos.api.exceptions.ExploitFailedException if the exploit fails with an error message + */ + public ExploitedTargetImpl exploit() throws ExploitFailedException { + if (api.getStats().getExploits() < 1) throw new ExploitFailedException("Not enough exploits"); + JSONObject object = Route.Network.EXPLOIT.compile(api, ip).getResponse().getJSON(); + ((StatsImpl) api.getStats()).setExploits( api.getStats().getExploits() -1); + try { + int result = object.getInt("result"); + switch (result){ + case 0: + return new ExploitedTargetImpl(api, ip); + case 1: + throw new ExploitFailedException("Exploit not found"); + case 2: + throw new ExploitFailedException("Not enough exploits (This shouldn't happen?)"); + case 3: + throw new ExploitFailedException("Tutor exploit failed"); + case 4: + throw new ExploitFailedException("Not enough SDK"); + case 5: + throw new ExploitFailedException("Connection already opened (This shouldn't happen?)"); + } + } catch (JSONException e) { + e.printStackTrace(); + } + + return null; + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskImpl.java new file mode 100644 index 0000000..a2fe3be --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskImpl.java @@ -0,0 +1,23 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import lombok.Setter; +import net.olympiccode.vhackos.api.appstore.Task; +import net.olympiccode.vhackos.api.entities.AppType; + +@Getter +@Setter +public class TaskImpl implements Task { + private long startTimestamp, endTimestamp, level, id; + private AppType type; + private boolean finished = false; + + public TaskImpl(AppType type, long startTimestamp, long endTimestamp, long level, long id) { + this.startTimestamp = startTimestamp; + this.type = type; + this.endTimestamp = endTimestamp; + this.level = level; + this.id = id; + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskManagerImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskManagerImpl.java new file mode 100644 index 0000000..71a4635 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/TaskManagerImpl.java @@ -0,0 +1,112 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import lombok.Getter; +import net.olympiccode.vhackos.api.appstore.Task; +import net.olympiccode.vhackos.api.appstore.TaskManager; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.entities.BruteForceState; +import net.olympiccode.vhackos.api.events.UpdateTaskFinishEvent; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class TaskManagerImpl implements TaskManager { + + private final vHackOSAPIImpl api; + + public TaskManagerImpl(vHackOSAPIImpl api) { + this.api = api; + } + + private List activeTasks = new ArrayList<>(); + @Getter + public List activeBrutes = new ArrayList<>(); + @Getter + private int finishAllCost = 0; + @Getter + private int boosters = 0; + + public void reloadTasks() { + JSONObject obj = Route.Tasks.GET_TASKS.compile(api).getResponse().getJSON(); + try { + this.finishAllCost = obj.optInt("finishallcosts", finishAllCost); + this.boosters = obj.optInt("boosters", 0); + if (obj.has("updates")) { + JSONArray array = obj.getJSONArray("updates"); + checkTasks(); + List newlist = new ArrayList<>(); + for (int i = 0; i < array.length(); i++) { + JSONObject taskobj = array.getJSONObject(i); + newlist.add(new TaskImpl(AppType.byId(Integer.parseInt(taskobj.getString("appid"))), taskobj.getLong("start") * 1000, taskobj.getLong("end") * 1000, taskobj.getInt("level"), taskobj.getInt("id"))); + } + activeTasks.clear(); + activeTasks.addAll(newlist); + } + if (obj.has("brutes")) { + JSONArray array = obj.getJSONArray("brutes"); + activeBrutes.clear(); + for (int i = 0; i < array.length(); i++) { + JSONObject taskobj = array.getJSONObject(i); + int result = taskobj.getInt("result"); + BruteForceState state = result == 0 ? BruteForceState.RUNNING : result == 1 ? BruteForceState.SUCCESS : BruteForceState.FAILED; + activeBrutes.add(new BruteForceImpl(api, state,taskobj.getString("user_ip"), taskobj.getLong("start") * 1000, taskobj.getLong("end") * 1000,taskobj.getString("username"), Integer.parseInt(taskobj.getString("id")))); } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public Task getTaskById(int id) { + return activeTasks.stream().filter(task -> task.getId() == id).collect(Collectors.toList()).get(0); + } + + public List getActiveTasks() { + return activeTasks.stream().map(task -> (Task) task).collect(Collectors.toList()); + } + + + public boolean finishAll() { + reloadTasks(); + if (activeTasks.size() < 1) return false; + JSONObject object = Route.Tasks.FINISH.compile(api, "500", String.valueOf(activeTasks.get(0).getId())).getResponse().getJSON(); + if (object.optInt("finishall", 0) == 1) { + ((StatsImpl) api.getStats()).setNetcoins(api.getStats().getNetcoins() - finishAllCost); + for (TaskImpl activeTask : activeTasks) { + activeTask.setEndTimestamp(0); + } + return true; + } + return false; + } + + public boolean boostAll() { + reloadTasks(); + JSONObject object = Route.Tasks.FINISH.compile(api, "888", String.valueOf(activeTasks.get(0).getId())).getResponse().getJSON(); + if (object.optInt("boosted", 0) == 1) { + reloadTasks(); + return true; + } + return false; + } + + public void checkTasks() { + List toremove = new ArrayList<>(); + activeTasks.forEach(task -> { + if (task.getEndTimestamp() <= System.currentTimeMillis()) { + toremove.add(task); + task.setFinished(true); + + } + }); + toremove.forEach(task -> { + activeTasks.remove(task); + api.fireEvent(new UpdateTaskFinishEvent(api, (TaskImpl) task)); + }); + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/UpdateableAppImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/UpdateableAppImpl.java new file mode 100644 index 0000000..fea2ee2 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/UpdateableAppImpl.java @@ -0,0 +1,39 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.appstore.UpdateableApp; +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.requests.Response; +import net.olympiccode.vhackos.api.requests.Route; +import org.json.JSONObject; + +public class UpdateableAppImpl extends AppImpl implements UpdateableApp { + + private final vHackOSAPIImpl api; + + public UpdateableAppImpl(vHackOSAPIImpl api, AppType type, long price, int level, int requiredLevel, int maxLevel) { + super(api, type, price, level, requiredLevel, maxLevel); + this.api = api; + } + + public boolean update() { + Route.CompiledRoute route = Route.AppStore.APP_ACTION.compile(api, "100", String.valueOf(getType().getId())); + Response r = api.getRequester().getResponse(route); + JSONObject object = r.getJSON(); + if (Integer.valueOf(object.optString("updated", "1")) == 0) { + api.getTaskManager().reloadTasks(); + return true; + } + return false; + } + + public boolean fillTasks() { + Route.CompiledRoute route = Route.AppStore.APP_ACTION.compile(api, "5500", String.valueOf(getType().getId())); + Response r = api.getRequester().getResponse(route); + JSONObject object = r.getJSON(); + if (Integer.valueOf(object.optString("filled", "1")) == 1) { + api.getTaskManager().reloadTasks(); + return true; + } + return false; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/entities/impl/vHackOSAPIImpl.java b/src/main/java/net/olympiccode/vhackos/api/entities/impl/vHackOSAPIImpl.java new file mode 100644 index 0000000..b6ca068 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/entities/impl/vHackOSAPIImpl.java @@ -0,0 +1,212 @@ +package net.olympiccode.vhackos.api.entities.impl; + +import net.olympiccode.vhackos.api.appstore.AppManager; +import net.olympiccode.vhackos.api.entities.Stats; +import net.olympiccode.vhackos.api.events.Event; +import net.olympiccode.vhackos.api.events.EventListener; +import net.olympiccode.vhackos.api.events.StatsUpdateEvent; +import net.olympiccode.vhackos.api.requests.Requester; +import net.olympiccode.vhackos.api.requests.Response; +import net.olympiccode.vhackos.api.requests.Route; +import net.olympiccode.vhackos.api.vHackOSAPI; +import okhttp3.OkHttpClient; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.security.auth.login.LoginException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +public class vHackOSAPIImpl implements vHackOSAPI { + + private static final Logger LOG = LoggerFactory.getLogger("vHackOSAPI"); + + private final OkHttpClient.Builder httpClientBuilder; + private List listeners = new ArrayList<>(); + private int corePoolSize; + private Status status = Status.INITIALIZING; + private Requester requester; + private String username = null; + private String password = null; + private String accessToken = ""; + private String uid = ""; + private boolean invalidToken = false; + private boolean debugResponses = false; + + private StatsImpl stats = new StatsImpl(this); + private AppManagerImpl appManager = new AppManagerImpl(this); + private TaskManagerImpl taskManager = new TaskManagerImpl(this); + private NetworkManagerImpl networkManager = new NetworkManagerImpl(this); + private MinerImpl miner = new MinerImpl(this); + private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(corePoolSize, new APIThreadFactory()); + + public vHackOSAPIImpl(OkHttpClient.Builder httpClientBuilder, boolean autoReconnect, int maxReconnectDelay, int corePoolSize) { + this.httpClientBuilder = httpClientBuilder; + boolean autoReconnect1 = autoReconnect; + int maxReconnectDelay1 = maxReconnectDelay; + this.requester = new Requester(this); + this.corePoolSize = corePoolSize; + } + + public void login(String username, String password) throws LoginException { + setStatus(Status.LOGGING_IN); + if (username == null || username.isEmpty()) + throw new LoginException("Provided username was null or empty!"); + if (password == null || password.isEmpty()) + throw new LoginException("Provided password was null or empty!"); + setUsername(username); + setPassword(password); + setStatus(Status.AWAITING_LOGIN_CONFIRMATION); + verifyDetails(); + setup(); + setStatus(Status.CONNECTED); + } + + public void verifyDetails() throws LoginException { + Route.CompiledRoute r = Route.Misc.LOGIN.compile(this); + try { + Response resp = getRequester().getResponse(r); + JSONObject userResponse = resp.getJSON(); + this.accessToken = userResponse.getString("accesstoken"); + this.uid = userResponse.getString("uid"); + LOG.info("Login Successful!"); + } catch (RuntimeException e) { + Throwable ex = e.getCause() != null ? e.getCause().getCause() : null; + if (ex instanceof LoginException) + throw (LoginException) ex; + else + throw e; + } catch (JSONException e) { + e.printStackTrace(); + } + + } + + private void setup() { + setStatus(Status.LOADING_SUBSYSTEMS); + LOG.info("Loading subsystems..."); + updateData(); + taskManager.reloadTasks(); + executorService.scheduleAtFixedRate(() -> updateData(), 30000, 30000, TimeUnit.MILLISECONDS); + executorService.scheduleAtFixedRate(() -> taskManager.checkTasks(), 1000, 1000, TimeUnit.MILLISECONDS); + executorService.scheduleAtFixedRate(() -> taskManager.reloadTasks(), 30000, 30000, TimeUnit.MILLISECONDS); + Runtime.getRuntime().addShutdownHook(new Thread(() -> executorService.shutdownNow())); + } + + private void updateData() { + LOG.debug("Updating data"); + Route.CompiledRoute route = Route.Misc.UPDATE.compile(this); + Response resp = getRequester().getResponse(route); + try { + JSONObject object = new JSONObject(resp.getString()); + stats.setExperience(Long.parseLong(object.optString("exp", "0"))); + stats.setExploits(Long.parseLong(object.optString("exploits", "0"))); + stats.setIpAddress(object.optString("ipaddress", "0")); + stats.setLevel(Long.parseLong(object.optString("level", "0"))); + stats.setLevelPorcentage(Long.parseLong(object.optString("exppc", "0"))); + stats.setMoney(Long.parseLong(object.optString("money", "0"))); + stats.setUsername(object.optString("statsname")); + stats.setNetcoins(Long.parseLong(object.optString("netcoins", "0"))); + stats.setRequiredExperience(Long.parseLong(object.optString("expreq", "0"))); + } catch (JSONException e) { + e.printStackTrace(); + } + fireEvent(new StatsUpdateEvent(this)); + } + + public void fireEvent(Event e) { + listeners.forEach(eventListener -> eventListener.onEvent(e)); + } + + public OkHttpClient.Builder getHttpClientBuilder() { + return httpClientBuilder; + } + + public void setStatus(Status status) { + this.status = status; + } + + public void addEventListener(Object... listener) { + for (Object o : listener) if (o instanceof EventListener) listeners.add((EventListener) o); + } + + public Status getStatus() { + return status; + } + + public String getUsername() { + return username; + } + + public Requester getRequester() { + return requester; + } + + private void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + private void setPassword(String password) { + this.password = password; + } + + public void removeEventListener(Object... listener) { + for (Object o : listener) if (o instanceof EventListener) listeners.remove(o); + } + + public void setDebugResponses(boolean debugResponses) { + this.debugResponses = debugResponses; + } + + public boolean isDebugResponses() { + return debugResponses; + } + + public List getRegisteredListeners() { + return listeners; + } + + public String getUid() { + return uid; + } + + public String getAccessToken() { + return accessToken; + } + + public AppManager getAppManager() { + return appManager; + } + + public Stats getStats() { + return stats; + } + + public TaskManagerImpl getTaskManager() { + return taskManager; + } + + public NetworkManagerImpl getNetworkManager() { + return networkManager; + } + + public MinerImpl getMiner() { return miner; } + class APIThreadFactory implements ThreadFactory { + private int counter = 0; + private String prefix = "vHackOSAPI"; + + public Thread newThread(Runnable r) { + return new Thread(r, prefix + "-" + counter++); + } + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/events/Event.java b/src/main/java/net/olympiccode/vhackos/api/events/Event.java new file mode 100644 index 0000000..6bd08b5 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/events/Event.java @@ -0,0 +1,18 @@ +package net.olympiccode.vhackos.api.events; + + +import net.olympiccode.vhackos.api.vHackOSAPI; + +public class Event { + final vHackOSAPI api; + + Event(vHackOSAPI api) + { + this.api = api; + } + + public vHackOSAPI getAPI() + { + return api; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/events/EventListener.java b/src/main/java/net/olympiccode/vhackos/api/events/EventListener.java new file mode 100644 index 0000000..ed307ae --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/events/EventListener.java @@ -0,0 +1,6 @@ +package net.olympiccode.vhackos.api.events; + +public interface EventListener +{ + void onEvent(Event event); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/events/StatsUpdateEvent.java b/src/main/java/net/olympiccode/vhackos/api/events/StatsUpdateEvent.java new file mode 100644 index 0000000..235e902 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/events/StatsUpdateEvent.java @@ -0,0 +1,14 @@ +package net.olympiccode.vhackos.api.events; + +import net.olympiccode.vhackos.api.entities.Stats; +import net.olympiccode.vhackos.api.vHackOSAPI; + +public class StatsUpdateEvent extends Event { + public StatsUpdateEvent(vHackOSAPI api) { + super(api); + } + + public Stats getStats() { + return api.getStats(); + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/events/UpdateTaskFinishEvent.java b/src/main/java/net/olympiccode/vhackos/api/events/UpdateTaskFinishEvent.java new file mode 100644 index 0000000..b7887d1 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/events/UpdateTaskFinishEvent.java @@ -0,0 +1,18 @@ +package net.olympiccode.vhackos.api.events; + +import lombok.Getter; +import net.olympiccode.vhackos.api.appstore.Task; +import net.olympiccode.vhackos.api.entities.impl.TaskImpl; +import net.olympiccode.vhackos.api.vHackOSAPI; + +public class UpdateTaskFinishEvent extends Event { + @Getter + Task task; + public UpdateTaskFinishEvent(vHackOSAPI api, TaskImpl task) { + super(api); + this.task = task; + } + + + +} \ No newline at end of file diff --git a/src/main/java/net/olympiccode/vhackos/api/exceptions/ExploitFailedException.java b/src/main/java/net/olympiccode/vhackos/api/exceptions/ExploitFailedException.java new file mode 100644 index 0000000..ac39721 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/exceptions/ExploitFailedException.java @@ -0,0 +1,6 @@ +package net.olympiccode.vhackos.api.exceptions; + +public class ExploitFailedException extends Exception { + public ExploitFailedException() { super(); } + public ExploitFailedException(String msg) { super(msg); } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/misc/Miner.java b/src/main/java/net/olympiccode/vhackos/api/misc/Miner.java new file mode 100644 index 0000000..d53d83a --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/misc/Miner.java @@ -0,0 +1,8 @@ +package net.olympiccode.vhackos.api.misc; + +public interface Miner { + boolean isRunning(); + boolean claim(); + boolean isDone(); + boolean start(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/network/BruteForce.java b/src/main/java/net/olympiccode/vhackos/api/network/BruteForce.java new file mode 100644 index 0000000..75e5489 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/network/BruteForce.java @@ -0,0 +1,17 @@ +package net.olympiccode.vhackos.api.network; + +import net.olympiccode.vhackos.api.entities.AppType; +import net.olympiccode.vhackos.api.entities.BruteForceState; +import net.olympiccode.vhackos.api.vHackOSAPI; + +public interface BruteForce { + ExploitedTarget exploit(); + boolean remove(); + String getUsername(); + String getIp(); + vHackOSAPI getApi(); + long getStartTimestamp(); + long getEndTimestamp(); + long getId(); + BruteForceState getState(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/network/ExploitedTarget.java b/src/main/java/net/olympiccode/vhackos/api/network/ExploitedTarget.java new file mode 100644 index 0000000..bce7231 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/network/ExploitedTarget.java @@ -0,0 +1,34 @@ +package net.olympiccode.vhackos.api.network; + +import net.olympiccode.vhackos.api.vHackOSAPI; + +import java.util.List; + +public interface ExploitedTarget { + String getSystemLog(); + boolean clearSystemLog(); + boolean setSystemLog(String s); + long getLevel(); + vHackOSAPI getApi(); + String getIp(); + String getUsername(); + Banking getBanking(); + + interface Banking { + boolean startBruteForce(); + boolean withdraw(); + boolean isBruteForced(); + long getAvaliableMoney(); + int getTransactionCount(); + int getSavings(); + int getTotal(); + int getMaxSavings(); + List getTransactions(); + interface Transaction { + long getTime(); + String getFrom_ip(); + String getTo_ip(); + long getAmount(); + } + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/network/NetworkManager.java b/src/main/java/net/olympiccode/vhackos/api/network/NetworkManager.java new file mode 100644 index 0000000..1ac0e86 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/network/NetworkManager.java @@ -0,0 +1,10 @@ +package net.olympiccode.vhackos.api.network; + +import net.olympiccode.vhackos.api.vHackOSAPI; + +import java.util.List; + +public interface NetworkManager { + List getTargets(); + vHackOSAPI getApi(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/network/Target.java b/src/main/java/net/olympiccode/vhackos/api/network/Target.java new file mode 100644 index 0000000..a815da7 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/network/Target.java @@ -0,0 +1,13 @@ +package net.olympiccode.vhackos.api.network; + +import net.olympiccode.vhackos.api.exceptions.ExploitFailedException; +import net.olympiccode.vhackos.api.vHackOSAPI; + +public interface Target { + ExploitedTarget exploit() throws ExploitFailedException; + int getFirewall(); + int getLevel(); + String getIp(); + boolean isOpen(); + vHackOSAPI getApi(); +} diff --git a/src/main/java/net/olympiccode/vhackos/api/requests/Requester.java b/src/main/java/net/olympiccode/vhackos/api/requests/Requester.java new file mode 100644 index 0000000..79e302d --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/requests/Requester.java @@ -0,0 +1,117 @@ +package net.olympiccode.vhackos.api.requests; + +import net.olympiccode.vhackos.api.entities.impl.vHackOSAPIImpl; +import net.olympiccode.vhackos.api.vHackOSAPI; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.security.auth.login.LoginException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import java.util.zip.GZIPInputStream; + +public class Requester { + private static final Logger LOG = LoggerFactory.getLogger("Requester"); + private final vHackOSAPIImpl api; + private long lastRequest = 0; + private final OkHttpClient httpClient; + + private volatile boolean retryOnTimeout = false; + + + public Requester(vHackOSAPI api) { + + this.api = (vHackOSAPIImpl) api; + this.httpClient = this.api.getHttpClientBuilder().build(); + } + + public static InputStream getBody(okhttp3.Response response) throws IOException { + String encoding = response.header("content-encoding", ""); + if (Objects.equals(encoding, "gzip")) + return new GZIPInputStream(Objects.requireNonNull(response.body()).byteStream()); + return Objects.requireNonNull(response.body()).byteStream(); + } + + public vHackOSAPIImpl getAPI() { + return api; + } + + public OkHttpClient getHttpClient() { + return this.httpClient; + } + + private int triesLeft = 3; + private int success = 0; + public Response getResponse(Route.CompiledRoute route) { + if (lastRequest >= System.currentTimeMillis() - 1000) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + lastRequest = System.currentTimeMillis(); + Request request = new Request.Builder() + .url(route.getCompiledRoute()) + .addHeader("user-agent", "Dalvik/1.6.0 (Linux; U; Android 4.4.4; SM-N935F Build/KTU84P)") + .addHeader("Accept-Encoding", "gzip").build(); + final Response[] response = new Response[1]; + okhttp3.Response r; + try { + r = httpClient.newCall(request).execute(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + if (r.isSuccessful()) { + response[0] = new Response(r); + } else { + throw new RuntimeException("Failed to get response from vHackOS " + r.code() + " {" + route.getCompiledRoute() + "}"); + } + try { + JSONObject object = response[0].getJSON(); + + switch (object.getString("result")) { + case "2": + if (!route.getCompiledRoute().contains("remotelog")) { + api.setStatus(vHackOSAPI.Status.FAILED_TO_LOGIN); + throw new LoginException("Invalid username or password"); + } + break; + case "36": + if (triesLeft <= 0) { + LOG.error("Failed to relogin after 3 tries, you are probably running the game while the bot is also running."); + throw new LoginException("Failed to re-login after 3 tries"); + } + LOG.error("Server returned invalid access token error, trying to reconnect..."); + api.setStatus(vHackOSAPI.Status.AWAITING_LOGIN_CONFIRMATION); + api.verifyDetails(); + success = 0; + triesLeft--; + return getResponse(route); + case "10": + throw new RuntimeException("The server returned error 10, this might mean the bot is outdated or a bug ocurred."); + case "1": + throw new RuntimeException("Your vhack account has been banned"); + } + } catch (RuntimeException | LoginException e) { + e.printStackTrace(); + } catch (final Exception e) { + throw new IllegalStateException("An error occurred while processing rest request", e); + } finally { + r.close(); + } + r.close(); + success++; + if (success >= 2) { + triesLeft = 3; + } + if (api.isDebugResponses()) LOG.info(response[0].getJSON().toString()); + return response[0]; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/requests/Response.java b/src/main/java/net/olympiccode/vhackos/api/requests/Response.java new file mode 100644 index 0000000..7b681ca --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/requests/Response.java @@ -0,0 +1,107 @@ +package net.olympiccode.vhackos.api.requests; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +import java.io.*; +import java.util.Objects; +import java.util.stream.Collectors; + +public class Response implements Closeable +{ + public static final int ERROR_CODE = 0; + public static final String ERROR_MESSAGE = "ERROR"; + + private final String response; + private final okhttp3.Response rawResponse; + + + + Response(final okhttp3.Response response) + { + this.rawResponse = response; + if (response == null || Objects.requireNonNull(response.body()).contentLength() == 0) + { + this.response = null; + return; + } + + InputStream body = null; + BufferedReader reader = null; + try + { + body = Requester.getBody(response); + reader = new BufferedReader(new InputStreamReader(body)); + char begin; + int mark = 1; + do + { + reader.mark(mark++); + begin = (char) reader.read(); + } + while (Character.isWhitespace(begin)); + + reader.reset(); + + switch (begin) { + case '{': + this.response = new JSONObject(new JSONTokener(reader)).toString(); + break; + case '[': + this.response = new JSONArray(new JSONTokener(reader)).toString(); + break; + default: + this.response = reader.lines().collect(Collectors.joining()); + break; + } + } + catch (final Exception ee) + { + throw new IllegalStateException("An error occurred while parsing the response for a RestAction", ee); + } + finally + { + try + { + Objects.requireNonNull(body).close(); + Objects.requireNonNull(reader).close(); + } catch (NullPointerException | IOException ignored) {} + } + } + + + + public String getString() + { + return Objects.toString(response); + } + + public JSONObject getJSON() { + try { + return new JSONObject(getString()); + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } + + public okhttp3.Response getRawResponse() + { + return this.rawResponse; + } + + @Override + public String toString() + { + return "HTTPResponse[" + response + ']'; + } + + @Override + public void close() + { + if (rawResponse != null) + rawResponse.close(); + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/requests/Route.java b/src/main/java/net/olympiccode/vhackos/api/requests/Route.java new file mode 100644 index 0000000..ba8c183 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/requests/Route.java @@ -0,0 +1,172 @@ +package net.olympiccode.vhackos.api.requests; + +import net.olympiccode.vhackos.api.entities.impl.vHackOSAPIImpl; +import net.olympiccode.vhackos.api.utils.Encryption; +import net.olympiccode.vhackos.api.vHackOSAPI; +import net.olympiccode.vhackos.api.vHackOSInfo; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class Route { + private final String route; + private final String compilableRoute; + private final int paramCount; + private final String[] majorParameters; + private final List majorParamIndexes = new ArrayList<>(); + + private Route(String route, String... majorParameters) { + this.route = route; + this.paramCount = majorParameters.length; + this.majorParameters = majorParameters; + compilableRoute = route + ".php?user=%s&pass=%s"; + } + + public String getRoute() { + return route; + } + + public String getCompilableRoute() { + return compilableRoute; + } + + public int getParamCount() { + return paramCount; + } + + public CompiledRoute compile(vHackOSAPI apir, String... params) { + if (params.length != paramCount) { + throw new IllegalArgumentException("Error Compiling Route: [" + route + "], incorrect amount of parameters provided." + + "Expected: " + (paramCount) + ", Provided: " + params.length); + } + + + vHackOSAPIImpl api = (vHackOSAPIImpl) apir; + JSONObject arguments = new JSONObject(); + if (api.getStatus() != vHackOSAPI.Status.AWAITING_LOGIN_CONFIRMATION) { + try { + arguments.put("uid", api.getUid()); + arguments.put("accesstoken", api.getAccessToken()); + } catch (JSONException e) { + e.printStackTrace(); + } + } else { + try { + arguments.put("password", Encryption.md5Hash(api.getPassword())); + arguments.put("username", api.getUsername()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + AtomicInteger i = new AtomicInteger(); + for (String s : majorParameters) { + try { + arguments.put(s, params[i.getAndIncrement()]); + } catch (JSONException e) { + e.printStackTrace(); + } + } + String json = arguments.toString(); + + + String base64 = Encryption.base64Encrypt(json); + String pass = Encryption.md5Hash(json + json + Encryption.md5Hash(json)); + String compiledRoute = vHackOSInfo.API_PREFIX + route + ".php?user=" + base64 + "&pass=" + pass; + return new CompiledRoute(api, this, compiledRoute); + } + + @Override + public int hashCode() { + return (route).hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Route)) + return false; + + Route oRoute = (Route) o; + return paramCount == (oRoute.paramCount) && route.equals(oRoute.route); + } + + @Override + public String toString() { + return "Route(" + route + ")"; + } + + public static class Misc { + public static final Route LOGIN = new Route("login"); + public static final Route UPDATE = new Route("update"); + public static final Route MINER = new Route("mining"); + public static final Route MINER_ACT = new Route("mining", "action"); + } + + public static class AppStore { + public static final Route APP_ACTION = new Route("store", "action", "appcode"); + public static final Route GET_APPS = new Route("store"); + } + + public static class Tasks { + public static final Route GET_TASKS = new Route("tasks"); + public static final Route REMOVE_BRUTE = new Route("tasks", "action", "updateid"); + public static final Route FINISH = new Route("tasks", "action", "updateid"); + } + + public static class Network { + public static final Route TARGET_LIST = new Route("network"); + public static final Route EXPLOIT = new Route("exploit", "target"); + public static final Route REMOTE = new Route("remote", "target"); + public static final Route REMOTE_BANKING = new Route("remotebanking", "target"); + public static final Route BANKING_RETRIEVE = new Route("remotebanking", "action", "target"); + public static final Route START_BRUTEFORCE = new Route("startbruteforce", "target"); + public static final Route GET_LOG = new Route("remotelog", "target"); + public static final Route EDIT_LOG = new Route("remotelog", "target", "action", "log"); + } + + public class CompiledRoute { + private final Route baseRoute; + private final String compiledRoute; + private final vHackOSAPIImpl api; + + private CompiledRoute(vHackOSAPIImpl api, Route baseRoute, String compiledRoute) { + this.api = api; + this.baseRoute = baseRoute; + this.compiledRoute = compiledRoute; + } + + public String getCompiledRoute() { + return compiledRoute; + } + + Route getBaseRoute() { + return baseRoute; + } + + @Override + public int hashCode() { + return (compiledRoute).hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof CompiledRoute)) + return false; + + CompiledRoute oCompiled = (CompiledRoute) o; + + return baseRoute.equals(oCompiled.getBaseRoute()) && compiledRoute.equals(oCompiled.compiledRoute); + } + + public Response getResponse() { + return api.getRequester().getResponse(this); + } + + @Override + public String toString() { + return "CompiledRoute(" + compiledRoute + ")"; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/olympiccode/vhackos/api/utils/Checks.java b/src/main/java/net/olympiccode/vhackos/api/utils/Checks.java new file mode 100644 index 0000000..aa9ff69 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/utils/Checks.java @@ -0,0 +1,17 @@ +package net.olympiccode.vhackos.api.utils; + +public class Checks { + + public static void notNull(final Object argument, final String name) + { + if (argument == null) + throw new IllegalArgumentException(name + " may not be null"); + } + + public static void check(final boolean expression, final String message, final Object arg) + { + if (!expression) + throw new IllegalArgumentException(String.format(message, arg)); + } + +} diff --git a/src/main/java/net/olympiccode/vhackos/api/utils/Encryption.java b/src/main/java/net/olympiccode/vhackos/api/utils/Encryption.java new file mode 100644 index 0000000..0e2c55c --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/utils/Encryption.java @@ -0,0 +1,25 @@ +package net.olympiccode.vhackos.api.utils; + +import javax.xml.bind.DatatypeConverter; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class Encryption { + public static String md5Hash(String str) { + try { + MessageDigest instance = MessageDigest.getInstance("MD5"); + instance.update(str.getBytes()); + byte[] digest = instance.digest(); + return DatatypeConverter + .printHexBinary(digest).toLowerCase(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return ""; + } + } + + public static String base64Encrypt(String string) { + return new String(Base64.getEncoder().encode(string.getBytes())).replaceAll("=", ""); + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/vHackOSAPI.java b/src/main/java/net/olympiccode/vhackos/api/vHackOSAPI.java new file mode 100644 index 0000000..9622667 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/vHackOSAPI.java @@ -0,0 +1,63 @@ +package net.olympiccode.vhackos.api; + +import net.olympiccode.vhackos.api.appstore.AppManager; +import net.olympiccode.vhackos.api.appstore.TaskManager; +import net.olympiccode.vhackos.api.entities.Stats; +import net.olympiccode.vhackos.api.events.EventListener; +import net.olympiccode.vhackos.api.misc.Miner; +import net.olympiccode.vhackos.api.network.NetworkManager; + +import java.util.List; + +public interface vHackOSAPI { + + enum Status + { + INITIALIZING(true), + INITIALIZED(true), + LOGGING_IN(true), + AWAITING_LOGIN_CONFIRMATION(true), + LOADING_SUBSYSTEMS(true), + CONNECTED(true), + SHUTDOWN, + FAILED_TO_LOGIN; + + private final boolean isInit; + + Status(boolean isInit) + { + this.isInit = isInit; + } + + Status() + { + this.isInit = false; + } + + public boolean isInit() + { + return isInit; + } + } + + Status getStatus(); + + + void addEventListener(Object... listeners); + + void removeEventListener(Object... listeners); + + List getRegisteredListeners(); + + Stats getStats(); + + AppManager getAppManager(); + + TaskManager getTaskManager(); + + NetworkManager getNetworkManager(); + + Miner getMiner(); + +} + diff --git a/src/main/java/net/olympiccode/vhackos/api/vHackOSAPIBuilder.java b/src/main/java/net/olympiccode/vhackos/api/vHackOSAPIBuilder.java new file mode 100644 index 0000000..b477339 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/vHackOSAPIBuilder.java @@ -0,0 +1,89 @@ +package net.olympiccode.vhackos.api; + +import net.olympiccode.vhackos.api.entities.impl.vHackOSAPIImpl; +import net.olympiccode.vhackos.api.utils.Checks; +import okhttp3.OkHttpClient; + +import javax.security.auth.login.LoginException; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class vHackOSAPIBuilder { + private final List listeners; + + private OkHttpClient.Builder httpClientBuilder = null; + private String username; + private String password; + + public vHackOSAPIBuilder() + { + listeners = new LinkedList<>(); + } + + + public vHackOSAPIBuilder setUsername(String username) + { + this.username = username; + return this; + } + + + public vHackOSAPIBuilder setPassword(String password) + { + this.password = password; + return this; + } + + public vHackOSAPIBuilder setHttpClientBuilder(OkHttpClient.Builder builder) + { + this.httpClientBuilder = builder; + return this; + } + + + public vHackOSAPIBuilder addEventListener(Object... listeners) + { + Collections.addAll(this.listeners, listeners); + return this; + } + + + public vHackOSAPIBuilder removeEventListener(Object... listeners) + { + this.listeners.removeAll(Arrays.asList(listeners)); + return this; + } + + + private vHackOSAPI buildAsync() throws LoginException, IllegalArgumentException + { + OkHttpClient.Builder httpClientBuilder = this.httpClientBuilder == null ? new OkHttpClient.Builder() : this.httpClientBuilder; + boolean autoReconnect = true; + int maxReconnectDelay = 900; + vHackOSAPIImpl api = new vHackOSAPIImpl(httpClientBuilder, autoReconnect, maxReconnectDelay, 5); + + listeners.forEach(api::addEventListener); + api.setStatus(vHackOSAPI.Status.INITIALIZED); + api.login(username, password); + return api; + } + + + public vHackOSAPI buildBlocking() throws LoginException, IllegalArgumentException, InterruptedException + { + Checks.notNull(vHackOSAPI.Status.CONNECTED, "Status"); + Checks.check(vHackOSAPI.Status.CONNECTED.isInit(), "Cannot await the status %s as it is not part of the login cycle!", vHackOSAPI.Status.CONNECTED); + vHackOSAPI api = buildAsync(); + while (!api.getStatus().isInit() + || api.getStatus().ordinal() < vHackOSAPI.Status.CONNECTED.ordinal()) + { + if (api.getStatus() == vHackOSAPI.Status.SHUTDOWN) + throw new IllegalStateException("vHackOSAPI was unable to finish starting up!"); + Thread.sleep(50); + } + + return api; + } +} diff --git a/src/main/java/net/olympiccode/vhackos/api/vHackOSInfo.java b/src/main/java/net/olympiccode/vhackos/api/vHackOSInfo.java new file mode 100644 index 0000000..13265a4 --- /dev/null +++ b/src/main/java/net/olympiccode/vhackos/api/vHackOSInfo.java @@ -0,0 +1,6 @@ +package net.olympiccode.vhackos.api; + +public class vHackOSInfo { + private static final int REST_VERSION = 8; + public static final String API_PREFIX = String.format("https://api.vhack.cc/mobile/%d/", REST_VERSION); +}