spectrum2/src/userregistration.cpp
2011-07-10 15:32:01 +02:00

371 lines
12 KiB
C++

/**
* libtransport -- C++ library for easy XMPP Transports development
*
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "transport/userregistration.h"
#include "transport/usermanager.h"
#include "transport/storagebackend.h"
#include "transport/transport.h"
#include "transport/user.h"
#include "Swiften/Elements/ErrorPayload.h"
#include <boost/shared_ptr.hpp>
#include "log4cxx/logger.h"
using namespace Swift;
using namespace log4cxx;
namespace Transport {
static LoggerPtr logger = Logger::getLogger("UserRegistration");
UserRegistration::UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend) : Swift::Responder<Swift::InBandRegistrationPayload>(component->m_iqRouter) {
m_component = component;
m_config = m_component->m_config;
m_storageBackend = storageBackend;
m_userManager = userManager;
}
UserRegistration::~UserRegistration(){
}
bool UserRegistration::registerUser(const UserInfo &row) {
// TODO: move this check to sql()->addUser(...) and let it return bool
UserInfo user;
bool registered = m_storageBackend->getUser(row.jid, user);
// This user is already registered
if (registered)
return false;
m_storageBackend->setUser(row);
Swift::Presence::ref response = Swift::Presence::create();
response->setFrom(m_component->getJID());
response->setTo(Swift::JID(row.jid));
response->setType(Swift::Presence::Subscribe);
m_component->m_component->sendPresence(response);
onUserRegistered(row);
return true;
}
bool UserRegistration::unregisterUser(const std::string &barejid) {
UserInfo userInfo;
bool registered = m_storageBackend->getUser(barejid, userInfo);
// This user is not registered
if (!registered)
return false;
onUserUnregistered(userInfo);
Swift::Presence::ref response;
User *user = m_userManager->getUser(barejid);
// roster contains already escaped jids
std::list <BuddyInfo> roster;
m_storageBackend->getBuddies(userInfo.id, roster);
for(std::list<BuddyInfo>::iterator u = roster.begin(); u != roster.end() ; u++){
std::string name = (*u).legacyName;
response = Swift::Presence::create();
response->setTo(Swift::JID(barejid));
response->setFrom(Swift::JID(name + "@" + m_component->getJID().toString()));
response->setType(Swift::Presence::Unsubscribe);
m_component->m_component->sendPresence(response);
response = Swift::Presence::create();
response->setTo(Swift::JID(barejid));
response->setFrom(Swift::JID(name + "@" + m_component->getJID().toString()));
response->setType(Swift::Presence::Unsubscribed);
m_component->m_component->sendPresence(response);
}
// Remove user from database
m_storageBackend->removeUser(userInfo.id);
// Disconnect the user
if (user) {
m_userManager->removeUser(user);
}
response = Swift::Presence::create();
response->setTo(Swift::JID(barejid));
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unsubscribe);
m_component->m_component->sendPresence(response);
response = Swift::Presence::create();
response->setTo(Swift::JID(barejid));
response->setFrom(m_component->getJID());
response->setType(Swift::Presence::Unsubscribed);
m_component->m_component->sendPresence(response);
return true;
}
bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::InBandRegistrationPayload> payload) {
if (CONFIG_STRING(m_config, "service.protocol") == "irc") {
sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify);
return true;
}
std::string barejid = from.toBare().toString();
// User *user = m_userManager->getUserByJID(barejid);
if (!CONFIG_BOOL(m_config,"registration.enable_public_registration")) {
std::list<std::string> const &x = CONFIG_LIST(m_config,"service.allowed_servers");
if (std::find(x.begin(), x.end(), from.getDomain()) == x.end()) {
// Log("UserRegistration", "This user has no permissions to register an account");
sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify);
return true;
}
}
// const char *_language = user ? user->getLang() : CONFIG_STRING(m_config, "registration.language").c_str();
boost::shared_ptr<InBandRegistrationPayload> reg(new InBandRegistrationPayload());
UserInfo res;
bool registered = m_storageBackend->getUser(barejid, res);
std::string instructions = CONFIG_STRING(m_config, "registration.instructions");
reg->setInstructions(instructions);
reg->setRegistered(registered);
reg->setUsername(res.uin);
if (CONFIG_STRING(m_config, "service.protocol") != "twitter" && CONFIG_STRING(m_config, "service.protocol") != "bonjour")
reg->setPassword(res.password);
std::string usernameField = CONFIG_STRING(m_config, "registration.username_field");
Form::ref form(new Form(Form::FormType));
form->setTitle(tr(_language, _("Registration")));
form->setInstructions(tr(_language, instructions));
HiddenFormField::ref type = HiddenFormField::create();
type->setName("FORM_TYPE");
type->setValue("jabber:iq:register");
form->addField(type);
TextSingleFormField::ref username = TextSingleFormField::create();
username->setName("username");
username->setLabel(tr(_language, usernameField));
username->setValue(res.uin);
username->setRequired(true);
form->addField(username);
if (CONFIG_STRING(m_config, "service.protocol") != "twitter" && CONFIG_STRING(m_config, "service.protocol") != "bonjour") {
TextPrivateFormField::ref password = TextPrivateFormField::create();
password->setName("password");
password->setLabel(tr(_language, _("Password")));
password->setRequired(true);
form->addField(password);
}
ListSingleFormField::ref language = ListSingleFormField::create();
language->setName("language");
language->setLabel(tr(_language, _("Language")));
if (registered)
language->setValue(res.language);
else
language->setValue(CONFIG_STRING(m_config, "registration.language"));
// std::map <std::string, std::string> languages = localization.getLanguages();
// for (std::map <std::string, std::string>::iterator it = languages.begin(); it != languages.end(); it++) {
// language->addOption(FormField::Option((*it).second, (*it).first));
// }
form->addField(language);
TextSingleFormField::ref encoding = TextSingleFormField::create();
encoding->setName("encoding");
encoding->setLabel(tr(_language, _("Encoding")));
if (registered)
encoding->setValue(res.encoding);
else
encoding->setValue(CONFIG_STRING(m_config, "registration.encoding"));
form->addField(encoding);
if (registered) {
BooleanFormField::ref boolean = BooleanFormField::create();
boolean->setName("unregister");
boolean->setLabel(tr(_language, _("Remove your registration")));
boolean->setValue(0);
form->addField(boolean);
}
reg->setForm(form);
sendResponse(from, id, reg);
return true;
}
bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::InBandRegistrationPayload> payload) {
if (CONFIG_STRING(m_config, "service.protocol") == "irc") {
sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify);
return true;
}
std::string barejid = from.toBare().toString();
// AbstractUser *user = m_component->userManager()->getUserByJID(barejid);
if (!CONFIG_BOOL(m_config,"registration.enable_public_registration")) {
std::list<std::string> const &x = CONFIG_LIST(m_config,"service.allowed_servers");
if (std::find(x.begin(), x.end(), from.getDomain()) == x.end()) {
// Log("UserRegistration", "This user has no permissions to register an account");
sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify);
return true;
}
}
UserInfo res;
bool registered = m_storageBackend->getUser(barejid, res);
std::string encoding;
std::string language;
Form::ref form = payload->getForm();
if (form) {
const std::vector<FormField::ref> fields = form->getFields();
for (std::vector<FormField::ref>::const_iterator it = fields.begin(); it != fields.end(); it++) {
TextSingleFormField::ref textSingle = boost::dynamic_pointer_cast<TextSingleFormField>(*it);
if (textSingle) {
if (textSingle->getName() == "username") {
payload->setUsername(textSingle->getValue());
}
else if (textSingle->getName() == "encoding") {
encoding = textSingle->getValue();
}
continue;
}
TextPrivateFormField::ref textPrivate = boost::dynamic_pointer_cast<TextPrivateFormField>(*it);
if (textPrivate) {
if (textPrivate->getName() == "password") {
payload->setPassword(textPrivate->getValue());
}
continue;
}
ListSingleFormField::ref listSingle = boost::dynamic_pointer_cast<ListSingleFormField>(*it);
if (listSingle) {
if (listSingle->getName() == "language") {
language = listSingle->getValue();
}
continue;
}
BooleanFormField::ref boolean = boost::dynamic_pointer_cast<BooleanFormField>(*it);
if (boolean) {
if (boolean->getName() == "unregister") {
if (boolean->getValue()) {
payload->setRemove(true);
}
}
continue;
}
}
}
if (payload->isRemove()) {
unregisterUser(barejid);
sendResponse(from, id, InBandRegistrationPayload::ref());
return true;
}
if (!payload->getUsername() || !payload->getPassword()) {
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;
}
// Register or change password
if (payload->getUsername()->empty() ||
(payload->getPassword()->empty() && CONFIG_STRING(m_config, "service.protocol") != "twitter" && CONFIG_STRING(m_config, "service.protocol") != "bonjour")
// || localization.getLanguages().find(language) == localization.getLanguages().end()
)
{
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;
}
if (CONFIG_STRING(m_config, "service.protocol") == "xmpp") {
// User tries to register himself.
if ((Swift::JID(*payload->getUsername()).toBare() == from.toBare())) {
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;
}
// User tries to register someone who's already registered.
UserInfo user_row;
bool registered = m_storageBackend->getUser(Swift::JID(*payload->getUsername()).toBare().toString(), user_row);
if (registered) {
sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
return true;
}
}
std::string username = *payload->getUsername();
// m_component->protocol()->prepareUsername(username);
std::string newUsername(username);
if (!CONFIG_STRING(m_config, "registration.username_mask").empty()) {
newUsername = CONFIG_STRING(m_config, "registration.username_mask");
// replace(newUsername, "$username", username.c_str());
}
// if (!m_component->protocol()->isValidUsername(newUsername)) {
// Log("UserRegistration", "This is not valid username: "<< newUsername);
// sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
// return true;
// }
// #if GLIB_CHECK_VERSION(2,14,0)
// if (!CONFIG_STRING(m_config, "registration.reg_allowed_usernames").empty() &&
// !g_regex_match_simple(CONFIG_STRING(m_config, "registration.reg_allowed_usernames"), newUsername.c_str(),(GRegexCompileFlags) (G_REGEX_CASELESS | G_REGEX_EXTENDED), (GRegexMatchFlags) 0)) {
// Log("UserRegistration", "This is not valid username: "<< newUsername);
// sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify);
// return true;
// }
// #endif
if (!registered) {
res.jid = barejid;
res.uin = username;
res.password = *payload->getPassword();
res.language = language;
res.encoding = encoding;
res.vip = 0;
registerUser(res);
}
else {
// change passwordhttp://soumar.jabbim.cz/phpmyadmin/index.php
// Log("UserRegistration", "changing user password: "<< barejid << ", " << username);
res.jid = barejid;
res.password = *payload->getPassword();
res.language = language;
res.encoding = encoding;
m_storageBackend->setUser(res);
onUserUpdated(res);
}
sendResponse(from, id, InBandRegistrationPayload::ref());
return true;
}
}