monolith/utils/deliver_relay_commands.py

163 lines
6.0 KiB
Python

import main
from twisted.internet.ssl import DefaultOpenSSLContextFactory
from twisted.internet import reactor
from twisted.words.protocols.irc import IRCClient
from twisted.internet.protocol import ReconnectingClientFactory
from utils.parsing import parsen
from utils.logging.log import log, error
from utils.logging.send import sendAll
from modules import userinfo
from datetime import datetime
from core.relay import sendRelayNotification
from utils.get import getRelay
# TODO: strip out non-relay functionality
class IRCRelay(IRCClient):
def __init__(self, num, relayCommands, user, stage2):
self.isconnected = False
self.buffer = ""
if user is None:
self.user = main.config["Relay"]["User"]
else:
self.user = user.lower()
password = main.config["Relay"]["Password"]
self.nickname = "relay"
self.realname = "relay"
self.username = self.user
self.password = self.user + ":" + password
self.relayCommands = relayCommands
self.num = num
self.stage2 = stage2
self.loop = None
def privmsg(self, user, channel, msg):
nick, ident, host = parsen(user)
for i in main.ZNCErrors:
if i in msg:
error("ZNC issue:", msg)
if nick[0] == main.config["Tweaks"]["ZNC"]["Prefix"]:
nick = nick[1:]
if nick in self.relayCommands.keys():
sendAll("[%s] %s -> %s" % (self.num, nick, msg))
def irc_ERR_PASSWDMISMATCH(self, prefix, params):
log("%s: relay password mismatch" % self.num)
sendAll("%s: relay password mismatch" % self.num)
def sendStage2(self):
# [["user", {"sasl": ["message1", "message2"]}], []]
if not len(self.stage2) == 0:
user = self.stage2[0].pop(0)
commands = self.stage2[0].pop(0)
del self.stage2[0]
deliverRelayCommands(self.num, commands, user, self.stage2)
def signedOn(self):
if not self.isconnected:
self.isconnected = True
# log("signed on as a relay: %s" % self.num)
sleeptime = 0
increment = 0.8
for i in self.relayCommands.keys():
for x in self.relayCommands[i]:
reactor.callLater(
sleeptime,
self.msg,
main.config["Tweaks"]["ZNC"]["Prefix"] + i,
x,
)
sleeptime += increment
increment += 0.8
if self.stage2 is not None:
reactor.callLater(sleeptime, self.sendStage2)
reactor.callLater(sleeptime + 5, self.transport.loseConnection)
return
class IRCRelayFactory(ReconnectingClientFactory):
def __init__(self, net, num=None, relayCommands=None, user=None, stage2=None):
if net is None:
self.num = num
self.net = None
self.name = "relay - %i" % num
self.relay = True
else:
self.name = net + str(num)
self.num = num
self.net = net
self.relay = False
self.client = None
self.maxDelay = main.config["Tweaks"]["Delays"]["MaxDelay"]
self.initialDelay = main.config["Tweaks"]["Delays"]["InitialDelay"]
self.factor = main.config["Tweaks"]["Delays"]["Factor"]
self.jitter = main.config["Tweaks"]["Delays"]["Jitter"]
self.relayCommands, self.user, self.stage2 = relayCommands, user, stage2
def buildProtocol(self, addr):
entry = IRCRelay(self.num, self.relayCommands, self.user, self.stage2)
self.client = entry
return entry
def clientConnectionLost(self, connector, reason):
if not self.relay:
userinfo.delChannels(self.net, self.client.channels)
if self.client is not None:
self.client.isconnected = False
self.client.authenticated = False
self.client.channels = []
error = reason.getErrorMessage()
if not self.relay:
log("%s - %i: connection lost: %s" % (self.net, self.num, error))
sendAll("%s - %i: connection lost: %s" % (self.net, self.num, error))
ctime = str(datetime.now().isoformat())
sendRelayNotification(
{
"type": "conn",
"net": self.net,
"num": self.num,
"status": "lost",
"message": error,
"ts": ctime,
}
)
self.retry(connector)
# ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def clientConnectionFailed(self, connector, reason):
if self.client is not None:
self.client.isconnected = False
self.client.authenticated = False
self.client.channels = []
error = reason.getErrorMessage()
log("%s - %i: connection failed: %s" % (self.net, self.num, error))
if not self.relay:
sendAll("%s - %s: connection failed: %s" % (self.net, self.num, error))
ctime = str(datetime.now().isoformat())
sendRelayNotification(
{
"type": "conn",
"net": self.net,
"num": self.num,
"status": "failed",
"message": error,
"ts": ctime,
}
)
self.retry(connector)
# ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
def deliverRelayCommands(num, relayCommands, user=None, stage2=None):
keyFN = main.certPath + main.config["Key"]
certFN = main.certPath + main.config["Certificate"]
contextFactory = DefaultOpenSSLContextFactory(keyFN.encode("utf-8", "replace"), certFN.encode("utf-8", "replace"))
bot = IRCRelayFactory(net=None, num=num, relayCommands=relayCommands, user=user, stage2=stage2)
host, port = getRelay(num)
reactor.connectSSL(host, port, bot, contextFactory)