2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "AccountMgr.h"
20 #include "Database/DatabaseEnv.h"
21 #include "ObjectAccessor.h"
22 #include "ObjectGuid.h"
24 #include "Policies/SingletonImp.h"
26 #include "Auth/Sha1.h"
28 extern DatabaseType LoginDatabase
;
30 INSTANTIATE_SINGLETON_1(AccountMgr
);
32 AccountMgr::AccountMgr()
35 AccountMgr::~AccountMgr()
38 AccountOpResult
AccountMgr::CreateAccount(std::string username
, std::string password
)
40 if (utf8length(username
) > MAX_ACCOUNT_STR
)
41 return AOR_NAME_TOO_LONG
; // username's too long
43 normalizeString(username
);
44 normalizeString(password
);
48 return AOR_NAME_ALREDY_EXIST
; // username does already exist
51 if (!LoginDatabase
.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username
.c_str(), CalculateShaPassHash(username
, password
).c_str()))
52 return AOR_DB_INTERNAL_ERROR
; // unexpected error
53 LoginDatabase
.Execute("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");
55 return AOR_OK
; // everything's fine
58 AccountOpResult
AccountMgr::DeleteAccount(uint32 accid
)
60 QueryResult
* result
= LoginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%u'", accid
);
62 return AOR_NAME_NOT_EXIST
; // account doesn't exist
65 // existing characters list
66 result
= CharacterDatabase
.PQuery("SELECT guid FROM characters WHERE account='%u'", accid
);
71 Field
* fields
= result
->Fetch();
72 uint32 guidlo
= fields
[0].GetUInt32();
73 ObjectGuid guid
= ObjectGuid(HIGHGUID_PLAYER
, guidlo
);
75 // kick if player currently
76 ObjectAccessor::KickPlayer(guid
);
77 Player::DeleteFromDB(guid
, accid
, false); // no need to update realm characters
79 while (result
->NextRow());
84 // table realm specific but common for all characters of account for realm
85 CharacterDatabase
.PExecute("DELETE FROM character_tutorial WHERE account = '%u'", accid
);
87 LoginDatabase
.BeginTransaction();
90 LoginDatabase
.PExecute("DELETE FROM account WHERE id='%u'", accid
) &&
91 LoginDatabase
.PExecute("DELETE FROM account_access WHERE id ='%d'", accid
) &&
92 LoginDatabase
.PExecute("DELETE FROM realmcharacters WHERE acctid='%u'", accid
);
94 LoginDatabase
.CommitTransaction();
97 return AOR_DB_INTERNAL_ERROR
; // unexpected error;
102 AccountOpResult
AccountMgr::ChangeUsername(uint32 accid
, std::string new_uname
, std::string new_passwd
)
104 QueryResult
* result
= LoginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%u'", accid
);
106 return AOR_NAME_NOT_EXIST
; // account doesn't exist
109 if (utf8length(new_uname
) > MAX_ACCOUNT_STR
)
110 return AOR_NAME_TOO_LONG
;
112 if (utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
113 return AOR_PASS_TOO_LONG
;
115 normalizeString(new_uname
);
116 normalizeString(new_passwd
);
118 std::string safe_new_uname
= new_uname
;
119 LoginDatabase
.escape_string(safe_new_uname
);
121 if (!LoginDatabase
.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%u'", safe_new_uname
.c_str(),
122 CalculateShaPassHash(new_uname
, new_passwd
).c_str(), accid
))
123 return AOR_DB_INTERNAL_ERROR
; // unexpected error
128 AccountOpResult
AccountMgr::ChangePassword(uint32 accid
, std::string new_passwd
)
130 std::string username
;
132 if (!GetName(accid
, username
))
133 return AOR_NAME_NOT_EXIST
; // account doesn't exist
135 if (utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
136 return AOR_PASS_TOO_LONG
;
138 normalizeString(new_passwd
);
140 // also reset s and v to force update at next realmd login
141 if (!LoginDatabase
.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%u'",
142 CalculateShaPassHash(username
, new_passwd
).c_str(), accid
))
143 return AOR_DB_INTERNAL_ERROR
; // unexpected error
148 uint32
AccountMgr::GetId(std::string username
)
150 LoginDatabase
.escape_string(username
);
151 QueryResult
* result
= LoginDatabase
.PQuery("SELECT id FROM account WHERE username = '%s'", username
.c_str());
156 uint32 id
= (*result
)[0].GetUInt32();
162 AccountTypes
AccountMgr::GetSecurity(uint32 acc_id
)
164 QueryResult
* result
= LoginDatabase
.PQuery("SELECT gmlevel FROM account_access WHERE id = '%u'", acc_id
);
167 AccountTypes sec
= AccountTypes((*result
)[0].GetInt32());
175 bool AccountMgr::GetName(uint32 acc_id
, std::string
& name
)
177 QueryResult
* result
= LoginDatabase
.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id
);
180 name
= (*result
)[0].GetCppString();
188 uint32
AccountMgr::GetCharactersCount(uint32 acc_id
)
190 // check character count
191 QueryResult
* result
= CharacterDatabase
.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%u'", acc_id
);
194 Field
* fields
= result
->Fetch();
195 uint32 charcount
= fields
[0].GetUInt32();
203 bool AccountMgr::CheckPassword(uint32 accid
, std::string passwd
)
205 std::string username
;
206 if (!GetName(accid
, username
))
209 normalizeString(passwd
);
211 QueryResult
* result
= LoginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%u' AND sha_pass_hash='%s'", accid
, CalculateShaPassHash(username
, passwd
).c_str());
221 bool AccountMgr::normalizeString(std::string
& utf8str
)
223 wchar_t wstr_buf
[MAX_ACCOUNT_STR
+ 1];
225 size_t wstr_len
= MAX_ACCOUNT_STR
;
226 if (!Utf8toWStr(utf8str
, wstr_buf
, wstr_len
))
229 std::transform(&wstr_buf
[0], wstr_buf
+ wstr_len
, &wstr_buf
[0], wcharToUpperOnlyLatin
);
231 return WStrToUtf8(wstr_buf
, wstr_len
, utf8str
);
234 std::string
AccountMgr::CalculateShaPassHash(std::string
& name
, std::string
& password
)
238 sha
.UpdateData(name
);
240 sha
.UpdateData(password
);
244 hexEncodeByteArray(sha
.GetDigest(), sha
.GetLength(), encoded
);