aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp85
-rw-r--r--src/server/game/Accounts/AccountMgr.h17
-rw-r--r--src/server/game/Accounts/RBAC.h8
-rw-r--r--src/server/game/Miscellaneous/Language.h13
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_account.cpp358
-rw-r--r--src/server/scripts/Commands/cs_learn.cpp8
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp60
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp7
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h3
-rw-r--r--src/server/worldserver/worldserver.conf.dist11
12 files changed, 511 insertions, 63 deletions
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index a9f178685d9..819a3b85fe6 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -34,21 +34,24 @@ AccountMgr::~AccountMgr()
ClearRBAC();
}
-AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password)
+AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "")
{
if (utf8length(username) > MAX_ACCOUNT_STR)
return AOR_NAME_TOO_LONG; // username's too long
normalizeString(username);
normalizeString(password);
+ normalizeString(email);
if (GetId(username))
- return AOR_NAME_ALREDY_EXIST; // username does already exist
+ return AOR_NAME_ALREADY_EXIST; // username does already exist
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
stmt->setString(0, username);
stmt->setString(1, CalculateShaPassHash(username, password));
+ stmt->setString(2, email);
+ stmt->setString(3, email);
LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail
@@ -202,6 +205,52 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass
return AOR_OK;
}
+AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail)
+{
+ std::string username;
+
+ if (!GetName(accountId, username))
+ return AOR_NAME_NOT_EXIST; // account doesn't exist
+
+ if (utf8length(newEmail) > MAX_EMAIL_STR)
+ return AOR_EMAIL_TOO_LONG;
+
+ normalizeString(username);
+ normalizeString(newEmail);
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL);
+
+ stmt->setString(0, newEmail);
+ stmt->setUInt32(1, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ return AOR_OK;
+}
+
+AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail)
+{
+ std::string username;
+
+ if (!GetName(accountId, username))
+ return AOR_NAME_NOT_EXIST; // account doesn't exist
+
+ if (utf8length(newEmail) > MAX_EMAIL_STR)
+ return AOR_EMAIL_TOO_LONG;
+
+ normalizeString(username);
+ normalizeString(newEmail);
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL);
+
+ stmt->setString(0, newEmail);
+ stmt->setUInt32(1, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ return AOR_OK;
+}
+
uint32 AccountMgr::GetId(std::string const& username)
{
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
@@ -245,6 +294,21 @@ bool AccountMgr::GetName(uint32 accountId, std::string& name)
return false;
}
+bool AccountMgr::GetEmail(uint32 accountId, std::string& email)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ email = (*result)[0].GetString();
+ return true;
+ }
+
+ return false;
+}
+
bool AccountMgr::CheckPassword(uint32 accountId, std::string password)
{
std::string username;
@@ -263,6 +327,23 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password)
return (result) ? true : false;
}
+bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail)
+{
+ std::string oldEmail;
+
+ // We simply return false for a non-existing email
+ if (!GetEmail(accountId, oldEmail))
+ return false;
+
+ normalizeString(oldEmail);
+ normalizeString(newEmail);
+
+ if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0)
+ return true;
+
+ return false;
+}
+
uint32 AccountMgr::GetCharactersCount(uint32 accountId)
{
// check character count
diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h
index 878ecde24f9..92c1e2292d0 100644
--- a/src/server/game/Accounts/AccountMgr.h
+++ b/src/server/game/Accounts/AccountMgr.h
@@ -27,12 +27,21 @@ enum AccountOpResult
AOR_OK,
AOR_NAME_TOO_LONG,
AOR_PASS_TOO_LONG,
- AOR_NAME_ALREDY_EXIST,
+ AOR_EMAIL_TOO_LONG,
+ AOR_NAME_ALREADY_EXIST,
AOR_NAME_NOT_EXIST,
AOR_DB_INTERNAL_ERROR
};
+enum PasswordChangeSecurity
+{
+ PW_NONE,
+ PW_EMAIL,
+ PW_RBAC
+};
+
#define MAX_ACCOUNT_STR 16
+#define MAX_EMAIL_STR 64
typedef std::map<uint32, RBACPermission*> RBACPermissionsContainer;
typedef std::map<uint32, RBACRole*> RBACRolesContainer;
@@ -48,16 +57,20 @@ class AccountMgr
~AccountMgr();
public:
- AccountOpResult CreateAccount(std::string username, std::string password);
+ AccountOpResult CreateAccount(std::string username, std::string password, std::string email);
static AccountOpResult DeleteAccount(uint32 accountId);
static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
+ static AccountOpResult ChangeEmail(uint32 accountId, std::string newEmail);
+ static AccountOpResult ChangeRegEmail(uint32 accountId, std::string newEmail);
static bool CheckPassword(uint32 accountId, std::string password);
+ static bool CheckEmail(uint32 accountId, std::string newEmail);
static uint32 GetId(std::string const& username);
static uint32 GetSecurity(uint32 accountId);
static uint32 GetSecurity(uint32 accountId, int32 realmId);
static bool GetName(uint32 accountId, std::string& name);
+ static bool GetEmail(uint32 accountId, std::string& email);
static uint32 GetCharactersCount(uint32 accountId);
static std::string CalculateShaPassHash(std::string const& name, std::string const& password);
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index be4356f6b54..ab8354554ec 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -96,6 +96,8 @@ enum RBACPermissions
RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR = 46,
RBAC_PERM_CHECK_FOR_LOWER_SECURITY = 47,
RBAC_PERM_COMMANDS_PINFO_CHECK_PERSONAL_DATA = 48,
+ RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE = 49,
+ RBAC_PERM_MAY_CHECK_OWN_EMAIL = 50,
// Leave some space for core permissions
RBAC_PERM_COMMAND_RBAC = 200,
RBAC_PERM_COMMAND_RBAC_ACC = 201,
@@ -160,8 +162,12 @@ enum RBACPermissions
RBAC_PERM_COMMAND_BF_SWITCH = 260,
RBAC_PERM_COMMAND_BF_TIMER = 261,
RBAC_PERM_COMMAND_BF_ENABLE = 262,
+ RBAC_PERM_COMMAND_ACCOUNT_EMAIL = 263,
+ RBAC_PERM_COMMAND_ACCOUNT_SET_SEC = 264,
+ RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL = 265,
+ RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_REGMAIL = 266,
- // custom permissions 1000+
+ // custom permissions 1000+
RBAC_PERM_MAX
};
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 772d5bcfb75..ce280a11fc3 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -811,6 +811,7 @@ enum TrinityStrings
LANG_PINFO_ACC_ACCOUNT = 714,
LANG_PINFO_ACC_LASTLOGIN = 716,
LANG_PINFO_ACC_OS = 749,
+ LANG_PINFO_ACC_REGMAILS = 879,
LANG_PINFO_ACC_IP = 752,
LANG_PINFO_CHR_LEVEL_LOW = 843,
LANG_PINFO_CHR_RACE = 844,
@@ -844,7 +845,17 @@ enum TrinityStrings
LANG_ARENA_INFO_MEMBERS = 869,
LANG_ARENA_LOOKUP = 870,
// = 871, see LANG_PINFO_CHR_LEVEL_HIGH
- // Room for in-game strings 872-999 not used
+ LANG_COMMAND_WRONGEMAIL = 872,
+ LANG_NEW_EMAILS_NOT_MATCH = 873,
+ LANG_COMMAND_EMAIL = 874,
+ LANG_EMAIL_TOO_LONG = 875,
+ LANG_COMMAND_NOTCHANGEEMAIL = 876,
+ LANG_OLD_EMAIL_IS_NEW_EMAIL = 877,
+ LANG_COMMAND_EMAIL_OUTPUT = 878,
+ // = 879, see LANG_PINFO_CHR_REGMAILS
+ LANG_ACCOUNT_SEC_TYPE = 880,
+ LANG_RBAC_EMAIL_REQUIRED = 881,
+ // Room for in-game strings 882-999 not used
// Level 4 (CLI only commands)
LANG_COMMAND_EXIT = 1000,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 12ec033dfa7..cf6ad3f9886 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1192,6 +1192,9 @@ void World::LoadConfigSettings(bool reload)
// DBC_ItemAttributes
m_bool_configs[CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES] = sConfigMgr->GetBoolDefault("DBC.EnforceItemAttributes", true);
+ // Accountpassword Secruity
+ m_int_configs[CONFIG_ACC_PASSCHANGESEC] = sConfigMgr->GetIntDefault("Account.PasswordChangeSecurity", 0);
+
// Max instances per hour
m_int_configs[CONFIG_MAX_INSTANCES_PER_HOUR] = sConfigMgr->GetIntDefault("AccountInstancesPerHour", 5);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index d4d9c4e2431..907491437c4 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -329,6 +329,7 @@ enum WorldIntConfigs
CONFIG_PACKET_SPOOF_POLICY,
CONFIG_PACKET_SPOOF_BANMODE,
CONFIG_PACKET_SPOOF_BANDURATION,
+ CONFIG_ACC_PASSCHANGESEC,
INT_CONFIG_VALUE_COUNT
};
diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp
index 42e33faee1c..467b74f4954 100644
--- a/src/server/scripts/Commands/cs_account.cpp
+++ b/src/server/scripts/Commands/cs_account.cpp
@@ -35,35 +35,43 @@ public:
ChatCommand* GetCommands() const OVERRIDE
{
+ static ChatCommand accountSetSecTable[] =
+ {
+ { "regmail", RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_REGMAIL, true, &HandleAccountSetRegEmailCommand, "", NULL },
+ { "email", RBAC_PERM_COMMAND_ACCOUNT_SET_SEC_EMAIL, true, &HandleAccountSetEmailCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
static ChatCommand accountSetCommandTable[] =
{
- { "addon", RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON, true, &HandleAccountSetAddonCommand, "", NULL },
- { "gmlevel", RBAC_PERM_COMMAND_ACCOUNT_SET_GMLEVEL, true, &HandleAccountSetGmLevelCommand, "", NULL },
- { "password", RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD, true, &HandleAccountSetPasswordCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "addon", RBAC_PERM_COMMAND_ACCOUNT_SET_ADDON, true, &HandleAccountSetAddonCommand, "", NULL },
+ { "sec", RBAC_PERM_COMMAND_ACCOUNT_SET_SEC, true, NULL, "", accountSetSecTable },
+ { "gmlevel", RBAC_PERM_COMMAND_ACCOUNT_SET_GMLEVEL, true, &HandleAccountSetGmLevelCommand, "", NULL },
+ { "password", RBAC_PERM_COMMAND_ACCOUNT_SET_PASSWORD, true, &HandleAccountSetPasswordCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
static ChatCommand accountLockCommandTable[] =
{
- { "country", RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY, true, &HandleAccountLockCountryCommand, "", NULL },
- { "ip", RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP, true, &HandleAccountLockIpCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "country", RBAC_PERM_COMMAND_ACCOUNT_LOCK_COUNTRY, true, &HandleAccountLockCountryCommand, "", NULL },
+ { "ip", RBAC_PERM_COMMAND_ACCOUNT_LOCK_IP, true, &HandleAccountLockIpCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
static ChatCommand accountCommandTable[] =
{
- { "addon", RBAC_PERM_COMMAND_ACCOUNT_ADDON, false, &HandleAccountAddonCommand, "", NULL },
- { "create", RBAC_PERM_COMMAND_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "", NULL },
- { "delete", RBAC_PERM_COMMAND_ACCOUNT_DELETE, true, &HandleAccountDeleteCommand, "", NULL },
- { "onlinelist", RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST, true, &HandleAccountOnlineListCommand, "", NULL },
- { "lock", RBAC_PERM_COMMAND_ACCOUNT_LOCK, false, NULL, "", accountLockCommandTable },
- { "set", RBAC_PERM_COMMAND_ACCOUNT_SET, true, NULL, "", accountSetCommandTable },
- { "password", RBAC_PERM_COMMAND_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "", NULL },
- { "", RBAC_PERM_COMMAND_ACCOUNT, false, &HandleAccountCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "addon", RBAC_PERM_COMMAND_ACCOUNT_ADDON, false, &HandleAccountAddonCommand, "", NULL },
+ { "create", RBAC_PERM_COMMAND_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "", NULL },
+ { "delete", RBAC_PERM_COMMAND_ACCOUNT_DELETE, true, &HandleAccountDeleteCommand, "", NULL },
+ { "email", RBAC_PERM_COMMAND_ACCOUNT_EMAIL, false, &HandleAccountEmailCommand, "", NULL },
+ { "onlinelist", RBAC_PERM_COMMAND_ACCOUNT_ONLINE_LIST, true, &HandleAccountOnlineListCommand, "", NULL },
+ { "lock", RBAC_PERM_COMMAND_ACCOUNT_LOCK, false, NULL, "", accountLockCommandTable },
+ { "set", RBAC_PERM_COMMAND_ACCOUNT_SET, true, NULL, "", accountSetCommandTable },
+ { "password", RBAC_PERM_COMMAND_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "", NULL },
+ { "", RBAC_PERM_COMMAND_ACCOUNT, false, &HandleAccountCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
{
- { "account", RBAC_PERM_COMMAND_ACCOUNT, true, NULL, "", accountCommandTable },
- { NULL, 0, false, NULL, "", NULL }
+ { "account", RBAC_PERM_COMMAND_ACCOUNT, true, NULL, "", accountCommandTable },
+ { NULL, 0, false, NULL, "", NULL }
};
return commandTable;
}
@@ -106,29 +114,35 @@ public:
if (!*args)
return false;
+ char* email;
+
///- %Parse the command line arguments
char* accountName = strtok((char*)args, " ");
char* password = strtok(NULL, " ");
+ if (!(email = strtok(NULL, " '")))
+ email = "";
+
if (!accountName || !password)
return false;
- AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password));
+ AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), std::string(email));
switch (result)
{
case AOR_OK:
handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName);
if (handler->GetSession())
{
- TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %d (IP: %s) Character:[%s] (GUID: %u) Change Password.",
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %d (IP: %s) Character:[%s] (GUID: %u) created Account %s (Email: '%s')",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
- handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
+ accountName, email);
}
break;
case AOR_NAME_TOO_LONG:
handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG);
handler->SetSentErrorMessage(true);
return false;
- case AOR_NAME_ALREDY_EXIST:
+ case AOR_NAME_ALREADY_EXIST:
handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
handler->SetSentErrorMessage(true);
return false;
@@ -338,6 +352,89 @@ public:
return false;
}
+ static bool HandleAccountEmailCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* oldEmail = strtok(NULL, " ");
+ char* password = strtok(NULL, " ");
+ char* email = strtok((char*)args, " ");
+ char* emailConfirmation = strtok(NULL, " ");
+
+ if (!oldEmail || !password || !email || !emailConfirmation)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (!AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(oldEmail)))
+ {
+ handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL);
+ handler->SetSentErrorMessage(true);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided email [%s] is not equal to registration email [%s].",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
+ email, oldEmail);
+ return false;
+ }
+
+ if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(password)))
+ {
+ handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
+ handler->SetSentErrorMessage(true);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
+ return false;
+ }
+
+ if (strcmp(email, oldEmail) == 0)
+ {
+ handler->SendSysMessage(LANG_OLD_EMAIL_IS_NEW_EMAIL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (strcmp(email, emailConfirmation) != 0)
+ {
+ handler->SendSysMessage(LANG_NEW_EMAILS_NOT_MATCH);
+ handler->SetSentErrorMessage(true);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change email, but the provided password is wrong.",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
+ return false;
+ }
+
+
+ AccountOpResult result = AccountMgr::ChangeEmail(handler->GetSession()->GetAccountId(), std::string(email));
+ switch (result)
+ {
+ case AOR_OK:
+ handler->SendSysMessage(LANG_COMMAND_EMAIL);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
+ oldEmail, email);
+ break;
+ case AOR_EMAIL_TOO_LONG:
+ handler->SendSysMessage(LANG_EMAIL_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->SendSysMessage(LANG_COMMAND_NOTCHANGEEMAIL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
+
static bool HandleAccountPasswordCommand(ChatHandler* handler, char const* args)
{
if (!*args)
@@ -347,9 +444,12 @@ public:
return false;
}
+ uint32 pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
+
char* oldPassword = strtok((char*)args, " ");
char* newPassword = strtok(NULL, " ");
char* passwordConfirmation = strtok(NULL, " ");
+ char* emailConfirmation = strtok(NULL, " ");
if (!oldPassword || !newPassword || !passwordConfirmation)
{
@@ -358,16 +458,37 @@ public:
return false;
}
+ if ((pwConfig == PW_EMAIL || pwConfig == PW_RBAC && handler->HasPermission(RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE)) && !emailConfirmation)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but entered no email at all. Has Perm: [%s]",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
+ handler->HasPermission(RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE) ? "Yes" : "No");
+ }
+
if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword)))
{
handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
handler->SetSentErrorMessage(true);
- TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password.",
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the provided old password is wrong.",
handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
return false;
}
+ if ((pwConfig == PW_EMAIL || pwConfig == PW_RBAC && handler->HasPermission(RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE)) // Either PW_EMAIL or PW_RBAC with the Permission
+ && !AccountMgr::CheckEmail(handler->GetSession()->GetAccountId(), std::string(emailConfirmation)))
+ {
+ handler->SendSysMessage(LANG_COMMAND_WRONGEMAIL);
+ handler->SetSentErrorMessage(true);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the entered email [%s] is wrong.",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(),
+ emailConfirmation);
+ }
+
if (strcmp(newPassword, passwordConfirmation) != 0)
{
handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
@@ -399,8 +520,40 @@ public:
static bool HandleAccountCommand(ChatHandler* handler, char const* /*args*/)
{
+ // GM Level
AccountTypes gmLevel = handler->GetSession()->GetSecurity();
handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmLevel));
+
+ // Security level required
+ bool hasRBAC = (handler->HasPermission(RBAC_PERM_EMAIL_CONFIRM_FOR_PASS_CHANGE) ? true : false);
+ uint32 pwConfig = sWorld->getIntConfig(CONFIG_ACC_PASSCHANGESEC); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
+
+ handler->PSendSysMessage(LANG_ACCOUNT_SEC_TYPE, (pwConfig == PW_NONE ? "Lowest level: No Email input required." :
+ pwConfig == PW_EMAIL ? "Highest level: Email input required." :
+ pwConfig == PW_RBAC ? "Special level: Your account may require email input depending on settings. That is the case if another lien is printed." :
+ "Unknown security level: Notify technician for details."));
+
+ // RBAC required display - is not displayed for console
+ if (pwConfig == PW_RBAC && handler->GetSession() && hasRBAC)
+ handler->PSendSysMessage(LANG_RBAC_EMAIL_REQUIRED);
+
+ // Email display if sufficient rights
+ if (handler->HasPermission(RBAC_PERM_MAY_CHECK_OWN_EMAIL))
+ {
+ std::string emailoutput;
+ uint32 accountId = handler->GetSession()->GetAccountId();
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ emailoutput = (*result)[0].GetString();
+ handler->PSendSysMessage(LANG_COMMAND_EMAIL_OUTPUT, emailoutput.c_str());
+ }
+ }
+
return true;
}
@@ -471,7 +624,11 @@ public:
static bool HandleAccountSetGmLevelCommand(ChatHandler* handler, char const* args)
{
if (!*args)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
return false;
+ }
std::string targetAccountName;
uint32 targetAccountId = 0;
@@ -524,7 +681,7 @@ public:
playerSecurity = SEC_CONSOLE;
// can set security level only for target with less security and to less security that we have
- // This is also reject self apply in fact
+ // This also restricts setting handler's own security.
targetSecurity = AccountMgr::GetSecurity(targetAccountId, gmRealmID);
if (targetSecurity >= playerSecurity || gm >= playerSecurity)
{
@@ -570,7 +727,11 @@ public:
static bool HandleAccountSetPasswordCommand(ChatHandler* handler, char const* args)
{
if (!*args)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
return false;
+ }
///- Get the command line arguments
char* account = strtok((char*)args, " ");
@@ -597,7 +758,7 @@ public:
}
/// can set password only for target with less security
- /// This is also reject self apply in fact
+ /// This also restricts setting handler's own password
if (handler->HasLowerSecurityAccount(NULL, targetAccountId, true))
return false;
@@ -630,6 +791,153 @@ public:
}
return true;
}
+
+ /// Set normal email for account
+ static bool HandleAccountSetEmailCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ ///- Get the command line arguments
+ char* account = strtok((char*)args, " ");
+ char* email = strtok(NULL, " ");
+ char* emailConfirmation = strtok(NULL, " ");
+
+ if (!account || !email || !emailConfirmation)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ std::string accountName = account;
+ if (!AccountMgr::normalizeString(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 targetAccountId = AccountMgr::GetId(accountName);
+ if (!targetAccountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ /// can set email only for target with less security
+ /// This also restricts setting handler's own email.
+ if (handler->HasLowerSecurityAccount(NULL, targetAccountId, true))
+ return false;
+
+ if (strcmp(email, emailConfirmation) != 0)
+ {
+ handler->SendSysMessage(LANG_NEW_EMAILS_NOT_MATCH);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ AccountOpResult result = AccountMgr::ChangeEmail(targetAccountId, email);
+ switch (result)
+ {
+ case AOR_OK:
+ handler->SendSysMessage(LANG_COMMAND_EMAIL);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "ChangeEmail: Account %s [Id: %u] had it's email changed to %s.",
+ accountName.c_str(), targetAccountId, email);
+ break;
+ case AOR_NAME_NOT_EXIST:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_EMAIL_TOO_LONG:
+ handler->SendSysMessage(LANG_EMAIL_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->SendSysMessage(LANG_COMMAND_NOTCHANGEEMAIL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Change registration email for account
+ static bool HandleAccountSetRegEmailCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ //- We do not want anything short of console to use this by default.
+ //- So we force that.
+ if (handler->GetSession())
+ return false;
+
+ ///- Get the command line arguments
+ char* account = strtok((char*)args, " ");
+ char* email = strtok(NULL, " ");
+ char* emailConfirmation = strtok(NULL, " ");
+
+ if (!account || !email || !emailConfirmation)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ std::string accountName = account;
+ if (!AccountMgr::normalizeString(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 targetAccountId = AccountMgr::GetId(accountName);
+ if (!targetAccountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ /// can set email only for target with less security
+ /// This also restricts setting handler's own email.
+ if (handler->HasLowerSecurityAccount(NULL, targetAccountId, true))
+ return false;
+
+ if (strcmp(email, emailConfirmation) != 0)
+ {
+ handler->SendSysMessage(LANG_NEW_EMAILS_NOT_MATCH);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ AccountOpResult result = AccountMgr::ChangeRegEmail(targetAccountId, email);
+ switch (result)
+ {
+ case AOR_OK:
+ handler->SendSysMessage(LANG_COMMAND_EMAIL);
+ TC_LOG_INFO(LOG_FILTER_CHARACTER, "ChangeRegEmail: Account %s [Id: %u] had it's Registration Email changed to %s.",
+ accountName.c_str(), targetAccountId, email);
+ break;
+ case AOR_NAME_NOT_EXIST:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_EMAIL_TOO_LONG:
+ handler->SendSysMessage(LANG_EMAIL_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->SendSysMessage(LANG_COMMAND_NOTCHANGEEMAIL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
};
void AddSC_account_commandscript()
diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp
index f2ff911fdf9..c165eebe3b5 100644
--- a/src/server/scripts/Commands/cs_learn.cpp
+++ b/src/server/scripts/Commands/cs_learn.cpp
@@ -339,8 +339,12 @@ public:
return true;
}
- static bool HandleLearnAllCraftsCommand(ChatHandler* handler, char const* /*args*/)
+ static bool HandleLearnAllCraftsCommand(ChatHandler* handler, char const* args)
{
+ Player* target;
+ if (!handler->extractPlayerTarget((char*)args, &target))
+ return false;
+
for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
{
SkillLineEntry const* skillInfo = sSkillLineStore.LookupEntry(i);
@@ -350,7 +354,7 @@ public:
if ((skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY) &&
skillInfo->canLink) // only prof. with recipes have
{
- HandleLearnSkillRecipesHelper(handler->GetSession()->GetPlayer(), skillInfo->id);
+ HandleLearnSkillRecipesHelper(target, skillInfo->id);
}
}
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index ee31542c53a..9c29e31af96 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -1520,20 +1520,21 @@ public:
* ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted)
* * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT
* * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN
- * * Uses OS: %s - Latency: %u ms - Email %s - VII. LANG_PINFO_ACC_OS
- * * Last IP: %u (Locked: %s) - VIII. LANG_PINFO_ACC_IP
- * * Level: %u (%u/%u XP (%u XP left) - IX. LANG_PINFO_CHR_LEVEL
- * * Race: %s %s, Class %s - X. LANG_PINFO_CHR_RACE
- * * Alive ?: %s - XI. LANG_PINFO_CHR_ALIVE
- * * Phase: %s - XII. LANG_PINFO_CHR_PHASE (if not GM)
- * * Money: %ug%us%uc - XIII. LANG_PINFO_CHR_MONEY
- * * Map: %s, Area: %s - XIV. LANG_PINFO_CHR_MAP
- * * Guild: %s (Id: %u) - XV. LANG_PINFO_CHR_GUILD (if in guild)
- * ** Rank: %s - XVI. LANG_PINFO_CHR_GUILD_RANK (if in guild)
- * ** Note: %s - XVII. LANG_PINFO_CHR_GUILD_NOTE (if in guild and has note)
- * ** O. Note: %s - XVIII.LANG_PINFO_CHR_GUILD_ONOTE (if in guild and has officer note)
- * * Played time: %s - XIX. LANG_PINFO_CHR_PLAYEDTIME
- * * Mails: %u Read/%u Total - XX. LANG_PINFO_CHR_MAILS (if has mails)
+ * * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS
+ * * Registration Email: %s - Email: %s - VIII. LANG_PINFO_ACC_REGMAILS
+ * * Last IP: %u (Locked: %s) - IX. LANG_PINFO_ACC_IP
+ * * Level: %u (%u/%u XP (%u XP left) - X. LANG_PINFO_CHR_LEVEL
+ * * Race: %s %s, Class %s - XI. LANG_PINFO_CHR_RACE
+ * * Alive ?: %s - XII. LANG_PINFO_CHR_ALIVE
+ * * Phase: %s - XIII. LANG_PINFO_CHR_PHASE (if not GM)
+ * * Money: %ug%us%uc - XIV. LANG_PINFO_CHR_MONEY
+ * * Map: %s, Area: %s - XV. LANG_PINFO_CHR_MAP
+ * * Guild: %s (Id: %u) - XVI. LANG_PINFO_CHR_GUILD (if in guild)
+ * ** Rank: %s - XVII. LANG_PINFO_CHR_GUILD_RANK (if in guild)
+ * ** Note: %s - XVIII.LANG_PINFO_CHR_GUILD_NOTE (if in guild and has note)
+ * ** O. Note: %s - XVIX. LANG_PINFO_CHR_GUILD_ONOTE (if in guild and has officer note)
+ * * Played time: %s - XX. LANG_PINFO_CHR_PLAYEDTIME
+ * * Mails: %u Read/%u Total - XXI. LANG_PINFO_CHR_MAILS (if has mails)
*
* Not all of them can be moved to the top. These should
* place the most important ones to the head, though.
@@ -1546,6 +1547,7 @@ public:
uint32 accId = 0;
uint32 lowguid = GUID_LOPART(targetGuid);
std::string eMail = handler->GetTrinityString(LANG_ERROR);
+ std::string regMail = handler->GetTrinityString(LANG_ERROR);
uint32 security = 0;
std::string lastIp = handler->GetTrinityString(LANG_ERROR);
uint8 locked = 0;
@@ -1666,8 +1668,9 @@ public:
(!handler->GetSession() || handler->GetSession()->GetSecurity() >= AccountTypes(security)))
{
eMail = fields[2].GetString();
- lastIp = fields[3].GetString();
- lastLogin = fields[4].GetString();
+ regMail = fields[3].GetString();
+ lastIp = fields[4].GetString();
+ lastLogin = fields[5].GetString();
uint32 ip = inet_addr(lastIp.c_str());
EndianConvertReverse(ip);
@@ -1689,12 +1692,12 @@ public:
lastIp = "Unauthorized";
lastLogin = "Unauthorized";
}
- muteTime = fields[5].GetUInt64();
- muteReason = fields[6].GetString();
- muteBy = fields[7].GetString();
- failedLogins = fields[8].GetUInt32();
- locked = fields[9].GetUInt8();
- OS = fields[10].GetString();
+ muteTime = fields[6].GetUInt64();
+ muteReason = fields[7].GetString();
+ muteBy = fields[8].GetString();
+ failedLogins = fields[9].GetUInt32();
+ locked = fields[10].GetUInt8();
+ OS = fields[11].GetString();
}
// Creates a chat link to the character. Returns nameLink
@@ -1783,8 +1786,11 @@ public:
// Output VI. LANG_PINFO_ACC_LASTLOGIN
handler->PSendSysMessage(LANG_PINFO_ACC_LASTLOGIN, lastLogin.c_str(), failedLogins);
- // Output VIII. LANG_PINFO_ACC_OS
- handler->PSendSysMessage(LANG_PINFO_ACC_OS, OS.c_str(), latency, eMail.c_str());
+ // Output VII. LANG_PINFO_ACC_OS
+ handler->PSendSysMessage(LANG_PINFO_ACC_OS, OS.c_str(), latency);
+
+ // Output VIII. LANG_PINFO_ACC_REGMAILS
+ handler->PSendSysMessage(LANG_PINFO_ACC_REGMAILS, regMail.c_str(), eMail.c_str());
// Output IX. LANG_PINFO_ACC_IP
handler->PSendSysMessage(LANG_PINFO_ACC_IP, lastIp.c_str(), locked ? "Yes" : "No");
@@ -1828,7 +1834,7 @@ public:
if (target)
handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->name[locale], (!zoneName.empty() ? zoneName.c_str() : "<Unknown>"), (!areaName.empty() ? areaName.c_str() : "<Unknown>"));
- // Output XVII. - XX. if they are not empty
+ // Output XVII. - XVIX. if they are not empty
if (!guildName.empty())
{
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD, guildName.c_str(), guildId);
@@ -1839,7 +1845,7 @@ public:
handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_ONOTE, officeNote.c_str());
}
- // Output XXI. LANG_PINFO_CHR_PLAYEDTIME
+ // Output XX. LANG_PINFO_CHR_PLAYEDTIME
handler->PSendSysMessage(LANG_PINFO_CHR_PLAYEDTIME, (secsToTimeString(totalPlayerTime, true, true)).c_str());
// Mail Data - an own query, because it may or may not be useful.
@@ -1861,7 +1867,7 @@ public:
// ... we have to convert it from Char to int. We can use totalmail as it is
rmailint = atol(readmail.c_str());
- // Output XXII. LANG_INFO_CHR_MAILS if at least one mail is given
+ // Output XXI. LANG_INFO_CHR_MAILS if at least one mail is given
if (totalmail >= 1)
handler->PSendSysMessage(LANG_PINFO_CHR_MAILS, rmailint, totalmail);
}
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index 26940c8a599..6e01e8f515a 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -56,7 +56,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
- PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, reg_mail, email, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_SYNCH);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
@@ -64,6 +64,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_INS_LOG, "INSERT INTO logs (time, realm, type, level, string) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_USERNAME, "UPDATE account SET v = 0, s = 0, username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_PASSWORD, "UPDATE account SET v = 0, s = 0, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_EMAIL, "UPDATE account SET email = ? WHERE id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_REG_EMAIL, "UPDATE account SET reg_mail = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
@@ -79,7 +81,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_CHECK_PASSWORD, "SELECT 1 FROM account WHERE id = ? AND sha_pass_hash = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT 1 FROM account WHERE username = ? AND sha_pass_hash = ?", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby, a.failed_logins, a.locked, a.OS FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.reg_mail, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby, a.failed_logins, a.locked, a.OS FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM account_banned WHERE id = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO, "SELECT a.username, a.last_ip, aa.gmlevel, a.expansion FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.id = ?", CONNECTION_SYNCH);
@@ -92,6 +94,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 97cf91fc178..47fa48c6ada 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -84,6 +84,8 @@ enum LoginDatabaseStatements
LOGIN_INS_LOG,
LOGIN_UPD_USERNAME,
LOGIN_UPD_PASSWORD,
+ LOGIN_UPD_EMAIL,
+ LOGIN_UPD_REG_EMAIL,
LOGIN_UPD_MUTE_TIME,
LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP,
@@ -112,6 +114,7 @@ enum LoginDatabaseStatements
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_IP2NATION_COUNTRY,
LOGIN_SEL_AUTOBROADCAST,
+ LOGIN_GET_EMAIL_BY_ID,
LOGIN_SEL_ACCOUNT_ACCESS_BY_ID,
LOGIN_SEL_RBAC_ACCOUNT_GROUPS,
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index a98a4e61448..018cd309805 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1132,6 +1132,15 @@ AccountInstancesPerHour = 5
RBAC.DefaultGroups = ""
#
+# Account.PasswordChangeSecurity
+# Description: Controls how secure you want the password changes to be.
+# Default: 2 - RBAC (RBAC en- or disables Email confirmation per group)
+# 1 - Email (Email confirmation necessary)
+# 0 - None (Just Old and new password comparision. Default.)
+
+Account.PasswordChangeSecurity = 0
+
+#
###################################################################################################
###################################################################################################
@@ -2829,4 +2838,4 @@ PacketSpoof.BanMode = 0
PacketSpoof.BanDuration = 86400
#
-################################################################################################### \ No newline at end of file
+###################################################################################################