00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifdef HAVE_MYSQLPP
00017
00018 #include "forum_user_handler.hpp"
00019 #include "../hash.hpp"
00020 #include "log.hpp"
00021 #include "config.hpp"
00022
00023 #include <stdlib.h>
00024 #include <sstream>
00025
00026 static lg::log_domain log_mp_user_handler("mp_user_handler");
00027 #define ERR_UH LOG_STREAM(err, log_mp_user_handler)
00028 #define WRN_UH LOG_STREAM(warn, log_mp_user_handler)
00029 #define LOG_UH LOG_STREAM(info, log_mp_user_handler)
00030 #define DBG_UH LOG_STREAM(debug, log_mp_user_handler)
00031
00032 namespace {
00033 const int USER_INACTIVE = 1;
00034 const int USER_IGNORE = 2;
00035 }
00036
00037 fuh::fuh(const config& c) {
00038 db_name_ = c["db_name"].str();
00039 db_host_ = c["db_host"].str();
00040 db_user_ = c["db_user"].str();
00041 db_password_ = c["db_password"].str();
00042 db_users_table_ = c["db_users_table"].str();
00043 db_extra_table_ = c["db_extra_table"].str();
00044
00045 conn = mysql_init(NULL);
00046
00047 if(!conn || !mysql_real_connect(conn, db_host_.c_str(), db_user_.c_str(), db_password_.c_str(), db_name_.c_str(), 0, NULL, 0)) {
00048 ERR_UH << "Could not connect to database: " << mysql_errno(conn) << ": " << mysql_error(conn) << std::endl;
00049 }
00050 }
00051
00052 fuh::~fuh() {
00053 mysql_close(conn);
00054 }
00055
00056 void fuh::add_user(const std::string& , const std::string& , const std::string& ) {
00057 throw error("For now please register at http://forum.wesnoth.org");
00058 }
00059
00060 void fuh::remove_user(const std::string& ) {
00061 throw error("'Dropping your nickname is currently impossible");
00062 }
00063
00064
00065 bool fuh::login(const std::string& name, const std::string& password, const std::string& seed) {
00066
00067
00068
00069 std::string hash;
00070
00071 try {
00072 hash = get_hash(name);
00073 } catch (error& e) {
00074 ERR_UH << "Could not retrieve hash for user '" << name << "' :" << e.message << std::endl;
00075 return false;
00076 }
00077
00078
00079 if(!util::is_valid_hash(hash)) {
00080 ERR_UH << "Invalid hash for user '" << name << "'" << std::endl;
00081 return false;
00082 }
00083
00084 std::string valid_hash = util::create_hash(hash.substr(12,34), seed);
00085
00086 if(password == valid_hash) return true;
00087
00088 return false;
00089 }
00090
00091 std::string fuh::create_pepper(const std::string& name) {
00092
00093
00094 if(!(user_exists(name))) {
00095 return "";
00096 }
00097
00098 std::string hash;
00099
00100 try {
00101 hash = get_hash(name);
00102 } catch (error& e) {
00103 ERR_UH << "Could not retrieve hash for user '" << name << "' :" << e.message << std::endl;
00104 return "";
00105 }
00106
00107 if(!util::is_valid_hash(hash)) return "";
00108
00109 return hash.substr(0,12);
00110 }
00111
00112 void fuh::user_logged_in(const std::string& name) {
00113 set_lastlogin(name, time(NULL));
00114 }
00115
00116 bool fuh::user_exists(const std::string& name) {
00117
00118
00119 try {
00120 return mysql_fetch_row(db_query("SELECT username FROM " + db_users_table_ + " WHERE UPPER(username)=UPPER('" + name + "')"));
00121 } catch (error& e) {
00122 ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl;
00123
00124 return false;
00125 }
00126 }
00127
00128 bool fuh::user_is_active(const std::string& name) {
00129 try {
00130 int user_type = atoi(get_detail_for_user(name, "user_type").c_str());
00131 return user_type != USER_INACTIVE && user_type != USER_IGNORE;
00132 } catch (error& e) {
00133 ERR_UH << "Could not retrieve user type for user '" << name << "' :" << e.message << std::endl;
00134 return false;
00135 }
00136 }
00137
00138 bool fuh::user_is_moderator(const std::string& name) {
00139
00140 if(!user_exists(name)) return false;
00141
00142 try {
00143 return get_writable_detail_for_user(name, "user_is_moderator") == "1";
00144 } catch (error& e) {
00145 ERR_UH << "Could not query user_is_moderator for user '" << name << "' :" << e.message << std::endl;
00146
00147 return false;
00148 }
00149 }
00150
00151 void fuh::set_is_moderator(const std::string& name, const bool& is_moderator) {
00152
00153 if(!user_exists(name)) return;
00154
00155 try {
00156 write_detail(name, "user_is_moderator", is_moderator ? "1" : "0");
00157 } catch (error& e) {
00158 ERR_UH << "Could not set is_moderator for user '" << name << "' :" << e.message << std::endl;
00159 }
00160 }
00161
00162 void fuh::password_reminder(const std::string& ) {
00163 throw error("For now please use the password recovery "
00164 "function provided at http://forum.wesnoth.org");
00165 }
00166
00167 std::string fuh::user_info(const std::string& name) {
00168 if(!user_exists(name)) {
00169 throw error("No user with the name '" + name + "' exists.");
00170 }
00171
00172 time_t reg_date = get_registrationdate(name);
00173 time_t ll_date = get_lastlogin(name);
00174
00175 std::string reg_string = ctime(®_date);
00176 std::string ll_string;
00177
00178 if(ll_date) {
00179 ll_string = ctime(&ll_date);
00180 } else {
00181 ll_string = "Never";
00182 }
00183
00184 std::stringstream info;
00185 info << "Name: " << name << "\n"
00186 << "Registered: " << reg_string
00187 << "Last login: " << ll_string;
00188 if(!user_is_active(name)) {
00189 info << "This account is currently inactive.\n";
00190 }
00191
00192 return info.str();
00193 }
00194
00195 void fuh::set_user_detail(const std::string& , const std::string& , const std::string& ) {
00196 throw error("For now this is a 'read-only' user_handler");
00197 }
00198
00199 std::string fuh::get_valid_details() {
00200 return "For now this is a 'read-only' user_handler";
00201 }
00202
00203 std::string fuh::get_hash(const std::string& user) {
00204 try {
00205 return get_detail_for_user(user, "user_password");
00206 } catch (error& e) {
00207 ERR_UH << "Could not retrieve password for user '" << user << "' :" << e.message << std::endl;
00208 return time_t(0);
00209 }
00210 }
00211
00212 std::string fuh::get_mail(const std::string& user) {
00213 try {
00214 return get_detail_for_user(user, "user_email");
00215 } catch (error& e) {
00216 ERR_UH << "Could not retrieve email for user '" << user << "' :" << e.message << std::endl;
00217 return time_t(0);
00218 }
00219 }
00220
00221 time_t fuh::get_lastlogin(const std::string& user) {
00222 try {
00223 int time_int = atoi(get_writable_detail_for_user(user, "user_lastvisit").c_str());
00224 return time_t(time_int);
00225 } catch (error& e) {
00226 ERR_UH << "Could not retrieve last visit for user '" << user << "' :" << e.message << std::endl;
00227 return time_t(0);
00228 }
00229 }
00230
00231 time_t fuh::get_registrationdate(const std::string& user) {
00232 try {
00233 int time_int = atoi(get_detail_for_user(user, "user_regdate").c_str());
00234 return time_t(time_int);
00235 } catch (error& e) {
00236 ERR_UH << "Could not retrieve registration date for user '" << user << "' :" << e.message << std::endl;
00237 return time_t(0);
00238 }
00239 }
00240
00241 void fuh::set_lastlogin(const std::string& user, const time_t& lastlogin) {
00242
00243 std::stringstream ss;
00244 ss << lastlogin;
00245
00246 try {
00247 write_detail(user, "user_lastvisit", ss.str());
00248 } catch (error& e) {
00249 ERR_UH << "Could not set last visit for user '" << user << "' :" << e.message << std::endl;
00250 }
00251 }
00252
00253 MYSQL_RES* fuh::db_query(const std::string& sql) {
00254 if(mysql_query(conn, sql.c_str())) {
00255 WRN_UH << "not connected to database, reconnecting..." << std::endl;
00256
00257 if(!mysql_real_connect(conn, db_host_.c_str(), db_user_.c_str(), db_password_.c_str(), db_name_.c_str(), 0, NULL, 0)
00258 || mysql_query(conn, sql.c_str())) {
00259 ERR_UH << "Could not connect to database: " << mysql_errno(conn) << ": " << mysql_error(conn) << std::endl;
00260 throw error("Error querying database.");
00261 }
00262 }
00263 return mysql_store_result(conn);
00264 }
00265
00266 std::string fuh::db_query_to_string(const std::string& sql) {
00267 return std::string(mysql_fetch_row(db_query(sql))[0]);
00268 }
00269
00270
00271 std::string fuh::get_detail_for_user(const std::string& name, const std::string& detail) {
00272 return db_query_to_string("SELECT " + detail + " FROM " + db_users_table_ + " WHERE UPPER(username)=UPPER('" + name + "')");
00273 }
00274
00275 std::string fuh::get_writable_detail_for_user(const std::string& name, const std::string& detail) {
00276 if(!extra_row_exists(name)) return "";
00277 return db_query_to_string("SELECT " + detail + " FROM " + db_extra_table_ + " WHERE UPPER(username)=UPPER('" + name + "')");
00278 }
00279
00280 void fuh::write_detail(const std::string& name, const std::string& detail, const std::string& value) {
00281 try {
00282
00283 if(!extra_row_exists(name)) {
00284
00285 db_query("INSERT INTO " + db_extra_table_ + " VALUES('" + name + "','" + value + "','0')");
00286 }
00287 db_query("UPDATE " + db_extra_table_ + " SET " + detail + "='" + value + "' WHERE UPPER(username)=UPPER('" + name + "')");
00288 } catch (error& e) {
00289 ERR_UH << "Could not set detail for user '" << name << "': " << e.message << std::endl;
00290 }
00291 }
00292
00293 bool fuh::extra_row_exists(const std::string& name) {
00294
00295
00296 try {
00297 return mysql_fetch_row(db_query("SELECT username FROM " + db_extra_table_ + " WHERE UPPER(username)=UPPER('" + name + "')"));
00298 } catch (error& e) {
00299 ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl;
00300 return false;
00301 }
00302 }
00303
00304 #endif //HAVE_MYSQLPP