2 * Copyright (C) 2005-2009 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"
23 #include "Policies/SingletonImp.h"
25 #include "Auth/Sha1.h"
27 extern DatabaseType loginDatabase
;
29 INSTANTIATE_SINGLETON_1(AccountMgr
);
31 AccountMgr::AccountMgr()
34 AccountMgr::~AccountMgr()
37 AccountOpResult
AccountMgr::CreateAccount(std::string username
, std::string password
)
39 if(utf8length(username
) > MAX_ACCOUNT_STR
)
40 return AOR_NAME_TOO_LONG
; // username's too long
42 normalizeString(username
);
43 normalizeString(password
);
47 return AOR_NAME_ALREDY_EXIST
; // username does already exist
50 if(!loginDatabase
.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", username
.c_str(), CalculateShaPassHash(username
, password
).c_str()))
51 return AOR_DB_INTERNAL_ERROR
; // unexpected error
52 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");
54 return AOR_OK
; // everything's fine
57 AccountOpResult
AccountMgr::DeleteAccount(uint32 accid
)
59 QueryResult
*result
= loginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%d'", accid
);
61 return AOR_NAME_NOT_EXIST
; // account doesn't exist
64 result
= CharacterDatabase
.PQuery("SELECT guid FROM characters WHERE account='%d'",accid
);
69 Field
*fields
= result
->Fetch();
70 uint32 guidlo
= fields
[0].GetUInt32();
71 uint64 guid
= MAKE_NEW_GUID(guidlo
, 0, HIGHGUID_PLAYER
);
73 // kick if player currently
74 if(Player
* p
= ObjectAccessor::GetObjectInWorld(guid
, (Player
*)NULL
))
76 WorldSession
* s
= p
->GetSession();
77 s
->KickPlayer(); // mark session to remove at next session list update
78 s
->LogoutPlayer(false); // logout player without waiting next session list update
81 Player::DeleteFromDB(guid
, accid
, false); // no need to update realm characters
82 } while (result
->NextRow());
87 // table realm specific but common for all characters of account for realm
88 CharacterDatabase
.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid
);
90 loginDatabase
.BeginTransaction();
93 loginDatabase
.PExecute("DELETE FROM account WHERE id='%d'", accid
) &&
94 loginDatabase
.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid
);
96 loginDatabase
.CommitTransaction();
99 return AOR_DB_INTERNAL_ERROR
; // unexpected error;
104 AccountOpResult
AccountMgr::ChangeUsername(uint32 accid
, std::string new_uname
, std::string new_passwd
)
106 QueryResult
*result
= loginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%d'", accid
);
108 return AOR_NAME_NOT_EXIST
; // account doesn't exist
111 if(utf8length(new_uname
) > MAX_ACCOUNT_STR
)
112 return AOR_NAME_TOO_LONG
;
114 if(utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
115 return AOR_PASS_TOO_LONG
;
117 normalizeString(new_uname
);
118 normalizeString(new_passwd
);
120 std::string safe_new_uname
= new_uname
;
121 loginDatabase
.escape_string(safe_new_uname
);
123 if(!loginDatabase
.PExecute("UPDATE account SET v='0',s='0',username='%s',sha_pass_hash='%s' WHERE id='%d'", safe_new_uname
.c_str(),
124 CalculateShaPassHash(new_uname
, new_passwd
).c_str(), accid
))
125 return AOR_DB_INTERNAL_ERROR
; // unexpected error
130 AccountOpResult
AccountMgr::ChangePassword(uint32 accid
, std::string new_passwd
)
132 std::string username
;
134 if(!GetName(accid
, username
))
135 return AOR_NAME_NOT_EXIST
; // account doesn't exist
137 if (utf8length(new_passwd
) > MAX_ACCOUNT_STR
)
138 return AOR_PASS_TOO_LONG
;
140 normalizeString(new_passwd
);
142 // also reset s and v to force update at next realmd login
143 if(!loginDatabase
.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'",
144 CalculateShaPassHash(username
, new_passwd
).c_str(), accid
))
145 return AOR_DB_INTERNAL_ERROR
; // unexpected error
150 uint32
AccountMgr::GetId(std::string username
)
152 loginDatabase
.escape_string(username
);
153 QueryResult
*result
= loginDatabase
.PQuery("SELECT id FROM account WHERE username = '%s'", username
.c_str());
158 uint32 id
= (*result
)[0].GetUInt32();
164 uint32
AccountMgr::GetSecurity(uint32 acc_id
)
166 QueryResult
*result
= loginDatabase
.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id
);
169 uint32 sec
= (*result
)[0].GetUInt32();
177 bool AccountMgr::GetName(uint32 acc_id
, std::string
&name
)
179 QueryResult
*result
= loginDatabase
.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id
);
182 name
= (*result
)[0].GetCppString();
190 bool AccountMgr::CheckPassword(uint32 accid
, std::string passwd
)
192 std::string username
;
193 if(!GetName(accid
, username
))
196 normalizeString(passwd
);
198 QueryResult
*result
= loginDatabase
.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash='%s'", accid
, CalculateShaPassHash(username
, passwd
).c_str());
208 bool AccountMgr::normalizeString(std::string
& utf8str
)
210 wchar_t wstr_buf
[MAX_ACCOUNT_STR
+1];
212 size_t wstr_len
= MAX_ACCOUNT_STR
;
213 if(!Utf8toWStr(utf8str
,wstr_buf
,wstr_len
))
216 std::transform( &wstr_buf
[0], wstr_buf
+wstr_len
, &wstr_buf
[0], wcharToUpperOnlyLatin
);
218 return WStrToUtf8(wstr_buf
,wstr_len
,utf8str
);
221 std::string
AccountMgr::CalculateShaPassHash(std::string
& name
, std::string
& password
)
225 sha
.UpdateData(name
);
227 sha
.UpdateData(password
);
231 hexEncodeByteArray(sha
.GetDigest(), sha
.GetLength(), encoded
);