diff --git a/plugins/User/plugin.py b/plugins/User/plugin.py index 8ba41b702..d8f4b0a38 100644 --- a/plugins/User/plugin.py +++ b/plugins/User/plugin.py @@ -321,6 +321,7 @@ class User(callbacks.Plugin): must be sent to the bot privately (not on a channel) since it may contain a password. """ + caller_is_owner = ircdb.checkCapability(msg.prefix, 'owner') if not hostmask: hostmask = msg.prefix if not ircutils.isUserHostmask(hostmask): @@ -335,15 +336,17 @@ class User(callbacks.Plugin): try: otherId = ircdb.users.getUserId(hostmask) if otherId != user.id: - irc.error(_('That hostmask is already registered.'), - Raise=True) + if caller_is_owner: + err = _('That hostmask is already registered to %s.') + err %= otherId + else: + err = _('That hostmask is already registered.') + irc.error(err, Raise=True) except KeyError: pass if not user.checkPassword(password) and \ - not user.checkHostmask(msg.prefix): - if ircdb.checkCapability(msg.prefix, 'owner'): - u = ircdb.users.getUser(msg.prefix) - else: + not user.checkHostmask(msg.prefix) and \ + not caller_is_owner: irc.error(conf.supybot.replies.incorrectAuthentication(), Raise=True) try: @@ -352,10 +355,14 @@ class User(callbacks.Plugin): irc.error(str(e), Raise=True) try: ircdb.users.setUser(user) - except ircdb.DuplicateHostmask: + except ircdb.DuplicateHostmask as e: user.removeHostmask(hostmask) - irc.error(_('That hostmask is already registered.'), - Raise=True) + if caller_is_owner: + err = _('That hostmask is already registered to %s.') \ + % e.args[0] + else: + err = _('That hostmask is already registered.') + irc.error(err, Raise=True) except ValueError as e: irc.error(str(e), Raise=True) irc.replySuccess() diff --git a/plugins/User/test.py b/plugins/User/test.py index 85b0987d0..3dae049e9 100644 --- a/plugins/User/test.py +++ b/plugins/User/test.py @@ -40,6 +40,7 @@ class UserTestCase(PluginTestCase): plugins = ('User', 'Admin', 'Config') prefix1 = 'somethingElse!user@host1.tld' prefix2 = 'EvensomethingElse!user@host2.tld' + prefix3 = 'Completely!Different@host3.tld__no_testcap__' def testHostmaskList(self): self.assertError('hostmask list') @@ -67,14 +68,36 @@ class UserTestCase(PluginTestCase): self.assertResponse('whoami', 'bar', frm=self.prefix2) self.assertNotError('hostmask add foo *!*@foobar/b', frm=self.prefix1) + self.assertResponse('hostmask add bar *!*@foobar/*', - 'Error: That hostmask is already registered.', + 'Error: That hostmask is already registered to foo.', frm=self.prefix2) self.assertRegexp('hostmask list foo', '\*!\*@foobar/b', frm=self.prefix1) self.assertNotRegexp('hostmask list bar', 'foobar', frm=self.prefix2) + def testHostmaskOverlapPrivacy(self): + self.assertNotError('register foo passwd', frm=self.prefix1) + self.assertNotError('register bar passwd', frm=self.prefix3) + self.assertResponse('whoami', 'foo', frm=self.prefix1) + self.assertResponse('whoami', 'bar', frm=self.prefix3) + self.assertNotError('hostmask add foo *!*@foobar/b', + frm=self.prefix1) + + ircdb.users.getUser('bar').addCapability('owner') + self.assertResponse('whoami', 'bar', + frm=self.prefix3) + self.assertResponse('capabilities', '[owner]', + frm=self.prefix3) + self.assertResponse('hostmask add *!*@foobar/*', + 'Error: That hostmask is already registered to foo.', + frm=self.prefix3) + ircdb.users.getUser('bar').removeCapability('owner') + self.assertResponse('hostmask add *!*@foobar/*', + 'Error: That hostmask is already registered.', + frm=self.prefix3) + def testHostmask(self): self.assertResponse('hostmask', self.prefix) diff --git a/src/ircdb.py b/src/ircdb.py index 40d513384..f7c25dbe3 100644 --- a/src/ircdb.py +++ b/src/ircdb.py @@ -775,7 +775,7 @@ class UsersDictionary(utils.IterableMap): self.nextId = max(self.nextId, user.id) try: if self.getUserId(user.name) != user.id: - raise DuplicateHostmask(user.name) + raise DuplicateHostmask(user.name, user.name) except KeyError: pass for hostmask in user.hostmasks: @@ -788,10 +788,10 @@ class UsersDictionary(utils.IterableMap): # raise an exception. So instead, we'll raise an # exception, but be nice and give the offending hostmask # back at the same time. - raise DuplicateHostmask(hostmask) + raise DuplicateHostmask(u.name, hostmask) for otherHostmask in u.hostmasks: if ircutils.hostmaskPatternEqual(hostmask, otherHostmask): - raise DuplicateHostmask(hostmask) + raise DuplicateHostmask(u.name, hostmask) self.invalidateCache(user.id) self.users[user.id] = user if flush: