class State: loginid: str = None ip: str = None host: str = None tls: bool = False nick: str = None group: str = None authenticated: bool = False signon: datetime = dateutils.now() t_recv: Timer = None t_alive: Timer = None t_ping: Timer = None beep: BeepMode = BeepMode.ON echo: EchoMode = EchoMode.OFF away: str = None t_away: Timer = None hushlist: Hushlist = None notifylist: Notifylist = None def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) @property def loggedin(self): return self.nick and self.group @property def address(self): return "%s@%s" % (self.loginid, self.host)
def __get_today__(self, scope): now = dateutils.now() if not self.__date or (self.__date.year != now.year or self.__date.month != now.month or self.__date.day != now.day): self.__date = now self.__stats = None if not self.__stats: cur = scope.get_handle() cur.execute( "select * from Stats where Year=? and Month=? and Day=?", (self.__date.year, self.__date.month, self.__date.day)) row = cur.fetchone() if row: self.__stats = self.__create_stats__(row) else: cur.execute( "insert into Stats (Year, Month, Day) values (?, ?, ?) ", (self.__date.year, self.__date.month, self.__date.day)) self.__stats = statsdb.Stats() return self.__stats
def set_signoff(self, scope, nick, timestamp=None): cur = scope.get_handle() if not timestamp: timestamp = dateutils.now() cur.execute("update Nick set Signoff=? where Name=?", (int(timestamp.timestamp()), nick))
def year(self, scope): now = dateutils.now() cur = scope.get_handle() cur.execute(self.__build_accumulate_query__("where Year=%d" % now.year)) return self.__create_stats__(cur.fetchone())
def mark_registered(self, session_id): with self.nickdb_connection.enter_scope() as scope: state = self.session.get(session_id) self.nickdb.set_lastlogin(scope, state.nick, state.loginid, state.host) now = dateutils.now() self.nickdb.set_signon(scope, state.nick, now) self.session.update(session_id, signon=now, authenticated=True) self.broker.deliver(session_id, ltd.encode_status_msg("Register", "Nick registered.")) self.reputation.good(session_id) scope.complete()
async def run_services(opts): data_dir = opts.get("data_dir") mapping = config.json.load(opts["config"]) preferences = config.from_mapping(mapping) logger = log.new_logger("icbd", preferences.logging_verbosity) registry = log.Registry() registry.register(logger) logger.info("Starting server process with pid %d.", os.getpid()) container = di.default_container connection = sqlite.Connection(preferences.database_filename) ipfilter_storage = ipfilter.sqlite.Storage() ipfilter_cached = ipfilter.cache.Storage(ipfilter_storage) container.register(logging.Logger, logger) container.register(log.Registry, registry) container.register(config.Config, preferences) container.register(ipc.Broadcast, ipc.Broadcast()) container.register(shutdown.Shutdown, shutdown.Shutdown()) container.register(ipfilter.Connection, connection) container.register(ipfilter.Storage, ipfilter_cached) container.register(broker.Broker, broker.memory.Broker()) container.register(session.Store, session.memory.Store()) container.register(session.AwayTimeoutTable, timer.TimeoutTable()) container.register(session.NotificationTimeoutTable, timer.TimeoutTable()) container.register(reputation.Reputation, reputation.memory.Reputation()) container.register(group.Store, group.memory.Store()) container.register(nickdb.Connection, connection) container.register(nickdb.NickDb, nickdb.sqlite.NickDb()) container.register(statsdb.Connection, connection) container.register(statsdb.StatsDb, statsdb.sqlite.StatsDb()) container.register(confirmation.Connection, connection) container.register(confirmation.Confirmation, confirmation.sqlite.Confirmation()) container.register(passwordreset.Connection, connection) container.register(passwordreset.PasswordReset, passwordreset.sqlite.PasswordReset()) container.register(motd.Motd, motd.plaintext.Motd(os.path.join(data_dir, "motd"))) container.register(manual.Manual, manual.plaintext.Manual(os.path.join(data_dir, "help"))) container.register(news.News, news.plaintext.News(os.path.join(data_dir, "news"))) container.register( template.Template, template.plaintext.Template(os.path.join(data_dir, "templates"))) container.register(mail.Connection, connection) container.register(mail.Sink, mail.sqlite.Sink()) container.register(avatar.Connection, connection) container.register(avatar.Reader, avatar.sqlite.Reader()) container.register( avatar.Writer, avatar.sqlite.Writer(preferences.avatar_reload_timeout, preferences.avatar_retry_timeout, preferences.avatar_max_errors, preferences.avatar_error_timeout)) if avatar.is_available(): container.register( avatar.Storage, avatar.fs.AsciiFiles(preferences.avatar_directory, preferences.avatar_ascii_width, preferences.avatar_ascii_height)) else: logger.info("Avatar preview not available.") container.register(avatar.Storage, avatar.void.Storage()) with connection.enter_scope() as scope: container.resolve(ipfilter.Storage).setup(scope) container.resolve(nickdb.NickDb).setup(scope) container.resolve(statsdb.StatsDb).setup(scope) container.resolve(confirmation.Confirmation).setup(scope) container.resolve(mail.Sink).setup(scope) container.resolve(avatar.Reader).setup(scope) container.resolve(avatar.Writer).setup(scope) container.resolve(passwordreset.PasswordReset).setup(scope) scope.complete() container.resolve(avatar.Storage).setup() bus = ipc.Bus() await bus.start() if os.name == "posix": loop = asyncio.get_event_loop() loop.add_signal_handler(signal.SIGINT, lambda: server.close()) loop.add_signal_handler(signal.SIGTERM, lambda: server.close()) processes = [MailProcess()] if avatar.is_available(): processes.append(AvatarProcess()) asyncio.gather(*[p.spawn(opts) for p in processes]) failed = False try: server = network.Server() await server.run() except asyncio.CancelledError: pass except: logger.warning(traceback.format_exc()) failed = True await bus.close() for p in processes: p.exit() logger.info("Server stopped.") with container.resolve(nickdb.Connection).enter_scope() as scope: container.resolve(nickdb.NickDb).set_signoff(scope, core.NICKSERV, dateutils.now()) scope.complete() sys.exit(server.exit_code if not failed else core.EXIT_FAILURE)
def message_admins(*args, **kwargs): """ Asynchronously send messages to all administrators. :param preference: if set, the corresponding preference of each admin user is checked to see if he/she wants to receive the message or not. :type preference: str, unicode or None (default) :param timestamping: if ``True``, a timestamp is prepended to the message. The timestamp will be translated in the user langage and timezone. :type timestamping: bool (default: ``True``) """ timestamping = kwargs.pop('timestamping', True) preference = kwargs.pop('preference', None) admins = User.objects.filter(is_active=True).filter( Q(is_superuser=True) | Q(is_staff=True)).filter( preferences__staff__super_powers_enabled=True) if preference is not None: query_kwargs = {'preference__staff__{}'.format(preference): True} admins.filter(**query_kwargs) if timestamping: args = list(args) # This is an UTC datetime. dtnow = now() initial_lang = translation.get_language() prev_lang = initial_lang for admin in admins: uargs = args[:] # default datetime is UTC. udtnow = dtnow try: if admin.account.timezone: udtnow = dtnow.astimezone(pytz.timezone( admin.account.timezone)) if admin.account.language: if prev_lang != admin.account.language: translation.activate(admin.account.language) prev_lang = admin.account.language uargs[0] = _(u'{}: {}').format( formats.date_format(udtnow, 'SHORT_DATETIME_FORMAT'), uargs[0]) except ObjectDoesNotExist: # Mostly "user has no account" LOGGER.warning('Admin %s has no account ?', admin) message_user(admin, *uargs, **kwargs) if initial_lang is not None: translation.activate(initial_lang) else: message_users(admins, *args, **kwargs)
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()
def rename(self, session_id, nick): if not validate.is_valid_nick(nick): raise LtdErrorException("Nickname is invalid.") state = self.session.get(session_id) old_nick = state.nick was_authenticated = False if old_nick: self.log.debug("Renaming %s to %s.", old_nick, nick) was_authenticated = state.authenticated if self.session.find_nick(nick): self.reputation.warning(session_id) raise LtdErrorException("Nick already in use.") if state.group: self.log.debug("Renaming %s to %s in channel %s.", old_nick, nick, state.group) self.broker.to_channel( state.group, ltd.encode_status_msg( "Name", "%s changed nickname to %s." % (old_nick, nick))) if self.groups.get(state.group).moderator == session_id: self.broker.to_channel( state.group, ltd.encode_status_msg("Pass", "%s is now mod." % nick)) self.session.update(session_id, nick=nick, authenticated=False) registered = False is_admin = False with self.nickdb_connection.enter_scope() as scope: if was_authenticated and self.nickdb.exists(scope, old_nick): self.nickdb.set_signoff(scope, old_nick) if self.nickdb.exists(scope, nick): is_admin = self.nickdb.is_admin(scope, nick) if self.nickdb.is_secure(scope, nick): self.broker.deliver( session_id, ltd.encode_status_msg( "Register", "Send password to authenticate your nickname.") ) else: self.log.debug( "Nick not secure, trying to register automatically." ) lastlogin = self.nickdb.get_lastlogin(scope, nick) if lastlogin: self.log.debug("Last login: %s@%s", lastlogin[0], lastlogin[1]) registered = (lastlogin[0] == state.loginid and lastlogin[1] == state.host) else: self.broker.deliver( session_id, ltd.encode_status_msg( "No-Pass", "To register your nickname type /m server p password." )) registration = ACTION(Registration) if registered: registration.mark_registered(session_id) elif is_admin: self.broker.deliver( session_id, ltd.encode_str( "e", "Registration failed, administrative account requires a password." )) self.reputation.fatal(session_id) self.__auto_rename__(session_id) else: registration.notify_messagebox(session_id) self.session.update(session_id, signon=dateutils.now())