From 3d621b00dfa089fa6e11bb59dc978bc5c58224f9 Mon Sep 17 00:00:00 2001 From: James Lu Date: Tue, 25 Aug 2015 20:38:32 -0700 Subject: [PATCH] Move checkAuthenticated() to utils, and give it and isOper() toggles for allowing oper/PyLink logins --- classes.py | 3 --- plugins/admin.py | 33 +++++++++++---------------------- utils.py | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/classes.py b/classes.py index af7ef87..d8ba00a 100644 --- a/classes.py +++ b/classes.py @@ -12,9 +12,6 @@ import utils ### Exceptions -class NotAuthenticatedError(Exception): - pass - class ProtocolError(Exception): pass diff --git a/plugins/admin.py b/plugins/admin.py index a834222..695e241 100644 --- a/plugins/admin.py +++ b/plugins/admin.py @@ -1,28 +1,17 @@ # admin.py: PyLink administrative commands import sys import os -import inspect sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import utils from log import log -class NotAuthenticatedError(Exception): - pass - -def checkauthenticated(irc, source): - lastfunc = inspect.stack()[1][3] - if not irc.users[source].identified: - log.warning('(%s) Access denied for %s calling %r', irc.name, - utils.getHostmask(irc, source), lastfunc) - raise NotAuthenticatedError("You are not authenticated!") - def _exec(irc, source, args): """ Admin-only. Executes in the current PyLink instance. \x02**WARNING: THIS CAN BE DANGEROUS IF USED IMPROPERLY!**\x02""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) args = ' '.join(args) if not args.strip(): utils.msg(irc, source, 'No code entered!') @@ -37,7 +26,7 @@ def spawnclient(irc, source, args): Admin-only. Spawns the specified PseudoClient on the PyLink server. Note: this doesn't check the validity of any fields you give it!""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick, ident, host = args[:3] except ValueError: @@ -50,7 +39,7 @@ def quit(irc, source, args): """ [] Admin-only. Quits the PyLink client with nick , if one exists.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] except IndexError: @@ -68,7 +57,7 @@ def joinclient(irc, source, args): """ ,[], etc. Admin-only. Joins , the nick of a PyLink client, to a comma-separated list of channels.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] clist = args[1].split(',') @@ -93,7 +82,7 @@ def nick(irc, source, args): """ Admin-only. Changes the nick of , a PyLink client, to .""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] newnick = args[1] @@ -114,7 +103,7 @@ def part(irc, source, args): """ ,[],... [] Admin-only. Parts , the nick of a PyLink client, from a comma-separated list of channels.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] clist = args[1].split(',') @@ -135,7 +124,7 @@ def kick(irc, source, args): """ [] Admin-only. Kicks from via , where is the nick of a PyLink client.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] channel = args[1] @@ -160,7 +149,7 @@ def showuser(irc, source, args): """ Admin-only. Shows information about .""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: target = args[0] except IndexError: @@ -179,7 +168,7 @@ def showchan(irc, source, args): """ Admin-only. Shows information about .""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: channel = args[0].lower() except IndexError: @@ -197,7 +186,7 @@ def mode(irc, source, args): """ Admin-only. Sets modes on from , where is either the nick of a PyLink client, or the SID of a PyLink server.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: modesource, target, modes = args[0], args[1], args[2:] except IndexError: @@ -226,7 +215,7 @@ def msg(irc, source, args): """ Admin-only. Sends message from , where is the nick of a PyLink client.""" - checkauthenticated(irc, source) + utils.checkAuthenticated(irc, source, allowOper=False) try: msgsource, target, text = args[0], args[1], ' '.join(args[2:]) except IndexError: diff --git a/utils.py b/utils.py index db02ff4..697eab7 100644 --- a/utils.py +++ b/utils.py @@ -2,9 +2,9 @@ import string import re from collections import defaultdict import threading +import inspect from log import log - global bot_commands, command_hooks # This should be a mapping of command names to functions bot_commands = {} @@ -15,6 +15,10 @@ plugins = [] whois_handlers = [] started = threading.Event() +# This is separate from classes.py to prevent import loops. +class NotAuthenticatedError(Exception): + pass + class TS6UIDGenerator(): """TS6 UID Generator module, adapted from InspIRCd source https://github.com/inspircd/inspircd/blob/f449c6b296ab/src/server.cpp#L85-L156 @@ -350,15 +354,38 @@ def isInternalServer(irc, sid): """ return (sid in irc.servers and irc.servers[sid].internal) -def isOper(irc, uid): +def isOper(irc, uid, allowAuthed=True, allowOper=True): """ Returns whether has operator status on PyLink. This can be achieved - by either identifying to PyLink as admin, or having user mode +o set. + by either identifying to PyLink as admin (if allowAuthed is True), + or having user mode +o set (if allowOper is True). At least one of + allowAuthed or allowOper must be True for this to give any meaningful + results. """ - return (uid in irc.users and (("o", None) in irc.users[uid].modes or irc.users[uid].identified)) + if uid in irc.users: + if allowOper and ("o", None) in irc.users[uid].modes: + return True + elif allowAuthed and irc.users[uid].identified: + return True + return False + +def checkAuthenticated(irc, uid, allowAuthed=True, allowOper=True): + """ + + Checks whether user has operator status on PyLink, raising + NotAuthenticatedError and logging the access denial if not.""" + lastfunc = inspect.stack()[1][3] + if not isOper(irc, uid, allowAuthed=allowAuthed, allowOper=allowOper): + log.warning('(%s) Access denied for %s calling %r', irc.name, + getHostmask(irc, uid), lastfunc) + raise NotAuthenticatedError("You are not authenticated!") + return True def getHostmask(irc, user): + """ + + Gets the hostmask of user , if present.""" userobj = irc.users.get(user) if userobj is None: return ''