/**
* This file is part of aion-emu <aion-emu.com>.
*
* aion-emu is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aion-emu is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with aion-emu. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aionemu.loginserver.controller;
import java.util.HashMap;
import java.util.Map;
import com.aionemu.commons.database.dao.DAOManager;
import com.aionemu.commons.utils.NetworkUtils;
import com.aionemu.loginserver.GameServerInfo;
import com.aionemu.loginserver.GameServerTable;
import com.aionemu.loginserver.configs.Config;
import com.aionemu.loginserver.dao.AccountDAO;
import com.aionemu.loginserver.dao.AccountTimeDAO;
import com.aionemu.loginserver.model.Account;
import com.aionemu.loginserver.model.ReconnectingAccount;
import com.aionemu.loginserver.network.aion.AionAuthResponse;
import com.aionemu.loginserver.network.aion.AionConnection;
import com.aionemu.loginserver.network.aion.AionConnection.State;
import com.aionemu.loginserver.network.aion.SessionKey;
import com.aionemu.loginserver.network.aion.serverpackets.SM_UPDATE_SESSION;
import com.aionemu.loginserver.network.gameserver.GsConnection;
import com.aionemu.loginserver.network.gameserver.serverpackets.SM_ACCOUNT_AUTH_RESPONSE;
import com.aionemu.loginserver.utils.AccountUtils;
/**
* This class is resposible for controlling all account actions
*
* @author KID
* @author SoulKeeper
*/
public class AccountController
{
/**
* Map with accounts that are active on LoginServer or joined GameServer and are not authenticated yet.
*/
private static final Map<Integer, AionConnection> accountsOnLS = new HashMap<Integer,
AionConnection>();
/**
* Map with accounts that are reconnecting to LoginServer ie was joined GameServer.
*/
private static final Map<Integer, ReconnectingAccount> reconnectingAccounts = new HashMap<Integer,
ReconnectingAccount>();
/**
* Removes account from list of connections
*
* @param account
* account
*/
public static synchronized void removeAccountOnLS(Account account)
{
accountsOnLS.remove(account.getId());
}
/**
* This method is for answering GameServer question about account authentication on GameServer side.
*
* @param key
* @param gsConnection
*/
public static synchronized void checkAuth(SessionKey key, GsConnection gsConnection)
{
AionConnection con = accountsOnLS.get(key.accountId);
if(con != null)
{
if(con.getSessionKey().checkSessionKey(key))
{
/**
* account is successful logged in on gs remove it from here
*/
accountsOnLS.remove(key.accountId);
GameServerInfo gsi = gsConnection.getGameServerInfo();
Account acc = con.getAccount();
/**
* Add account to accounts on GameServer list and update accounts last server
*/
gsi.addAccountToGameServer(acc);
acc.setLastServer(gsi.getId());
getAccountDAO().updateLastServer(acc.getId(), acc.getLastServer());
/**
* Send response to GameServer
*/
gsConnection.sendPacket(new SM_ACCOUNT_AUTH_RESPONSE(key.accountId, true, acc.getName(), acc
.getAccessLevel(), acc.getMembership()));
}
}
else
{
gsConnection.sendPacket(new SM_ACCOUNT_AUTH_RESPONSE(key.accountId, false, null, (byte)0, (byte) 0));
}
}
/**
* Add account to reconnectionAccount list
*
* @param acc
*/
public static synchronized void addReconnectingAccount(ReconnectingAccount acc)
{
reconnectingAccounts.put(acc.getAccount().getId(), acc);
}
/**
* Check if reconnecting account may auth.
*
* @param accountId
* id of account
* @param loginOk
* loginOk
* @param reconnectKey
* reconnect key
* @param client
* aion client
*/
public static synchronized void authReconnectingAccount(int accountId, int loginOk, int reconnectKey,
AionConnection client)
{
ReconnectingAccount reconnectingAccount = reconnectingAccounts.remove(accountId);
if(reconnectingAccount != null && reconnectingAccount.getReconnectionKey() == reconnectKey)
{
Account acc = reconnectingAccount.getAccount();
client.setAccount(acc);
accountsOnLS.put(acc.getId(), client);
client.setState(State.AUTHED_LOGIN);
client.setSessionKey(new SessionKey(client.getAccount()));
client.sendPacket(new SM_UPDATE_SESSION(client.getSessionKey()));
}
else
{
client.close( /* new SM_UPDATE_SESSION, */true);
}
}
/**
* Tries to authentificate account.<br>
* If success returns {@link AionAuthResponse#AUTHED} and sets account object to connection.<br>
*
* If {@link com.aionemu.loginserver.configs.Config#ACCOUNT_AUTO_CREATION} is enabled - creates new account.<br>
*
* @param name
* name of account
* @param password
* password of account
* @param connection
* connection for account
* @return Response with error code
*/
public static AionAuthResponse login(String name, String password, AionConnection connection)
{
Account account = loadAccount(name);
// Try to create new account
if(account == null && Config.ACCOUNT_AUTO_CREATION)
{
account = createAccount(name, password);
}
// If account not found and not created
if(account == null)
{
return AionAuthResponse.INVALID_PASSWORD;
}
// check for paswords beeing equals
if(!account.getPasswordHash().equals(AccountUtils.encodePassword(password)))
{
return AionAuthResponse.INVALID_PASSWORD;
}
// check for paswords beeing equals
if(account.getActivated() != 1)
{
return AionAuthResponse.INVALID_PASSWORD;
}
// If account expired
if(AccountTimeController.isAccountExpired(account))
{
return AionAuthResponse.TIME_EXPIRED;
}
// if account is banned
if(AccountTimeController.isAccountPenaltyActive(account))
{
return AionAuthResponse.BAN_IP;
}
// if account is restricted to some ip or mask
if(account.getIpForce() != null)
{
if(!NetworkUtils.checkIPMatching(account.getIpForce(), connection.getIP()))
{
return AionAuthResponse.BAN_IP;
}
}
// if ip is banned
if(BannedIpController.isBanned(connection.getIP()))
{
return AionAuthResponse.BAN_IP;
}
// Do not allow to login two times with same account
synchronized (AccountController.class)
{
if(GameServerTable.isAccountOnAnyGameServer(account))
{
GameServerTable.kickAccountFromGameServer(account);
return AionAuthResponse.ALREADY_LOGGED_IN;
}
// If someone is at loginserver, he should be disconnected
if(accountsOnLS.containsKey(account.getId()))
{
AionConnection aionConnection = accountsOnLS.remove(account.getId());
aionConnection.close(true);
return AionAuthResponse.ALREADY_LOGGED_IN;
}
else
{
connection.setAccount(account);
accountsOnLS.put(account.getId(), connection);
}
}
AccountTimeController.updateOnLogin(account);
// if everything was OK
getAccountDAO().updateLastIp(account.getId(), connection.getIP());
return AionAuthResponse.AUTHED;
}
/**
* Loads account from DB and returns it, or returns null if account was not loaded
* @param name acccount name
* @return loaded account or null
*/
public static Account loadAccount(String name)
{
Account account = getAccountDAO().getAccount(name);
if (account != null)
{
account.setAccountTime(getAccountTimeDAO().getAccountTime(account.getId()));
}
return account;
}
/**
* Creates new account and stores it in DB. Returns account object in case of success or null if failed
*
* @param name
* account name
* @param password
* account password
* @return account object or null
*/
public static Account createAccount(String name, String password)
{
String passwordHash = AccountUtils.encodePassword(password);
Account account = new Account();
account.setName(name);
account.setPasswordHash(passwordHash);
account.setAccessLevel((byte) 0);
account.setMembership((byte) 0);
account.setActivated((byte) 1);
if(getAccountDAO().insertAccount(account))
{
return account;
}
else
{
return null;
}
}
/**
* Returns {@link com.aionemu.loginserver.dao.AccountDAO}, just a shortcut
*
* @return {@link com.aionemu.loginserver.dao.AccountDAO}
*/
private static AccountDAO getAccountDAO()
{
return DAOManager.getDAO(AccountDAO.class);
}
/**
* Returns {@link com.aionemu.loginserver.dao.AccountTimeDAO}, just a shortcut
*
* @return {@link com.aionemu.loginserver.dao.AccountTimeDAO}
*/
private static AccountTimeDAO getAccountTimeDAO()
{
return DAOManager.getDAO(AccountTimeDAO.class);
}
}