2 * Copyright (C) 2005-2010 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 "ObjectDefines.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='%d'", accid
);
62 return AOR_NAME_NOT_EXIST
; // account doesn't exist
65 result
= CharacterDatabase
.PQuery("SELECT guid FROM characters WHERE account='%d'",accid
);
70 Field
*fields
= result
->Fetch();
71 uint32 guidlo
= fields
[0].GetUInt32();
72 uint64 guid
= MAKE_NEW_GUID(guidlo
, 0, HIGHGUID_PLAYER
);
74 // kick if player currently
75 ObjectAccessor::KickPlayer(guid
);
76 Player::DeleteFromDB(guid
, accid
, false); // no need to update realm characters
77 } while (result
->NextRow());
82 // table realm specific but common for all characters of account for realm
83 CharacterDatabase
.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid
);
85 loginDatabase
.BeginTransaction();
88 loginDatabase
.PExecute("DELETE FROM account WHERE id='%d'", accid
) &&
89 loginDatabase
.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid
);
91 loginDatabase
.CommitTransaction();
94 return AOR_DB_INTERNAL_ERROR
; // unexpected error;
99 AccountOpResult
AccountMgr::ChangeUsername(uint32 accid
, std::string new_uname
, std::string new_passwd
)
101 QueryResult
*result
= loginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%d'", accid
);
103 return AOR_NAME_NOT_EXIST
; // account doesn't exist
106 if(utf8length(new_uname
) > MAX_ACCOUNT_STR
)
107 return AOR_NAME_TOO_LONG
;
109 if(utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
110 return AOR_PASS_TOO_LONG
;
112 normalizeString(new_uname
);
113 normalizeString(new_passwd
);
115 std::string safe_new_uname
= new_uname
;
116 loginDatabase
.escape_string(safe_new_uname
);
118 if(!loginDatabase
.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname
.c_str(),
119 CalculateShaPassHash(new_uname
, new_passwd
).c_str(), accid
))
120 return AOR_DB_INTERNAL_ERROR
; // unexpected error
125 AccountOpResult
AccountMgr::ChangePassword(uint32 accid
, std::string new_passwd
)
127 std::string username
;
129 if(!GetName(accid
, username
))
130 return AOR_NAME_NOT_EXIST
; // account doesn't exist
132 if (utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
133 return AOR_PASS_TOO_LONG
;
135 normalizeString(new_passwd
);
137 // also reset s and v to force update at next realmd login
138 if(!loginDatabase
.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'",
139 CalculateShaPassHash(username
, new_passwd
).c_str(), accid
))
140 return AOR_DB_INTERNAL_ERROR
; // unexpected error
145 uint32
AccountMgr::GetId(std::string username
)
147 loginDatabase
.escape_string(username
);
148 QueryResult
*result
= loginDatabase
.PQuery("SELECT id FROM account WHERE username = '%s'", username
.c_str());
153 uint32 id
= (*result
)[0].GetUInt32();
159 AccountTypes
AccountMgr::GetSecurity(uint32 acc_id
)
161 QueryResult
*result
= loginDatabase
.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id
);
164 AccountTypes sec
= AccountTypes((*result
)[0].GetInt32());
172 bool AccountMgr::GetName(uint32 acc_id
, std::string
&name
)
174 QueryResult
*result
= loginDatabase
.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id
);
177 name
= (*result
)[0].GetCppString();
185 bool AccountMgr::CheckPassword(uint32 accid
, std::string passwd
)
187 std::string username
;
188 if(!GetName(accid
, username
))
191 normalizeString(passwd
);
193 QueryResult
*result
= loginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash='%s'", accid
, CalculateShaPassHash(username
, passwd
).c_str());
203 bool AccountMgr::normalizeString(std::string
& utf8str
)
205 wchar_t wstr_buf
[MAX_ACCOUNT_STR
+1];
207 size_t wstr_len
= MAX_ACCOUNT_STR
;
208 if(!Utf8toWStr(utf8str
,wstr_buf
,wstr_len
))
211 std::transform( &wstr_buf
[0], wstr_buf
+wstr_len
, &wstr_buf
[0], wcharToUpperOnlyLatin
);
213 return WStrToUtf8(wstr_buf
,wstr_len
,utf8str
);
216 std::string
AccountMgr::CalculateShaPassHash(std::string
& name
, std::string
& password
)
220 sha
.UpdateData(name
);
222 sha
.UpdateData(password
);
226 hexEncodeByteArray(sha
.GetDigest(), sha
.GetLength(), encoded
);