server/forum_user_handler.cpp

Go to the documentation of this file.
00001 /* $Id: forum_user_handler.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Thomas Baumhauer <thomas.baumhauer@NOSPAMgmail.com>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
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& /*name*/, const std::string& /*mail*/, const std::string& /*password*/) {
00057     throw error("For now please register at http://forum.wesnoth.org");
00058 }
00059 
00060 void fuh::remove_user(const std::string& /*name*/) {
00061     throw error("'Dropping your nickname is currently impossible");
00062 }
00063 
00064 // The hashing code is basically taken from forum_auth.cpp
00065 bool fuh::login(const std::string& name, const std::string& password, const std::string& seed) {
00066 
00067     // Retrieve users' password as hash
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     // Check hash prefix, if different than $H$ hash is invalid
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     // Some doulbe security, this should never be neeeded
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     // Make a test query for this username
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         // If the database is down just let all usernames log in
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         // If the database is down mark nobody as a mod
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& /*name*/) {
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(&reg_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& /*user*/, const std::string& /*detail*/, const std::string& /*value*/) {
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         //Try to reconnect and execute query again
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         // Check if we do already have a row for this user in the extra table
00283         if(!extra_row_exists(name)) {
00284             // If not create the row
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     // Make a test query for this username
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:09 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs