diff options
| -rw-r--r-- | server/alias_plugin.py (renamed from server/plugin.py) | 0 | ||||
| -rw-r--r-- | server/object.py | 5 | ||||
| -rw-r--r-- | server/server.py | 4 | ||||
| -rw-r--r-- | server/user.py | 29 | ||||
| -rw-r--r-- | server/xep_0077.py | 158 |
5 files changed, 185 insertions, 11 deletions
diff --git a/server/plugin.py b/server/alias_plugin.py index 2001b1b..2001b1b 100644 --- a/server/plugin.py +++ b/server/alias_plugin.py diff --git a/server/object.py b/server/object.py index 6a5e45c..7a2e46f 100644 --- a/server/object.py +++ b/server/object.py @@ -8,6 +8,7 @@ import zlib import datetime import fileinput import logging +import pickle logger = logging.getLogger(__name__) from permission import * @@ -93,11 +94,11 @@ class ObjectReader(Object): file.close() return content, key - def get_private_key(self): + def get_registration_data(self): pass class ObjectWriter(Object): - def __init__(self, owner, hash = None): + def __init__(self, owner, hash = None, content): Object.__init__(self, owner, hash) if not os.path.exists(self.owner_path): logger.error("User {} is not registered".format(self.owner)) diff --git a/server/server.py b/server/server.py index 0404ca6..3bd953e 100644 --- a/server/server.py +++ b/server/server.py @@ -10,7 +10,9 @@ class ObjectComponent(ComponentXMPP): def __init__(self, jid, secret, server, port, root): ComponentXMPP.__init__(self, jid, secret, server, port) self.register_plugin('xep_0030') - self.register_plugin("AliasPlugin", module = "plugin", pconfig = {'root': root}) + self.register_plugin('xep_0077', pconfig = {'root': root}) + self.plugin['xep_0077'].setForm('pubkey','privkey','salt') + self.register_plugin("AliasPlugin", module = "alias_plugin", pconfig = {'root': root}) self.add_event_handler("session_start", self.start) self.add_event_handler("presence_probe", self.presence_probe) self.add_event_handler("message", self.message) diff --git a/server/user.py b/server/user.py index 2491164..3fbf55c 100644 --- a/server/user.py +++ b/server/user.py @@ -11,22 +11,35 @@ class UserHandler: def __init__(self, root): self.root = root - def register(self, name): - userDir = self.root + '/' + name + def register(self, jid, registration): + userDir = self.root + '/' + jid if os.path.exists(userDir): - logger.error("User {} path already exists".format(name)) + logger.error("User {} path already exists".format(jid)) os.mkdir(userDir) - ObjectWriter(name) + ObjectWriter(jid) + return True - def registered(self, name): - return os.path.exists(self.root + '/' + name) + def registered(self, jid): + return os.path.exists(self.root + '/' + jid) - def unregister(self, name): - shutil.rmtree(self.root + '/' + name) + def unregister(self, jid): + shutil.rmtree(self.root + '/' + jid) def get_user_list(self): return os.listdir(self.root) +def register(self, jid, registration): + username = registration['username'] + + def filter_usernames(user): + return user != jid and self.users[user]['username'] == username + + conflicts = filter(filter_usernames, self.users.keys()) + if conflicts: + return False + + self.users[jid] = registration + return True class User: def __init__(self, name): diff --git a/server/xep_0077.py b/server/xep_0077.py new file mode 100644 index 0000000..b07105b --- /dev/null +++ b/server/xep_0077.py @@ -0,0 +1,158 @@ +""" +Creating a SleekXMPP Plugin + +This is a minimal implementation of XEP-0077 to serve +as a tutorial for creating SleekXMPP plugins. +""" + +from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.xmlstream.handler.callback import Callback +from sleekxmpp.xmlstream.matcher.xpath import MatchXPath +from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin +from sleekxmpp import Iq +from user import UserHandler +from config import config + +class Registration(ElementBase): + namespace = 'jabber:iq:register' + name = 'query' + plugin_attrib = 'register' + interfaces = set(('pubkey', 'privkey', 'salt' + 'registered', 'remove', 'instructions')) + sub_interfaces = interfaces + + def getRegistered(self): + present = self.xml.find('{%s}registered' % self.namespace) + return present is not None + + def getRemove(self): + present = self.xml.find('{%s}remove' % self.namespace) + return present is not None + + def setRegistered(self, registered): + if registered: + self.addField('registered') + else: + del self['registered'] + + def setRemove(self, remove): + if remove: + self.addField('remove') + else: + del self['remove'] + + def addField(self, name): + itemXML = ET.Element('{%s}%s' % (self.namespace, name)) + self.xml.append(itemXML) + + +class UserStore(object): + def __init__(self): + self.users = {} + + def __getitem__(self, jid): + return self.users.get(jid, None) + + def register(self, jid, registration): + username = registration['username'] + + def filter_usernames(user): + return user != jid and self.users[user]['username'] == username + + conflicts = filter(filter_usernames, self.users.keys()) + if conflicts: + return False + + self.users[jid] = registration + return True + + def unregister(self, jid): + del self.users[jid] + +class xep_0077(base_plugin): + """ + XEP-0077 In-Band Registration + """ + + def plugin_init(self): + self.description = "In-Band Registration" + self.xep = "0077" + self.form_fields = () + self.form_instructions = "" + self.backend = UserHandler(config.root) + + self.xmpp.registerHandler( + Callback('In-Band Registration', + MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns), + self.__handleRegistration)) + register_stanza_plugin(Iq, Registration) + + def post_init(self): + base_plugin.post_init(self) + self.xmpp['xep_0030'].add_feature("jabber:iq:register") + + def __handleRegistration(self, iq): + if iq['type'] == 'get': + # Registration form requested + self.sendRegistrationForm(iq, self.backend) + elif iq['type'] == 'set': + if iq['register']['remove']: + # Remove an account + self.backend.unregister(iq['from'].bare) + #self.xmpp.event('unregistered_user', iq) + iq.reply().send() + return + + for field in self.form_fields: + if not iq['register'][field]: + # Incomplete Registration + self._sendError(iq, '406', 'modify', 'not-acceptable', + "Please fill in all fields.") + return + + if self.backend.register(iq['from'].bare, iq['register']): + # Successful registration + #self.xmpp.event('registered_user', iq) + iq.reply().setPayload(iq['register'].xml) + iq.send() + else: + # Conflicting registration + self._sendError(iq, '409', 'cancel', 'conflict', + "That username is already taken.") + + def setForm(self, *fields): + self.form_fields = fields + + def setInstructions(self, instructions): + self.form_instructions = instructions + + def sendRegistrationForm(self, iq, userHandler): + reg = iq['register'] + if user + userData = {} + else: + reg['registered'] = True + + if self.form_instructions: + reg['instructions'] = self.form_instructions + + for field in self.form_fields: + data = userData.get(field, '') + if data: + # Add field with existing data + reg[field] = data + else: + # Add a blank field + reg.addField(field) + + iq.reply().setPayload(reg.xml) + iq.send() + + def _sendError(self, iq, code, error_type, name, text=''): + iq.reply().setPayload(iq['register'].xml) + iq.error() + iq['error']['code'] = code + iq['error']['type'] = error_type + iq['error']['condition'] = name + iq['error']['text'] = text + iq.send()
\ No newline at end of file |
