Ejemplo n.º 1
0
    def send(self, session_id, message, exclude=None):
        state = self.session.get(session_id)

        info = self.groups.get(state.group)

        if info.volume == group.Volume.QUIET:
            raise LtdErrorException(
                "Open messages are not permitted in quiet groups.")

        if info.control == group.Control.CONTROLLED and info.moderator != session_id:
            if (not info.nick_can_talk(state.nick, state.authenticated)
                    and not info.address_can_talk(state.loginid, state.ip,
                                                  state.host,
                                                  state.authenticated)):
                self.reputation.warning(session_id)

                raise LtdErrorException(
                    "You do not have permission to talk in this group.")

        if len(self.broker.get_subscribers(state.group)) == 1:
            raise LtdErrorException("No one else in group.")

        max_len = 254 - validate.NICK_MAX - 2

        for part in wrap(message, max_len):
            e = ltd.Encoder("b")

            e.add_field_str(state.nick, append_null=False)
            e.add_field_str(part, append_null=True)

            if exclude:
                excluded_sessions = set()

                excluded_id = self.session.find_nick(exclude)

                if not excluded_id:
                    raise LtdStatusException("Exclude", "Nick not found.")

                subscribers = self.broker.get_subscribers(info.key)

                if not excluded_id in subscribers:
                    raise LtdStatusException("Exclude", "Nick is not here.")

                excluded_sessions.add(excluded_id)

                if state.echo == session.EchoMode.OFF:
                    excluded_sessions.add(session_id)

                msg = e.encode()

                for sub_id in [
                        s for s in subscribers if not s in excluded_sessions
                ]:
                    self.broker.deliver(sub_id, msg)
            else:
                if state.echo == session.EchoMode.OFF:
                    self.broker.to_channel_from(session_id, state.group,
                                                e.encode())
                else:
                    self.broker.to_channel(state.group, e.encode())
Ejemplo n.º 2
0
    def request_confirmation(self, session_id):
        self.log.debug("Requesting email confirmation.")

        nick, details = self.__load_details_if_confirmed__(session_id)
        code = None

        with self.confirmation_connection.enter_scope() as scope:
            pending = self.confirmation.count_pending_requests(scope, nick, details.email, self.config.timeouts_confirmation_request)

            if pending > 0:
                self.reputation.warning(session_id)

                raise LtdStatusException("Confirmation", "Confirmation request pending, please check your inbox.")

            code = self.confirmation.create_request(scope, nick, details.email)

            scope.complete()

        self.log.debug("Confirmation code generated: %s", code)

        with self.mail_sink_connection.enter_scope() as scope:
            text = self.template.load("confirm_email")
            tpl = Template(text)
            body = tpl.substitute(nick=nick, code=code)

            self.mail_sink.put(scope, details.email, "Email confirmation", body)

            self.broker.deliver(session_id, ltd.encode_co_output("Confirmation mail sent."))

            scope.complete()
Ejemplo n.º 3
0
    def change_password(self, session_id, nick, password):
        state = self.session.get(session_id)

        if state.nick.lower() == nick.lower():
            if not state.authenticated:
                raise LtdErrorException("You must be registered to change your password.")
        else:
            self.__test_admin__(session_id)

        self.log.debug("Changing password of user %s." % nick)

        with self.nickdb_connection.enter_scope() as scope:
            if not self.nickdb.exists(scope, nick):
                raise LtdErrorException("%s not found." % nick)

            self.log.debug("Nick found, changing password.")

            if not validate.is_valid_password(password):
                raise LtdStatusException("Password",
                                         "Password format not valid. Password length must be between %d and %d characters."
                                         % (validate.PASSWORD_MIN, validate.PASSWORD_MAX))

            self.nickdb.set_password(scope, nick, password)

            self.broker.deliver(session_id, ltd.encode_status_msg("Pass", "Password changed."))

            scope.complete()
Ejemplo n.º 4
0
    def __login_no_password__(self, session_id, loginid, nick):
        self.log.debug("No password given, skipping authentication.")

        loggedin_session = self.session.find_nick(nick)

        if loggedin_session:
            self.log.debug("%s already logged in, aborting login.", nick)

            raise LtdStatusException("Register", "Nick already in use.")

        with self.nickdb_connection.enter_scope() as scope:
            if self.nickdb.exists(scope, nick):
                if self.nickdb.is_admin(scope, nick):
                    raise LtdErrorException(
                        "You need a password to login as administrator.")

                self.broker.deliver(
                    session_id,
                    ltd.encode_status_msg(
                        "Register",
                        "Send password to authenticate your nickname."))
            else:
                self.broker.deliver(
                    session_id,
                    ltd.encode_status_msg(
                        "No-Pass", "Your nickname does not have a password."))

                self.broker.deliver(
                    session_id,
                    ltd.encode_status_msg("No-Pass",
                                          "For help type /m server ?"))

        self.session.update(session_id, loginid=loginid, nick=nick)
Ejemplo n.º 5
0
    def reset_password(self, session_id, email):
        self.log.debug("Resetting user password.")

        if not email:
            raise LtdErrorException("Usage: /newpasswd {confirmed email address}")

        if not validate.is_valid_email(email):
            raise LtdErrorException("Wrong email address.")

        state = self.session.get(session_id)
        details = None

        with self.nickdb_connection.enter_scope() as scope:
            if not self.nickdb.exists(scope, state.nick):
                self.reputation.warning(session_id)

                raise LtdErrorException("Nick not registered.")

            if not self.nickdb.is_email_confirmed(scope, state.nick):
                self.reputation.warning(session_id)

                raise LtdErrorException("Wrong email address.")

            details = self.nickdb.lookup(scope, state.nick)

            if details.email.lower() != email.lower():
                self.reputation.critical(session_id)

                raise LtdErrorException("Wrong email address.")

        code = None

        with self.password_reset_connection.enter_scope() as scope:
            pending = self.password_reset.count_pending_requests(scope, state.nick, self.config.timeouts_password_reset_request)

            if pending > 0:
                self.reputation.critical(session_id)

                raise LtdStatusException("Pass", "Password reset pending, please check your inbox.")

            code = self.password_reset.create_request(scope, state.nick)

            scope.complete()

        self.log.debug("Reset code generated: %s", code)

        with self.mail_sink_connection.enter_scope() as scope:
            text = self.template.load("password_reset_email")
            tpl = Template(text)
            body = tpl.substitute(nick=state.nick, code=code)

            self.mail_sink.put(scope, details.email, "Password reset", body)

            self.broker.deliver(session_id, ltd.encode_co_output("Email sent."))

            scope.complete()
Ejemplo n.º 6
0
    def noaway(self, session_id):
        state = self.session.get(session_id)

        if not state.away:
            raise LtdStatusException("Away", "No away message set.")

        self.session.update(session_id, away=None, t_away=None)

        self.broker.deliver(
            session_id, ltd.encode_status_msg("Away", "Away message unset."))
Ejemplo n.º 7
0
    def news_item(self, session_id, news_item, msgid=""):
        item = self.__news.get_item(news_item)

        if not item:
            raise LtdStatusException("News", "Entry not found.")

        self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))

        for line in item:
            self.broker.deliver(session_id, ltd.encode_co_output(line, msgid))

        self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))
Ejemplo n.º 8
0
    def all_news(self, session_id, msgid=""):
        news = self.__news.all()

        if not news:
            raise LtdStatusException("News", "No news.")

        self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))

        for item in news:
            for line in item:
                self.broker.deliver(session_id, ltd.encode_co_output(line, msgid))

            self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))
Ejemplo n.º 9
0
    def __load_details_if_confirmed__(self, session_id):
        state = self.session.get(session_id)

        if not state.authenticated:
            raise LtdErrorException("You must be registered to confirm your email address.")

        with self.nickdb_connection.enter_scope() as scope:
            if self.nickdb.is_email_confirmed(scope, state.nick):
                raise LtdResponseException("Already already confirmed.",
                                           ltd.encode_co_output("Email address already confirmed."))

            details = self.nickdb.lookup(scope, state.nick)

            if not details.email:
                raise LtdStatusException("Confirmation", "No email address set.")

            return state.nick, details
Ejemplo n.º 10
0
    def change_password(self, session_id, old_pwd, new_pwd):
        self.log.debug("Changing user password.")

        state = self.session.get(session_id)

        is_reset_code = False

        with self.password_reset_connection.enter_scope() as scope:
            is_reset_code = self.password_reset.has_pending_request(scope, state.nick, old_pwd, self.config.timeouts_password_reset_code)

        with self.nickdb_connection.enter_scope() as scope:
            if not self.nickdb.exists(scope, state.nick):
                raise LtdErrorException("Authorization failure.")

            if not is_reset_code:
                self.log.debug("Validating password.")

                if not state.authenticated:
                    self.reputation.critical(session_id)

                    raise LtdErrorException("You must be registered to change your password.")

                if not self.nickdb.check_password(scope, state.nick, old_pwd):
                    self.reputation.fatal(session_id)

                    raise LtdErrorException("Authorization failure.")
            else:
                self.log.debug("Password reset code found: %s", old_pwd)

            if not validate.is_valid_password(new_pwd):
                raise LtdStatusException("Pass",
                                         "Password format not valid. Password length must be between %d and %d characters."
                                         % (validate.PASSWORD_MIN, validate.PASSWORD_MAX))

            self.nickdb.set_password(scope, state.nick, new_pwd)

            self.broker.deliver(session_id, ltd.encode_status_msg("Pass", "Password changed."))

            scope.complete()

        if is_reset_code:
            with self.password_reset_connection.enter_scope() as scope:
                self.password_reset.delete_requests(scope, state.nick)

                scope.complete()
Ejemplo n.º 11
0
    def confirm(self, session_id, code):
        nick, details = self.__load_details_if_confirmed__(session_id)

        with self.confirmation_connection.enter_scope() as scope:
            if not self.confirmation.has_pending_request(scope, nick, code, details.email, self.config.timeouts_confirmation_code):
                self.reputation.fatal(session_id)

                raise LtdStatusException("Confirmation", "Confirmation failed.")

            self.confirmation.delete_requests(scope, nick)

            scope.complete()

        with self.nickdb_connection.enter_scope() as scope:
            self.nickdb.set_email_confirmed(scope, nick, True)

            scope.complete()

        self.broker.deliver(session_id,
                            ltd.encode_status_msg("Confirmation", "Email address confirmed. Enable message forwarding with /forward."))
Ejemplo n.º 12
0
    def __login_password__(self, session_id, loginid, nick, password):
        self.log.debug("Password set, trying to authenticate %s.", nick)

        registered = False
        is_admin = False

        with self.nickdb_connection.enter_scope() as scope:
            if self.nickdb.exists(scope, nick):
                registered = self.nickdb.check_password(scope, nick, password)
                is_admin = self.nickdb.is_admin(scope, nick)

            if not registered:
                self.log.debug("Password is invalid.")

                self.reputation.critical(session_id)

                self.broker.deliver(
                    session_id, ltd.encode_str("e", "Authorization failure."))
                self.broker.deliver(
                    session_id,
                    ltd.encode_status_msg(
                        "Register",
                        "Send password to authenticate your nickname."))

                if is_admin:
                    raise LtdErrorException(
                        "You need a password to login as administrator.")

        loggedin_session = self.session.find_nick(nick)

        if loggedin_session and not registered:
            self.log.debug("%s already logged in, aborting login.", nick)

            raise LtdStatusException("Register", "Nick already in use.")

        if loggedin_session:
            self.__auto_rename__(loggedin_session)

        self.session.update(session_id, loginid=loginid, nick=nick)

        return registered
Ejemplo n.º 13
0
    def beep(self, session_id, receiver):
        loggedin_session = self.session.find_nick(receiver)

        if not loggedin_session:
            raise LtdErrorException("%s is not signed on." % receiver)

        loggedin_state = self.session.get(loggedin_session)

        state = self.session.get(session_id)

        if state.echo == session.EchoMode.VERBOSE:
            self.broker.deliver(
                session_id,
                ltd.encode_co_output("<*to: %s*> [=Beep=]" % receiver))

        if loggedin_state.beep != session.BeepMode.ON:
            if loggedin_state.beep == session.BeepMode.VERBOSE:
                self.broker.deliver(
                    loggedin_session,
                    ltd.encode_status_msg(
                        "No-Beep",
                        "%s attempted (and failed) to beep you." % state.nick))

            raise LtdStatusException("Beep", "User has nobeep enabled.")

        self.broker.deliver(loggedin_session, ltd.encode_str("k", state.nick))

        if loggedin_state.away:
            if not self.away_table.is_alive(session_id, receiver):
                self.broker.deliver(
                    session_id,
                    ltd.encode_status_msg(
                        "Away", "%s (since %s)." %
                        (loggedin_state.away,
                         loggedin_state.t_away.elapsed_str())))

                self.away_table.set_alive(session_id, receiver,
                                          self.config.timeouts_away_message)
Ejemplo n.º 14
0
    def register(self, session_id, password):
        self.log.debug("Starting user registration.")

        state = self.session.get(session_id)

        registered = False

        with self.nickdb_connection.enter_scope() as scope:
            if self.nickdb.exists(scope, state.nick):
                self.log.debug("Nick found, validating password.")

                if not self.nickdb.check_password(scope, state.nick, password):
                    self.reputation.fatal(session_id)

                    raise LtdErrorException("Authorization failure.")

                registered = True
            else:
                self.log.debug("Creating new user profile for %s.", state.nick)

                if not validate.is_valid_password(password):
                    raise LtdStatusException("Register",
                                             "Password format not valid. Password length must be between %d and %d characters."
                                             % (validate.PASSWORD_MIN, validate.PASSWORD_MAX))

                self.nickdb.create(scope, state.nick)
                self.nickdb.set_secure(scope, state.nick, True)
                self.nickdb.set_admin(scope, state.nick, False)
                self.nickdb.set_password(scope, state.nick, password)
                self.nickdb.set_mbox_limit(scope, state.nick, self.config.mbox_limit)

                registered = True

                scope.complete()

        if registered:
            self.mark_registered(session_id)
            self.notify_messagebox(session_id)
Ejemplo n.º 15
0
    def login(self,
              session_id,
              loginid,
              nick,
              password,
              group_name,
              status="",
              remote_address=""):
        self.log.debug("User login: loginid=%s, nick=%s, password=%s", loginid,
                       nick, hide_chars(password))

        if not validate.is_valid_loginid(loginid):
            raise LtdErrorException(
                "loginid must consist of at least %d and at most %d alphabetic characters."
                % (validate.LOGINID_MIN, validate.LOGINID_MAX))

        if not validate.is_valid_nick(nick):
            raise LtdErrorException(
                "Nickname must consist of at least %d and at most %d alphanumeric characters."
                % (validate.NICK_MIN, validate.NICK_MAX))

        self.__resolve_bridged_user__(session_id, loginid, remote_address)

        self.broker.deliver(session_id, ltd.encode_empty_cmd("a"))

        if nick == core.NICKSERV:
            raise LtdStatusException("Register", "Nick already in use.")

        ACTION(Motd).receive(session_id)

        registered = self.config.server_unsecure_login and self.__try_login_unsecure__(
            session_id, loginid, nick)

        if not registered:
            if not password:
                self.__login_no_password__(session_id, loginid, nick)
            else:
                registered = self.__login_password__(session_id, loginid, nick,
                                                     password)

        self.session.update(session_id, signon=dateutils.now())

        registration = ACTION(Registration)

        if registered:
            registration.mark_registered(session_id)

        self.__test_connection_limit__(session_id)
        self.__test_ip__(session_id)

        registration.notify_messagebox(session_id)

        if not group_name:
            group_name = core.DEFAULT_GROUP

        self.join(session_id, group_name, status)

        ACTION(Notify).notify_signon(session_id)

        s = self.resolve(shutdown.Shutdown)
        request = s.pending_request

        if request != shutdown.PendingRequest.NONE:
            msg = "Server is %s in %s." % (
                "restarting" if request == shutdown.PendingRequest.RESTART else
                "shutting down", s.time_left_str)

            self.broker.deliver(session_id,
                                ltd.encode_status_msg("Shutdown", msg))

        with self.statsdb_connection.enter_scope() as scope:
            self.statsdb.add_signon(scope)
            self.statsdb.set_max_logins(scope, self.session.count_logins())

            scope.complete()