Exemplo n.º 1
0
def join(self, ircd, channel):
    mod = next((m for m in ircd.channel_mode_class if m.mode == chmode), None)
    if not mod:
        logging.error(f"Module for channele mode '{chmode}' not found.")
        return
    if not hasattr(channel, mod.list_name):
        setattr(channel, mod.list_name, {})

    last_level = 0
    total_modes, total_params = '+', ''
    for entry in channel.whitelist:
        level = int(entry.split(':')[0])
        if level > last_level:
            # Found higher level.
            last_level = level
        mask = entry.split(':')[1]
        modes = ''
        if match(mask, self.fullmask()):
            if level >= 9999:
                modes += 'oq'
            elif level >= 10:
                modes += 'oa'
            elif level >= 5:
                modes += 'o'
            elif level >= 4:
                modes += 'h'
            elif level >= 1:
                modes += 'v'
        if modes:
            nicks = '{} '.format(self.nickname) * len(modes)
            total_modes += modes
            total_params += nicks
    if total_modes and total_params:
        ircd.handle('MODE', '{} {} {}'.format(channel.name, total_modes,
                                              total_params))
Exemplo n.º 2
0
def join(self, ircd, channel):
    if chmode in channel.modes and 'j' in channel.chmodef and not self.ocheck(
            'o', 'override') and self.server.eos:
        r = int(round(time.time() * 1000))
        channel.joinQueue[r] = {}
        channel.joinQueue[r]['ctime'] = int(time.time())
        if len(channel.joinQueue) > channel.chmodef['j']['amount']:
            channel.joinQueue = {}
            if channel.chmodef['j']['action'] == 'i':
                ircd.handle('MODE', '{} +i'.format(channel.name))
            elif channel.chmodef['j']['action'] == 'R':
                ircd.handle('MODE', '{} +R'.format(channel.name))
            channel.chmodef['j']['actionSet'] = int(time.time())
Exemplo n.º 3
0
def msg(self, ircd, channel, msg):
    if chmode in channel.modes and 'm' in channel.chmodef and self.chlevel(
            channel) < 2 and 'o' not in self.modes:
        if self not in channel.messageQueue:
            channel.messageQueue[self] = {}
            channel.messageQueue[self]['ctime'] = time.time()
        channel.messageQueue[self][int(round(time.time() * 1000))] = None
        if len(channel.messageQueue[self]) > channel.chmodef['m']['amount']:
            p = {'sync': False}
            if channel.chmodef['m']['action'] == 'kick':
                ircd.handle(
                    'KICK',
                    '{} {} :Flood! Limit is {} messages in {} seconds.'.format(
                        channel.name, self.uid, channel.chmodef['m']['amount'],
                        channel.chmodef['m']['time']),
                    params=p)
            elif channel.chmodef['m']['action'] == 'b':
                duration = channel.chmodef['m']['duration']
                ircd.handle(
                    'MODE', '{} +b ~t:{}:*@{}'.format(channel.name, duration,
                                                      self.cloakhost))
                ircd.handle(
                    'KICK',
                    '{} {} :Flood! Limit is {} messages in {} seconds.'.format(
                        channel.name, self.uid, channel.chmodef['m']['amount'],
                        channel.chmodef['m']['time']),
                    params=p)
            elif channel.chmodef['m']['action'] == 'm':
                ircd.handle('MODE', '{} +m'.format(channel.name))
                channel.chmodef['m']['actionSet'] = int(time.time())
            del channel.messageQueue[self]
Exemplo n.º 4
0
def checkExpiredBans(ircd):
    remove_bans = {}
    for chan in ircd.channels:
        remove_bans[chan] = []
        for ban in [ban for ban in chan.bans if ban and ban[:2] == '~t']:
            minutes = int(ban.split(':')[1]) * 60
            banset = int(chan.bans[ban]['ctime'])
            if int(time.time()) >= (minutes + banset):
                remove_bans[chan].append(ban)
    for chan in remove_bans:
        if len(remove_bans[chan]) < 1:
            continue
        bans = ' '.join(remove_bans[chan])
        tmodes = 'b' * len(remove_bans[chan])
        ircd.handle('MODE', '{} -{} {} 0'.format(chan.name, tmodes, bans))
Exemplo n.º 5
0
def checkExpiredFloods(ircd):
    # Checking for timed-out flood protection.
    channels = (channel for channel in ircd.channels
                if chmode in channel.modes and 'm' in channel.chmodef)
    for chan in channels:
        if chan.chmodef['m']['action'] == 'm' and 'm' in chan.modes:
            if chan.chmodef['m']['actionSet'] and int(
                    time.time()) - chan.chmodef['m'][
                        'actionSet'] > chan.chmodef['m']['duration'] * 60:
                ircd.handle('MODE', '{} -m'.format(chan.name))
                chan.chmodef['m']['actionSet'] = None

        for user in (user for user in chan.users
                     if user in dict(chan.messageQueue)):
            if time.time(
            ) - chan.messageQueue[user]['ctime'] > chan.chmodef['m']['time']:
                # print('Resetting flood for {} on {}'.format(user,chan))
                del chan.messageQueue[user]

    channels = (channel for channel in ircd.channels
                if chmode in channel.modes and 'j' in channel.chmodef)
    for chan in channels:
        for entry in (entry for entry in dict(chan.joinQueue)):
            if int(time.time(
            )) - chan.joinQueue[entry]['ctime'] > chan.chmodef['j']['time']:
                # print('Resetting flood for {} on {}'.format(user, chan))
                del chan.joinQueue[entry]
        if chan.chmodef['j']['action'] == 'i' and 'i' in chan.modes:
            if chan.chmodef['j']['actionSet'] and int(
                    time.time()) - chan.chmodef['j'][
                        'actionSet'] > chan.chmodef['j']['duration'] * 60:
                ircd.handle('MODE', '{} -i'.format(chan.name))
                chan.chmodef['j']['actionSet'] = None
        elif chan.chmodef['j']['action'] == 'R' and 'R' in chan.modes:
            if chan.chmodef['j']['actionSet'] and int(
                    time.time()) - chan.chmodef['j'][
                        'actionSet'] > chan.chmodef['j']['duration'] * 60:
                ircd.handle('MODE', '{} -R'.format(chan.name))
                chan.chmodef['j']['actionSet'] = None
Exemplo n.º 6
0
def processModes(self,
                 ircd,
                 channel,
                 recv,
                 sync=True,
                 sourceServer=None,
                 sourceUser=None):
    logging.debug('processModes(): {} :: {}'.format(self, recv))
    try:
        if sourceServer != ircd or (type(sourceUser).__name__ == 'User'
                                    and sourceUser.server != ircd):
            hook = 'remote_chanmode'
        else:
            hook = 'local_chanmode'
        rawModes = ' '.join(recv[1:])
        if rawModes.startswith(':'):
            rawModes = rawModes[1:]
        if type(sourceUser).__name__ == 'User':
            displaySource = sourceUser.uid
        else:
            displaySource = sourceUser.sid
            # if not sourceServer.eos and sourceServer != ircd:
            #    sync = False
    except Exception as ex:
        logging.exception(ex)
    try:
        # global modebuf, parambuf, action, prevaction, commandQueue
        modebuf, parambuf, commandQueue = [], [], []
        action = ''
        prevaction = ''
        paramcount = -1
        chmodes = ircd.chstatus
        ircd.parammodes = ircd.chstatus
        for x in range(0, 4):
            for m in [m for m in ircd.channel_modes[x] if m not in chmodes]:
                chmodes += m
                if str(x) in '012' and m not in ircd.parammodes:
                    ircd.parammodes += m

        global oper_override
        extban_prefix = None
        if 'EXTBAN' in ircd.support:
            extban_prefix = ircd.support['EXTBAN'][0]
            # logging.info('Extban prefix set: {}'.format(extban_prefix))

        # Setting some mode level shit.
        # +v = 1
        # +h = 2
        # +o = 3
        # +a = 4
        # +q = 5
        # oper = 6
        # server = 7
        modeLevel = {
            # Channel statuses. Users with +h or higher can always remove their own status.
            # These numbers may seem off, but it's correct. This determines the level requirement to set levels.
            # For example, you can only give voice if you have 2 (+h) or higher, and only give ops with level 3 (+o) or higher.
            'v': 2,
            'h': 3,
            'o': 3,
            'a': 4,
            'q': 5
        }
        for t in ircd.channel_modes:
            for m in ircd.channel_modes[t]:
                level = ircd.channel_modes[t][m][0]
                modeLevel[m] = level
        # for m in [m for m in recv[1] if m in chmodes + '+-' or m in channel.modes]:
        warn = []
        modes = recv[1][1:] if recv[1].startswith(':') else recv[1]
        for m in modes:
            if m not in chmodes + '+-' and m not in channel.modes and type(
                    self).__name__ != 'Server':
                if m not in warn:
                    self.sendraw(ircd.ERR.UNKNOWNMODE,
                                 f"{m} :unknown mode bar")
                    warn.append(m)
                continue
            param_mode = None
            if m in ircd.parammodes:
                if (action == '+') or (action == '-' and m not in list(
                        ircd.channel_modes[2]) + list(ircd.channel_modes[3])):
                    # if (action == '+') or (action == '-' and m in list(ircd.channel_modes[0])+list(ircd.channel_modes[1])):
                    paramcount += 1
                    if len(recv[2:]) > paramcount:
                        param_mode = recv[2:][paramcount]
                        logging.info('Param for {}{}: {}'.format(
                            action, m, param_mode))
                    elif m not in ircd.channel_modes[0]:
                        logging.warning(
                            'Received param mode {}{} without param'.format(
                                action, m))
                        continue
            if m in '+-' and action != m:
                action = m
                # logging.debug('Action set: {}'.format(action))
                if action != prevaction:
                    if modebuf and modebuf[-1] in '-+':
                        modebuf = modebuf[1:]
                    modebuf.append(action)
                    # logging.debug('Modebuf now: {}'.format(modebuf))
                prevaction = action
                continue

            if not action:
                action = '+'
            if m in modeLevel and modeLevel[m] == 6 and (
                    type(self).__name__ != 'Server' and 'o' not in self.modes):
                continue
            if m in modeLevel and modeLevel[m] == 7 and type(
                    self).__name__ != 'Server':
                continue
            if m not in '+-' and action != prevaction and (
                (m in chmodes or m in ircd.chstatus) or
                (action in '+-' and m in channel.modes)):
                modebuf.append(action)
                prevaction = action
            if m not in ircd.chstatus and m not in '+-':
                if m in modeLevel and self.chlevel(
                        channel) < modeLevel[m] and not self.ocheck(
                            'o', 'override'):
                    continue
                elif m in modeLevel and self.chlevel(
                        channel) < modeLevel[m] != 6:
                    oper_override = True

            if m not in ircd.core_chmodes:
                c = next((x for x in ircd.channel_mode_class if x.mode == m),
                         None)
                if c:
                    if not c.check(channel, action, param_mode):
                        continue
                    c.modebuf = modebuf
                    c.parambuf = parambuf
                    if (action == '+' and c.set_mode(self, channel, param_mode)
                        ) or (action == '-'
                              and c.remove_mode(self, channel, param_mode)):
                        pass
                else:
                    # Modules like extbans do not have a mode, so we will check for hooks manually.
                    for callable in [
                            callable for callable in ircd.hooks
                            if callable[0].lower() == 'pre_' +
                            hook and m in callable[1]
                    ]:
                        try:
                            callable[2](self, ircd, channel, modebuf, parambuf,
                                        action, m, param_mode)
                        except Exception as ex:
                            logging.exception(ex)

            if action == '+' and (m in chmodes
                                  or type(self).__name__ == 'Server'):
                # SETTING CHANNEL MODES
                if m == 'l' and len(recv) > 2:
                    if not param_mode.isdigit():
                        continue
                    if int(param_mode) <= 0:
                        continue
                    if m in ircd.chan_params[channel] and int(
                            ircd.chan_params[channel][m]) == int(param_mode):
                        continue
                    else:
                        if m not in channel.modes:
                            channel.modes += m
                        modebuf.append(m)
                        parambuf.append(param_mode)

                elif m == 'k' and m not in ircd.chan_params[channel]:
                    if m not in channel.modes:
                        channel.modes += m
                    modebuf.append(m)
                    parambuf.append(param_mode)

                elif m == 'L':
                    param_mode = param_mode.split(',')[0]
                    if param_mode[0] not in ircd.chantypes:
                        continue
                    redirect = None if 'L' not in channel.modes else ircd.chan_params[
                        channel]['L']
                    if redirect == param_mode or param_mode.lower(
                    ) == channel.name.lower():
                        continue
                    chan_exists = [
                        chan for chan in ircd.channels
                        if chan.name.lower() == param_mode.lower()
                    ]
                    if not chan_exists:
                        self.sendraw(
                            690, ':Target channel {} does not exist.'.format(
                                param_mode))
                        continue
                    if self.chlevel(chan_exists[0]) < 3 and not self.ocheck(
                            'o', 'override'):
                        self.sendraw(
                            690,
                            ':You must be opped on target channel {} to set it as redirect.'
                            .format(chan_exists[0].name))
                        continue
                    if 'L' in chan_exists[0].modes:
                        self.sendraw(690,
                                     ':Destination channel already has +L.')
                        continue
                    elif self.chlevel(channel) < modeLevel[m]:
                        oper_override = True
                    if m not in channel.modes:
                        channel.modes += m
                    modebuf.append(m)
                    parambuf.append(param_mode)

                elif m in 'beI':
                    if extban_prefix and param_mode.startswith(extban_prefix):
                        continue
                    mask = make_mask(ircd, param_mode)
                    if m == 'b':
                        data = channel.bans
                        s = 'ban'
                    elif m == 'e':
                        data = channel.excepts
                        s = 'excepts'
                    elif m == 'I':
                        data = channel.invex
                        s = 'invex'
                    if mask not in data:
                        if len(data) >= ircd.maxlist[m] and type(
                                self).__name__ == 'User':
                            self.sendraw(
                                478, '{} {} :Channel {} list is full'.format(
                                    channel.name, mask, s))
                            continue
                        try:
                            setter = self.fullmask()
                        except:
                            setter = self.hostname
                        modebuf.append(m)
                        parambuf.append(mask)
                        data[mask] = {}
                        data[mask]['setter'] = setter
                        data[mask]['ctime'] = int(time.time())
                        continue

                elif m in ircd.chstatus:
                    timed = False
                    # + status
                    temp_user = param_mode
                    try:
                        t = param_mode.split(':')
                        temp_user = t[0]
                        try:
                            channel.temp_status
                        except:
                            channel.temp_status = {}
                        if valid_expire(t[1]):
                            timed = valid_expire(t[1])
                    except:
                        pass

                    user = list(
                        filter(
                            lambda u: u.uid == temp_user or u.nickname.lower()
                            == temp_user.lower(), channel.users))
                    if not user:
                        continue
                    else:
                        user = user[0]
                    if m in channel.usermodes[user]:
                        continue
                    if type(self).__name__ != 'Server':
                        if self.chlevel(
                                channel) < modeLevel[m] and not self.ocheck(
                                    'o', 'override'):
                            continue
                        elif self.chlevel(channel) < modeLevel[m]:
                            oper_override = True

                    channel.usermodes[user] += m
                    modebuf.append(m)
                    parambuf.append(user.nickname)
                    if timed:
                        channel.temp_status[user] = {}
                        channel.temp_status[user][m] = {}
                        channel.temp_status[user][m]['ctime'] = int(
                            time.time()) + timed
                        channel.temp_status[user][m]['action'] = '-'

                if m not in channel.modes and (m
                                               in list(ircd.channel_modes[3]) +
                                               list(ircd.channel_modes[2])):
                    # If the mode is not handled by modules, do it here.
                    if not next(
                        (x for x in ircd.channel_mode_class if x.mode == m),
                            None):
                        modebuf.append(m)
                        channel.modes += m
                        logging.debug(
                            'Non-modulair mode "{}" has been handled by m_mode'
                            .format(m))

                    if m == 'O' and len(channel.users) > 2:
                        for user in [
                                user for user in channel.users
                                if 'o' not in user.modes
                        ]:
                            cmd = ('KICK', '{} {} :Opers only'.format(
                                channel.name, user.nickname))
                            commandQueue.append(cmd)

            elif action == '-' and ((m in chmodes or m in channel.modes)
                                    or type(self).__name__ == 'Server'):
                # REMOVING CHANNEL MODES
                if m in channel.modes:
                    if m == 'l':
                        # channel.limit = 0
                        if 'L' in channel.modes:  # Also unset -L because we do not need it anymore.
                            channel.modes = channel.modes.replace('L', '')
                            modebuf.append('L')
                            parambuf.append(ircd.chan_params[channel]['L'])

                    elif m == 'k':
                        if param_mode != ircd.chan_params[channel]['k']:
                            continue
                        parambuf.append(ircd.chan_params[channel][m])

                    elif m == 'L':
                        parambuf.append(ircd.chan_params[channel]['L'])
                        # channel.redirect = None

                    elif m == 'P':
                        if len(channel.users) == 0:
                            ircd.channels.remove(channel)

                        try:
                            with open(ircd.rootdir + '/db/chans.db') as f:
                                current_perm = f.read().split('\n')[0]
                                current_perm = json.loads(current_perm)
                                del current_perm[channel.name]
                            with open(ircd.rootdir + '/db/chans.db',
                                      'w+') as f:
                                json.dump(current_perm, f)
                        except Exception as ex:
                            logging.debug(ex)

                    if m in channel.modes:
                        # Only remove mode if it's a core mode. ChannelMode class handles the rest.
                        if m in ircd.core_chmodes:
                            channel.modes = channel.modes.replace(m, '')
                            modebuf.append(m)

                elif m in 'beI':
                    mask = make_mask(ircd, param_mode)
                    if m == 'b':
                        data = channel.bans
                    elif m == 'e':
                        data = channel.excepts
                    elif m == 'I':
                        data = channel.invex
                    if mask in data:
                        del data[mask]
                        parambuf.append(mask)
                        modebuf.append(m)
                    elif param_mode in data:
                        del data[param_mode]
                        parambuf.append(param_mode)
                        modebuf.append(m)
                    # continue
                elif m in ircd.chstatus:
                    timed = False
                    # -qaohv
                    temp_user = param_mode
                    try:
                        t = param_mode.split(':')
                        temp_user = t[0]
                        try:
                            channel.temp_status
                        except:
                            channel.temp_status = {}
                        if valid_expire(t[1]):
                            timed = valid_expire(t[1])
                    except:
                        pass
                    user = list(
                        filter(
                            lambda u: temp_user and u.uid == temp_user or u.
                            nickname.lower() == temp_user.lower(),
                            channel.users))
                    if not user:
                        continue
                    else:
                        user = user[0]
                    if m not in channel.usermodes[user]:
                        continue
                    if 'S' in user.modes and user.server.hostname in ircd.conf[
                            'settings']['ulines'] and not self.ocheck(
                                'o', 'override'):
                        self.sendraw(
                            974, '{} :{} is a protected service bot'.format(
                                m, user.nickname))
                        continue
                    elif 'S' in user.modes:
                        oper_override = True
                    if type(self).__name__ != 'Server':
                        if self.chlevel(
                                channel) < modeLevel[m] and not self.ocheck(
                                    'o', 'override') and user != self:
                            continue
                        elif self.chlevel(channel) < modeLevel[m]:
                            oper_override = True

                    channel.usermodes[user] = channel.usermodes[user].replace(
                        m, '')
                    modebuf.append(m)
                    parambuf.append(user.nickname)
                    if timed:
                        channel.temp_status[user] = {}
                        channel.temp_status[user][m] = {}
                        channel.temp_status[user][m]['ctime'] = int(
                            time.time()) + timed
                        channel.temp_status[user][m]['action'] = '+'

            if m in ircd.core_chmodes:
                # Finally, call modules for core modes.
                for callable in [
                        callable for callable in ircd.hooks
                        if callable[0].lower() == 'pre_' +
                        hook and m in callable[1]
                ]:
                    try:
                        callable[2](self, ircd, channel, modebuf, parambuf,
                                    action, m, param_mode)
                    except Exception as ex:
                        logging.exception(ex)
            continue

        if not re.sub('[+-]', '', ''.join(modebuf)):
            return

        while modebuf[-1] in '+-':
            modebuf = modebuf[:-1]

        if channel.name[0] == '&':
            sync = False

        modes = ''.join(modebuf)
        # total_modes, total_params = [], []
        if len(modebuf) > 1:
            total_modes, total_params = [], []
            paramcount = 0
            action = ''
            for m in modes:
                if m in '+-':
                    action = m
                    total_modes.append(m)
                    continue

                total_modes.append(m)
                if m in list(ircd.channel_modes[1]) + list(
                        ircd.channel_modes[2]):
                    # If a module handles a channel mode with a param, but for some reason forgets to add it to the chan_params dict,
                    # we will add it here. It is really important that param-modes have their params saved.
                    if action == '+':
                        if m in ircd.core_chmodes:
                            logging.debug(
                                '[core] Storing param of {}: {}'.format(
                                    m, parambuf[paramcount]))
                            ircd.chan_params[channel][m] = parambuf[paramcount]
                        elif m not in ircd.chan_params[channel]:
                            logging.debug(
                                '[fallback] Storing param of {}: {}'.format(
                                    m, parambuf[paramcount]))
                            ircd.chan_params[channel][m] = parambuf[paramcount]

                    elif action == '-' and m in ircd.chan_params[channel]:
                        logging.debug(
                            '[fallback] Forgetting param of {}: {}'.format(
                                m, ircd.chan_params[channel][m]))
                        del ircd.chan_params[channel][m]

                for callable in [
                        callable for callable in ircd.hooks
                        if callable[0].lower() == hook
                ]:
                    try:
                        callable[2](self, ircd, channel, modes, parambuf)
                    except Exception as ex:
                        logging.exception(ex)

                if m in ircd.parammodes and (
                        m not in ircd.channel_modes[2]
                        or action == '+') and len(parambuf) > paramcount:
                    # logging.debug(f"Paramcount: {paramcount}")
                    # logging.debug(f"Parambuf: {action}{m} {parambuf}")
                    total_params.append(parambuf[paramcount])
                    paramcount += 1
                    # logging.debug(f"Increased paramcount (now={paramcount}) - moving on")

                totalLength = len(''.join(total_modes) + ' ' +
                                  ' '.join(total_params))
                mode_amount = len(re.sub('[+-]', '', ''.join(total_modes)))
                if mode_amount >= MAXMODES or totalLength >= 400:
                    all_modes = ''.join(total_modes) + ' ' + ' '.join(
                        total_params)
                    if oper_override and type(self).__name__ != 'Server':
                        sourceServer.snotice(
                            's',
                            '*** OperOverride by {} ({}@{}) with MODE {} {}'.
                            format(sourceUser.nickname, sourceUser.ident,
                                   sourceUser.hostname, channel.name,
                                   all_modes))
                    if sync:
                        ircd.new_sync(
                            ircd, sourceServer, ':{} MODE {} :{}'.format(
                                displaySource, channel.name, all_modes if
                                type(self).__name__ == 'User' else rawModes))
                    sourceUser.broadcast(channel.users,
                                         'MODE {} {}'.format(
                                             channel.name, all_modes),
                                         source=sourceUser)
                    total_modes, total_params = [action], []
                    continue
            if len(total_modes) > 1:
                all_modes = ''.join(total_modes) + ' ' + ' '.join(total_params)
                if oper_override and type(self).__name__ != 'Server':
                    sourceServer.snotice(
                        's', '*** OperOverride by {} ({}@{}) with MODE {} {}'.
                        format(sourceUser.nickname, sourceUser.ident,
                               sourceUser.hostname, channel.name, all_modes))
                if sync:
                    ircd.new_sync(
                        ircd, sourceServer, ':{} MODE {} :{}'.format(
                            displaySource, channel.name, all_modes
                            if type(self).__name__ == 'User' else rawModes))
                sourceUser.broadcast(channel.users,
                                     'MODE {} {}'.format(
                                         channel.name, all_modes),
                                     source=sourceUser)

            for cmd, data in commandQueue:
                ircd.handle(cmd, data)

            save_db(ircd)

    except Exception as ex:
        logging.exception(ex)