Implement registration and confirmation of nicks

This commit is contained in:
Mark Veidemanis 2020-05-30 21:40:10 +01:00
parent d99c3c394f
commit a3cdb35e05
9 changed files with 149 additions and 15 deletions

27
commands/confirm.py Normal file
View File

@ -0,0 +1,27 @@
import main
from modules import regproc
class ConfirmCommand:
def __init__(self, *args):
self.confirm(*args)
def confirm(self, addr, authed, data, obj, spl, success, failure, info, incUsage, length):
if authed:
if length == 4:
if not spl[1] in main.network.keys():
failure("No such network: %s" % spl[1])
return
if not spl[2].isdigit():
failure("Must be a number, not %s" % spl[2])
return
if not int(spl[2]) in main.network[spl[1]].relays.keys():
failure("No such relay on %s: %s" % (spl[2], spl[1]))
return
regproc.confirmAccount(spl[1], int(spl[2]), spl[3])
success("Requested confirmation on %s - %s with token %s" % (spl[1], spl[2], spl[3]))
return
else:
incUsage("confirm")
return
else:
incUsage(None)

27
commands/reg.py Normal file
View File

@ -0,0 +1,27 @@
import main
from modules import regproc
class RegCommand:
def __init__(self, *args):
self.reg(*args)
def reg(self, addr, authed, data, obj, spl, success, failure, info, incUsage, length):
if authed:
if length == 3:
if not spl[1] in main.network.keys():
failure("No such network: %s" % spl[1])
return
if not spl[2].isdigit():
failure("Must be a number, not %s" % spl[2])
return
if not int(spl[2]) in main.network[spl[1]].relays.keys():
failure("No such relay on %s: %s" % (spl[2], spl[1]))
return
regproc.registerAccount(spl[1], int(spl[2]))
success("Requested registration on %s - %s" % (spl[1], spl[2]))
return
else:
incUsage("reg")
return
else:
incUsage(None)

View File

@ -15,6 +15,7 @@
"RedisSocket": "/tmp/redis.sock",
"UsePassword": true,
"ConnectOnCreate": false,
"AutoReg": false,
"Debug": false,
"Relay": {
"Host": "127.0.0.1",

9
conf/example/irc.json Normal file
View File

@ -0,0 +1,9 @@
{
"_": {
"register": true,
"entity": "NickServ",
"email": "{nickname}@example.com",
"register": "REGISTER {password} {email}",
"confirm": "CONFIRM {token}"
}
}

View File

@ -13,7 +13,7 @@
"load": "load <(file)|list|all>",
"dist": "dist",
"loadmod": "loadmod <module>",
"msg": "msg <name> <target> <message...>",
"msg": "msg <network> <num> <target> <message...>",
"mon": "mon -h",
"chans": "chans <nick> [<nick> ...]",
"users": "users <channel> [<channel> ...]",
@ -28,5 +28,7 @@
"admall": "admall <entity> <text ...>",
"swho": "swho <network> [<channel>]",
"list": "list <network>",
"exec": "exec <expr ...>"
"exec": "exec <expr ...>",
"reg": "reg <network> <num>",
"confirm": "confirm <network> <num> <token>"
}

View File

@ -14,6 +14,7 @@ from modules import userinfo
from modules import counters
from modules import monitor
from modules import chankeep
from modules import regproc
from core.relay import sendRelayNotification
from utils.dedup import dedup
@ -97,12 +98,12 @@ class IRCRelay(IRCClient):
sendAll("%s: relay password mismatch" % self.num)
def sendStage2(self):
if not self.stage2 == None: # [["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)
# [["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:
@ -115,7 +116,8 @@ class IRCRelay(IRCClient):
reactor.callLater(sleeptime, self.msg, main.config["Tweaks"]["ZNC"]["Prefix"]+i, x)
sleeptime += increment
increment += 0.8
reactor.callLater(sleeptime, self.sendStage2)
if not self.stage2 == None:
reactor.callLater(sleeptime, self.sendStage2)
reactor.callLater(sleeptime+5, self.transport.loseConnection)
return
@ -392,6 +394,9 @@ 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))
return
if self.listAttempted:
debug("List request dropped, already asked for LIST - %s - %i" % (self.net, self.num))
return
@ -448,7 +453,7 @@ class IRCBot(IRCClient):
else:
if self.listRetried:
self.listRetried = False
debug("List received after retry - defaulting to simple list syntax")
debug("List received after retry - defaulting to simple list syntax: %s - %i" % (self.net, self.num))
self.listSimple = True
def got_list(self, listinfo):
@ -464,6 +469,10 @@ class IRCBot(IRCClient):
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"]:
regproc.registerAccount(self.net, self.num)
debug("Attempting to register: %s - %i" % (self.net, self.num))
for i in options:
if i.startswith("CHANLIMIT"):
if ":" in i:
@ -673,7 +682,7 @@ class IRCBotFactory(ReconnectingClientFactory):
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))
sendAll("%s - %s: connection failed: %s" % (self.net, self.num, error))
sendRelayNotification({"type": "conn", "net": self.net, "num": self.num, "status": "failed", "message": error})
self.retry(connector)
#ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)

View File

@ -63,6 +63,4 @@ def generate_alias():
if rand == 3 or rand == 4:
realname = realname.capitalize()
password = generate_password()
return {"nick": nick, "altnick": altnick, "ident": ident, "realname": realname, "password": password}
return {"nick": nick, "altnick": altnick, "ident": ident, "realname": realname}

View File

@ -27,10 +27,19 @@ class Network:
self.last += 1
elif num == self.last:
self.last += 1
registered = False
if self.net in main.irc.keys():
if "register" in main.irc[self.net].keys():
if not main.irc[self.net]["register"]:
registered = True
# Don't need to register if it's been disabled in definitions,
# so we'll pretend we already did
self.relays[num] = {
"enabled": main.config["ConnectOnCreate"],
"net": self.net,
"id": num
"id": num,
"registered": registered
}
password = alias.generate_password()
if not num in main.alias.keys():

52
modules/regproc.py Normal file
View File

@ -0,0 +1,52 @@
import main
from modules import provision
from utils.logging.log import *
def registerAccount(net, num):
alias = main.alias[num]
nickname = alias["nick"]
username = nickname+"/"+net
password = main.network[net].aliases[num]["password"]
if net in main.irc.keys():
inst = main.irc[net]
else:
inst = main.irc["_"]
if not inst["register"]:
error("Cannot register for %s: function disabled" % (net))
return False
entity = inst["entity"]
email = inst["email"]
cmd = inst["register"]
email = email.replace("{nickname}", nickname)
cmd = cmd.replace("{password}", password)
cmd = cmd.replace("{email}", email)
name = net+str(num)
main.IRCPool[name].msg(entity, cmd)
def confirmAccount(net, num, token):
if net in main.irc.keys():
inst = main.irc[net]
else:
inst = main.irc["_"]
entity = inst["entity"]
cmd = inst["confirm"]
cmd = cmd.replace("{token}", token)
name = net+str(num)
main.IRCPool[name].msg(entity, cmd)
enableAuthentication(net, num)
def enableAuthentication(net, num):
obj = main.network[net]
nick = main.alias[num]["nick"]
security = obj.security
auth = obj.auth
password = obj.aliases[num]["password"]
uname = main.alias[num]["nick"]+"/"+net
provision.provisionAuthenticationData(num, nick, net, security, auth, password) # Set up for auth
if obj.relays[num]["registered"]:
warn("Authentication already enabled: %s - %i" % (net, num))
obj.relays[num]["registered"] = True
main.saveConf("network")
main.IRCPool[net+str(num)].msg(main.config["Tweaks"]["ZNC"]["Prefix"]+"status", "Jump")