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", "RedisSocket": "/tmp/redis.sock",
"UsePassword": true, "UsePassword": true,
"ConnectOnCreate": false, "ConnectOnCreate": false,
"AutoReg": false,
"Debug": false, "Debug": false,
"Relay": { "Relay": {
"Host": "127.0.0.1", "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>", "load": "load <(file)|list|all>",
"dist": "dist", "dist": "dist",
"loadmod": "loadmod <module>", "loadmod": "loadmod <module>",
"msg": "msg <name> <target> <message...>", "msg": "msg <network> <num> <target> <message...>",
"mon": "mon -h", "mon": "mon -h",
"chans": "chans <nick> [<nick> ...]", "chans": "chans <nick> [<nick> ...]",
"users": "users <channel> [<channel> ...]", "users": "users <channel> [<channel> ...]",
@ -28,5 +28,7 @@
"admall": "admall <entity> <text ...>", "admall": "admall <entity> <text ...>",
"swho": "swho <network> [<channel>]", "swho": "swho <network> [<channel>]",
"list": "list <network>", "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 counters
from modules import monitor from modules import monitor
from modules import chankeep from modules import chankeep
from modules import regproc
from core.relay import sendRelayNotification from core.relay import sendRelayNotification
from utils.dedup import dedup from utils.dedup import dedup
@ -97,12 +98,12 @@ class IRCRelay(IRCClient):
sendAll("%s: relay password mismatch" % self.num) sendAll("%s: relay password mismatch" % self.num)
def sendStage2(self): def sendStage2(self):
if not self.stage2 == None: # [["user", {"sasl": ["message1", "message2"]}], []] # [["user", {"sasl": ["message1", "message2"]}], []]
if not len(self.stage2) == 0: if not len(self.stage2) == 0:
user = self.stage2[0].pop(0) user = self.stage2[0].pop(0)
commands = self.stage2[0].pop(0) commands = self.stage2[0].pop(0)
del self.stage2[0] del self.stage2[0]
deliverRelayCommands(self.num, commands, user, self.stage2) deliverRelayCommands(self.num, commands, user, self.stage2)
def signedOn(self): def signedOn(self):
if not self.isconnected: if not self.isconnected:
@ -115,7 +116,8 @@ class IRCRelay(IRCClient):
reactor.callLater(sleeptime, self.msg, main.config["Tweaks"]["ZNC"]["Prefix"]+i, x) reactor.callLater(sleeptime, self.msg, main.config["Tweaks"]["ZNC"]["Prefix"]+i, x)
sleeptime += increment sleeptime += increment
increment += 0.8 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) reactor.callLater(sleeptime+5, self.transport.loseConnection)
return return
@ -392,6 +394,9 @@ class IRCBot(IRCClient):
return d return d
def list(self, noargs=False, nocheck=False): 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: if self.listAttempted:
debug("List request dropped, already asked for LIST - %s - %i" % (self.net, self.num)) debug("List request dropped, already asked for LIST - %s - %i" % (self.net, self.num))
return return
@ -448,7 +453,7 @@ class IRCBot(IRCClient):
else: else:
if self.listRetried: if self.listRetried:
self.listRetried = False 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 self.listSimple = True
def got_list(self, listinfo): def got_list(self, listinfo):
@ -464,6 +469,10 @@ class IRCBot(IRCClient):
if not self.isconnected: # we don't care about if not self.isconnected: # we don't care about
log("endpoint connected: %s - %i" % (self.net, self.num)) log("endpoint connected: %s - %i" % (self.net, self.num))
self.isconnected = True 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: for i in options:
if i.startswith("CHANLIMIT"): if i.startswith("CHANLIMIT"):
if ":" in i: if ":" in i:
@ -673,7 +682,7 @@ class IRCBotFactory(ReconnectingClientFactory):
error = reason.getErrorMessage() error = reason.getErrorMessage()
log("%s - %i: connection failed: %s" % (self.net, self.num, error)) log("%s - %i: connection failed: %s" % (self.net, self.num, error))
if not self.relay: 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}) sendRelayNotification({"type": "conn", "net": self.net, "num": self.num, "status": "failed", "message": error})
self.retry(connector) self.retry(connector)
#ReconnectingClientFactory.clientConnectionFailed(self, connector, reason) #ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)

View File

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

View File

@ -27,10 +27,19 @@ class Network:
self.last += 1 self.last += 1
elif num == self.last: elif num == self.last:
self.last += 1 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] = { self.relays[num] = {
"enabled": main.config["ConnectOnCreate"], "enabled": main.config["ConnectOnCreate"],
"net": self.net, "net": self.net,
"id": num "id": num,
"registered": registered
} }
password = alias.generate_password() password = alias.generate_password()
if not num in main.alias.keys(): 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")