Merge branch 'master' into datarestructure

This commit is contained in:
Mark Veidemanis 2019-08-19 20:19:42 +01:00
commit ff74968ff8
16 changed files with 273 additions and 118 deletions

23
commands/all.py Normal file
View File

@ -0,0 +1,23 @@
import main
from core.bot import deliverRelayCommands
class All:
def __init__(self, *args):
self.all(*args)
def all(self, addr, authed, data, obj, spl, success, failure, info, incUsage, length):
if authed:
if length > 2:
for i in main.pool.keys():
relay = main.pool[i]["relay"]
network = main.pool[i]["network"]
alias = main.pool[i]["alias"]
commands = {spl[1]: [" ".join(spl[2:])]}
success("Sending commands to relay %s as user %s" % (relay, alias+"/"+network))
deliverRelayCommands(relay, commands, user=alias+"/"+network)
return
else:
incUsage("all")
return
else:
incUsage(None)

46
commands/allc.py Normal file
View File

@ -0,0 +1,46 @@
import main
from core.bot import deliverRelayCommands
class Allc:
def __init__(self, *args):
self.allc(*args)
def allc(self, addr, authed, data, obj, spl, success, failure, info, incUsage, length):
if authed:
if length > 4:
targets = []
if spl[1] == "network":
if spl[2] in main.network.keys():
for i in main.pool.keys():
if main.pool[i]["network"] == spl[2]:
targets.append(i)
else:
failure("No such network: %s" % spl[2])
return
elif spl[1] == "alias":
if spl[2] in main.alias.keys():
for i in main.pool.keys():
if main.pool[i]["alias"] == spl[2]:
targets.append(i)
else:
failure("No such alias: %s" % spl[2])
return
else:
incUsage("allc")
return
if len(targets) == 0:
failure("No matches found: %s" % spl[2])
return
for i in targets:
relay = main.pool[i]["relay"]
network = main.pool[i]["network"]
alias = main.pool[i]["alias"]
commands = {spl[3]: [" ".join(spl[4:])]}
success("Sending commands to relay %s as user %s" % (relay, alias+"/"+network))
deliverRelayCommands(relay, commands, user=alias+"/"+network)
return
else:
incUsage("allc")
return
else:
incUsage(None)

View File

@ -19,22 +19,22 @@ class ProvisionCommand:
failure("No such network: %s" % spl[3]) failure("No such network: %s" % spl[3])
return return
if "users" in main.relay[spl[1]]: #if "users" in main.relay[spl[1]]:
if not spl[2] in main.relay[spl[1]]["users"]: # if not spl[2] in main.relay[spl[1]]["users"]:
failure("Relay %s not provisioned for alias %s" % (spl[1], spl[2])) # failure("Relay %s not provisioned for alias %s" % (spl[1], spl[2]))
return # return
else: #else:
failure("Relay %s not provisioned for alias %s" % (spl[1], spl[2])) # failure("Relay %s not provisioned for alias %s" % (spl[1], spl[2]))
return # return
rtrn = provision.provisionRelayForNetwork(spl[1], spl[2], spl[3]) rtrn = provision.provisionRelayForNetwork(spl[1], spl[2], spl[3])
if rtrn == "PROVISIONED": #if rtrn == "PROVISIONED":
failure("Relay %s already provisioned for alias %s on network %s" % (spl[1], spl[2], spl[3])) # failure("Relay %s already provisioned for alias %s on network %s" % (spl[1], spl[2], spl[3]))
return # return
elif rtrn == "DUPLICATE": #elif rtrn == "DUPLICATE":
failure("Instance with relay %s and alias %s already exists for network %s" % (spl[1], spl[2], spl[3])) # failure("Instance with relay %s and alias %s already exists for network %s" % (spl[1], spl[2], spl[3]))
return # return
elif rtrn: if rtrn:
success("Started provisioning network %s on relay %s for alias %s" % (spl[3], spl[1], spl[2])) success("Started provisioning network %s on relay %s for alias %s" % (spl[3], spl[1], spl[2]))
info("Instance name is %s" % rtrn) info("Instance name is %s" % rtrn)
return return
@ -43,10 +43,10 @@ class ProvisionCommand:
return return
if length == 3: # provision for relay and alias only if length == 3: # provision for relay and alias only
rtrn = provision.provisionRelayForAlias(spl[1], spl[2]) rtrn = provision.provisionRelayForAlias(spl[1], spl[2])
if rtrn == "PROVISIONED": #if rtrn == "PROVISIONED":
failure("Relay %s already provisioned for alias %s" % (spl[1], spl[2])) # failure("Relay %s already provisioned for alias %s" % (spl[1], spl[2]))
return # return
elif rtrn: if rtrn:
success("Started provisioning relay %s for alias %s" % (spl[1], spl[2])) success("Started provisioning relay %s for alias %s" % (spl[1], spl[2]))
return return
else: else:

View File

@ -15,6 +15,7 @@
"RedisSocket": "/tmp/redis.sock", "RedisSocket": "/tmp/redis.sock",
"UsePassword": true, "UsePassword": true,
"ConnectOnCreate": false, "ConnectOnCreate": false,
"Debug": false,
"Dist": { "Dist": {
"Enabled": true, "Enabled": true,
"SendOutput": false, "SendOutput": false,
@ -26,6 +27,8 @@
}, },
"Password": "s", "Password": "s",
"Tweaks": { "Tweaks": {
"MaxHash": 10,
"DedupPrecision": 9,
"ZNC": { "ZNC": {
"Prefix": "*" "Prefix": "*"
}, },

View File

@ -22,5 +22,7 @@
"network": "network <add|del|list> [<name> <address> <port> <ssl|plain> <sasl|ns|none>]", "network": "network <add|del|list> [<name> <address> <port> <ssl|plain> <sasl|ns|none>]",
"provision": "provision <relay> <alias> [<network>]", "provision": "provision <relay> <alias> [<network>]",
"cmd": "cmd <network> <relay> <user> <entity> <text ...>", "cmd": "cmd <network> <relay> <user> <entity> <text ...>",
"token": "token <add|del|list> [<key>] [<relay>]" "token": "token <add|del|list> [<key>] [<relay>]",
"all": "all <entity> <text ...>",
"allc": "allc <network|alias> <(network)|(alias)> <entity> <text ...>"
} }

View File

@ -9,10 +9,11 @@ from random import randint
from copy import deepcopy from copy import deepcopy
from modules import userinfo from modules import userinfo
from modules import counters as count from modules import counters
from modules import monitor from modules import monitor
from core.relay import sendRelayNotification from core.relay import sendRelayNotification
from utils.dedup import dedup
import main import main
from utils.logging.log import * from utils.logging.log import *
@ -137,7 +138,8 @@ class IRCBot(IRCClient):
del cast[i] del cast[i]
if "muser" in cast.keys(): if "muser" in cast.keys():
cast["nick"], cast["ident"], cast["host"] = self.parsen(cast["muser"]) cast["nick"], cast["ident"], cast["host"] = self.parsen(cast["muser"])
del cast["muser"] #if not cast["type"] in ["nick", "kick", "quit", "part", "join"]:
# del cast["muser"]
if set(["nick", "ident", "host", "message"]).issubset(set(cast)): if set(["nick", "ident", "host", "message"]).issubset(set(cast)):
if "message" in cast.keys(): if "message" in cast.keys():
if cast["ident"] == "znc" and cast["host"] == "znc.in": if cast["ident"] == "znc" and cast["host"] == "znc.in":
@ -148,9 +150,9 @@ class IRCBot(IRCClient):
del cast["host"] del cast["host"]
del cast["target"] del cast["target"]
if not cast["type"] in ["query", "self", "highlight", "znc", "who"]: if not cast["type"] in ["query", "self", "highlight", "znc", "who"]:
if "target" in cast.keys(): if "target" in cast.keys() and not cast["type"] == "mode": # don't handle modes here
if cast["target"].lower() == self.nickname.lower(): if cast["target"].lower() == self.nickname.lower(): # as they are target == nickname
#castDup = deepcopy(cast) #castDup = deepcopy(cast) # however modes are not queries!
cast["mtype"] = cast["type"] cast["mtype"] = cast["type"]
cast["type"] = "query" cast["type"] = "query"
cast["name"] = self.name cast["name"] = self.name
@ -170,21 +172,21 @@ class IRCBot(IRCClient):
castDup["mtype"] = cast["type"] castDup["mtype"] = cast["type"]
castDup["type"] = "self" castDup["type"] = "self"
castDup["name"] = self.name castDup["name"] = self.name
self.event(**castDup) if not cast["target"].lower() == self.nickname.lower(): # modes has been set on us directly
self.event(**castDup) # don't tell anyone else
if "message" in cast.keys() and not cast["type"] == "query": # Don't highlight queries if "message" in cast.keys() and not cast["type"] == "query": # Don't highlight queries
if self.nickname.lower() in cast["message"].lower(): if not cast["message"] == None:
castDup = deepcopy(cast) if self.nickname.lower() in cast["message"].lower():
castDup["mtype"] = cast["type"] castDup = deepcopy(cast)
castDup["type"] = "highlight" castDup["mtype"] = cast["type"]
castDup["name"] = self.name castDup["type"] = "highlight"
self.event(**castDup) castDup["name"] = self.name
self.event(**castDup)
if "name" not in cast.keys(): if not "name" in cast.keys():
cast["name"] = self.net cast["name"] = self.net
if cast["type"] in ["msg", "notice", "action"]: counters.event(self.net, cast["type"])
userinfo.editUser(self.net, cast["nick"]+"!"+cast["ident"]+"@"+cast["host"]) monitor.event(self.name, cast)
count.event(self.net, cast["type"])
monitor.event(self.net, self.name, cast)
def privmsg(self, user, channel, msg): def privmsg(self, user, channel, msg):
self.event(type="msg", muser=user, target=channel, message=msg) self.event(type="msg", muser=user, target=channel, message=msg)
@ -212,10 +214,8 @@ class IRCBot(IRCClient):
return newnick return newnick
def nickChanged(self, olduser, newnick): def nickChanged(self, olduser, newnick):
oldnick, ident, host = self.parsen(olduser)
userinfo.renameUser(self.net, oldnick, olduser, newnick, newnick+"!"+ident+"@"+host)
self.nickname = newnick self.nickname = newnick
self.event(type="self", mtype="nick", nick=oldnick, ident=ident, host=host, user=newnick) self.event(type="self", mtype="nick", muser=olduser, user=newnick)
def irc_ERR_NICKNAMEINUSE(self, prefix, params): def irc_ERR_NICKNAMEINUSE(self, prefix, params):
self._attemptedNick = self.alterCollidedNick(self._attemptedNick) self._attemptedNick = self.alterCollidedNick(self._attemptedNick)
@ -379,8 +379,8 @@ class IRCBot(IRCClient):
if not channel in self.channels: if not channel in self.channels:
self.channels.append(channel) self.channels.append(channel)
self.names(channel).addCallback(self.got_names) self.names(channel).addCallback(self.got_names)
self.who(channel).addCallback(self.got_who)
if main.config["Toggles"]["Who"]: if main.config["Toggles"]["Who"]:
self.who(channel).addCallback(self.got_who)
lc = LoopingCall(self.who, channel) lc = LoopingCall(self.who, channel)
self._getWho[channel] = lc self._getWho[channel] = lc
intrange = main.config["Tweaks"]["Delays"]["WhoRange"] intrange = main.config["Tweaks"]["Delays"]["WhoRange"]
@ -395,63 +395,54 @@ class IRCBot(IRCClient):
lc = self._getWho[channel] lc = self._getWho[channel]
lc.stop() lc.stop()
del self._getWho[channel] del self._getWho[channel]
userinfo.delChannel(self.net, channel) userinfo.delChannel(self.net, channel) # < we do not need to deduplicate this
log("Can no longer cover %s, removing records" % channel) #log("Can no longer cover %s, removing records" % channel)# as it will only be matched once --
# other bots have different nicknames so
def left(self, user, channel, message): def left(self, user, channel, message): # even if they saw it, they wouldn't react
self.event(type="part", muser=user, target=channel, message=message) self.event(type="part", muser=user, target=channel, message=message)
self.botLeft(channel) self.botLeft(channel)
def userJoined(self, user, channel): def userJoined(self, user, channel):
nick, ident, host = self.parsen(user) self.event(type="join", muser=user, target=channel)
userinfo.addUser(self.net, channel, nick, user)
self.event(type="join", nick=nick, ident=ident, host=host, target=channel)
def userLeft(self, user, channel, message): def userLeft(self, user, channel, message):
nick, ident, host = self.parsen(user) self.event(type="part", muser=user, target=channel, message=message)
userinfo.delUser(self.net, channel, nick, user)
self.event(type="part", nick=nick, ident=ident, host=host, target=channel, message=message)
def userQuit(self, user, quitMessage): def userQuit(self, user, quitMessage):
nick, ident, host = self.parsen(user) self.chanlessEvent({"type": "quit", "muser": user, "message": quitMessage})
self.chanlessEvent(type="quit", nick=nick, ident=ident, host=host, message=quitMessage)
userinfo.delUserByNetwork(self.net, nick, user)
def userKicked(self, kickee, channel, kicker, message): def userKicked(self, kickee, channel, kicker, message):
nick, ident, host = self.parsen(kicker) if kickee.lower() == self.nickname.lower():
userinfo.editUser(self.net, kicker)
userinfo.delUserByNick(self.net, channel, kickee)
if kickee.lower == self.nickname.lower:
self.botLeft(channel) self.botLeft(channel)
self.event(type="kick", nick=nick, ident=ident, host=host, target=channel, message=message, user=kickee) self.event(type="kick", muser=kicker, target=channel, message=message, user=kickee)
def chanlessEvent(self, **cast): def chanlessEvent(self, cast):
chans = userinfo.getChansSingle(self.net, cast["nick"]) cast["nick"], cast["ident"], cast["host"] = self.parsen(cast["muser"])
if dedup(self.name, cast):
return # stop right there sir!
chans = userinfo.getChanList(self.net, cast["nick"])
if chans == None: if chans == None:
self.event(**cast) error("No channels returned for chanless event: %s" % cast)
# self.event(**cast) -- no, should NEVER happen
return return
for i in chans: # getChansSingle returns all channels of the user, we only want to use
# ones we have common with them
realChans = set(chans).intersection(set(self.channels))
for i in realChans:
cast["target"] = i cast["target"] = i
self.event(**cast) self.event(**cast)
def userRenamed(self, oldname, newname): def userRenamed(self, oldname, newname):
nick, ident, host = self.parsen(oldname) self.chanlessEvent({"type": "nick", "muser": oldname, "user": newname})
self.chanlessEvent(type="nick", nick=nick, ident=ident, host=host, user=newname)
userinfo.renameUser(self.net, nick, oldname, newname, newname+"!"+ident+"@"+host)
def topicUpdated(self, user, channel, newTopic): def topicUpdated(self, user, channel, newTopic):
nick, ident, host = self.parsen(user) self.event(type="topic", muser=user, target=channel, message= newTopic)
userinfo.editUser(self.net, user)
self.event(type="topic", nick=nick, ident=ident, host=host, target=channel, message= newTopic)
def modeChanged(self, user, channel, toset, modes, args): def modeChanged(self, user, channel, toset, modes, args):
nick, ident, host = self.parsen(user)
userinfo.editUser(self.net, user)
argList = list(args) argList = list(args)
modeList = [i for i in modes] modeList = [i for i in modes]
for a, m in zip(argList, modeList): for a, m in zip(argList, modeList):
self.event(type="mode", nick=nick, ident=ident, host=host, target=channel, modes=m, status=toset, modeargs=a) self.event(type="mode", muser=user, target=channel, modes=m, status=toset, modeargs=a)
class IRCBotFactory(ReconnectingClientFactory): class IRCBotFactory(ReconnectingClientFactory):
def __init__(self, name, relay=None, relayCommands=None, user=None, stage2=None): def __init__(self, name, relay=None, relayCommands=None, user=None, stage2=None):
@ -488,7 +479,7 @@ class IRCBotFactory(ReconnectingClientFactory):
log("%s: connection lost: %s" % (self.name, error)) log("%s: connection lost: %s" % (self.name, error))
if not self.relay: if not self.relay:
sendAll("%s: connection lost: %s" % (self.name, error)) sendAll("%s: connection lost: %s" % (self.name, error))
sendRelayNotification(self.name, {"type": "conn", "status": "lost", "message": error}) sendRelayNotification({"type": "conn", "name": self.name, "status": "lost", "message": error})
self.retry(connector) self.retry(connector)
#ReconnectingClientFactory.clientConnectionLost(self, connector, reason) #ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
@ -500,7 +491,7 @@ class IRCBotFactory(ReconnectingClientFactory):
log("%s: connection failed: %s" % (self.name, error)) log("%s: connection failed: %s" % (self.name, error))
if not self.relay: if not self.relay:
sendAll("%s: connection failed: %s" % (self.name, error)) sendAll("%s: connection failed: %s" % (self.name, error))
sendRelayNotification(self.name, {"type": "conn", "status": "failed", "message": error}) sendRelayNotification({"type": "conn", "name": self.name, "status": "failed", "message": error})
self.retry(connector) self.retry(connector)
#ReconnectingClientFactory.clientConnectionFailed(self, connector, reason) #ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)

View File

@ -132,11 +132,10 @@ class RelayFactory(Factory):
else: else:
return return
def sendRelayNotification(name, cast): def sendRelayNotification(cast):
for i in main.relayConnections.keys(): for i in main.relayConnections.keys():
if main.relayConnections[i].authed: if main.relayConnections[i].authed:
if cast["type"] in main.relayConnections[i].subscriptions: if cast["type"] in main.relayConnections[i].subscriptions:
newCast = deepcopy(cast) newCast = deepcopy(cast)
newCast["name"] = name newCast["time"] = str(datetime.now().isoformat())
newCast["time"] = str(datetime.now())
main.relayConnections[i].send(dumps(newCast)) main.relayConnections[i].send(dumps(newCast))

View File

@ -2,6 +2,8 @@ import json
import pickle import pickle
from redis import StrictRedis from redis import StrictRedis
from string import digits from string import digits
from os import urandom
from utils.logging.log import * from utils.logging.log import *
configPath = "conf/" configPath = "conf/"
@ -33,6 +35,10 @@ CommandMap = {}
runningSample = 0 runningSample = 0
lastMinuteSample = 0 lastMinuteSample = 0
# Generate 16-byte hex key for message checksums
hashKey = urandom(16)
lastEvents = {}
def nets(): def nets():
if not "pool" in globals(): if not "pool" in globals():
return return

View File

@ -1,8 +1,11 @@
from copy import deepcopy from copy import deepcopy
from json import dumps from json import dumps
from datetime import datetime
import main import main
from core.relay import sendRelayNotification from core.relay import sendRelayNotification
from modules import userinfo
from utils.dedup import dedup
def testNetTarget(name, target): def testNetTarget(name, target):
called = False called = False
@ -50,28 +53,53 @@ def magicFunction(A, B):
else: else:
return all(A[k] in B[k] for k in set(A) & set(B)) and set(B) <= set(A) return all(A[k] in B[k] for k in set(A) & set(B)) and set(B) <= set(A)
def event(name, numberedName, cast, event=None): def event(numName, c): # yes I'm using a short variable because otherwise it goes off the screen
if "target" in cast.keys(): if not "target" in c.keys():
target = cast["target"] c["target"] = None
else:
target = None
sendRelayNotification(name, cast) if dedup(numName, c):
monitorGroups = testNetTarget(name, target) return
# metadata scraping
# need to check if this was received from a relay
# in which case, do not do this
if c["type"] in ["msg", "notice", "action", "topic", "mode"]:
userinfo.editUser(c["name"], c["muser"])
elif c["type"] == "nick":
userinfo.renameUser(c["name"], c["nick"], c["muser"], c["user"], c["user"]+"!"+c["ident"]+"@"+c["host"])
elif c["type"] == "kick":
userinfo.editUser(c["name"], c["muser"])
userinfo.delUserByNick(c["name"], c["target"], c["user"])
elif c["type"] == "quit":
userinfo.delUserByNetwork(c["name"], c["nick"], c["muser"])
elif c["type"] == "join":
userinfo.addUser(c["name"], c["target"], c["nick"], c["muser"])
elif c["type"] == "part":
userinfo.delUser(c["name"], c["target"], c["nick"], c["muser"])
if "mtype" in c.keys():
if c["mtype"] == "nick":
userinfo.renameUser(c["name"], c["nick"], c["muser"], c["user"], c["user"]+"!"+c["ident"]+"@"+c["host"])
if "muser" in c.keys():
del c["muser"]
sendRelayNotification(c)
# only monitors below
monitorGroups = testNetTarget(c["name"], c["target"])
if monitorGroups == False: if monitorGroups == False:
return return
for monitorGroup in monitorGroups: for monitorGroup in monitorGroups:
matcher = magicFunction(deepcopy(cast), deepcopy(main.monitor[monitorGroup])) matcher = magicFunction(deepcopy(c), deepcopy(main.monitor[monitorGroup]))
if matcher == True: if matcher == True:
cast["monitor"] = True c["monitor"] = True
if "send" in main.monitor[monitorGroup].keys(): if "send" in main.monitor[monitorGroup].keys():
for i in main.monitor[monitorGroup]["send"].keys(): for i in main.monitor[monitorGroup]["send"].keys():
if isinstance(main.monitor[monitorGroup]["send"][i], bool): if isinstance(main.monitor[monitorGroup]["send"][i], bool):
sendRelayNotification(name, {"type": "err", "name": name, "target": target, "message": cast, "reason": "errdeliv"}) sendRelayNotification({"type": "err", "name": name, "target": target, "message": c, "reason": "errdeliv"})
continue continue
if not i in main.pool.keys(): if not i in main.pool.keys():
sendRelayNotification(name, {"type": "err", "name": name, "target": target, "message": cast, "reason": "noname"}) sendRelayNotification({"type": "err", "name": name, "target": target, "message": c, "reason": "noname"})
if not i in main.IRCPool.keys(): if not i in main.IRCPool.keys():
sendRelayNotification(name, {"type": "err", "name": name, "target": target, "message": cast, "reason": "noinstance"}) sendRelayNotification({"type": "err", "name": name, "target": target, "message": c, "reason": "noinstance"})
for x in main.monitor[monitorGroup]["send"][i]: for x in main.monitor[monitorGroup]["send"][i]:
main.IRCPool[i].msg(x, "monitor [%s] (%s) %s" % (monitorGroup, name, cast)) main.IRCPool[i].msg(x, "monitor [%s] (%s) %s" % (monitorGroup, c["name"], c))

View File

@ -34,7 +34,7 @@ def provisionNetworkData(relay, alias, network, host, port, security, auth, pass
elif auth == "ns": elif auth == "ns":
stage2commands["status"] = [] stage2commands["status"] = []
stage2commands["nickserv"] = [] stage2commands["nickserv"] = []
stage2commands["status"].append("LoadMod NickServ") stage2commands["status"].append("LoadMod nickserv")
stage2commands["nickserv"].append("Set %s" % password) stage2commands["nickserv"].append("Set %s" % password)
if not main.config["ConnectOnCreate"]: if not main.config["ConnectOnCreate"]:
stage3commands["status"] = [] stage3commands["status"] = []
@ -42,46 +42,47 @@ def provisionNetworkData(relay, alias, network, host, port, security, auth, pass
if main.config["Toggles"]["CycleChans"]: if main.config["Toggles"]["CycleChans"]:
stage2commands["status"] = [] stage2commands["status"] = []
stage2commands["status"].append("LoadMod disconkick") stage2commands["status"].append("LoadMod disconkick")
stage2commands["status"].append("LoadMod chansaver")
deliverRelayCommands(relay, commands, deliverRelayCommands(relay, commands,
stage2=[[alias+"/"+network, stage2commands], stage2=[[alias+"/"+network, stage2commands],
[alias+"/"+network, stage3commands]]) [alias+"/"+network, stage3commands]])
return return
def provisionRelayForAlias(relay, alias): def provisionRelayForAlias(relay, alias):
if "users" in main.relay[relay].keys(): #if "users" in main.relay[relay].keys():
if alias in main.relay[relay]["users"]: # if alias in main.relay[relay]["users"]:
return "PROVISIONED" # return "PROVISIONED"
else: #else:
main.relay[relay]["users"] = [] # main.relay[relay]["users"] = []
main.relay[relay]["users"].append(alias) #main.relay[relay]["users"].append(alias)
provisionUserData(relay, alias, main.alias[alias]["nick"], provisionUserData(relay, alias, main.alias[alias]["nick"],
main.alias[alias]["altnick"], main.alias[alias]["altnick"],
main.alias[alias]["ident"], main.alias[alias]["ident"],
main.alias[alias]["realname"], main.alias[alias]["realname"],
main.relay[relay]["password"]) main.relay[relay]["password"])
main.saveConf("relay") #main.saveConf("relay")
return True return True
def provisionRelayForNetwork(relay, alias, network): def provisionRelayForNetwork(relay, alias, network):
if set(["users", "networks"]).issubset(main.relay[relay].keys()): #if set(["users", "networks"]).issubset(main.relay[relay].keys()):
if network in main.relay[relay]["networks"] and alias in main.relay[relay]["users"]: # if network in main.relay[relay]["networks"] and alias in main.relay[relay]["users"]:
return "PROVISIONED" # return "PROVISIONED"
else: #else:
main.relay[relay]["networks"] = [] # main.relay[relay]["networks"] = []
main.relay[relay]["networks"].append(network) #main.relay[relay]["networks"].append(network)
provisionNetworkData(relay, alias, network, provisionNetworkData(relay, alias, network,
main.network[network]["host"], main.network[network]["host"],
main.network[network]["port"], main.network[network]["port"],
main.network[network]["security"], main.network[network]["security"],
main.network[network]["auth"], main.network[network]["auth"],
main.alias[alias]["password"]) main.alias[alias]["password"])
main.saveConf("relay") #main.saveConf("relay")
storedNetwork = False storedNetwork = False
num = 1 num = 1
while not storedNetwork: while not storedNetwork:
i = str(num) i = str(num)
if num == 1000: if num == 1000:
error("Too many iterations in while trying to choose name for r: %s a: %s n: %s" % (relay, alias, network)) error("Iteration limit exceeded while trying to choose name for r: %s a: %s n: %s" % (relay, alias, network))
return False return False
if network+i in main.pool.keys(): if network+i in main.pool.keys():

View File

@ -1,6 +1,9 @@
import main from twisted.internet.threads import deferToThread
from string import digits from string import digits
import main
from utils.logging.log import * from utils.logging.log import *
from utils.logging.debug import debug
def getWhoSingle(name, query): def getWhoSingle(name, query):
result = main.r.sscan("live.who."+name, 0, query, count=9999999) result = main.r.sscan("live.who."+name, 0, query, count=9999999)
@ -23,6 +26,13 @@ def getChansSingle(name, nick):
return None return None
return [i.decode() for i in result] return [i.decode() for i in result]
def getChanList(name, nick):
chanspace = "live.chan."+name+"."+nick
result = main.r.smembers(chanspace)
if len(result) == 0:
return None
return [i.decode() for i in result]
def getChans(nick): def getChans(nick):
result = {} result = {}
for i in main.nets(): for i in main.nets():
@ -61,14 +71,19 @@ def getNamespace(name, channel, nick):
chanspace = "live.chan.%s.%s" % (name, nick) chanspace = "live.chan.%s.%s" % (name, nick)
return [gnamespace, namespace, chanspace] return [gnamespace, namespace, chanspace]
def initialUsers(name, channel, users): def _initialUsers(name, channel, users):
gnamespace = "live.who.%s" % name gnamespace = "live.who.%s" % name
p = main.r.pipeline() p = main.r.pipeline()
for i in users: for i in users:
p.sadd(gnamespace, i[0]+"!"+i[1]+"@"+i[2]) p.sadd(gnamespace, i[0]+"!"+i[1]+"@"+i[2])
p.execute() p.execute()
def initialNames(name, channel, names): def initialUsers(name, channel, users):
debug("Initialising WHO records for %s on %s" % (channel, name))
d = deferToThread(_initialUsers, name, channel, users)
#d.addCallback(testCallback)
def _initialNames(name, channel, names):
namespace = "live.who.%s.%s" % (name, channel) namespace = "live.who.%s.%s" % (name, channel)
p = main.r.pipeline() p = main.r.pipeline()
for i in names: for i in names:
@ -76,6 +91,11 @@ def initialNames(name, channel, names):
p.sadd("live.chan."+name+"."+i, channel) p.sadd("live.chan."+name+"."+i, channel)
p.execute() p.execute()
def initialNames(name, channel, names):
debug("Initialising NAMES records for %s on %s" % (channel, name))
d = deferToThread(_initialNames, name, channel, names)
#d.addCallback(testCallback)
def editUser(name, user): def editUser(name, user):
gnamespace = "live.who.%s" % name gnamespace = "live.who.%s" % name
main.r.sadd(gnamespace, user) main.r.sadd(gnamespace, user)
@ -151,7 +171,7 @@ def delUserByNetwork(name, nick, user):
p.delete(chanspace) p.delete(chanspace)
p.execute() p.execute()
def delChannel(name, channel): # This function is extremely expensive, look to replace def _delChannel(name, channel): # This function is extremely expensive, look to replace
gnamespace = "live.who.%s" % name gnamespace = "live.who.%s" % name
namespace = "live.who.%s.%s" % (name, channel) namespace = "live.who.%s.%s" % (name, channel)
p = main.r.pipeline() p = main.r.pipeline()
@ -166,10 +186,16 @@ def delChannel(name, channel): # This function is extremely expensive, look to r
p.srem("live.chan."+name+"."+i.decode(), channel) p.srem("live.chan."+name+"."+i.decode(), channel)
p.delete(namespace) p.delete(namespace)
p.execute() p.execute()
return [name, channel]
def delChannel(name, channel):
debug("Purging channel %s for %s" % (channel, name))
d = deferToThread(_delChannel, name, channel)
#d.addCallback(testCallback)
def delNetwork(name, channels): def delNetwork(name, channels):
log("Purging channels for %s" % name) debug("Purging channels for %s" % name)
for i in channels: for i in channels:
delChannel(name, i) delChannel(name, i)
log("Finished purging channels for %s" % name) #log("Finished purging channels for %s" % name)
return return

View File

@ -1,14 +1,19 @@
#!/usr/bin/env python #!/usr/bin/env python
from twisted.internet import reactor from twisted.internet import reactor
from twisted.internet.ssl import DefaultOpenSSLContextFactory from twisted.internet.ssl import DefaultOpenSSLContextFactory
from sys import argv, stdout, stderr
#from twisted.python import log #from twisted.python import log
#from sys import stdout #from sys import stdout
#log.startLogging(stdout) #log.startLogging(stdout)
from codecs import getwriter # fix printing odd shit to the terminal
stdout = getwriter("utf8")(stdout) # this is a generic fix but we all know
stderr = getwriter("utf8")(stderr) # it's just for the retards on Rizon using
# unicode quit messages for no reason
import main import main
main.initMain() main.initMain()
if "--debug" in argv: # yes really
main.config["Debug"] = True
from utils.logging.log import * from utils.logging.log import *
from utils.loaders.command_loader import loadCommands from utils.loaders.command_loader import loadCommands
from core.server import Server, ServerFactory from core.server import Server, ServerFactory

21
utils/dedup.py Normal file
View File

@ -0,0 +1,21 @@
from datetime import datetime
from csiphash import siphash24
from json import dumps
import main
from utils.logging.debug import debug
def dedup(numName, c):
# deduplication
c["approxtime"] = str(datetime.utcnow().timestamp())[:main.config["Tweaks"]["DedupPrecision"]]
castHash = siphash24(main.hashKey, dumps(c, sort_keys=True).encode("utf-8"))
del c["approxtime"]
isDuplicate= any(castHash in main.lastEvents[x] for x in main.lastEvents.keys() if not x == numName)
if isDuplicate:
debug("Duplicate: %s" % (c))
return True
if numName in main.lastEvents.keys():
main.lastEvents[numName].insert(0, castHash)
main.lastEvents[numName] = main.lastEvents[numName][0:main.config["Tweaks"]["MaxHash"]]
else:
main.lastEvents[numName] = [castHash]
return False

View File

@ -1,6 +1,6 @@
from os import listdir from os import listdir
from utils.logging.log import * from utils.logging.debug import debug
import commands import commands
from main import CommandMap from main import CommandMap

7
utils/logging/debug.py Normal file
View File

@ -0,0 +1,7 @@
import main
# we need a seperate module to log.py, as log.py is imported by main.py, and we need to access main
# to read the setting
def debug(data):
if main.config["Debug"]:
print("[DEBUG]", data)

View File

@ -1,9 +1,6 @@
def log(data): def log(data):
print("[LOG]", data) print("[LOG]", data)
def debug(data):
print("[DEBUG]", data)
def warn(data): def warn(data):
print("[WARNING]", data) print("[WARNING]", data)