Ejemplo n.º 1
0
class ConsoleInput(LineReceiver):
    name = 'Console'
    admin = True
    delimiter = b'\n'

    def __init__(self, protocol):
        self.protocol = protocol
        self.user_types = AttributeSet(['admin', 'console'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.get_rights(user_type))

    def lineReceived(self, line):
        if not line:
            return

        try:
            result = commands.handle_input(self, line.decode())
        # pylint: disable=broad-except
        except Exception:
            traceback.print_exc()
        else:
            if result is not None:
                print(result)

    # methods used to emulate the behaviour of regular Connection objects to
    # prevent errors when command writers didn't test that their scripts would
    # work when run on the console
    def send_chat(self, value: str, _):
        print(value)

    def send_lines(self, lines: List[str]):
        print("\n".join(lines))
Ejemplo n.º 2
0
 def on_login(self, name):
     self.printable_name = name.encode('ascii', 'replace')
     print '%s (IP %s, ID %s) entered the game!' % (self.printable_name, 
         self.address[0], self.player_id)
     self.protocol.irc_say('* %s entered the game' % self.name)
     if self.user_types is None:
         self.user_types = AttributeSet()
         self.rights = AttributeSet()
         if self.protocol.everyone_is_admin:
             self.on_user_login('admin', False)
Ejemplo n.º 3
0
 def on_login(self, name):
     self.printable_name = name.encode('ascii', 'replace')
     print '%s (IP %s, ID %s) entered the game!' % (self.printable_name, 
         self.address[0], self.player_id)
     self.protocol.irc_say('* %s entered the game' % self.name)
     if self.user_types is None:
         self.user_types = AttributeSet()
         self.rights = AttributeSet()
         if self.protocol.everyone_is_admin:
             self.on_user_login('admin', False)
Ejemplo n.º 4
0
    def test_set(self):
        atset = AttributeSet(["test", "set", "name"])
        self.assertTrue(atset.test)
        self.assertTrue(atset.set)
        self.assertTrue(atset.name)
        self.assertFalse(atset.wrong)

        self.assertFalse(atset.new)
        atset.new = False
        self.assertFalse(atset.new)
        atset.new = True
        self.assertTrue(atset.new)
        atset.new = 0
        self.assertFalse(atset.new)
Ejemplo n.º 5
0
class IRCClientFactory(protocol.ClientFactory):
    protocol = IRCBot
    lost_reconnect_delay = 20
    failed_reconnect_delay = 60
    bot = None
    aliases = None
    colors = True
    admin = None
    user_types = None
    rights = None

    def __init__(self, server, config):
        self.aliases = {}
        self.admin = True
        self.user_types = AttributeSet(['admin', 'irc'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.get_rights(user_type))
        self.server = server
        self.nickname = config.get('nickname',
                                   'piqueserver%s' % random.randrange(0, 99))
        self.username = config.get('username', 'piqueserver')
        self.realname = config.get('realname', server.name)
        self.channel = config.get('channel', "#piqueserver.bots").lower()
        self.commandprefix = config.get('commandprefix', '.')
        self.chatprefix = config.get('chatprefix', '')
        self.password = config.get('password', '') or None

    def startedConnecting(self, connector):
        log.info("Connecting to IRC server...")

    def clientConnectionLost(self, connector, reason):
        log.info(
            "Lost connection to IRC server ({}), reconnecting in {} seconds".
            format(reason, self.lost_reconnect_delay))
        reactor.callLater(self.lost_reconnect_delay, connector.connect)

    def clientConnectionFailed(self, connector, reason):
        log.info(
            "Could not connect to IRC server ({}), retrying in {} seconds".
            format(reason, self.failed_reconnect_delay))
        reactor.callLater(self.failed_reconnect_delay, connector.connect)

    def buildProtocol(self, address):
        p = self.protocol()
        p.factory = self
        p.protocol = self.server
        self.bot = p
        return p
Ejemplo n.º 6
0
 def on_login(self, name: str) -> None:
     self.printable_name = escape_control_codes(name)
     if len(self.printable_name) > 15:
         self.kick(silent=True)
     log.info('{name} (IP {ip}, ID {pid}) entered the game!',
              name=self.printable_name,
              ip=self.address[0],
              pid=self.player_id)
     self.protocol.irc_say('* %s (IP %s, ID %s) entered the game!' %
                           (self.name, self.address[0], self.player_id))
     if self.user_types is None:
         self.user_types = AttributeSet()
         self.rights = AttributeSet()
         if self.protocol.everyone_is_admin:
             self.on_user_login('admin', False)
Ejemplo n.º 7
0
class IRCClientFactory(protocol.ClientFactory):
    protocol = IRCBot
    lost_reconnect_delay = 20
    failed_reconnect_delay = 60
    bot = None
    aliases = None
    colors = True
    admin = None
    user_types = None
    rights = None
    
    def __init__(self, server, config):
        self.aliases = {}
        self.admin = True
        self.user_types = AttributeSet(['admin', 'irc'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.rights.get(user_type, ()))
        self.server = server
        self.nickname = config.get('nickname', 
            'pyspades%s' % random.randrange(0, 99)).encode('ascii')
        self.username = config.get('username', 'pyspades').encode('ascii')
        self.realname = config.get('realname', server.name).encode('ascii')
        self.channel = config.get('channel', "#pyspades.bots").encode(
            'ascii').lower()
        self.commandprefix = config.get('commandprefix', '.').encode('ascii')
        self.chatprefix = config.get('chatprefix', '').encode('ascii')
        self.password = config.get('password', '').encode('ascii') or None
    
    def startedConnecting(self, connector):
        print "Connecting to IRC server..."
    
    def clientConnectionLost(self, connector, reason):
        print "Lost connection to IRC server (%s), reconnecting in %s seconds" % (
            reason, self.lost_reconnect_delay)
        reactor.callLater(self.lost_reconnect_delay, connector.connect)
    
    def clientConnectionFailed(self, connector, reason):
        print "Could not connect to IRC server (%s), retrying in %s seconds" % (
            reason, self.failed_reconnect_delay)
        reactor.callLater(self.failed_reconnect_delay, connector.connect)
    
    def buildProtocol(self, address):
        p = self.protocol()
        p.factory = self
        p.protocol = self.server
        self.bot = p
        return p
Ejemplo n.º 8
0
 def __init__(self, server, config):
     self.aliases = {}
     self.admin = True
     self.user_types = AttributeSet(['admin', 'irc'])
     self.rights = AttributeSet()
     for user_type in self.user_types:
         self.rights.update(commands.get_rights(user_type))
     self.server = server
     self.nickname = config.get('nickname',
                                'piqueserver%s' % random.randrange(0, 99))
     self.username = config.get('username', 'piqueserver')
     self.realname = config.get('realname', server.name)
     self.channel = config.get('channel', "#piqueserver.bots").lower()
     self.commandprefix = config.get('commandprefix', '.')
     self.chatprefix = config.get('chatprefix', '')
     self.password = config.get('password', '') or None
Ejemplo n.º 9
0
 def __init__(self, server, config):
     self.aliases = {}
     self.admin = True
     self.user_types = AttributeSet(['admin', 'moderator', 'guard', 'irc'])
     self.rights = AttributeSet()
     for user_type in self.user_types:
         self.rights.update(commands.rights.get(user_type, ()))
     self.server = server
     self.nickname = config.get('nickname', 
         'pyspades%s' % random.randrange(0, 99)).encode('ascii')
     self.username = config.get('username', 'pyspades').encode('ascii')
     self.realname = config.get('realname', server.name).encode('ascii')
     self.channel = config.get('channel', "#pyspades.bots").encode(
         'ascii').lower()
     self.commandprefix = config.get('commandprefix', '.').encode('ascii')
     self.chatprefix = config.get('chatprefix', '').encode('ascii')
     self.password = config.get('password', '').encode('ascii') or None
Ejemplo n.º 10
0
class ConsoleInput(LineReceiver):
    name = 'Console'
    admin = True
    delimiter = b'\n'

    def __init__(self, protocol):
        self.protocol = protocol
        self.user_types = AttributeSet(['admin', 'console'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.get_rights(user_type))

    def lineReceived(self, line):
        if not line:
            return

        result = commands.handle_input(self, line.decode())
        if result is not None:
            print(result)
Ejemplo n.º 11
0
class ConsoleInput(LineReceiver):
    name = 'Console'
    admin = True
    delimiter = '\n'

    def __init__(self, protocol):
        self.protocol = protocol
        self.user_types = AttributeSet(['admin', 'console'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.rights.get(user_type, ()))

    def lineReceived(self, line):
        if line.startswith('/'):
            line = line[1:]
            result = commands.handle_input(self, line)
            if result is not None:
                print result
        else:
            self.protocol.send_chat(line)
Ejemplo n.º 12
0
class ConsoleInput(LineReceiver):
    name = 'Console'
    admin = True
    delimiter = '\n'

    def __init__(self, protocol):
        self.protocol = protocol
        self.user_types = AttributeSet(['admin', 'console'])
        self.rights = AttributeSet()
        for user_type in self.user_types:
            self.rights.update(commands.get_rights(user_type))

    def lineReceived(self, line):
        if line.startswith('/'):
            line = line[1:]
            result = commands.handle_input(self, line)
            if result is not None:
                print(result)
        else:
            self.protocol.send_chat(line)
Ejemplo n.º 13
0
 def privmsg(self, user, channel, msg):
     if (user in self.owners or user in self.admins or
         user in self.moderators or user in self.guards or user in self.voices):
         if user in self.owners:
             prefix = '~'
             user_type = 'admin'
         elif user in self.admins:
             prefix = '&'
             user_type = 'admin'
         elif user in self.moderators:
             prefix = '@'
             user_type = 'moderator'
         elif user in self.guards:
             prefix = '%'
             user_type = 'guard'
         else:
             prefix = '+'
             user_type = 'none'
         alias = self.factory.aliases.get(user, user)
         if msg.startswith(self.factory.commandprefix) and (
             user in self.owners or user in self.admins or
             user in self.moderators or user in self.guards):
             self.unaliased_name = user
             self.name = prefix + alias
             input = msg[len(self.factory.commandprefix):]
             rights = self.rights
             self.rights = AttributeSet()
             self.rights.update(commands.rights.get(user_type, ()))
             self.rights.update(commands.rights.get('irc', ()))
             result = commands.handle_input(self, input)
             self.rights = rights
             if result is not None:
                 self.send("%s: %s" % (user, result))
         elif msg.startswith(self.factory.chatprefix):
             max_len = MAX_IRC_CHAT_SIZE - len(self.protocol.server_prefix) - 1
             msg = msg[len(self.factory.chatprefix):].strip()
             message = ("<%s> %s" % (prefix + alias, msg))[:max_len]
             message = message.decode('cp1252')
             print message.encode('ascii', 'replace')
             self.factory.server.send_chat(encode(message))
Ejemplo n.º 14
0
 def __init__(self, server, config):
     self.aliases = {}
     self.admin = True
     self.user_types = AttributeSet(['admin', 'irc'])
     self.rights = AttributeSet()
     for user_type in self.user_types:
         self.rights.update(commands.rights.get(user_type, ()))
     self.server = server
     self.nickname = config.get('nickname', 
         'pyspades%s' % random.randrange(0, 99)).encode('ascii')
     self.username = config.get('username', 'pyspades').encode('ascii')
     self.realname = config.get('realname', server.name).encode('ascii')
     self.channel = config.get('channel', "#pyspades.bots").encode(
         'ascii').lower()
     self.commandprefix = config.get('commandprefix', '.').encode('ascii')
     self.chatprefix = config.get('chatprefix', '').encode('ascii')
     self.password = config.get('password', '').encode('ascii') or None
Ejemplo n.º 15
0
 def reload_passes(self):
     self.users = config.get('users', {})
     self.usergroups = config.get('usergroups', {})
     self.defaultcommands = config.get('defaultcommands', {})
     for password in self.passwords.get('admin', []):
         if not password:
             self.everyone_is_admin = True
     commands.rights.update(config.get('rights', {}))
     for connection in self.connections.values():
         connection.rights = AttributeSet()
         name = connection.username
         if name is None:
             continue
         if name in self.users.keys():
             connection.on_user_login(name, True)
         else:
             connection.username = None
             connection.send_chat(
                 'You have been logged out. Your account name has changed or been deleted.'
             )
Ejemplo n.º 16
0
class FeatureConnection(ServerConnection):
    printable_name = None
    admin = False
    last_switch = None
    mute = False
    deaf = False
    login_retries = None
    god = False
    god_build = False
    fly = False
    invisible = False
    building = True
    killing = True
    streak = 0
    best_streak = 0
    last_chat = None
    chat_time = 0
    chat_count = 0
    user_types = None
    
    def on_connect(self):
        protocol = self.protocol
        client_ip = self.address[0]
        try:
            name, reason, timestamp = self.protocol.bans[client_ip]
            if timestamp is not None and reactor.seconds() >= timestamp:
                protocol.remove_ban(client_ip)
                protocol.save_bans()
            else:
                print 'banned user %s (%s) attempted to join' % (name, 
                    client_ip)
                self.disconnect(ERROR_BANNED)
                return
        except KeyError:
            pass
        manager = self.protocol.ban_manager
        if manager is not None:
            reason = manager.get_ban(client_ip)
            if reason is not None:
                print ('federated banned user (%s) attempted to join, '
                    'banned for %r') % (client_ip, reason)
                self.disconnect(ERROR_BANNED)
                return
        ServerConnection.on_connect(self)
    
    def on_join(self):
        if self.protocol.motd is not None:
            self.send_lines(self.protocol.motd)
    
    def on_login(self, name):
        self.printable_name = name.encode('ascii', 'replace')
        print '%s (IP %s, ID %s) entered the game!' % (self.printable_name, 
            self.address[0], self.player_id)
        self.protocol.irc_say('* %s entered the game' % self.name)
        if self.user_types is None:
            self.user_types = AttributeSet()
            self.rights = AttributeSet()
            if self.protocol.everyone_is_admin:
                self.on_user_login('admin', False)
    
    def get_spawn_location(self):
        get_location = self.protocol.map_info.get_spawn_location
        if get_location is not None:
            result = get_location(self)
            if result is not None:
                return result
        return ServerConnection.get_spawn_location(self)
    
    def on_disconnect(self):
        if self.name is not None:
            print self.printable_name, 'disconnected!'
            self.protocol.irc_say('* %s disconnected' % self.name)
            self.protocol.player_memory.append((self.name, self.address[0]))
        else:
            print '%s disconnected' % self.address[0]
        ServerConnection.on_disconnect(self)
    
    def on_command(self, command, parameters):
        result = commands.handle_command(self, command, parameters)
        if result == False:
            parameters = ['***'] * len(parameters)
        log_message = '<%s> /%s %s' % (self.name, command, 
            ' '.join(parameters))
        if result:
            log_message += ' -> %s' % result
            self.send_chat(result)
        print log_message.encode('ascii', 'replace')
    
    def _can_build(self):
        if not self.building:
            return False
        if not self.god and not self.protocol.building:
            return False
    
    def on_block_build_attempt(self, x, y, z):
        return self._can_build()
    
    def on_line_build_attempt(self, points):
        return self._can_build()
    
    def on_line_build(self, points):
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.update(points)
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.update(points)
    
    def on_block_build(self, x, y, z):
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.add((x, y, z))
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.add((x, y, z))
    
    def on_block_destroy(self, x, y, z, mode):
        map_on_block_destroy = self.protocol.map_info.on_block_destroy
        if map_on_block_destroy is not None:
            result = map_on_block_destroy(self, x, y, z, mode)
            if result == False:
                return result
        if not self.building:
            return False
        if not self.god:
            if not self.protocol.building:
                return False
            is_indestructable = self.protocol.is_indestructable
            if mode == DESTROY_BLOCK:
                if is_indestructable(x, y, z):
                    return False
            elif mode == SPADE_DESTROY:
                if (is_indestructable(x, y, z) or
                is_indestructable(x, y, z + 1) or
                is_indestructable(x, y, z - 1)):
                    return False
            elif mode == GRENADE_DESTROY:
                for nade_x in xrange(x - 1, x + 2):
                    for nade_y in xrange(y - 1, y + 2):
                        for nade_z in xrange(z - 1, z + 2):
                            if is_indestructable(nade_x, nade_y, nade_z):
                                return False
    
    def on_block_removed(self, x, y, z):
        if self.protocol.user_blocks is not None:
            self.protocol.user_blocks.discard((x, y, z))
        if self.protocol.god_blocks is not None:
            self.protocol.god_blocks.discard((x, y, z))
    
    def on_hit(self, hit_amount, player, type, grenade):
        if not self.protocol.killing:
            self.send_chat(
                "You can't kill anyone right now! Damage is turned OFF")
            return False
        if not self.killing:
            self.send_chat("%s. You can't kill anyone." % player.name)
            return False
        elif player.god:
            if not player.invisible:
                self.send_chat("You can't hurt %s! That player is in "
                    "*god mode*" % player.name)
            return False
        if self.god:
            self.protocol.send_chat('%s, killing in god mode is forbidden!' %
                self.name, irc = True)
            self.protocol.send_chat('%s returned to being a mere human.' %
                self.name, irc = True)
            self.god = False
            self.god_build = False

    def on_kill(self, killer, type, grenade):
        self.streak = 0
        if killer is None or self.team is killer.team:
            return
        if not grenade or grenade.name == 'grenade':
            # doesn't give streak kills on airstrikes (or other types of
            # explosions)
            killer.streak += 1
            killer.best_streak = max(killer.streak, killer.best_streak)
        killer.team.kills += 1
    
    def on_reset(self):
        self.streak = 0
        self.best_streak = 0
    
    def on_animation_update(self, jump, crouch, sneak, sprint):
        if self.fly and crouch and self.world_object.velocity.z != 0.0:
            jump = True
        return jump, crouch, sneak, sprint
    
    def on_fall(self, damage):
        if self.god:
            return False
        if not self.protocol.fall_damage:
            return False
    
    def on_grenade(self, time_left):
        if self.god:
            self.refill()
    
    def on_team_join(self, team):
        if self.team is not None:
            if self.protocol.teamswitch_interval:
                teamswitch_interval = self.protocol.teamswitch_interval
                if teamswitch_interval == 'never':
                    self.send_chat('Switching teams is not allowed')
                    return False
                if (self.last_switch is not None and 
                    reactor.seconds() - self.last_switch < teamswitch_interval * 60):
                    self.send_chat('You must wait before switching teams again')
                    return False
        if team.locked:
            self.send_chat('Team is locked')
            return False
        balanced_teams = self.protocol.balanced_teams
        if balanced_teams and not team.spectator:
            other_team = team.other
            if other_team.count() < team.count() + 1 - balanced_teams:
                self.send_chat('Team is full')
                return False
        self.last_switch = reactor.seconds()
    
    def on_chat(self, value, global_message):
        if not self.mute:
            current_time = reactor.seconds()
            if self.last_chat is None:
                self.last_chat = current_time
            else:
                self.chat_time += current_time - self.last_chat
                if self.chat_count > CHAT_WINDOW_SIZE:
                    if self.chat_count / self.chat_time > CHAT_PER_SECOND:
                        self.mute = True
                        self.protocol.send_chat(
                            '%s has been muted for excessive spam' % (self.name), 
                            irc = True)
                    self.chat_time = self.chat_count = 0
                else:
                    self.chat_count += 1
                self.last_chat = current_time
        message = '<%s> %s' % (self.name, value)
        if self.mute:
            message = '(MUTED) %s' % message
        elif global_message and self.protocol.global_chat:
            self.protocol.irc_say('<%s> %s' % (self.name, value))
        print message.encode('ascii', 'replace')
        if self.mute:
            self.send_chat('(Chat not sent - you are muted)')
            return False
        elif global_message and not self.protocol.global_chat:
            self.send_chat('(Chat not sent - global chat disabled)')
            return False
        return value
    
    def kick(self, reason = None, silent = False):
        if not silent:
            if reason is not None:
                message = '%s was kicked: %s' % (self.name, reason)
            else:
                message = '%s was kicked' % self.name
            self.protocol.send_chat(message, irc = True)
        # FIXME: Client should handle disconnect events the same way in both
        # main and initial loading network loops
        self.disconnect(ERROR_KICKED + 8)
    
    def ban(self, reason = None, duration = None):
        reason = ': ' + reason if reason is not None else ''
        duration = duration or None
        if duration is None:
            message = '%s permabanned%s' % (self.name, reason)
        else:
            message = '%s banned for %s%s' % (self.name,
                prettify_timespan(duration * 60), reason)
        if self.protocol.on_ban_attempt(self, reason, duration):
            self.protocol.send_chat(message, irc = True)
            self.protocol.on_ban(self, reason, duration)
            if self.address[0]=="127.0.0.1":
                self.protocol.send_chat("Ban ignored: localhost")
            else:
                self.protocol.add_ban(self.address[0], reason, duration,
                                      self.name)

    def send_lines(self, lines):
        current_time = 0
        for line in lines:
            reactor.callLater(current_time, self.send_chat, line)
            current_time += 2
    
    def on_hack_attempt(self, reason):
        print 'Hack attempt detected from %s: %s' % (self.printable_name, 
            reason)
        self.kick(reason)
    
    def on_user_login(self, user_type, verbose = True):
        if user_type == 'admin':
            self.admin = True
            self.speedhack_detect = False
        self.user_types.add(user_type)
        rights = set(commands.rights.get(user_type, ()))
        self.rights.update(rights)
        if verbose:
            message = ' logged in as %s' % (user_type)
            self.send_chat('You' + message)
            self.protocol.irc_say("* " + self.name + message)
    
    def timed_out(self):
        if self.name is not None:
            print '%s timed out' % self.printable_name
        ServerConnection.timed_out(self)
Ejemplo n.º 17
0
 def __init__(self, protocol):
     self.protocol = protocol
     self.user_types = AttributeSet(['admin', 'console'])
     self.rights = AttributeSet()
     for user_type in self.user_types:
         self.rights.update(commands.get_rights(user_type))
Ejemplo n.º 18
0
class FeatureConnection(ServerConnection):
    printable_name = None
    admin = False
    last_switch = None
    mute = False
    deaf = False
    login_retries = None
    god = False
    god_build = False
    fly = False
    invisible = False
    building = True
    killing = True
    streak = 0
    best_streak = 0
    last_chat = None
    chat_time = 0
    chat_count = 0
    user_types = None

    def on_connect(self):
        protocol = self.protocol
        client_ip = self.address[0]
        try:
            name, reason, timestamp, now = self.protocol.bans[client_ip]
            if timestamp is not None and reactor.seconds() >= timestamp:
                protocol.remove_ban(client_ip)
                protocol.save_bans()
            else:
                print 'banned user %s (%s) attempted to join' % (name,
                                                                 client_ip)
                self.disconnect(ERROR_BANNED)
                return
        except KeyError:
            pass
        manager = self.protocol.ban_manager
        if manager is not None:
            reason = manager.get_ban(client_ip)
            if reason is not None:
                print(
                    'federated banned user (%s) attempted to join, '
                    'banned for %r') % (client_ip, reason)
                self.disconnect(ERROR_BANNED)
                return
        ServerConnection.on_connect(self)

    def on_join(self):
        if self.protocol.motd is not None:
            self.send_lines(self.protocol.motd)

    def on_login(self, name):
        self.printable_name = name.encode('ascii', 'replace')
        print '%s (IP %s, ID %s) entered the game!' % (
            self.printable_name, self.address[0], self.player_id)
        self.protocol.irc_say('* %s (IP %s) entered the game' %
                              (self.name, self.address[0]))
        if self.user_types is None:
            self.user_types = AttributeSet()
            self.rights = AttributeSet()
            if self.protocol.everyone_is_admin:
                self.on_user_login('admin', False)

    def get_spawn_location(self):
        get_location = self.protocol.map_info.get_spawn_location
        if get_location is not None:
            result = get_location(self)
            if result is not None:
                return result
        return ServerConnection.get_spawn_location(self)

    def on_disconnect(self):
        if self.name is not None:
            print self.printable_name, 'disconnected!'
            self.protocol.irc_say('* %s (IP %s) disconnected' %
                                  (self.name, self.address[0]))
            self.protocol.player_memory.append((self.name, self.address[0]))
        else:
            print '%s disconnected' % self.address[0]
        ServerConnection.on_disconnect(self)

    def on_command(self, command, parameters):
        result = commands.handle_command(self, command, parameters)
        if result == False:
            parameters = ['***'] * len(parameters)
        log_message = '<%s> /%s %s' % (self.name, command,
                                       ' '.join(parameters))
        if result:
            log_message += ' -> %s' % result
            self.send_chat(result)
        print log_message.encode('ascii', 'replace')

    def _can_build(self):
        if not self.building:
            return False
        if not self.god and not self.protocol.building:
            return False

    def on_block_build_attempt(self, x, y, z):
        return self._can_build()

    def on_line_build_attempt(self, points):
        return self._can_build()

    def on_line_build(self, points):
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.update(points)
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.update(points)

    def on_block_build(self, x, y, z):
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.add((x, y, z))
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.add((x, y, z))

    def on_block_destroy(self, x, y, z, mode):
        map_on_block_destroy = self.protocol.map_info.on_block_destroy
        if map_on_block_destroy is not None:
            result = map_on_block_destroy(self, x, y, z, mode)
            if result == False:
                return result
        if not self.building:
            return False
        if not self.god:
            if not self.protocol.building:
                return False
            is_indestructable = self.protocol.is_indestructable
            if mode == DESTROY_BLOCK:
                if is_indestructable(x, y, z):
                    return False
            elif mode == SPADE_DESTROY:
                if (is_indestructable(x, y, z)
                        or is_indestructable(x, y, z + 1)
                        or is_indestructable(x, y, z - 1)):
                    return False
            elif mode == GRENADE_DESTROY:
                for nade_x in xrange(x - 1, x + 2):
                    for nade_y in xrange(y - 1, y + 2):
                        for nade_z in xrange(z - 1, z + 2):
                            if is_indestructable(nade_x, nade_y, nade_z):
                                return False

    def on_block_removed(self, x, y, z):
        if self.protocol.user_blocks is not None:
            self.protocol.user_blocks.discard((x, y, z))
        if self.protocol.god_blocks is not None:
            self.protocol.god_blocks.discard((x, y, z))

    def on_hit(self, hit_amount, player, type, grenade):
        if not self.protocol.killing:
            self.send_chat(
                "You can't kill anyone right now! Damage is turned OFF")
            return False
        if not self.killing:
            self.send_chat("%s. You can't kill anyone." % player.name)
            return False
        elif player.god:
            if not player.invisible:
                self.send_chat("You can't hurt %s! That player is in "
                               "*god mode*" % player.name)
            return False
        if self.god:
            self.protocol.send_chat('%s, killing in god mode is forbidden!' %
                                    self.name,
                                    irc=True)
            self.protocol.send_chat('%s returned to being a mere human.' %
                                    self.name,
                                    irc=True)
            self.god = False
            self.god_build = False

    def on_kill(self, killer, type, grenade):
        self.streak = 0
        if killer is None or self.team is killer.team:
            return
        if not grenade or grenade.name == 'grenade':
            # doesn't give streak kills on airstrikes (or other types of
            # explosions)
            killer.streak += 1
            killer.best_streak = max(killer.streak, killer.best_streak)
        killer.team.kills += 1

    def on_reset(self):
        self.streak = 0
        self.best_streak = 0

    def on_animation_update(self, jump, crouch, sneak, sprint):
        if self.fly and crouch and self.world_object.velocity.z != 0.0:
            jump = True
        return jump, crouch, sneak, sprint

    def on_fall(self, damage):
        if self.god:
            return False
        if not self.protocol.fall_damage:
            return False

    def on_grenade(self, time_left):
        if self.god:
            self.refill()

    def on_team_join(self, team):
        if self.team is not None:
            if self.protocol.teamswitch_interval:
                teamswitch_interval = self.protocol.teamswitch_interval
                if teamswitch_interval == 'never':
                    self.send_chat('Switching teams is not allowed')
                    return False
                if (self.last_switch is not None
                        and reactor.seconds() - self.last_switch <
                        teamswitch_interval * 60):
                    self.send_chat(
                        'You must wait before switching teams again')
                    return False
        if team.locked:
            self.send_chat('Team is locked')
            if not team.spectator and not team.other.locked:
                return team.other
            return False
        balanced_teams = self.protocol.balanced_teams
        if balanced_teams and not team.spectator:
            other_team = team.other
            if other_team.count() < team.count() + 1 - balanced_teams:
                if other_team.locked:
                    return False
                self.send_chat('Team is full, moved to %s' % other_team.name)
                return other_team
        self.last_switch = reactor.seconds()

    def on_chat(self, value, global_message):
        if not self.mute:
            current_time = reactor.seconds()
            if self.last_chat is None:
                self.last_chat = current_time
            else:
                self.chat_time += current_time - self.last_chat
                if self.chat_count > CHAT_WINDOW_SIZE:
                    if self.chat_count / self.chat_time > CHAT_PER_SECOND:
                        self.mute = True
                        self.protocol.send_chat(
                            '%s has been muted for excessive spam' %
                            (self.name),
                            irc=True)
                    self.chat_time = self.chat_count = 0
                else:
                    self.chat_count += 1
                self.last_chat = current_time
        message = '<%s> %s' % (self.name, value)
        if self.mute:
            message = '(MUTED) %s' % message
        elif global_message and self.protocol.global_chat:
            self.protocol.irc_say('<%s> %s' % (self.name, value))
        print message.encode('ascii', 'replace')
        if self.mute:
            self.send_chat('(Chat not sent - you are muted)')
            return False
        elif global_message and not self.protocol.global_chat:
            self.send_chat('(Chat not sent - global chat disabled)')
            return False
        return value

    def kick(self, reason=None, silent=False):
        if not silent:
            if reason is not None:
                message = '%s was kicked: %s' % (self.name, reason)
            else:
                message = '%s was kicked' % self.name
            self.protocol.send_chat(message, irc=False)
            self.protocol.irc_say('%s has been kicked by %s : %s ' %
                                  (self.name, connection.name, reason))
        # FIXME: Client should handle disconnect events the same way in both
        # main and initial loading network loops
        self.disconnect(ERROR_KICKED + 8)

    def ban(self, reason=None, duration=None):
        reason = ': ' + reason if reason is not None else ''
        duration = duration or None
        if duration is None:
            message = '%s permabanned%s' % (self.name, reason)
        else:
            message = '%s banned for %s%s' % (
                self.name, prettify_timespan(duration * 60), reason)
        if self.protocol.on_ban_attempt(self, reason, duration):
            self.protocol.irc_say('* %s  %s' % (message))
            self.protocol.on_ban(self, reason, duration)
            if self.address[0] == "127.0.0.1":
                self.protocol.send_chat("Ban ignored: localhost")
            else:
                self.protocol.add_ban(self.address[0], reason, duration,
                                      self.name)
                return '* %s  %s' % message

    def send_lines(self, lines):
        current_time = 0
        for line in lines:
            reactor.callLater(current_time, self.send_chat, line)
            current_time += 2

    def on_hack_attempt(self, reason):
        print 'Hack attempt detected from %s: %s' % (self.printable_name,
                                                     reason)
        self.kick(reason)

    def on_user_login(self, user_type, verbose=True):
        if user_type == 'admin':
            self.admin = True
            self.speedhack_detect = False
        self.user_types.add(user_type)
        rights = set(commands.rights.get(user_type, ()))
        self.rights.update(rights)
        if verbose:
            message = ' logged in as %s' % (user_type)
            self.send_chat('You' + message)
            self.protocol.irc_say("* " + self.name + message)

    def timed_out(self):
        if self.name is not None:
            print '%s timed out' % self.printable_name
        ServerConnection.timed_out(self)
Ejemplo n.º 19
0
 def __init__(self, protocol):
     self.protocol = protocol
     self.user_types = AttributeSet(['admin', 'console'])
     self.rights = AttributeSet()
     for user_type in self.user_types:
         self.rights.update(commands.rights.get(user_type, ()))
Ejemplo n.º 20
0
class IRCBot(irc.IRCClient):
    owners = None
    admins = None
    moderators = None
    guards = None
    voices = None
    unaliased_name = None
    
    def _get_nickname(self):
        return self.factory.nickname
    nickname = property(_get_nickname)
    
    def _get_colors(self):
        return self.factory.colors
    colors = property(_get_colors)
    
    def _get_admin(self):
        return self.factory.admin
    admin = property(_get_admin)
    
    def _get_user_types(self):
        return self.factory.user_types
    user_types = property(_get_user_types)
    
    def _get_rights(self):
        return self.factory.rights
    rights = property(_get_rights)
    
    def signedOn(self):
        self.join(self.factory.channel, self.factory.password)
    
    def joined(self, channel):
        if channel.lower() == self.factory.channel:
            self.owners = set()
            self.admins = set()
            self.moderators = set()
            self.guards = set()
            self.voices = set()
        print "Joined channel %s" % channel
    
    def irc_NICK(self, prefix, params):
        user = prefix.split('!', 1)[0]
        new_user = params[0]
        if user in self.owners:
            self.owners.discard(user)
            self.owners.add(new_user)
        if user in self.admins:
            self.admins.discard(user)
            self.admins.add(new_user)
        if user in self.moderators:
            self.moderators.discard(user)
            self.moderators.add(new_user)
        if user in self.guards:
            self.guards.discard(user)
            self.guards.add(new_user)
        if user in self.voices:
            self.voices.discard(user)
            self.voices.add(new_user)
    
    def irc_RPL_NAMREPLY(self, *arg):
        if not arg[1][2].lower() == self.factory.channel:
            return
        for name in arg[1][3].split():
            mode = name[0]
            l = {'~': self.owners, '&': self.admins, '@': self.moderators, '%': self.guards, '+': self.voices}
            if mode in l: 
                l[mode].add(name[1:])
    
    def left(self, channel):
        if channel.lower() == self.factory.channel:
            self.owners = None
            self.admins = None
            self.moderators = None
            self.guards = None
            self.voices = None
    
    @channel
    def modeChanged(self, user, channel, set, modes, args):
        ll = {'q' : self.owners, 'a' : self.admins, 'o' : self.moderators, 'h' : self.guards, 'v' : self.voices}
        for i in range(len(args)):
            mode, name = modes[i], args[i]
            if mode not in ll:
                continue
            l = ll[mode]
            if set:
                l.add(name)
            elif not set:
                l.discard(name)
    
    @channel
    def privmsg(self, user, channel, msg):
        if (user in self.owners or user in self.admins or
            user in self.moderators or user in self.guards or user in self.voices):
            if user in self.owners:
                prefix = '~'
                user_type = 'admin'
            elif user in self.admins:
                prefix = '&'
                user_type = 'admin'
            elif user in self.moderators:
                prefix = '@'
                user_type = 'moderator'
            elif user in self.guards:
                prefix = '%'
                user_type = 'guard'
            else:
                prefix = '+'
                user_type = 'none'
            alias = self.factory.aliases.get(user, user)
            if msg.startswith(self.factory.commandprefix) and (
                user in self.owners or user in self.admins or
                user in self.moderators or user in self.guards):
                self.unaliased_name = user
                self.name = prefix + alias
                input = msg[len(self.factory.commandprefix):]
                rights = self.rights
                self.rights = AttributeSet()
                self.rights.update(commands.rights.get(user_type, ()))
                self.rights.update(commands.rights.get('irc', ()))
                result = commands.handle_input(self, input)
                self.rights = rights
                if result is not None:
                    self.send("%s: %s" % (user, result))
            elif msg.startswith(self.factory.chatprefix):
                max_len = MAX_IRC_CHAT_SIZE - len(self.protocol.server_prefix) - 1
                msg = msg[len(self.factory.chatprefix):].strip()
                message = ("<%s> %s" % (prefix + alias, msg))[:max_len]
                message = message.decode('cp1252')
                print message.encode('ascii', 'replace')
                self.factory.server.send_chat(encode(message))
    
    @channel
    def userLeft(self, user, channel):
        self.owners.discard(user)
        self.admins.discard(user)
        self.moderators.discard(user)
        self.guards.discard(user)
        self.voices.discard(user)

    def userQuit(self, user, message):
        self.userLeft(user, self.factory.channel)

    def userKicked(self, kickee, channel, kicker, message):
        self.userLeft(kickee, channel)
    
    def send(self, msg, filter = False):
        msg = msg.encode('cp1252', 'replace')
        if filter:
            msg = filter_printable(msg)
        self.msg(self.factory.channel, msg)
    
    def me(self, msg, filter = False):
        msg = msg.encode('cp1252', 'replace')
        if filter:
            msg = filter_printable(msg)
        self.describe(self.factory.channel, msg)
Ejemplo n.º 21
0
class FeatureConnection(ServerConnection):
    def __init__(self, *args, **kwargs):
        self.printable_name = None
        self.admin = False
        self.last_switch = None
        self.mute = False
        self.deaf = False
        self.login_retries = None
        self.god = False
        self.god_build = False
        self.fly = False
        self.invisible = False
        self.building = True
        self.killing = True
        self.streak = 0
        self.best_streak = 0
        self.chat_limiter = RateLimiter(CHAT_WINDOW_SIZE,
                                        CHAT_WINDOW_SIZE / CHAT_PER_SECOND)
        self.user_types = None
        self.rights = None
        self.can_complete_line_build = True

        super().__init__(*args, **kwargs)

    def on_connect(self) -> None:
        protocol = self.protocol
        client_ip = self.address[0]

        if client_ip in self.protocol.bans:
            name, reason, timestamp = self.protocol.bans[client_ip]

            if timestamp is not None and reactor.seconds() >= timestamp:
                protocol.remove_ban(client_ip)
                protocol.save_bans()
            else:
                log.info('banned user {} ({}) attempted to join'.format(
                    name, client_ip))
                self.disconnect(ERROR_BANNED)
                return

        manager = self.protocol.ban_manager

        if manager is not None:
            reason = manager.get_ban(client_ip)
            if reason is not None:
                log.info(('federated banned user (%s) attempted to join, '
                          'banned for %r') % (client_ip, reason))
                self.disconnect(ERROR_BANNED)
                return

        ServerConnection.on_connect(self)

    def on_join(self) -> None:
        if self.protocol.motd is not None:
            self.send_lines(self.protocol.motd)

    def on_login(self, name: str) -> None:
        self.printable_name = escape_control_codes(name)
        if len(self.printable_name) > 15:
            self.kick(silent=True)
        log.info('{name} (IP {ip}, ID {pid}) entered the game!',
                 name=self.printable_name,
                 ip=self.address[0],
                 pid=self.player_id)
        self.protocol.irc_say('* %s (IP %s, ID %s) entered the game!' %
                              (self.name, self.address[0], self.player_id))
        if self.user_types is None:
            self.user_types = AttributeSet()
            self.rights = AttributeSet()
            if self.protocol.everyone_is_admin:
                self.on_user_login('admin', False)

    def get_spawn_location(self) -> Tuple[int, int, int]:
        get_location = self.protocol.map_info.get_spawn_location
        if get_location is not None:
            result = get_location(self)
            if result is not None:
                return result
        return ServerConnection.get_spawn_location(self)

    def on_disconnect(self) -> None:
        if self.name is not None:
            log.info('{name} disconnected!', name=self.printable_name)
            self.protocol.irc_say('* %s (IP %s) disconnected' %
                                  (self.name, self.address[0]))
            self.protocol.player_memory.append((self.name, self.address[0]))
        else:
            log.info('{ip} disconnected', ip=self.address[0])
        ServerConnection.on_disconnect(self)

    def on_command(self, command: str, parameters: List[str]) -> None:
        result = commands.handle_command(self, command, parameters)

        if result:
            for i in reversed(result.split("\n")):
                self.send_chat(i)

    def _can_build(self) -> bool:
        if not self.building:
            return False
        if not self.god and not self.protocol.building:
            return False

        return True

    def on_block_build_attempt(self, x: int, y: int, z: int) -> bool:
        return self._can_build()

    def on_line_build_attempt(self, points) -> bool:
        return self._can_build()

    def on_line_build(self, points) -> None:
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.update(points)
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.update(points)

    def on_block_build(self, x: int, y: int, z: int) -> None:
        if self.god:
            self.refill()
        if self.god_build:
            if self.protocol.god_blocks is None:
                self.protocol.god_blocks = set()
            self.protocol.god_blocks.add((x, y, z))
        elif self.protocol.user_blocks is not None:
            self.protocol.user_blocks.add((x, y, z))

    def on_block_destroy(self, x: int, y: int, z: int, mode: int) -> bool:
        map_on_block_destroy = self.protocol.map_info.on_block_destroy
        if map_on_block_destroy is not None:
            result = map_on_block_destroy(self, x, y, z, mode)
            if result == False:
                return result
        if not self.building:
            return False
        if not self.god:
            if not self.protocol.building:
                return False
            is_indestructable = self.protocol.is_indestructable
            if mode == DESTROY_BLOCK:
                if is_indestructable(x, y, z):
                    return False
            elif mode == SPADE_DESTROY:
                if (is_indestructable(x, y, z)
                        or is_indestructable(x, y, z + 1)
                        or is_indestructable(x, y, z - 1)):
                    return False
            elif mode == GRENADE_DESTROY:
                for nade_x in range(x - 1, x + 2):
                    for nade_y in range(y - 1, y + 2):
                        for nade_z in range(z - 1, z + 2):
                            if is_indestructable(nade_x, nade_y, nade_z):
                                return False

    def on_block_removed(self, x: int, y: int, z: int) -> None:
        if self.protocol.user_blocks is not None:
            self.protocol.user_blocks.discard((x, y, z))
        if self.protocol.god_blocks is not None:
            self.protocol.god_blocks.discard((x, y, z))

    def on_hit(self, hit_amount: float, player: 'FeatureConnection',
               _type: int, grenade: Grenade) -> HookValue:
        if not self.protocol.killing:
            self.send_chat(
                "You can't kill anyone right now! Damage is turned OFF")
            return False
        if not self.killing:
            self.send_chat("%s. You can't kill anyone." % player.name)
            return False
        elif player.god:
            if not player.invisible:
                self.send_chat("You can't hurt %s! That player is in "
                               "*god mode*" % player.name)
            return False
        if self.god:
            self.protocol.send_chat('%s, killing in god mode is forbidden!' %
                                    self.name,
                                    irc=True)
            self.protocol.send_chat('%s returned to being a mere human.' %
                                    self.name,
                                    irc=True)
            self.god = False
            self.god_build = False

    def on_kill(self, killer: Optional['FeatureConnection'], _type: int,
                grenade: None) -> None:
        self.streak = 0
        if killer is None or self.team is killer.team:
            return
        if not grenade or grenade.name == 'grenade':
            # doesn't give streak kills on airstrikes (or other types of
            # explosions)
            killer.streak += 1
            killer.best_streak = max(killer.streak, killer.best_streak)
        killer.team.kills += 1

    def on_reset(self) -> None:
        self.streak = 0
        self.best_streak = 0

    def on_animation_update(self, jump: bool, crouch: bool, sneak: bool,
                            sprint: bool) -> Tuple[bool, bool, bool, bool]:
        if self.fly and crouch and self.world_object.velocity.z != 0.0:
            jump = True
        return jump, crouch, sneak, sprint

    def on_fall(self, damage: int) -> HookValue:
        if self.god:
            return False
        if not self.protocol.fall_damage:
            return False

    def on_grenade(self, time_left: float) -> None:
        if self.god:
            self.refill()

    def on_team_join(self, team: Team) -> HookValue:
        if self.team is not None:
            if self.protocol.teamswitch_interval:
                teamswitch_interval = self.protocol.teamswitch_interval
                teamswitch_allowed = self.protocol.teamswitch_allowed
                if not teamswitch_allowed:
                    self.send_chat('Switching teams is not allowed')
                    return False
                if (self.last_switch is not None
                        and reactor.seconds() - self.last_switch <
                        teamswitch_interval):
                    self.send_chat(
                        'You must wait before switching teams again')
                    return False
        if team.locked:
            self.send_chat('Team is locked')
            if not team.spectator and not team.other.locked:
                return team.other
            return False
        balanced_teams = self.protocol.balanced_teams
        if balanced_teams and not team.spectator:
            other_team = team.other
            if other_team.count() < team.count() + 1 - balanced_teams:
                if other_team.locked:
                    return False
                self.send_chat('Team is full, moved to %s' % other_team.name)
                return other_team
        self.last_switch = reactor.seconds()

    def on_chat(self, value: str, global_message: bool) -> Union[str, bool]:
        """
        notifies when the server receives a chat message

        return False to block sending the message
        """
        message = '<{}> {}'.format(self.name, value)

        if self.mute:
            message = '(MUTED) {}'.format(message)
            self.send_chat('(Chat not sent - you are muted)')
            return False

        if global_message:
            if self.protocol.global_chat:
                # forward message to IRC
                self.protocol.irc_say(message)
            else:
                self.send_chat('(Chat not sent - global chat disabled)')
                return False

        # antispam:
        current_time = reactor.seconds()
        self.chat_limiter.record_event(current_time)
        if self.chat_limiter.above_limit():
            self.mute = True
            self.protocol.send_chat('%s has been muted for excessive spam' %
                                    (self.name),
                                    irc=True)

        log.info("<{name}> {message}",
                 name=escape_control_codes(self.name),
                 message=escape_control_codes(value))

        return value

    def kick(self, reason=None, silent=False):
        if not silent:
            if reason is not None:
                message = '{} was kicked: {}'.format(self.name, reason)
            else:
                message = '%s was kicked' % self.name
            self.protocol.send_chat(message, irc=True)
            log.info(message)
        # FIXME: Client should handle disconnect events the same way in both
        # main and initial loading network loops
        self.disconnect(ERROR_KICKED)

    def ban(self, reason=None, duration=None):
        reason = ': ' + reason if reason is not None else ''
        duration = duration or None
        if duration is None:
            message = '{} permabanned{}'.format(self.name, reason)
        else:
            message = '{} banned for {}{}'.format(self.name,
                                                  prettify_timespan(duration),
                                                  reason)
        if self.protocol.on_ban_attempt(self, reason, duration):
            self.protocol.send_chat(message, irc=True)
            self.protocol.on_ban(self, reason, duration)
            if self.address[0] == "127.0.0.1":
                self.protocol.send_chat("Ban ignored: localhost")
            else:
                self.protocol.add_ban(self.address[0], reason, duration,
                                      self.name)

    def send_lines(self, lines: List[str]) -> None:
        current_time = 0
        for line in lines:
            reactor.callLater(current_time, self.send_chat, line)
            current_time += 2

    def on_hack_attempt(self, reason):
        log.warn('Hack attempt detected from {}: {}'.format(
            self.printable_name, reason))
        self.kick(reason)

    def on_user_login(self, user_type, verbose=True):
        log.info("'{username}' logged in as {user_type}",
                 username=self.name,
                 user_type=user_type)

        if user_type == 'admin':
            self.admin = True
            self.speedhack_detect = False

        # notify of new release to admin on /login
        new_release = self.protocol.new_release
        if user_type == 'admin' and new_release:
            self.send_chat("!" * 30)
            self.send_chat(format_release(new_release))
            self.send_chat("!" * 30)

        self.user_types.add(user_type)
        rights = set(commands.get_rights(user_type))
        self.rights.update(rights)
        if verbose:
            message = ' logged in as %s' % (user_type)
            self.send_chat('You' + message)
            self.protocol.irc_say("* " + self.name + message)

    def timed_out(self):
        if self.name is not None:
            log.info('%s timed out' % self.printable_name)
        ServerConnection.timed_out(self)