aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAscathor <Break_the_Chain@web.de>2013-07-25 01:49:04 +0200
committerAscathor <Break_the_Chain@web.de>2013-09-01 21:21:16 +0200
commit722a6c143ae9adbab020df4bae4495e612a677ee (patch)
tree834d1e2feebf52c756325902f0abb6dc8291f514 /src
parent79d1b7f5439d9f8dacd49847e1e173c8b969171a (diff)
Core/Account: Make account password change security variable and various changes
Settings within worldserver.conf: Three settings for secruity level: 0 - None - No change to current system 1 - Email - Always requires the email entered on registration for confirming. 2 - RBAC - Groups applied with the RBAC role always require the email entered on registration for confirming. RBAC default to every group. Changed some logs to make it more clear what is going on at all. Emails may now no longer exceed 64 chars. Current email is used as regmail. On account creation, two emails are saved. Registration email and normal email. Normal email is relevant afterwards. Registration email can be changed by console ONLY. Includes new commands and changes to existing ones: .account fulfills several new functions: * Still prints GM Level. * If account has permission, it displays the current email. This is not defaulted to any group. * Security level is displayed. Also displays if user has RBAC perm if RBAC security mode is selected .account email allows user to change email with sufficient confirmation .account set sec email allows higher sec with higher sec than account to change the normal email. Registrationemail remains untouched here. .account set sec regmail allows console to change registration email. .pinfo now displays the registration and normal mail. Also fixes .learn all crafts. Closes #10558
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
+###################################################################################################