mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-19 17:09:27 +01:00
Added RFE #801859: no-hostmask (secure) option for users.
This commit is contained in:
parent
9cbc766b7c
commit
36984d3fa5
@ -315,6 +315,39 @@ class UserCommands(callbacks.Privmsg):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
irc.error(msg, conf.replyNotRegistered)
|
irc.error(msg, conf.replyNotRegistered)
|
||||||
|
|
||||||
|
def setsecure(self, irc, msg, args):
|
||||||
|
"""<password> [<True|False>]
|
||||||
|
|
||||||
|
Sets the secure flag on the user of the person sending the message.
|
||||||
|
Requires that the person's hostmask be in the list of hostmasks for
|
||||||
|
that user in addition to the password being correct. When the secure
|
||||||
|
flag is set, the user *must* identify before he can be recognized.
|
||||||
|
If a specific True/False value is not given, it inverts the current
|
||||||
|
value.
|
||||||
|
"""
|
||||||
|
if not self._checkNotChannel(irc, msg, password):
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
id = ircdb.users.getUserId(msg.prefix)
|
||||||
|
user = ircdb.users.getUser(id)
|
||||||
|
except KeyError:
|
||||||
|
irc.error(msg, conf.replyNotRegistered)
|
||||||
|
(password, value) = privmsgs.getArgs(args, optional=1)
|
||||||
|
if value == '':
|
||||||
|
value = not user.secure
|
||||||
|
elif value.lower() in ('true', 'false'):
|
||||||
|
value = eval(value.capitalize())
|
||||||
|
else:
|
||||||
|
irc.error(msg, '%s is not a valid boolean value.' % value)
|
||||||
|
return
|
||||||
|
if user.checkPassword(password) and \
|
||||||
|
user.checkHostmask(msg.prefix, useAuth=False):
|
||||||
|
user.secure = value
|
||||||
|
ircdb.users.setUser(id, user)
|
||||||
|
irc.reply(msg, 'Secure flag set to %s' % value)
|
||||||
|
else:
|
||||||
|
irc.error(msg, conf.replyIncorrectAuth)
|
||||||
|
|
||||||
|
|
||||||
Class = UserCommands
|
Class = UserCommands
|
||||||
|
|
||||||
|
14
src/ircdb.py
14
src/ircdb.py
@ -171,10 +171,11 @@ class IrcUser(object):
|
|||||||
"""This class holds the capabilities and authentications for a user.
|
"""This class holds the capabilities and authentications for a user.
|
||||||
"""
|
"""
|
||||||
def __init__(self, ignore=False, password='', name='',
|
def __init__(self, ignore=False, password='', name='',
|
||||||
capabilities=(), hostmasks=None):
|
capabilities=(), hostmasks=None, secure=False):
|
||||||
self.auth = None # The (time, hostmask) a user authenticated under
|
self.auth = None # The (time, hostmask) a user authenticated under
|
||||||
self.name = name # The name of the user.
|
self.name = name # The name of the user.
|
||||||
self.ignore = ignore # A boolean deciding if the person is ignored.
|
self.ignore = ignore # A boolean deciding if the person is ignored.
|
||||||
|
self.secure = secure # A boolean describing if hostmasks *must* match.
|
||||||
self.password = password # password (plaintext? hashed?)
|
self.password = password # password (plaintext? hashed?)
|
||||||
self.capabilities = UserCapabilitySet()
|
self.capabilities = UserCapabilitySet()
|
||||||
for capability in capabilities:
|
for capability in capabilities:
|
||||||
@ -186,9 +187,9 @@ class IrcUser(object):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(ignore=%s, password=%r, name=%r, '\
|
return '%s(ignore=%s, password=%r, name=%r, '\
|
||||||
'capabilities=%r, hostmasks=%r)\n' %\
|
'capabilities=%r, hostmasks=%r, secure=%r)\n' %\
|
||||||
(self.__class__.__name__, self.ignore, self.password,
|
(self.__class__.__name__, self.ignore, self.password,
|
||||||
self.name, self.capabilities, self.hostmasks)
|
self.name, self.capabilities, self.hostmasks, self.secure)
|
||||||
|
|
||||||
def addCapability(self, capability):
|
def addCapability(self, capability):
|
||||||
self.capabilities.add(capability)
|
self.capabilities.add(capability)
|
||||||
@ -211,8 +212,8 @@ class IrcUser(object):
|
|||||||
def checkPassword(self, password):
|
def checkPassword(self, password):
|
||||||
return (self.password == password)
|
return (self.password == password)
|
||||||
|
|
||||||
def checkHostmask(self, hostmask):
|
def checkHostmask(self, hostmask, useAuth=True):
|
||||||
if self.auth and (hostmask == self.auth[1]):
|
if useAuth and self.auth and (hostmask == self.auth[1]):
|
||||||
return True
|
return True
|
||||||
for pat in self.hostmasks:
|
for pat in self.hostmasks:
|
||||||
if ircutils.hostmaskPatternEqual(pat, hostmask):
|
if ircutils.hostmaskPatternEqual(pat, hostmask):
|
||||||
@ -558,6 +559,9 @@ def checkCapability(hostmask, capability, users=users, channels=channels):
|
|||||||
return _x(capability, True)
|
return _x(capability, True)
|
||||||
try:
|
try:
|
||||||
u = users.getUser(hostmask)
|
u = users.getUser(hostmask)
|
||||||
|
if u.secure and not u.checkHostmask(hostmask, useAuth=False):
|
||||||
|
debug.printf('Secure user with non-matching hostmask.')
|
||||||
|
raise KeyError
|
||||||
except KeyError:
|
except KeyError:
|
||||||
#debug.printf('user could not be found.')
|
#debug.printf('user could not be found.')
|
||||||
if isChannelCapability(capability):
|
if isChannelCapability(capability):
|
||||||
|
@ -307,6 +307,7 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
|||||||
antifoo = 'antifoo!antifoo@antifoo'
|
antifoo = 'antifoo!antifoo@antifoo'
|
||||||
justchanfoo = 'justchanfoo!justchanfoo@justchanfoo'
|
justchanfoo = 'justchanfoo!justchanfoo@justchanfoo'
|
||||||
antichanfoo = 'antichanfoo!antichanfoo@antichanfoo'
|
antichanfoo = 'antichanfoo!antichanfoo@antichanfoo'
|
||||||
|
securefoo = 'securefoo!securefoo@securefoo'
|
||||||
channel = '#channel'
|
channel = '#channel'
|
||||||
cap = 'foo'
|
cap = 'foo'
|
||||||
anticap = ircdb.makeAntiCapability(cap)
|
anticap = ircdb.makeAntiCapability(cap)
|
||||||
@ -325,35 +326,49 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
|||||||
pass
|
pass
|
||||||
self.users = ircdb.UsersDB(self.filename)
|
self.users = ircdb.UsersDB(self.filename)
|
||||||
self.channels = ircdb.ChannelsDictionary(self.filename)
|
self.channels = ircdb.ChannelsDictionary(self.filename)
|
||||||
|
|
||||||
(id, owner) = self.users.newUser()
|
(id, owner) = self.users.newUser()
|
||||||
owner.name = 'owner'
|
owner.name = 'owner'
|
||||||
owner.addCapability('owner')
|
owner.addCapability('owner')
|
||||||
owner.addHostmask(self.owner)
|
owner.addHostmask(self.owner)
|
||||||
self.users.setUser(id, owner)
|
self.users.setUser(id, owner)
|
||||||
|
|
||||||
(id, nothing) = self.users.newUser()
|
(id, nothing) = self.users.newUser()
|
||||||
nothing.name = 'nothing'
|
nothing.name = 'nothing'
|
||||||
nothing.addHostmask(self.nothing)
|
nothing.addHostmask(self.nothing)
|
||||||
self.users.setUser(id, nothing)
|
self.users.setUser(id, nothing)
|
||||||
|
|
||||||
(id, justfoo) = self.users.newUser()
|
(id, justfoo) = self.users.newUser()
|
||||||
justfoo.name = 'justfoo'
|
justfoo.name = 'justfoo'
|
||||||
justfoo.addCapability(self.cap)
|
justfoo.addCapability(self.cap)
|
||||||
justfoo.addHostmask(self.justfoo)
|
justfoo.addHostmask(self.justfoo)
|
||||||
self.users.setUser(id, justfoo)
|
self.users.setUser(id, justfoo)
|
||||||
|
|
||||||
(id, antifoo) = self.users.newUser()
|
(id, antifoo) = self.users.newUser()
|
||||||
antifoo.name = 'antifoo'
|
antifoo.name = 'antifoo'
|
||||||
antifoo.addCapability(self.anticap)
|
antifoo.addCapability(self.anticap)
|
||||||
antifoo.addHostmask(self.antifoo)
|
antifoo.addHostmask(self.antifoo)
|
||||||
self.users.setUser(id, antifoo)
|
self.users.setUser(id, antifoo)
|
||||||
|
|
||||||
(id, justchanfoo) = self.users.newUser()
|
(id, justchanfoo) = self.users.newUser()
|
||||||
justchanfoo.name = 'justchanfoo'
|
justchanfoo.name = 'justchanfoo'
|
||||||
justchanfoo.addCapability(self.chancap)
|
justchanfoo.addCapability(self.chancap)
|
||||||
justchanfoo.addHostmask(self.justchanfoo)
|
justchanfoo.addHostmask(self.justchanfoo)
|
||||||
self.users.setUser(id, justchanfoo)
|
self.users.setUser(id, justchanfoo)
|
||||||
|
|
||||||
(id, antichanfoo) = self.users.newUser()
|
(id, antichanfoo) = self.users.newUser()
|
||||||
antichanfoo.name = 'antichanfoo'
|
antichanfoo.name = 'antichanfoo'
|
||||||
antichanfoo.addCapability(self.antichancap)
|
antichanfoo.addCapability(self.antichancap)
|
||||||
antichanfoo.addHostmask(self.antichanfoo)
|
antichanfoo.addHostmask(self.antichanfoo)
|
||||||
self.users.setUser(id, antichanfoo)
|
self.users.setUser(id, antichanfoo)
|
||||||
|
|
||||||
|
(id, securefoo) = self.users.newUser()
|
||||||
|
securefoo.name = 'securefoo'
|
||||||
|
securefoo.addCapability(self.cap)
|
||||||
|
securefoo.secure = True
|
||||||
|
securefoo.addHostmask(self.securefoo)
|
||||||
|
self.users.setUser(id, securefoo)
|
||||||
|
|
||||||
channel = ircdb.IrcChannel()
|
channel = ircdb.IrcChannel()
|
||||||
self.channels.setChannel(self.channel, channel)
|
self.channels.setChannel(self.channel, channel)
|
||||||
|
|
||||||
@ -428,6 +443,19 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
|||||||
self.failUnless(self.checkCapability(self.antichanfoo,
|
self.failUnless(self.checkCapability(self.antichanfoo,
|
||||||
self.antichancap))
|
self.antichancap))
|
||||||
|
|
||||||
|
def testSecurefoo(self):
|
||||||
|
self.failUnless(self.checkCapability(self.securefoo, self.cap))
|
||||||
|
id = self.users.getUserId(self.securefoo)
|
||||||
|
u = self.users.getUser(id)
|
||||||
|
u.setAuth(self.securefoo)
|
||||||
|
self.users.setUser(id, u)
|
||||||
|
try:
|
||||||
|
originalConfDefaultAllow = conf.defaultAllow
|
||||||
|
conf.defaultAllow = False
|
||||||
|
self.failIf(self.checkCapability('a' + self.securefoo, self.cap))
|
||||||
|
finally:
|
||||||
|
conf.defaultAllow = originalConfDefaultAllow
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user