├── .gitignore ├── src └── main │ ├── java │ └── io │ │ └── forcesoftware │ │ ├── models │ │ ├── setting │ │ │ └── Settings.java │ │ ├── Proxy.java │ │ ├── task │ │ │ └── TaskData.java │ │ └── billing │ │ │ ├── Card.java │ │ │ ├── Address.java │ │ │ └── Profile.java │ │ ├── loaders │ │ ├── SettingsLoader.java │ │ ├── TaskLoader.java │ │ ├── ProfileLoader.java │ │ ├── ProxyLoader.java │ │ └── Loader.java │ │ ├── Main.java │ │ ├── tasks │ │ └── ShoePalaceTask.java │ │ └── ShoePalaceBot.java │ └── resources │ └── log4j2.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | logs/ 3 | target/ 4 | *.iml -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/setting/Settings.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models.setting; 2 | 3 | public class Settings { 4 | 5 | //TODO work out other settings 6 | private String webhookUrl; 7 | 8 | public String getWebhookUrl() { 9 | return webhookUrl; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/loaders/SettingsLoader.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.loaders; 2 | 3 | import io.forcesoftware.Main; 4 | import io.forcesoftware.models.setting.Settings; 5 | import lombok.Getter; 6 | 7 | public class SettingsLoader extends Loader { 8 | 9 | @Getter 10 | private Settings settings; 11 | 12 | public void loadSettings() { 13 | loadFile("{}"); 14 | 15 | settings = Main.GSON.fromJson(getFileContents(), Settings.class); 16 | 17 | Main.LOGGER.info("Loaded settings"); 18 | } 19 | 20 | @Override 21 | public String getFileName() { 22 | return "settings.json"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/loaders/TaskLoader.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.loaders; 2 | 3 | import com.google.gson.reflect.TypeToken; 4 | import io.forcesoftware.Main; 5 | import io.forcesoftware.models.task.TaskData; 6 | import lombok.Getter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class TaskLoader extends Loader { 12 | 13 | @Getter 14 | private List tasks; 15 | 16 | public void loadTasks() { 17 | this.tasks = new ArrayList<>(); 18 | 19 | loadFile("[]"); 20 | 21 | tasks = Main.GSON.fromJson(getFileContents(), new TypeToken>() { 22 | }.getType()); 23 | 24 | Main.LOGGER.info("Loaded " + tasks.size() + " tasks"); 25 | } 26 | 27 | public void saveTasks() { 28 | saveData(tasks); 29 | } 30 | 31 | @Override 32 | public String getFileName() { 33 | return "tasks.json"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/Main.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import lombok.Getter; 6 | import org.apache.commons.lang3.SystemUtils; 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | 10 | 11 | @Getter 12 | public class Main { 13 | 14 | public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); 15 | public static final Logger LOGGER = LogManager.getLogger("io.forcesoftware.Main"); 16 | 17 | public static String configPath; 18 | 19 | public static void main(String[] args) { 20 | if (SystemUtils.IS_OS_WINDOWS) { 21 | configPath = System.getenv("AppData") + "/spbot"; 22 | } else if (SystemUtils.IS_OS_MAC) { 23 | configPath = System.getProperty("user.home") + "/Library/Application Support/spbot"; 24 | } 25 | 26 | new ShoePalaceBot(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/Proxy.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models; 2 | 3 | public class Proxy { 4 | 5 | private String ip; 6 | private String port; 7 | private String username; 8 | private String password; 9 | private boolean auth = false; 10 | 11 | public Proxy(String ip, String port, String... up) { 12 | this.ip = ip; 13 | this.port = port; 14 | if (up.length != 0) { 15 | this.auth = true; 16 | this.username = up[0]; 17 | this.password = up[1]; 18 | } 19 | } 20 | 21 | public String getIp() { 22 | return ip; 23 | } 24 | 25 | public String getPort() { 26 | return port; 27 | } 28 | 29 | public String getUsername() { 30 | return username; 31 | } 32 | 33 | public String getPassword() { 34 | return password; 35 | } 36 | 37 | public boolean isAuth() { 38 | return auth; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/loaders/ProfileLoader.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.loaders; 2 | 3 | import com.google.gson.reflect.TypeToken; 4 | import io.forcesoftware.Main; 5 | import io.forcesoftware.models.billing.Profile; 6 | import lombok.Getter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class ProfileLoader extends Loader { 12 | 13 | @Getter 14 | private List profiles; 15 | 16 | public void loadProfiles() { 17 | this.profiles = new ArrayList<>(); 18 | 19 | loadFile("[]"); 20 | 21 | profiles = Main.GSON.fromJson(getFileContents(), new TypeToken>() { 22 | }.getType()); 23 | 24 | Main.LOGGER.info("Loaded " + profiles.size() + " profiles"); 25 | } 26 | 27 | public void saveProfiles() { 28 | saveData(profiles); 29 | } 30 | 31 | @Override 32 | public String getFileName() { 33 | return "profiles.json"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/tasks/ShoePalaceTask.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.tasks; 2 | 3 | import io.forcesoftware.ShoePalaceBot; 4 | import io.forcesoftware.models.billing.Profile; 5 | import io.forcesoftware.models.task.TaskData; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | 9 | public class ShoePalaceTask extends Thread { 10 | 11 | private Logger logger; 12 | 13 | private TaskData taskData; 14 | 15 | private Profile profile; 16 | 17 | public ShoePalaceTask(TaskData taskData) { 18 | super("ShoePalaceTask-" + taskData.getId()); 19 | 20 | this.logger = LogManager.getLogger("io.forcesoftware.Task"); 21 | this.taskData = taskData; 22 | } 23 | 24 | @Override 25 | public void run() { 26 | for (Profile profile : ShoePalaceBot.getInstance().getProfileLoader().getProfiles()) { 27 | if (profile.getAlias().equals(taskData.getProfileAlias())) { 28 | this.profile = profile; 29 | } 30 | } 31 | 32 | if (profile == null) { 33 | logger.error("Failed to find profile for task"); 34 | return; 35 | } 36 | 37 | logger.info("Task started"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [%d{HH:mm:ss.SSS}][%t][%level] %msg%n 7 | 8 | 9 | 10 | 11 | [%d{HH:mm:ss.SSS}][%t][%level] %msg%n 12 | 13 | 14 | 15 | 16 | [%d{HH:mm:ss.SSS}][%t][%level] %msg%n 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/task/TaskData.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models.task; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class TaskData { 9 | 10 | private String id; 11 | private String url; 12 | private String profileAlias; 13 | 14 | public String getId() { 15 | return id; 16 | } 17 | 18 | public String getUrl() { 19 | return url; 20 | } 21 | 22 | public String getProfileAlias() { 23 | return profileAlias; 24 | } 25 | 26 | public static class Builder { 27 | 28 | private TaskData taskData; 29 | 30 | public Builder() { 31 | this.taskData = new TaskData(); 32 | } 33 | 34 | public Builder(TaskData taskData) { 35 | this.taskData = taskData; 36 | } 37 | 38 | public Builder id(String id) { 39 | taskData.setId(id); 40 | return this; 41 | } 42 | 43 | public Builder url(String url) { 44 | taskData.setUrl(url); 45 | return this; 46 | } 47 | 48 | public Builder profileAlias(String profileAlias) { 49 | taskData.setProfileAlias(profileAlias); 50 | return this; 51 | } 52 | 53 | public TaskData builder() { 54 | return taskData; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/billing/Card.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models.billing; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class Card { 9 | 10 | private String cardNumber; 11 | private String cardExpiryMonth; 12 | private String cardExpiryYear; 13 | private String cardCvv; 14 | 15 | public static class Builder { 16 | 17 | private Card card; 18 | 19 | public Builder() { 20 | this.card = new Card(); 21 | } 22 | 23 | public Builder(Card card) { 24 | this.card = card; 25 | } 26 | 27 | public Builder cardNumber(String cardNumber) { 28 | this.card.setCardNumber(cardNumber); 29 | return this; 30 | } 31 | 32 | public Builder cardExpiryMonth(String cardExpiryMonth) { 33 | this.card.setCardExpiryMonth(cardExpiryMonth); 34 | return this; 35 | } 36 | 37 | public Builder cardExpiryYear(String cardExpiryYear) { 38 | this.card.setCardExpiryYear(cardExpiryYear); 39 | return this; 40 | } 41 | 42 | public Builder cardCvv(String cardCvv) { 43 | this.card.setCardCvv(cardCvv); 44 | return this; 45 | } 46 | 47 | public Card build() { 48 | return card; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/loaders/ProxyLoader.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.loaders; 2 | 3 | import io.forcesoftware.Main; 4 | import io.forcesoftware.models.Proxy; 5 | import lombok.Getter; 6 | 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.stream.Stream; 12 | 13 | public class ProxyLoader extends Loader { 14 | 15 | @Getter 16 | private List proxies; 17 | 18 | public void loadProxies() { 19 | this.proxies = new ArrayList<>(); 20 | 21 | loadFile(""); 22 | 23 | try (Stream stream = Files.lines(getFile().toPath())) { 24 | stream.forEach((line) -> { 25 | String[] text = line.split(":"); 26 | if (text.length >= 2) { 27 | Proxy proxy = new Proxy(text[0], text[1]); 28 | if (text.length > 2) { 29 | proxy = new Proxy(text[0], text[1], text[2], text[3]); 30 | } 31 | proxies.add(proxy); 32 | } 33 | }); 34 | } catch (IOException e) { 35 | Main.LOGGER.error("Could not load proxies: " + e.getLocalizedMessage()); 36 | e.printStackTrace(); 37 | return; 38 | } 39 | 40 | Main.LOGGER.info("Loaded " + proxies.size() + " proxies"); 41 | } 42 | 43 | @Override 44 | public String getFileName() { 45 | return "proxies.txt"; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/loaders/Loader.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.loaders; 2 | 3 | import io.forcesoftware.Main; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.charset.StandardCharsets; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public abstract class Loader { 14 | 15 | private File file; 16 | 17 | public abstract String getFileName(); 18 | 19 | protected void loadFile(String defaultContents) { 20 | file = new File(Main.configPath + "/" + getFileName()); 21 | 22 | if (!file.exists()) { 23 | try { 24 | file.createNewFile(); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | 29 | List lines = Collections.singletonList(defaultContents); 30 | try { 31 | Files.write(Paths.get(file.getPath()), lines, StandardCharsets.UTF_8); 32 | } catch (Exception e) { 33 | Runtime.getRuntime().halt(1); 34 | } 35 | } 36 | } 37 | 38 | protected void saveData(Object object) { 39 | try { 40 | Files.write(Paths.get(getFile().getAbsolutePath()), Main.GSON.toJson(object).getBytes()); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | public String getFileContents() { 47 | try { 48 | return new String(Files.readAllBytes(Paths.get(file.getPath()))); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | return null; 53 | } 54 | 55 | public File getFile() { 56 | return file; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/billing/Address.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models.billing; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class Address { 9 | 10 | private String firstName; 11 | private String lastName; 12 | private String addressOne; 13 | private String addressTwo; 14 | private String city; 15 | private String zip; 16 | private String state; 17 | private String phone; 18 | 19 | public static class Builder { 20 | 21 | private Address address; 22 | 23 | public Builder() { 24 | address = new Address(); 25 | } 26 | 27 | public Builder(Address address) { 28 | this.address = address; 29 | } 30 | 31 | public Builder firstName(String firstName) { 32 | this.address.setFirstName(firstName); 33 | return this; 34 | } 35 | 36 | public Builder lastName(String lastName) { 37 | this.address.setLastName(lastName); 38 | return this; 39 | } 40 | 41 | public Builder addressOne(String addressOne) { 42 | this.address.setAddressOne(addressOne); 43 | return this; 44 | } 45 | 46 | public Builder addressTwo(String addressTwo) { 47 | this.address.setAddressTwo(addressTwo); 48 | return this; 49 | } 50 | 51 | public Builder city(String city) { 52 | this.address.setCity(city); 53 | return this; 54 | } 55 | 56 | public Builder zip(String zip) { 57 | this.address.setZip(zip); 58 | return this; 59 | } 60 | 61 | public Builder state(String state) { 62 | this.address.setState(state); 63 | return this; 64 | } 65 | 66 | public Builder phone(String phone) { 67 | this.address.setPhone(phone); 68 | return this; 69 | } 70 | 71 | public Address build() { 72 | return address; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/models/billing/Profile.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware.models.billing; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class Profile { 9 | 10 | private String alias; 11 | private String email; 12 | 13 | private Address shippingAddress; 14 | private Address billingAddress; 15 | 16 | private Card card; 17 | 18 | public String getAlias() { 19 | return alias; 20 | } 21 | 22 | public String getEmail() { 23 | return email; 24 | } 25 | 26 | public Address getShippingAddress() { 27 | return shippingAddress; 28 | } 29 | 30 | public Address getBillingAddress() { 31 | return billingAddress; 32 | } 33 | 34 | public Card getCard() { 35 | return card; 36 | } 37 | 38 | public boolean isSameShippingAndBilling() { 39 | return shippingAddress != null && billingAddress == null; 40 | } 41 | 42 | public static class Builder { 43 | 44 | private Profile profile; 45 | 46 | public Builder() { 47 | this.profile = new Profile(); 48 | } 49 | 50 | public Builder(Profile profile) { 51 | this.profile = profile; 52 | } 53 | 54 | public Builder alias(String alias) { 55 | profile.setAlias(alias); 56 | return this; 57 | } 58 | 59 | public Builder email(String email) { 60 | profile.setEmail(email); 61 | return this; 62 | } 63 | 64 | public Builder shippingAddress(Address address) { 65 | profile.setShippingAddress(address); 66 | return this; 67 | } 68 | 69 | public Builder billingAddress(Address address) { 70 | profile.setBillingAddress(address); 71 | return this; 72 | } 73 | 74 | public Builder card(Card card) { 75 | profile.setCard(card); 76 | return this; 77 | } 78 | 79 | public Profile build() { 80 | return profile; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.forcesoftware 8 | shoepalace 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 8 17 | 8 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.commons 27 | commons-lang3 28 | 3.9 29 | 30 | 31 | org.apache.logging.log4j 32 | log4j-api 33 | 2.11.2 34 | 35 | 36 | org.apache.logging.log4j 37 | log4j-core 38 | 2.11.2 39 | 40 | 41 | com.lmax 42 | disruptor 43 | 3.3.7 44 | 45 | 46 | 47 | com.google.code.gson 48 | gson 49 | 2.8.6 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | 1.18.12 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/io/forcesoftware/ShoePalaceBot.java: -------------------------------------------------------------------------------- 1 | package io.forcesoftware; 2 | 3 | import io.forcesoftware.loaders.ProfileLoader; 4 | import io.forcesoftware.loaders.ProxyLoader; 5 | import io.forcesoftware.loaders.SettingsLoader; 6 | import io.forcesoftware.loaders.TaskLoader; 7 | import io.forcesoftware.models.billing.Address; 8 | import io.forcesoftware.models.billing.Card; 9 | import io.forcesoftware.models.billing.Profile; 10 | import io.forcesoftware.models.task.TaskData; 11 | import io.forcesoftware.tasks.ShoePalaceTask; 12 | import lombok.Getter; 13 | 14 | @Getter 15 | public class ShoePalaceBot { 16 | 17 | private static ShoePalaceBot instance; 18 | 19 | private ProfileLoader profileLoader; 20 | private ProxyLoader proxyLoader; 21 | private SettingsLoader settingsLoader; 22 | private TaskLoader taskLoader; 23 | 24 | public ShoePalaceBot() { 25 | instance = this; 26 | 27 | registerLoaders(); 28 | beginTasks(); 29 | 30 | setupShutdownHook(); 31 | 32 | // createDummyData(); 33 | } 34 | 35 | private void registerLoaders() { 36 | (profileLoader = new ProfileLoader()).loadProfiles(); 37 | (proxyLoader = new ProxyLoader()).loadProxies(); 38 | (settingsLoader = new SettingsLoader()).loadSettings(); 39 | (taskLoader = new TaskLoader()).loadTasks(); 40 | } 41 | 42 | private void setupShutdownHook() { 43 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 44 | profileLoader.saveProfiles(); 45 | taskLoader.saveTasks(); 46 | })); 47 | } 48 | 49 | private void beginTasks() { 50 | for (TaskData taskData : taskLoader.getTasks()) { 51 | ShoePalaceTask shoePalaceTask = new ShoePalaceTask(taskData); 52 | shoePalaceTask.start(); 53 | } 54 | } 55 | 56 | /** 57 | * Simple method which will generate dummy data to test with 58 | */ 59 | private void createDummyData() { 60 | Card card = new Card.Builder() 61 | .cardNumber("1234 1234 1234 1234") 62 | .cardExpiryMonth("10") 63 | .cardExpiryYear("2027") 64 | .cardCvv("123") 65 | .build(); 66 | 67 | Address address = new Address.Builder() 68 | .addressOne("123 south st.") 69 | .state("California") 70 | .city("Los Angeles") 71 | .zip("90405") 72 | .firstName("Joe") 73 | .lastName("Smith") 74 | .phone("123 456 7890") 75 | .build(); 76 | 77 | Profile profile = new Profile.Builder() 78 | .alias("test") 79 | .email("email@test.com") 80 | .card(card) 81 | .shippingAddress(address) 82 | .build(); 83 | 84 | TaskData taskData = new TaskData.Builder() 85 | .id("1") 86 | .url("https://shoepalace.com") 87 | .profileAlias("test") 88 | .builder(); 89 | 90 | profileLoader.getProfiles().add(profile); 91 | taskLoader.getTasks().add(taskData); 92 | } 93 | 94 | public static ShoePalaceBot getInstance() { 95 | return instance; 96 | } 97 | } 98 | --------------------------------------------------------------------------------