mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-12-24 19:52:54 +01:00
Added the ability to do hashed passwords.
This commit is contained in:
parent
8ae59844bf
commit
d174226c5c
29
src/User.py
29
src/User.py
@ -33,6 +33,7 @@
|
|||||||
Provides commands useful to users in general. This plugin is loaded by default.
|
Provides commands useful to users in general. This plugin is loaded by default.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import getopt
|
||||||
import string
|
import string
|
||||||
|
|
||||||
import conf
|
import conf
|
||||||
@ -50,14 +51,20 @@ class User(callbacks.Privmsg):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def register(self, irc, msg, args):
|
def register(self, irc, msg, args):
|
||||||
"""<name> <password>
|
"""[--hashed] <name> <password>
|
||||||
|
|
||||||
Registers <name> with the given password <password> and the current
|
Registers <name> with the given password <password> and the current
|
||||||
hostmask of the person registering. This command (and all other
|
hostmask of the person registering. This command (and all other
|
||||||
commands that include a password) must be sent to the bot privately,
|
commands that include a password) must be sent to the bot privately,
|
||||||
not in a channel.
|
not in a channel. If --hashed is given, the password will be hashed
|
||||||
|
on disk, rather than being stored in plaintext.
|
||||||
"""
|
"""
|
||||||
(name, password) = privmsgs.getArgs(args, needed=2)
|
(optlist, rest) = getopt.getopt(args, '', ['hashed'])
|
||||||
|
(name, password) = privmsgs.getArgs(rest, needed=2)
|
||||||
|
hashed = False
|
||||||
|
for (option, arg) in optlist:
|
||||||
|
if option == '--hashed':
|
||||||
|
hashed = True
|
||||||
if not self._checkNotChannel(irc, msg, password):
|
if not self._checkNotChannel(irc, msg, password):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@ -77,7 +84,7 @@ class User(callbacks.Privmsg):
|
|||||||
pass
|
pass
|
||||||
(id, user) = ircdb.users.newUser()
|
(id, user) = ircdb.users.newUser()
|
||||||
user.name = name
|
user.name = name
|
||||||
user.setPassword(password)
|
user.setPassword(password, hashed=hashed)
|
||||||
user.addHostmask(msg.prefix)
|
user.addHostmask(msg.prefix)
|
||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.reply(msg, conf.replySuccess)
|
irc.reply(msg, conf.replySuccess)
|
||||||
@ -200,13 +207,19 @@ class User(callbacks.Privmsg):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def setpassword(self, irc, msg, args):
|
def setpassword(self, irc, msg, args):
|
||||||
"""<name> <old password> <new password>
|
"""[--hashed] <name> <old password> <new password>
|
||||||
|
|
||||||
Sets the new password for the user specified by <name> to
|
Sets the new password for the user specified by <name> to
|
||||||
<new password>. Obviously this message must be sent to the bot
|
<new password>. Obviously this message must be sent to the bot
|
||||||
privately (not on a channel).
|
privately (not in a channel). If --hashed is given, the password will
|
||||||
|
be hashed on disk (rather than being stored in plaintext.
|
||||||
"""
|
"""
|
||||||
(name, oldpassword, newpassword) = privmsgs.getArgs(args, 3)
|
(optlist, rest) = getopt.getopt(args, '', ['hashed'])
|
||||||
|
(name, oldpassword, newpassword) = privmsgs.getArgs(rest, 3)
|
||||||
|
hashed = False
|
||||||
|
for (option, arg) in optlist:
|
||||||
|
if option == '--hashed':
|
||||||
|
hashed = True
|
||||||
if not self._checkNotChannel(irc, msg, oldpassword+newpassword):
|
if not self._checkNotChannel(irc, msg, oldpassword+newpassword):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@ -216,7 +229,7 @@ class User(callbacks.Privmsg):
|
|||||||
irc.error(msg, conf.replyNoUser)
|
irc.error(msg, conf.replyNoUser)
|
||||||
return
|
return
|
||||||
if user.checkPassword(oldpassword):
|
if user.checkPassword(oldpassword):
|
||||||
user.setPassword(newpassword)
|
user.setPassword(newpassword, hashed=hashed)
|
||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.reply(msg, conf.replySuccess)
|
irc.reply(msg, conf.replySuccess)
|
||||||
else:
|
else:
|
||||||
|
24
src/ircdb.py
24
src/ircdb.py
@ -186,11 +186,12 @@ class UserCapabilitySet(CapabilitySet):
|
|||||||
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='', name='',
|
def __init__(self, ignore=False, password='', name='',
|
||||||
capabilities=(), hostmasks=None, secure=False):
|
capabilities=(), hostmasks=None, secure=False, hashed=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.secure = secure # A boolean describing if hostmasks *must* match.
|
||||||
|
self.hashed = hashed # True if the password is hashed on disk.
|
||||||
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:
|
||||||
@ -201,10 +202,11 @@ class IrcUser(object):
|
|||||||
self.hostmasks = hostmasks
|
self.hostmasks = hostmasks
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(ignore=%s, password=%r, name=%r, '\
|
return '%s(ignore=%s, password=%r, name=%r, hashed=%r, '\
|
||||||
'capabilities=%r, hostmasks=%r, secure=%r)\n' %\
|
'capabilities=%r, hostmasks=%r, secure=%r)\n' %\
|
||||||
(self.__class__.__name__, self.ignore, self.password,
|
(self.__class__.__name__,
|
||||||
self.name, self.capabilities, self.hostmasks, self.secure)
|
self.ignore, self.password, self.name, self.hashed,
|
||||||
|
self.capabilities, self.hostmasks, self.secure)
|
||||||
|
|
||||||
def addCapability(self, capability):
|
def addCapability(self, capability):
|
||||||
"""Gives the user the given capability."""
|
"""Gives the user the given capability."""
|
||||||
@ -224,13 +226,21 @@ class IrcUser(object):
|
|||||||
else:
|
else:
|
||||||
return self.capabilities.check(capability)
|
return self.capabilities.check(capability)
|
||||||
|
|
||||||
def setPassword(self, password):
|
def setPassword(self, password, hashed=False):
|
||||||
"""Sets the user's password."""
|
"""Sets the user's password."""
|
||||||
self.password = password
|
if hashed or self.hashed:
|
||||||
|
self.hashed = True
|
||||||
|
self.password = utils.saltHash(password)
|
||||||
|
else:
|
||||||
|
self.password = password
|
||||||
|
|
||||||
def checkPassword(self, password):
|
def checkPassword(self, password):
|
||||||
"""Checks the user's password."""
|
"""Checks the user's password."""
|
||||||
return (self.password == password)
|
if self.hashed:
|
||||||
|
(salt, _) = self.password.split('|')
|
||||||
|
return (self.password == utils.saltHash(password, salt=salt))
|
||||||
|
else:
|
||||||
|
return (self.password == password)
|
||||||
|
|
||||||
def checkHostmask(self, hostmask, useAuth=True):
|
def checkHostmask(self, hostmask, useAuth=True):
|
||||||
"""Checks a given hostmask against the user's hostmasks or current
|
"""Checks a given hostmask against the user's hostmasks or current
|
||||||
|
@ -412,7 +412,7 @@ def saltHash(password, salt=None, hash='sha'):
|
|||||||
hasher = md5.md5
|
hasher = md5.md5
|
||||||
elif hash == 'sha':
|
elif hash == 'sha':
|
||||||
hasher = sha.sha
|
hasher = sha.sha
|
||||||
return salt + hasher(salt + password).hexdigest()
|
return '|'.join([salt, hasher(salt + password).hexdigest()])
|
||||||
|
|
||||||
class IterableMap(object):
|
class IterableMap(object):
|
||||||
"""Define .iteritems() in a class and subclass this to get the other iters.
|
"""Define .iteritems() in a class and subclass this to get the other iters.
|
||||||
|
@ -54,5 +54,15 @@ class UserTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
self.assertError('changeusername foo bar')
|
self.assertError('changeusername foo bar')
|
||||||
self.assertNotError('changeusername foo baz')
|
self.assertNotError('changeusername foo baz')
|
||||||
|
|
||||||
|
def testSetpassword(self):
|
||||||
|
self.prefix = self.prefix1
|
||||||
|
self.assertNotError('register foo bar')
|
||||||
|
self.assertEqual(ircdb.users.getUser(self.prefix).password, 'bar')
|
||||||
|
self.assertNotError('setpassword foo bar baz')
|
||||||
|
self.assertEqual(ircdb.users.getUser(self.prefix).password, 'baz')
|
||||||
|
self.assertNotError('setpassword --hashed foo baz biff')
|
||||||
|
self.assertNotEqual(ircdb.users.getUser(self.prefix).password, 'biff')
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
|
||||||
|
@ -212,6 +212,13 @@ class IrcUserTestCase(unittest.TestCase):
|
|||||||
self.failUnless(u.checkPassword('foobar'))
|
self.failUnless(u.checkPassword('foobar'))
|
||||||
self.failIf(u.checkPassword('somethingelse'))
|
self.failIf(u.checkPassword('somethingelse'))
|
||||||
|
|
||||||
|
def testHashedPassword(self):
|
||||||
|
u = ircdb.IrcUser()
|
||||||
|
u.setPassword('foobar', hashed=True)
|
||||||
|
self.failUnless(u.checkPassword('foobar'))
|
||||||
|
self.failIf(u.checkPassword('somethingelse'))
|
||||||
|
self.assertNotEqual(u.password, 'foobar')
|
||||||
|
|
||||||
def testHostmasks(self):
|
def testHostmasks(self):
|
||||||
prefix = 'foo!bar@baz'
|
prefix = 'foo!bar@baz'
|
||||||
hostmasks = ['*!bar@baz', 'foo!*@*']
|
hostmasks = ['*!bar@baz', 'foo!*@*']
|
||||||
|
@ -277,7 +277,8 @@ class UtilsTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testSaltHash(self):
|
def testSaltHash(self):
|
||||||
s = utils.saltHash('jemfinch')
|
s = utils.saltHash('jemfinch')
|
||||||
self.assertEqual(utils.saltHash('jemfinch', salt=s[:8]), s)
|
(salt, hash) = s.split('|')
|
||||||
|
self.assertEqual(utils.saltHash('jemfinch', salt=salt), s)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user