diff --git a/src/userregistration.cpp b/src/userregistration.cpp index ad467755910f15f68648e5ee4d5d19058c89a244..4060de42261e9887e074e5256e3fed338a772efc 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -25,7 +25,6 @@ #include "transport/rostermanager.h" #include "transport/user.h" #include "transport/logging.h" -#include "transport/formutils.h" #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/EventLoop/SimpleEventLoop.h" #include "Swiften/Network/BoostNetworkFactories.h" @@ -45,8 +44,7 @@ namespace Transport { DEFINE_LOGGER(logger, "UserRegistration"); UserRegistration::UserRegistration(Component *component, UserManager *userManager, - StorageBackend *storageBackend) -: Swift::Responder(component->m_iqRouter) { + StorageBackend *storageBackend) { m_component = component; m_config = m_component->m_config; m_storageBackend = storageBackend; @@ -60,19 +58,11 @@ bool UserRegistration::registerUser(const UserInfo &row) { UserInfo dummy; bool registered = m_storageBackend->getUser(row.jid, dummy); - // This user is already registered, nothing to do - if (registered) { - return false; - } - m_storageBackend->setUser(row); + doUserRegistration(row); + onUserRegistered(row); - // Check if the server supports remoteroster XEP by sending request for the registered user's roster. - AddressedRosterRequest::ref request = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), row.jid)); - request->onResponse.connect(boost::bind(&UserRegistration::handleRegisterRemoteRosterResponse, this, _1, _2, row)); - request->send(); - - return true; + return !registered; } bool UserRegistration::unregisterUser(const std::string &barejid) { @@ -84,102 +74,6 @@ bool UserRegistration::unregisterUser(const std::string &barejid) { return false; } - onUserUnregistered(userInfo); - - // Check if the server supports remoteroster XEP by sending request for the registered user's roster. - AddressedRosterRequest::ref request = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(), barejid)); - request->onResponse.connect(boost::bind(&UserRegistration::handleUnregisterRemoteRosterResponse, this, _1, _2, barejid)); - request->send(); - - return true; -} - -void UserRegistration::handleRegisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref remoteRosterNotSupported, const UserInfo &row){ - if (remoteRosterNotSupported || !payload) { - // Remote roster is not support, so send normal Subscribe presence to add transport. - 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->getStanzaChannel()->sendPresence(response); - } - else { - // Remote roster is support, so use remoteroster XEP to add transport. - Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload()); - Swift::RosterItemPayload item; - item.setJID(m_component->getJID()); - item.setSubscription(Swift::RosterItemPayload::Both); - payload->addItem(item); - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, row.jid, m_component->getIQRouter()); - request->send(); - } - - onUserRegistered(row); - - // If the JID for registration notification is configured, send the notification message. - std::vector const &x = CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid"); - BOOST_FOREACH(const std::string ¬ify_jid, x) { - boost::shared_ptr msg(new Swift::Message()); - msg->setBody(std::string("registered: ") + row.jid); - msg->setTo(notify_jid); - msg->setFrom(m_component->getJID()); - m_component->getStanzaChannel()->sendMessage(msg); - } -} - -void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref remoteRosterNotSupported, const std::string &barejid) { - UserInfo userInfo; - bool registered = m_storageBackend->getUser(barejid, userInfo); - // This user is not registered, nothing do to - if (!registered) - return; - - if (remoteRosterNotSupported || !payload) { - // Remote roster is ont support, so get the buddies from database - // and send Unsubsribe and Unsubscribed presence to them. - std::list roster; - m_storageBackend->getBuddies(userInfo.id, roster); - for(std::list::iterator u = roster.begin(); u != roster.end() ; u++){ - std::string name = (*u).legacyName; - if ((*u).flags & BUDDY_JID_ESCAPING) { - name = Swift::JID::getEscapedNode((*u).legacyName); - } - else { - if (name.find_last_of("@") != std::string::npos) { - name.replace(name.find_last_of("@"), 1, "%"); - } - } - - Swift::Presence::ref response; - 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->getStanzaChannel()->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->getStanzaChannel()->sendPresence(response); - } - } - else { - // Remote roster is support, so iterate over all buddies we received - // from the XMPP server and remove them using remote roster. - BOOST_FOREACH(Swift::RosterItemPayload it, payload->getItems()) { - Swift::RosterPayload::ref p = Swift::RosterPayload::ref(new Swift::RosterPayload()); - Swift::RosterItemPayload item; - item.setJID(it.getJID()); - item.setSubscription(Swift::RosterItemPayload::Remove); - - p->addItem(item); - - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(p, barejid, m_component->getIQRouter()); - request->send(); - } - } - // Remove user from database m_storageBackend->removeUser(userInfo.id); @@ -189,293 +83,9 @@ void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptrremoveUser(user); } - // Remove the transport contact itself the same way as the buddies. - if (remoteRosterNotSupported || !payload) { - Swift::Presence::ref response; - response = Swift::Presence::create(); - response->setTo(Swift::JID(barejid)); - response->setFrom(m_component->getJID()); - response->setType(Swift::Presence::Unsubscribe); - m_component->getStanzaChannel()->sendPresence(response); - - response = Swift::Presence::create(); - response->setTo(Swift::JID(barejid)); - response->setFrom(m_component->getJID()); - response->setType(Swift::Presence::Unsubscribed); - m_component->getStanzaChannel()->sendPresence(response); - } - else { - Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload()); - Swift::RosterItemPayload item; - item.setJID(m_component->getJID()); - item.setSubscription(Swift::RosterItemPayload::Remove); - payload->addItem(item); - - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, barejid, m_component->getIQRouter()); - request->send(); - } - - // If the JID for registration notification is configured, send the notification message. - std::vector const &x = CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid"); - BOOST_FOREACH(const std::string ¬ify_jid, x) { - boost::shared_ptr msg(new Swift::Message()); - msg->setBody(std::string("unregistered: ") + barejid); - msg->setTo(notify_jid); - msg->setFrom(m_component->getJID()); - m_component->getStanzaChannel()->sendMessage(msg); - } -} - -Form::ref UserRegistration::generateRegistrationForm(const UserInfo &res, bool registered) { - Form::ref form(new Form(Form::FormType)); - form->setTitle("Registration"); - form->setInstructions(CONFIG_STRING(m_config, "registration.instructions")); - - FormUtils::addHiddenField(form, "FORM_TYPE", "jabber:iq:register"); - FormUtils::addTextSingleField(form, "username", res.uin, - CONFIG_STRING(m_config, "registration.username_label"), - true); - - if (CONFIG_BOOL_DEFAULTED(m_config, "registration.needPassword", true)) { - FormUtils::addTextPrivateField(form, "password", "Password", true); - } - - std::string defLanguage = CONFIG_STRING(m_config, "registration.language"); - Swift::FormField::Option languages(defLanguage, defLanguage); - FormUtils::addListSingleField(form, "language", languages, "Language", - registered ? res.language : defLanguage); - - - if (registered) { - FormUtils::addBooleanField(form, "unregister", "0", "Remove your registration"); - } - else if (CONFIG_BOOL(m_config,"registration.require_local_account")) { - std::string localUsernameField = CONFIG_STRING(m_config, "registration.local_username_label"); - FormUtils::addTextSingleField(form, "local_username", "", localUsernameField, true); - FormUtils::addTextSingleField(form, "local_password", "", "Local password", true); - } - - return form; -} - -boost::shared_ptr UserRegistration::generateInBandRegistrationPayload(const Swift::JID& from) { - boost::shared_ptr reg(new InBandRegistrationPayload()); - - UserInfo res; - bool registered = m_storageBackend->getUser(from.toBare().toString(), res); - - reg->setInstructions(CONFIG_STRING(m_config, "registration.instructions")); - reg->setRegistered(registered); - reg->setUsername(res.uin); - - if (CONFIG_BOOL_DEFAULTED(m_config, "registration.needPassword", true)) { - reg->setPassword(""); - } - - Form::ref form = generateRegistrationForm(res, registered); - reg->setForm(form); - - return reg; -} - -bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload) { - // TODO: backend should say itself if registration is needed or not... - if (CONFIG_STRING(m_config, "service.protocol") == "irc") { - sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify); - return true; - } - - if (!CONFIG_BOOL(m_config,"registration.enable_public_registration")) { - std::vector const &x = CONFIG_VECTOR(m_config,"service.allowed_servers"); - if (std::find(x.begin(), x.end(), from.getDomain()) == x.end()) { - LOG4CXX_INFO(logger, from.toBare().toString() << ": This user has no permissions to register an account") - sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify); - return true; - } - } - - boost::shared_ptr reg = generateInBandRegistrationPayload(from); - sendResponse(from, id, reg); - - return true; -} - -bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload) { - // TODO: backend should say itself if registration is needed or not... - if (CONFIG_STRING(m_config, "service.protocol") == "irc") { - sendError(from, id, ErrorPayload::BadRequest, ErrorPayload::Modify); - return true; - } - - std::string barejid = from.toBare().toString(); - - if (!CONFIG_BOOL(m_config,"registration.enable_public_registration")) { - std::vector const &x = CONFIG_VECTOR(m_config,"service.allowed_servers"); - if (std::find(x.begin(), x.end(), from.getDomain()) == x.end()) { - LOG4CXX_INFO(logger, barejid << ": 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; - std::string local_username; - std::string local_password; - - Form::ref form = payload->getForm(); - if (form) { - std::string value; - - value = FormUtils::fieldValue(form, "username", ""); - if (!value.empty()) { - payload->setUsername(value); - } - - value = FormUtils::fieldValue(form, "password", ""); - if (!value.empty()) { - payload->setPassword(value); - } - - value = FormUtils::fieldValue(form, "unregister", ""); - if (value == "1" || value == "true") { - payload->setRemove(true); - } - - encoding = FormUtils::fieldValue(form, "encoding", ""); - local_username = FormUtils::fieldValue(form, "local_username", ""); - local_password = FormUtils::fieldValue(form, "local_password", ""); - language = FormUtils::fieldValue(form, "language", ""); - } - - if (payload->isRemove()) { - unregisterUser(barejid); - sendResponse(from, id, InBandRegistrationPayload::ref()); - return true; - } - - if (CONFIG_BOOL(m_config,"registration.require_local_account")) { - /* if (!local_username || !local_password) { - sendResponse(from, id, InBandRegistrationPayload::ref()); - return true - } else */ if (local_username == "" || local_password == "") { - sendResponse(from, id, InBandRegistrationPayload::ref()); - return true; - } -// Swift::logging = true; - bool validLocal = false; - std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server"); - std::string localLookupJID = local_username + std::string("@") + localLookupServer; - SimpleEventLoop localLookupEventLoop; - BoostNetworkFactories localLookupNetworkFactories(&localLookupEventLoop); - Client localLookupClient(localLookupJID, local_password, &localLookupNetworkFactories); - - // TODO: this is neccessary on my server ... but should maybe omitted - localLookupClient.setAlwaysTrustCertificates(); - localLookupClient.connect(); - - class SimpleLoopRunner { - public: - SimpleLoopRunner() {}; - - static void run(SimpleEventLoop * loop) { - loop->run(); - }; - }; - - // TODO: Really ugly and hacky solution, any other ideas more than welcome! - boost::thread thread(boost::bind(&(SimpleLoopRunner::run), &localLookupEventLoop)); - thread.timed_join(boost::posix_time::millisec(CONFIG_INT(m_config, "registration.local_account_server_timeout"))); - localLookupEventLoop.stop(); - thread.join(); - validLocal = localLookupClient.isAvailable(); - localLookupClient.disconnect(); - if (!validLocal) { - sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify); - return true; - } - } - - if (!payload->getUsername() || (!payload->getPassword() && CONFIG_BOOL_DEFAULTED(m_config, "registration.needPassword", true))) { - sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); - return true; - } - - if (!payload->getPassword()) { - payload->setPassword(""); - } - - // Register or change password - if (payload->getUsername()->empty()) { - sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); - return true; - } - - // TODO: Move this check to backend somehow - if (CONFIG_STRING(m_config, "service.protocol") == "prpl-jabber") { - // 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(); - - std::string newUsername(username); - if (!CONFIG_STRING(m_config, "registration.username_mask").empty()) { - newUsername = CONFIG_STRING(m_config, "registration.username_mask"); - boost::replace_all(newUsername, "$username", username); - } - -//TODO: Part of spectrum1 registration stuff, this should be potentially rewritten for S2 too -// if (!m_component->protocol()->isValidUsername(newUsername)) { -// Log("UserRegistration", "This is not valid username: "<< newUsername); -// sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); -// return true; -// } - - if (!CONFIG_STRING(m_config, "registration.allowed_usernames").empty()) { - boost::regex expression(CONFIG_STRING(m_config, "registration.allowed_usernames")); - if (!regex_match(newUsername, expression)) { - LOG4CXX_INFO(logger, "This is not valid username: " << newUsername); - sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); - return true; - } - } - - if (!registered) { - res.jid = barejid; - res.uin = newUsername; - res.password = *payload->getPassword(); - res.language = language; - res.encoding = encoding; - res.vip = 0; - res.id = 0; - registerUser(res); - } - else { - res.jid = barejid; - res.uin = newUsername; - res.password = *payload->getPassword(); - res.language = language; - res.encoding = encoding; - m_storageBackend->setUser(res); - onUserUpdated(res); - } + doUserUnregistration(userInfo); + onUserUnregistered(userInfo); - sendResponse(from, id, InBandRegistrationPayload::ref()); return true; }