gnuworld/mod.cservice/HELLOCommand.cc

375 lines
10 KiB
C++

/* HELLOCommand.cc */
#include <string>
#include "cservice_config.h"
#include "StringTokenizer.h"
#include "ELog.h"
#include "Network.h"
#include "ip.h"
#include "levels.h"
#include "dbHandle.h"
#include "cservice.h"
const char HELLOCommand_cc_rcsId[] = "$Id: HELLOCommand.cc,v 1.1 2005/04/03 22:11:42 dan_karrels Exp $" ;
namespace gnuworld
{
using std::string ;
using std::endl ;
using std::ends ;
using std::stringstream ;
bool HELLOCommand::Exec( iClient* theClient, const string& Message )
{
#ifdef ALLOW_HELLO
sqlUser* theUser = bot->isAuthed(theClient, false);
int admLevel = 0;
if (theUser)
{
admLevel = bot->getAdminAccessLevel(theUser);
if (admLevel == 0)
{
#ifndef ALLOW_USERS_HELLO
bot->Notice(theClient, "HELLO command is disabled. Use webinterface instead (if available)");
return true;
#endif
bot->Notice(theClient, "You can't create another "
"account when you already have one!");
return false;
}
}
else
{
#ifndef ALLOW_USERS_HELLO
bot->Notice(theClient, "HELLO command is disabled. Use webinterface instead (if available)");
return true;
#endif
}
bot->incStat("COMMANDS.HELLO");
StringTokenizer st( Message ) ;
if( st.size() < 6 )
{
Usage(theClient);
bot->Notice(theClient,"Valid verification answer numbers are: 1 to 3");
bot->Notice(theClient,"1: What's your mother's maiden name ?");
bot->Notice(theClient,"2: What's your dog's(or cat's) name ?");
bot->Notice(theClient,"3: What's your father's birth date ?");
return true;
}
const char validChars[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/*
* Check this IP hasn't already tried in the last 48 hours.
*/
cservice::helloIPListType::iterator itr = bot->helloIPList.find( theClient->getIP() ) ;
if (admLevel == 0) //(&& !theUser)) //only normal users has the one IP/user restriction, any Admin don't
if (itr != bot->helloIPList.end())
{
/*
* Has it been 48hours already?
*/
if (bot->currentTime() < itr->second)
{
bot->Notice(theClient, "Sorry, an account has "
"already been registered from this IP within "
"the last %i hours. "
"Please wait and try again, or contact cservice.",
bot->helloBlockPeriod / 3600);
return false;
}
}
sqlUser* newUser = bot->getUserRecord(st[1].c_str());
if(newUser)
{
bot->Notice(theClient, "This username already exists!");
return false;
}
/*
* Check the username contains valid characters/correct
length.
*/
if ( (st[1].size() < 2) || (st[1].size() > 12) )
{
bot->Notice(theClient, "Your username must be 2 to 12 chars long.");
return false;
}
string theUserName = st[1];
bool badName = false;
for( string::const_iterator ptr = theUserName.begin() ;
ptr != theUserName.end() ; ++ptr )
{
/*
* 62 entries in the table. 26 + 26 + 10 digits.
*/
bool found = false;
for (int f = 0; f < 62; f++)
{
if(*ptr == validChars[f])
{
found = true;
}
}
if (!found)
{
badName = true;
}
}
if (badName)
{
bot->Notice(theClient, "Your useraname must be made of letters (A-Z, a-z) and numbers (0-9).");
return false;
}
/*
* Do some basic validation of the email address.
*/
if (st[2].size() > 128)
{
bot->Notice(theClient, "E-mail address is too long.");
return false;
}
if( string::npos == st[2].find_first_of('@') )
{
/*
* No @?
*/
bot->Notice(theClient, "Invalid e-mail address.");
return false;
}
/*
* Check if they've at least vaugly attempted to specify a
* proper domain structure
* and we have the right number of @'s.
*/
StringTokenizer emailCheck( st[2], '@' ) ;
if ( (emailCheck.size() != 2) ||
(string::npos == emailCheck[1].find_first_of('.')) )
{
bot->Notice(theClient, "Invalid e-mail address.");
return false;
}
if(strcasecmp(st[2], st[3]))
{
bot->Notice(theClient, "E-mail addresses don't match!");
return false;
}
if (admLevel < level::hello)
{
/*
* Check this email address doesn't already exist in the database!
*/
stringstream theQuery;
theQuery << "SELECT email FROM users WHERE email IS NOT NULL"
<< ends;
if (!bot->SQLDb->Exec(theQuery, true))
{ bot->logDebugMessage("Error on HELLO.EmailQuery");
#ifdef LOG_SQL
//elog << "sqlQuery> " << theQuery.str().c_str() << endl;
elog << "Hello.EmailQuery> SQL Error: "
<< bot->SQLDb->ErrorMessage()
<< endl ;
#endif
return false;
} else if (bot->SQLDb->Tuples() != 0)
{
for (unsigned int i = 0 ; i < bot->SQLDb->Tuples(); i++)
if (!match(bot->SQLDb->GetValue(i,0),st[2]))
{
bot->Notice(theClient,"There is already an account registered with that email address.");
bot->Notice(theClient,"You can only have one account per person!");
if (bot->helloSendmailEnabled)
bot->Notice(theClient, "If you have lost your password and require a new one, request a password reset with /msg %s@%s NEWPASS <username>", bot->getNickName().c_str(), bot->getUplinkName().c_str());
else
bot->Notice(theClient,"If you have lost your password and require a new one, log in to webinterface and click on the New password link.");
return false;
}
}
} //admLevel
unsigned short verifID = atoi(st[4].c_str());
if ((verifID < 1) || (verifID > 3))
{
bot->Notice(theClient,"Valid verification answer numbers are: 1 to 3");
bot->Notice(theClient,"1: What's your mother's maiden name ?");
bot->Notice(theClient,"2: What's your dog's(or cat's) name ?");
bot->Notice(theClient,"3: What's your father's birth date ?");
return false;
}
string verifAnswer = st.assemble(5);
if ((verifAnswer.size() < 4) || (verifAnswer.size() > 300)) {
bot->Notice(theClient,"Your verification answer must be 4 - 300 charcters long.");
return false;
}
/*
* Check if user_name,email,verification answer is in NOREG/LOCKED
*/
if (admLevel < level::hello)
{
stringstream theQuery;
theQuery << "SELECT user_name,email,type,reason FROM noreg WHERE email IS NOT NULL OR user_name IS NOT NULL"
<< ends;
if (!bot->SQLDb->Exec(theQuery, true))
{ bot->logDebugMessage("Error on HELLO.NoregEmailQuery");
#ifdef LOG_SQL
//elog << "sqlQuery> " << theQuery.str().c_str() << endl;
elog << "Hello.NoregEmailQuery> SQL Error: "
<< bot->SQLDb->ErrorMessage()
<< endl ;
#endif
return false;
} else if (bot->SQLDb->Tuples() != 0)
{
unsigned short type;
string user_name,email;
string reason;
for (unsigned int i = 0 ; i < bot->SQLDb->Tuples(); i++)
{
user_name = bot->SQLDb->GetValue(i,0);
email = bot->SQLDb->GetValue(i,1);
type = atoi(bot->SQLDb->GetValue(i,2));
reason = bot->SQLDb->GetValue(i,3);
if ((user_name.size() > 0) && (user_name != "*"))
{
if ((type < 6) && (!match(user_name,st[1])))
{
if (type < 4) bot->Notice(theClient,"Invalid username (NOREG)");
if (type == 4) bot->Notice(theClient,"Invalid username (FRAUD)"); //this is set automatically when for a user is set the F_FRAUD flag on the webinterface
if (type == 5) bot->Notice(theClient,"Invalid username (LOCKED)");
bot->Notice(theClient,"Usernames matching %s are disallowed for the following reason:",user_name.c_str());
bot->Notice(theClient,reason.c_str());
return false;
}
if (type == 6)
{ //* This should be the matchcase - TODO: need to find a solution */
if (user_name[0] == '!') user_name.erase(0,1);
if (!match(user_name,verifAnswer))
{
bot->Notice(theClient,"Invalid verification answer (LOCKED)");
bot->Notice(theClient,"Verification answers matching %s are disallowed for the following reason:",user_name.c_str());
bot->Notice(theClient,reason.c_str());
return false;
}
}
}
if (((email.size() > 0) && (email != "*")) && (!match(email,st[2])))
{
if (type < 4) bot->Notice(theClient,"Invalid email address (NOREG)");
if (type == 5) bot->Notice(theClient,"Invalid email address (LOCKED)");
bot->Notice(theClient,"Email addresses matching %s are disallowed for the following reason:",email.c_str());
bot->Notice(theClient,reason.c_str());
return false;
}
}
}
/*
bot->helloIPList.erase(theClient->getIP());
bot->helloIPList.insert(
std::make_pair(theClient->getIP(),
bot->currentTime() + bot->helloBlockPeriod) );
*/
} //admLevel
//bot->Notice(theClient,"Username %s created successfully.",st[1].c_str());
//return true;
/*
* We need to give this user a password
*/
string plainpass;
for ( unsigned short int i = 0 ; i < 8 ; i++ )
{
int randNo = 1+(int) (62.0*rand()/(RAND_MAX+1.0));
plainpass += validChars[randNo];
}
string cryptpass = bot->CryptPass(plainpass);
string updatedBy = "HELLO used by: ";
updatedBy += theClient->getNickUserHost().c_str();
newUser = new (std::nothrow) sqlUser(bot->SQLDb);
newUser->setUserName(escapeSQLChars(st[1].c_str()));
newUser->setEmail(escapeSQLChars(st[2]));
newUser->setVerifNr(verifID);
newUser->setVerifData(verifAnswer);
newUser->setPassword(cryptpass.c_str());
newUser->setLastUpdatedBy(updatedBy);
newUser->setCreatedTS(bot->currentTime());
newUser->setInstantiatedTS(bot->currentTime());
newUser->setSignupIp(xIP(theClient->getIP()).GetNumericIP());
newUser->Insert();
delete (newUser);
if (bot->helloSendmailEnabled)
{
string themail = escapeSQLChars(st[2]);
stringstream mailstream;
mailstream << "The generated password is: " << plainpass << endl;
mailstream << "Login via IRC using /msg " << bot->getNickName().c_str() << "@" << bot->getUplinkName().c_str() << " LOGIN " << st[1].c_str() << " " << plainpass.c_str() << endl;
mailstream << "Then change your password using /msg " << bot->getNickName().c_str() << "@" << bot->getUplinkName().c_str() << " NEWPASS <new_password>" << endl;
mailstream << std::ends;
if (!bot->SendMail(themail, "Your CService account", mailstream))
{
bot->Notice(theClient, "An error occurred while sending newuser email, contact a CService representative.");
return false;
}
else
{
bot->Notice(theClient, "Username %s created successfully.", st[1].c_str());
bot->Notice(theClient, "Check your email (also in junk/spam) for the generated password.");
}
}
else
{
bot->Notice(theClient, "I generated this password for you: \002%s\002",
plainpass.c_str());
bot->Notice(theClient, "Login using \002/msg %s@%s LOGIN %s %s\002",
bot->getNickName().c_str(),
bot->getUplinkName().c_str(),
st[1].c_str(),
plainpass.c_str());
bot->Notice(theClient, "Then change your password using \002/msg "
"%s@%s NEWPASS <new_password>\002",
bot->getNickName().c_str(),
bot->getUplinkName().c_str());
}
//Record the IP only if below the required level
if (admLevel < level::hello)
{
bot->helloIPList.erase(theClient->getIP());
bot->helloIPList.insert(
std::make_pair(theClient->getIP(),
bot->currentTime() + bot->helloBlockPeriod) );
}
#endif //ALLOW_HELLO
return true ;
}
} // namespace gnuworld.