mirror of
				https://github.com/jlu5/PyLink.git
				synced 2025-11-04 08:57:25 +01:00 
			
		
		
		
	Support pre-auth irc.pseudoclient enumeration & configurable altnicks
Closes #516. Closes #288.
This commit is contained in:
		
							parent
							
								
									04cfa9c93e
								
							
						
					
					
						commit
						0bb4a35c6f
					
				@ -22,34 +22,36 @@ def spawn_service(irc, source, command, args):
 | 
			
		||||
    # Get the ServiceBot object.
 | 
			
		||||
    sbot = world.services[name]
 | 
			
		||||
 | 
			
		||||
    nick = sbot.get_nick(irc)
 | 
			
		||||
    ident = sbot.get_ident(irc)
 | 
			
		||||
    host = sbot.get_host(irc)
 | 
			
		||||
    realname = sbot.get_realname(irc)
 | 
			
		||||
 | 
			
		||||
    # Spawning service clients with these umodes where supported. servprotect usage is a
 | 
			
		||||
    # configuration option.
 | 
			
		||||
    preferred_modes = ['oper', 'hideoper', 'hidechans', 'invisible', 'bot']
 | 
			
		||||
    modes = []
 | 
			
		||||
 | 
			
		||||
    if conf.conf['pylink'].get('protect_services'):
 | 
			
		||||
        preferred_modes.append('servprotect')
 | 
			
		||||
 | 
			
		||||
    for mode in preferred_modes:
 | 
			
		||||
        mode = irc.umodes.get(mode)
 | 
			
		||||
        if mode:
 | 
			
		||||
            modes.append((mode, None))
 | 
			
		||||
 | 
			
		||||
    # Track the service's UIDs on each network.
 | 
			
		||||
    log.debug('(%s) spawn_service: Using nick %s for service %s', irc.name, nick, name)
 | 
			
		||||
    u = irc.nick_to_uid(nick)
 | 
			
		||||
    if u and irc.is_internal_client(u):  # If an internal client exists, reuse it.
 | 
			
		||||
        log.debug('(%s) spawn_service: Using existing client %s/%s', irc.name, u, nick)
 | 
			
		||||
        userobj = irc.users[u]
 | 
			
		||||
    if name == 'pylink' and irc.pseudoclient:
 | 
			
		||||
        # irc.pseudoclient already exists, for protocols like clientbot
 | 
			
		||||
        log.debug('(%s) spawn_service: Using existing nick %r for service %r', irc.name, irc.pseudoclient.nick, name)
 | 
			
		||||
        userobj = irc.pseudoclient
 | 
			
		||||
        userobj.opertype = "PyLink Service"
 | 
			
		||||
        userobj.manipulatable = sbot.manipulatable
 | 
			
		||||
    else:
 | 
			
		||||
        log.debug('(%s) spawn_service: Spawning new client %s', irc.name, nick)
 | 
			
		||||
        # No client exists, spawn a new one
 | 
			
		||||
        nick = sbot.get_nick(irc)
 | 
			
		||||
        ident = sbot.get_ident(irc)
 | 
			
		||||
        host = sbot.get_host(irc)
 | 
			
		||||
        realname = sbot.get_realname(irc)
 | 
			
		||||
 | 
			
		||||
        # Spawning service clients with these umodes where supported. servprotect usage is a
 | 
			
		||||
        # configuration option.
 | 
			
		||||
        preferred_modes = ['oper', 'hideoper', 'hidechans', 'invisible', 'bot']
 | 
			
		||||
        modes = []
 | 
			
		||||
 | 
			
		||||
        if conf.conf['pylink'].get('protect_services'):
 | 
			
		||||
            preferred_modes.append('servprotect')
 | 
			
		||||
 | 
			
		||||
        for mode in preferred_modes:
 | 
			
		||||
            mode = irc.umodes.get(mode)
 | 
			
		||||
            if mode:
 | 
			
		||||
                modes.append((mode, None))
 | 
			
		||||
 | 
			
		||||
        # Track the service's UIDs on each network.
 | 
			
		||||
        log.debug('(%s) spawn_service: Spawning new client %s for service %s', irc.name, nick, name)
 | 
			
		||||
        userobj = irc.spawn_client(nick, ident, host, modes=modes, opertype="PyLink Service",
 | 
			
		||||
                                        realname=realname, manipulatable=sbot.manipulatable)
 | 
			
		||||
                                   realname=realname, manipulatable=sbot.manipulatable)
 | 
			
		||||
 | 
			
		||||
    # Store the service name in the User object for easier access.
 | 
			
		||||
    userobj.service = name
 | 
			
		||||
@ -58,7 +60,7 @@ def spawn_service(irc, source, command, args):
 | 
			
		||||
 | 
			
		||||
    # Special case: if this is the main PyLink client being spawned,
 | 
			
		||||
    # assign this as irc.pseudoclient.
 | 
			
		||||
    if name == 'pylink':
 | 
			
		||||
    if name == 'pylink' and not irc.pseudoclient:
 | 
			
		||||
        log.debug('(%s) spawn_service: irc.pseudoclient set to UID %s', irc.name, u)
 | 
			
		||||
        irc.pseudoclient = userobj
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -53,6 +53,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
 | 
			
		||||
        self.handle_463 = self.handle_464 = self.handle_465 = self.handle_error
 | 
			
		||||
 | 
			
		||||
        self._use_builtin_005_handling = True
 | 
			
		||||
        self._nick_fails = 0
 | 
			
		||||
 | 
			
		||||
        self.hook_map = {'ACCOUNT': 'CLIENT_SERVICES_LOGIN'}
 | 
			
		||||
 | 
			
		||||
@ -92,14 +93,19 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
 | 
			
		||||
        self._cap_timer = threading.Timer(self.serverdata.get('sasl_timeout') or 15, _do_cap_end_wrapper)
 | 
			
		||||
        self._cap_timer.start()
 | 
			
		||||
 | 
			
		||||
        # This is a really gross hack to get the defined NICK/IDENT/HOST/GECOS.
 | 
			
		||||
        # But this connection stuff is done before any of the spawn_client stuff in
 | 
			
		||||
        # services_support fires.
 | 
			
		||||
        self.conf_nick = self.serverdata.get('pylink_nick') or conf.conf["bot"].get("nick", "PyLink")
 | 
			
		||||
        f('NICK %s' % (self.conf_nick))
 | 
			
		||||
        ident = self.serverdata.get('pylink_ident') or conf.conf["bot"].get("ident", "pylink")
 | 
			
		||||
        f('USER %s 8 * :%s' % (ident, # TODO: per net realnames or hostnames aren't implemented yet.
 | 
			
		||||
                              conf.conf["bot"].get("realname", "PyLink Clientbot")))
 | 
			
		||||
        # Log in to IRC and set our irc.pseudoclient object.
 | 
			
		||||
        sbot = world.services['pylink']
 | 
			
		||||
        self._nick_fails = 0
 | 
			
		||||
 | 
			
		||||
        nick = sbot.get_nick(self)
 | 
			
		||||
        ident = sbot.get_ident(self)
 | 
			
		||||
        realname = sbot.get_realname(self)
 | 
			
		||||
 | 
			
		||||
        f('NICK %s' % nick)
 | 
			
		||||
        f('USER %s 8 * :%s' % (ident, realname))
 | 
			
		||||
        self.pseudoclient = User(nick, int(time.time()), self.uidgen.next_uid(prefix='@ClientbotInternal'), self.sid,
 | 
			
		||||
                                 ident=ident, realname=realname)
 | 
			
		||||
        self.users[self.pseudoclient.uid] = self.pseudoclient
 | 
			
		||||
 | 
			
		||||
    # Note: clientbot clients are initialized with umode +i by default
 | 
			
		||||
    def spawn_client(self, nick, ident='unknown', host='unknown.host', realhost=None, modes={('i', None)},
 | 
			
		||||
@ -116,7 +122,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
 | 
			
		||||
 | 
			
		||||
        log.debug('(%s) spawn_client stub called, saving nick %s as PUID %s', self.name, nick, uid)
 | 
			
		||||
        u = self.users[uid] = User(nick, ts, uid, server, ident=ident, host=host, realname=realname,
 | 
			
		||||
                                          manipulatable=manipulatable, realhost=realhost, ip=ip)
 | 
			
		||||
                                   manipulatable=manipulatable, realhost=realhost, ip=ip)
 | 
			
		||||
        self.servers[server].users.add(uid)
 | 
			
		||||
 | 
			
		||||
        self.apply_modes(uid, modes)
 | 
			
		||||
@ -794,12 +800,12 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
 | 
			
		||||
 | 
			
		||||
    def handle_433(self, source, command, args):
 | 
			
		||||
        # <- :millennium.overdrivenetworks.com 433 * ice :Nickname is already in use.
 | 
			
		||||
        # HACK: I don't like modifying the config entries raw, but this is difficult because
 | 
			
		||||
        # irc.pseudoclient doesn't exist as an attribute until we get run the ENDBURST stuff
 | 
			
		||||
        # in service_support (this is mapped to 005 here).
 | 
			
		||||
        self.conf_nick += '_'
 | 
			
		||||
        self.serverdata['pylink_nick'] = self.conf_nick
 | 
			
		||||
        self.send('NICK %s' % self.conf_nick)
 | 
			
		||||
 | 
			
		||||
        self._nick_fails += 1
 | 
			
		||||
        newnick = self.pseudoclient.nick = world.services['pylink'].get_nick(self, fails=self._nick_fails)
 | 
			
		||||
        log.debug('(%s) _nick_fails = %s, trying new nick %r', self.name, self._nick_fails, newnick)
 | 
			
		||||
 | 
			
		||||
        self.send('NICK %s' % newnick)
 | 
			
		||||
    handle_432 = handle_437 = handle_433
 | 
			
		||||
 | 
			
		||||
    def handle_account(self, source, command, args):
 | 
			
		||||
@ -937,17 +943,15 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
 | 
			
		||||
        """Handles NICK changes."""
 | 
			
		||||
        # <- :GL|!~GL@127.0.0.1 NICK :GL_
 | 
			
		||||
 | 
			
		||||
        if not self.pseudoclient:
 | 
			
		||||
        if not self.connected.is_set():
 | 
			
		||||
            # We haven't properly logged on yet, so any initial NICK should be treated as a forced
 | 
			
		||||
            # nick change for US. For example, this clause is used to handle forced nick changes
 | 
			
		||||
            # nick change for us. For example, this clause is used to handle forced nick changes
 | 
			
		||||
            # sent by ZNC, when the login nick and the actual IRC nick of the bouncer differ.
 | 
			
		||||
 | 
			
		||||
            # HACK: change the nick config entry so services_support knows what our main
 | 
			
		||||
            # pseudoclient is called.
 | 
			
		||||
            oldnick = self.serverdata['pylink_nick']
 | 
			
		||||
            self.serverdata['pylink_nick'] = self.conf_nick = args[0]
 | 
			
		||||
            log.debug('(%s) Pre-auth FNC: Forcing configured nick to %s from %s', self.name, args[0], oldnick)
 | 
			
		||||
            self.pseudoclient.nick = args[0]
 | 
			
		||||
            log.debug('(%s) Pre-auth FNC: Changing our nick to %s', self.name, args[0])
 | 
			
		||||
            return
 | 
			
		||||
        elif source == self.pseudoclient.uid:
 | 
			
		||||
            self._nick_fails = 0  # Our last nick change succeeded.
 | 
			
		||||
 | 
			
		||||
        oldnick = self.users[source].nick
 | 
			
		||||
        self.users[source].nick = args[0]
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user