Fixes to auth detection and message parsing

* don't check authentication if the network doesn't need to
  register
* don't pass through muser for ZNC type messages
* avoid duplicate message for queries containing highlights
* make a copy of the cast for metadata analysis to avoid poisoning it
* set up callback for when the instance is authenticated, so we can
  request a LIST immediately if so desired
* separate out seeding functions to populate CHANLIMIT to ease future
  work involving other options, such as PREFIX
This commit is contained in:
2020-06-07 17:26:53 +01:00
parent 2a9869d0f9
commit 3acf182171
5 changed files with 116 additions and 85 deletions

View File

@@ -125,9 +125,9 @@ class IRCRelay(IRCClient):
class IRCBot(IRCClient):
def __init__(self, net, num):
self.isconnected = False
self.authenticated = False
self.channels = []
self.net = net
self.authenticated = not regproc.needToRegister(self.net)
self.num = num
self.buffer = ""
self.name = net + str(num)
@@ -230,6 +230,7 @@ class IRCBot(IRCClient):
del cast["ident"]
del cast["host"]
del cast["channel"]
del cast["muser"]
if "Disconnected from IRC" in cast["msg"]:
log("ZNC disconnected on %s - %i" % (self.net, self.num))
self.isconnected = False
@@ -244,16 +245,16 @@ class IRCBot(IRCClient):
cast["num"] = self.num
if "channel" in cast.keys():
if cast["type"] == "mode":
if self.nickname.lower() == cast["channel"].lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "self"
self.event(**castDup)
if cast["modearg"]:
if cast["channel"].lower() == self.nickname.lower():
#castDup = deepcopy(cast)
cast["mtype"] = cast["type"]
cast["type"] = "self"
#self.event(**castDup)
if cast["modearg"]: # check if modearg is non-NoneType
if self.nickname.lower() == cast["modearg"].lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "self"
castDup["type"] = "highlight"
self.event(**castDup)
else:
if cast["channel"].lower() == self.nickname.lower():
@@ -263,34 +264,39 @@ class IRCBot(IRCClient):
# Don't call self.event for this one because queries are not events on a
# channel, but we still want to see them
# we have been kicked
if "user" in cast.keys():
if cast["user"].lower() == self.nickname.lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "self"
self.event(**castDup)
# we sent a message/left/joined/kick someone/quit
if "nick" in cast.keys():
if cast["nick"].lower() == self.nickname.lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "self"
# we have been mentioned in a msg/notice/action/part/quit/topic message
if "msg" in cast.keys(): # Don't highlight queries
if not cast["msg"] == None:
if self.nickname.lower() in cast["msg"].lower():
# TODO: better way to do this
# as we changed the types above, check again
if not cast["type"] in {"query", "self", "highlight", "znc", "who"}:
# we have been kicked
if "user" in cast.keys():
if cast["user"].lower() == self.nickname.lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "highlight"
castDup["type"] = "self"
self.event(**castDup)
# we sent a message/left/joined/kick someone/quit
if "nick" in cast.keys():
if cast["nick"].lower() == self.nickname.lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "self"
# we have been mentioned in a msg/notice/action/part/quit/topic message
if "msg" in cast.keys(): # Don't highlight queries
if not cast["msg"] == None:
if self.nickname.lower() in cast["msg"].lower():
castDup = deepcopy(cast)
castDup["mtype"] = cast["type"]
castDup["type"] = "highlight"
self.event(**castDup)
if not "net" in cast.keys():
cast["net"] = self.net
if not "num" in cast.keys():
cast["num"] = self.num
if not self.authenticated:
regproc.registerTest(cast)
counters.event(self.net, cast["type"])
monitor.event(self.net, cast)
@@ -429,8 +435,8 @@ class IRCBot(IRCClient):
return d
def list(self, noargs=False, nocheck=False):
if not main.network[self.net].relays[self.num]["registered"]:
debug("Will not send LIST, unregistered: %s - %i" % (self.net, self.num))
if not self.authenticated:
debug("Will not send LIST, unauthenticated: %s - %i" % (self.net, self.num))
return
if self.listAttempted:
debug("List request dropped, already asked for LIST - %s - %i" % (self.net, self.num))
@@ -496,45 +502,15 @@ class IRCBot(IRCClient):
return
chankeep.initialList(self.net, self.num, listinfo, self.chanlimit)
def isupport(self, options):
interested = ("CHANLIMIT", "MAXCHANNELS")
if not any((x for x in options if any(y in x for y in interested))):
return # check if any of interested is in any of options, some networks
chanlimit = None # call isupport() more than once, so discard swiftly anything
if not self.isconnected: # we don't care about
log("endpoint connected: %s - %i" % (self.net, self.num))
self.isconnected = True
if not main.network[self.net].relays[self.num]["registered"]:
if main.config["AutoReg"]:
self._regAttempt = reactor.callLater(5, regproc.registerAccount, self.net, self.num)
#regproc.registerAccount(self.net, self.num)
for i in options:
if i.startswith("CHANLIMIT"):
if ":" in i:
split = i.split(":")
if len(split) >= 2:
chanlimit = split[1]
break
elif i.startswith("MAXCHANNELS"):
if "=" in i:
split = i.split("=")
if len(split) == 2:
chanlimit = split[1]
break
try:
self.chanlimit = int(chanlimit)
except TypeError:
warn("Invalid chanlimit: %s" % i)
if self.chanlimit == 0:
self.chanlimit = 200 # don't take the piss if it's not limited
def recheckList(self):
print("list being rechecked")
allRelays = chankeep.allRelaysActive(self.net)
if allRelays:
for i in main.network.keys():
for x in main.network[i].relays.keys():
name = i+str(x)
if main.IRCPool[name].wantList == True:
main.IRCPool[name].list(nocheck=True)
debug("Asking for a list for %s after final relay %i connected" % (self.net, self.num))
print("allrelays now passed")
name = self.net+"1"
if main.IRCPool[name].wantList == True:
main.IRCPool[name].list(nocheck=True)
debug("Asking for a list for %s after final relay %i connected" % (self.net, self.num))
if self.num == 1: # Only one instance should do a list
if self.chanlimit:
if allRelays:
@@ -545,6 +521,51 @@ class IRCBot(IRCClient):
debug("Aborting LIST due to bad chanlimit")
self.checkChannels()
def seed_chanlimit(self, chanlimit):
if not main.network[self.net].relays[self.num]["registered"]: #TODO: add check for register request sent, only send it once
if main.config["AutoReg"]:
self._regAttempt = reactor.callLater(5, regproc.registerAccount, self.net, self.num)
#regproc.registerAccount(self.net, self.num)
try:
self.chanlimit = int(chanlimit)
except TypeError:
warn("Invalid chanlimit: %s" % i)
if self.chanlimit == 0:
self.chanlimit = 200 # don't take the piss if it's not limited
if not regproc.needToRegister(self.net): # if we need to register, only recheck on auth confirmation
self.recheckList()
def seed_prefix(self, prefix):
print("PREFIX", prefix)
def isupport(self, options):
interested = {"CHANLIMIT", "MAXCHANNELS", "PREFIX"}
newOptions = {x for x in options if any(y in x for y in interested)}
if len(newOptions) == 0:
return
if not self.isconnected:
log("endpoint connected: %s - %i" % (self.net, self.num))
self.isconnected = True
for i in newOptions:
if i.startswith("PREFIX"):
if "=" in i:
split = i.split("=")
if len(split) == 2:
prefix = split[1]
self.seed_prefix(prefix)
elif i.startswith("CHANLIMIT"):
if ":" in i:
split = i.split(":")
if len(split) >= 2:
chanlimit = split[1]
self.seed_chanlimit(chanlimit)
elif i.startswith("MAXCHANNELS"):
if "=" in i:
split = i.split("=")
if len(split) == 2:
chanlimit = split[1]
self.seed_chanlimit(chanlimit)
# We need to override these functions as Twisted discards
# the hostname and other useful information in the functions
# that these call by default