Finally passes all tests.

This commit is contained in:
Jeremy Fincher 2003-04-20 21:52:53 +00:00
parent 9fee5f17a9
commit 959459d063

View File

@ -42,11 +42,12 @@ import world
import ircutils import ircutils
def fromChannelCapability(capability): def fromChannelCapability(capability):
assert isChannelCapability(capability)
return capability.split('.', 1) return capability.split('.', 1)
def isChannelCapability(capability): def isChannelCapability(capability):
if '.' in capability: if '.' in capability:
(channel, capability) = fromChannelCapability(capability) (channel, capability) = capability.split('.', 1)
return ircutils.isChannel(channel) return ircutils.isChannel(channel)
else: else:
return False return False
@ -66,21 +67,100 @@ def makeAntiCapability(capability):
else: else:
return '!' + capability return '!' + capability
def unAntiCapability(capability):
assert isAntiCapability(capability)
if isChannelCapability(capability):
(channel, capability) = fromChannelCapability(capability)
return '.'.join((channel, capability[1:]))
else:
return capability[1:]
def invertCapability(capability):
if isAntiCapability(capability):
return unAntiCapability(capability)
else:
return makeAntiCapability(capability)
_normal = string.maketrans('\r\n', ' ') _normal = string.maketrans('\r\n', ' ')
def normalize(s): def normalize(s):
return s.translate(_normal) return s.translate(_normal)
class CapabilitySet(set):
def __init__(self, capabilities=()):
set.__init__(self)
for capability in capabilities:
self.add(capability)
def add(self, capability):
capability = ircutils.toLower(capability)
inverted = invertCapability(capability)
if set.__contains__(self, inverted):
set.remove(self, inverted)
set.add(self, capability)
def remove(self, capability):
capability = ircutils.toLower(capability)
set.remove(self, capability)
def __contains__(self, capability):
capability = ircutils.toLower(capability)
if set.__contains__(self, capability):
return True
if set.__contains__(self, invertCapability(capability)):
return True
else:
return False
def check(self, capability):
capability = ircutils.toLower(capability)
if set.__contains__(self, capability):
return True
elif set.__contains__(self, invertCapability(capability)):
return False
else:
raise KeyError, capability
def repr(self):
return '%s([%r])' % (self.__class__.__name__, ', '.join(self))
class UserCapabilitySet(CapabilitySet):
def __contains__(self, capability):
capability = ircutils.toLower(capability)
if CapabilitySet.__contains__(self, 'owner'):
return True
else:
return CapabilitySet.__contains__(self, capability)
def check(self, capability):
capability = ircutils.toLower(capability)
if capability == 'owner':
if CapabilitySet.__contains__(self, 'owner'):
return True
else:
return False
if 'owner' in self:
if isAntiCapability(capability):
return False
else:
return True
else:
return CapabilitySet.check(self, capability)
def add(self, capability):
capability = ircutils.toLower(capability)
assert capability != '!owner', '"!owner" disallowed.'
CapabilitySet.add(self, capability)
class IrcUser(object): 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='', auth=None, def __init__(self, ignore=False, password='', auth=None,
capabilities=None, hostmasks=None): capabilities=(), hostmasks=None):
self.auth = auth # The (time, hostmask) a user authenticated under. self.auth = auth # The (time, hostmask) a user authenticated under.
self.ignore = ignore # A boolean deciding if the person is ignored. self.ignore = ignore # A boolean deciding if the person is ignored.
self.password = password # password (plaintext? hashed?) self.password = password # password (plaintext? hashed?)
self.capabilities = set() self.capabilities = UserCapabilitySet()
if capabilities is not None:
for capability in capabilities: for capability in capabilities:
self.capabilities.add(capability) self.capabilities.add(capability)
if hostmasks is None: if hostmasks is None:
@ -102,20 +182,13 @@ class IrcUser(object):
self.capabilities.remove(capability) self.capabilities.remove(capability)
def checkCapability(self, capability): def checkCapability(self, capability):
if 'owner' in self.capabilities: if self.ignore:
if isAntiCapability(capability):
return False
else:
return True
elif self.ignore:
if isAntiCapability(capability): if isAntiCapability(capability):
return True return True
else: else:
return False return False
elif capability in self.capabilities:
return True
else: else:
return False return self.capabilities.check(capability)
def setPassword(self, password): def setPassword(self, password):
self.password = password self.password = password
@ -177,10 +250,9 @@ class IrcChannel(object):
else: else:
self.ignores = ignores self.ignores = ignores
if capabilities is None: if capabilities is None:
self.capabilities = set() self.capabilities = CapabilitySet()
else: else:
self.capabilities = capabilities self.capabilities = capabilities
for capability in self.defaultOff: for capability in self.defaultOff:
if capability not in self.capabilities: if capability not in self.capabilities:
self.capabilities.add(makeAntiCapability(capability)) self.capabilities.add(makeAntiCapability(capability))
@ -222,13 +294,10 @@ class IrcChannel(object):
def checkCapability(self, capability): def checkCapability(self, capability):
if capability in self.capabilities: if capability in self.capabilities:
return True return self.capabilities.check(capability)
else:
if isAntiCapability(capability): if isAntiCapability(capability):
return not self.defaultAllow return not self.defaultAllow
else:
anticapability = makeAntiCapability(capability)
if anticapability in self.capabilities:
return False
else: else:
return self.defaultAllow return self.defaultAllow
@ -421,74 +490,53 @@ def checkIgnored(hostmask, recipient='', users=users, channels=channels):
return False return False
def checkCapability(hostmask, capability, users=users, channels=channels): def checkCapability(hostmask, capability, users=users, channels=channels):
"""checkCapability(hostmask, recipient, capability) -> True/False
Checks if the user represented by hostmask has capability with recipient.
"""
###
# This is a hard function to write correctly.
#
# Basically, we want to return whether or not a user has a certain
# capability in a given channel. This should be easy, but the various
# different cases are all hard to get right.
if world.startup: if world.startup:
# Are we in special startup mode?
if isAntiCapability(capability): if isAntiCapability(capability):
return False return False
else: else:
return True return True
try: try:
u = users.getUser(hostmask) u = users.getUser(hostmask)
except KeyError: # the user isn't in the database. except KeyError:
# First, check to see if we're asking for a channel capability:
if isChannelCapability(capability): if isChannelCapability(capability):
# If it is, we'll check the channel.
try:
(channel, capability) = fromChannelCapability(capability) (channel, capability) = fromChannelCapability(capability)
except ValueError: # unpack list of wrong size try:
debug.msg('Invalid channel capability in checkCapability')
return False # stupid, invalid capability.
# Now, go fetch the channel and check to see what it thinks about
# said capability.
c = channels.getChannel(channel) c = channels.getChannel(channel)
# Channels have their own defaults, so we can just directly return if capability in c.capabilities:
# what the channel has to say about the capability.
return c.checkCapability(capability) return c.checkCapability(capability)
else: # It's not a channel capability. else:
# If it's not a channel, then the only thing we have to go by is return c.defaultAllow
# conf.defaultCapabilities. except KeyError:
return (capability in conf.defaultCapabilities) pass
# Good, the user exists. if capability in conf.defaultCapabilities:
# First, we check to see if it's an owner -- if it is, it should have all return True
# capabilities and should not have any negative capabilities. elif invertCapability(capability) in conf.defaultCapabilities:
if u.checkCapability('owner'):
if isAntiCapability(capability):
return False return False
else: else:
return True return conf.defaultAllow
# Now, we need to check if it's a channel capability or not. if capability in u.capabilities:
if isChannelCapability(capability):
# First check to see if the user has the capability already; if so,
# it can be returned without checking the channel.
if u.checkCapability(capability):
return True
else:
# User doesn't have the capability. Check the channel.
try:
(channel, capability) = fromChannelCapability(capability)
except ValueError:
debug.msg('Invalid channel capability in checkCapability')
return False # stupid, invalid capability.
c = channels.getChannel(channel)
# And return the channel's opinion.
return c.checkCapability(capability)
else: # It's not a channel capability.
# Just check the user.
try:
return u.checkCapability(capability) return u.checkCapability(capability)
else:
if isChannelCapability(capability):
(channel, capability) = fromChannelCapability(capability)
try:
c = channels.getChannel(channel)
if capability in c.capabilities:
return c.checkCapability(capability)
else:
return c.defaultAllow
except KeyError: except KeyError:
return (capability in conf.defaultCapabilities) pass
if capability in conf.defaultCapabilities:
return True
elif invertCapability(capability) in conf.defaultCapabilities:
return False
else:
return conf.defaultAllow
def checkCapabilities(hostmask, capabilities, requireAll=False): def checkCapabilities(hostmask, capabilities, requireAll=False):
"""Checks that a user has capabilities in a list. """Checks that a user has capabilities in a list.