package net.teamlixo.eggcrack.authentication;
import net.teamlixo.eggcrack.EggCrack;
import net.teamlixo.eggcrack.account.AuthenticatedAccount;
import net.teamlixo.eggcrack.credential.Credentials;
import net.teamlixo.eggcrack.list.AbstractExtendedList;
import net.teamlixo.eggcrack.account.Account;
import net.teamlixo.eggcrack.account.AccountListener;
import net.teamlixo.eggcrack.credential.Credential;
import net.teamlixo.eggcrack.session.Session;
import net.teamlixo.eggcrack.session.Tracker;
import java.net.Proxy;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.logging.Level;
/**
* Helper class designed to provide asynchronous authentication functionality to EggCrack. Calls AuthenticationCallback
* with completed or failed responses. Handles one account, but narrows down to the AuthenticationService class, which
* should be both thread-safe and support many separate requesting accounts asynchronously.
*/
public class RunnableAuthenticator implements Runnable {
private Session session;
private AuthenticationService authenticationService;
private Account account;
private Iterator<Credential> credentialIterator;
private Iterator<Proxy> proxyIterator;
private AuthenticationCallback authenticationCallback;
private Tracker tracker;
public RunnableAuthenticator(Session session,
AuthenticationService authenticationService,
Account account,
Tracker tracker,
Iterator<Credential> credentialIterator,
Iterator<Proxy> proxyIterator,
AuthenticationCallback authenticationCallback) {
this.session = session;
this.authenticationService = authenticationService;
this.account = account;
this.credentialIterator = credentialIterator;
this.proxyIterator = proxyIterator;
this.authenticationCallback = authenticationCallback;
this.tracker = tracker;
}
@Override
public void run() {
if (!session.isRunning()) return;
account.setState(Account.State.STARTED);
Thread.currentThread().setName("Authenticator-" + account.getUsername());
AccountListener accountListener = account.getListener();
if (accountListener != null)
accountListener.onAccountStarted(account);
Credential credential = account.getUncheckedPassword() != null ?
Credentials.createPassword(account.getUncheckedPassword()) : null;
if (credential != null && accountListener != null)
accountListener.onAccountAttempting(account, credential);
else if (credential == null) { // Restore password index and progress values.
for (int i = 0; i < account.getPasswordIndex(); i++) credential = credentialIterator.next();
account.setProgress(((AbstractExtendedList.LoopedIterator)credentialIterator).getProgress());
}
while (proxyIterator.hasNext() && session.isRunning()) {
try {
if (credential == null) {
if (accountListener != null)
accountListener.onAccountTried(account, credential);
credential = credentialIterator.next();
if (accountListener != null && session.isRunning())
accountListener.onAccountAttempting(account, credential);
}
EggCrack.LOGGER.finest("[Account: " + account.getUsername() +
"] Sending authentication request [password=" + credential.toString() + "]...");
try {
AuthenticatedAccount authenticatedAccount =
authenticationService.authenticate(account, credential, proxyIterator.next());
if (authenticatedAccount != null) {
authenticationCallback.onAuthenticationCompleted(authenticatedAccount);
tracker.setAttempts(tracker.getAttempts() + 1);
if (accountListener != null && session.isRunning())
accountListener.onAccountCompleted(account, credential);
return;
} else
throw new AuthenticationException(
AuthenticationException.AuthenticationFailure.INCORRECT_CREDENTIAL, "Incorrect credential"
);
} catch (AuthenticationException exception) {
if (exception.getFailure().hasRequested()) {
tracker.setRequests(tracker.getRequests() + 1);
if (accountListener != null && session.isRunning())
accountListener.onAccountRequested(account);
}
if (exception.getFailure().getAction() == AuthenticationException.AuthenticationAction.STOP) {
tracker.setAttempts(tracker.getAttempts() + 1);
EggCrack.LOGGER.warning("Stopping session for " + account.getUsername() + ": "
+ exception.getMessage() + " (" + exception.getDetails() + ")");
break;
} else if (exception.getFailure().getAction() == AuthenticationException.AuthenticationAction.NEXT_CREDENTIALS) {
account.setProgress(((AbstractExtendedList.LoopedIterator)credentialIterator).getProgress());
if (accountListener != null && session.isRunning())
accountListener.onAccountTried(account, credential);
tracker.setAttempts(tracker.getAttempts() + 1);
if (account.getUncheckedPassword() == null) {
credential = credentialIterator.next();
if (accountListener != null && session.isRunning())
accountListener.onAccountAttempting(account, credential);
account.setPasswordIndex(account.getPasswordIndex() + 1);
} else
break; // Checker only tries one password.
}
}
} catch (NoSuchElementException exception) {
exception.printStackTrace();
break;
} catch (Throwable ex) {
//Just ignore it.
EggCrack.LOGGER.log(Level.SEVERE, "Unhandled exception in thread " + Thread.currentThread().getName(), ex);
}
}
if (accountListener != null && session.isRunning()) accountListener.onAccountFailed(account );
authenticationCallback.onAuthenticationFailed(account);
account.setState(Account.State.FINISHED);
}
}