aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/README7
-rw-r--r--server/__init__.py3
-rw-r--r--server/alias_plugin.py93
-rw-r--r--server/component.py54
-rw-r--r--server/config.ini.sample9
-rw-r--r--server/config.py18
-rw-r--r--server/object.py151
-rw-r--r--server/permission.py9
-rw-r--r--server/server.py97
-rw-r--r--server/user.py45
-rw-r--r--server/version.py5
-rw-r--r--server/xep_0077.py154
12 files changed, 0 insertions, 645 deletions
diff --git a/server/README b/server/README
deleted file mode 100644
index 81ee68b..0000000
--- a/server/README
+++ /dev/null
@@ -1,7 +0,0 @@
-This is Alias server written in python. It depends on SleekXMPP library :
-
- git clone git://github.com/fritzy/SleekXMPP.git
- cd SleekXMPP/
- sudo python setup.py install
-
-Make sure sleekxmpp is in your pythonpath before starting the server.
diff --git a/server/__init__.py b/server/__init__.py
deleted file mode 100644
index faaaf79..0000000
--- a/server/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
diff --git a/server/alias_plugin.py b/server/alias_plugin.py
deleted file mode 100644
index 77bcb5d..0000000
--- a/server/alias_plugin.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import logging
-logger = logging.getLogger(__name__)
-import base64
-import hashlib
-from xml.etree import cElementTree as ET
-
-from sleekxmpp.xmlstream.stanzabase import ElementBase, register_stanza_plugin
-from sleekxmpp.plugins.base import base_plugin
-from sleekxmpp.xmlstream.handler.callback import Callback
-from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
-from sleekxmpp import Iq
-
-from object import ObjectReader, ObjectError
-from permission import PermissionError
-from config import config
-
-class AliasQuery(ElementBase):
- namespace = 'alias:iq:object'
- name = 'query'
- plugin_attrib = 'alias'
- interfaces = set(('node', 'type', 'content', 'permission', 'key'))
- sub_interfaces = set(('content', 'permission', 'key'))
-
- def addItem(self, node, key, permission = None):
- item = AliasItem(None, self)
- item['node'] = node
- item['key'] = key
- if permission is not None:
- item['permission'] = str(permission)
-
-class AliasItem(ElementBase):
- namespace = 'alias:query'
- name = 'item'
- plugin_attrib = 'item'
- interfaces = set(('node', 'permission', 'key'))
-
-class AliasPlugin(base_plugin):
-
- def plugin_init(self):
- self.description = 'Plugin to handle alias queries'
- register_stanza_plugin(Iq, AliasQuery)
- query_parser = MatchXPath('{{{}}}iq/{{{}}}query'.format(self.xmpp.default_ns,
- AliasQuery.namespace))
- self.xmpp.register_handler(Callback('Alias queries', query_parser,
- self.handle_alias_query))
-
- def post_init(self):
- base_plugin.post_init(self)
- self.xmpp.plugin['xep_0030'].add_feature("alias:query")
-
- def send_permission_error(self, iq, message):
- node = iq['alias']['node']
- iq.reply()
- iq['alias']['type'] = 'error'
- iq['alias']['node'] = node
- iq['alias']['permission'] = message
- iq.send()
-
- def handle_alias_query(self, iq):
- caller = iq['from'].bare
-
- try:
- callee = base64.b64decode(iq['to'].user)
- except TypeError:
- logger.error("callee field not base64 encoded")
-
- node = iq['alias']['node']
- node = ObjectReader(node, callee)
- if iq['alias']['type'] == 'get':
- try:
- content, key = node.get_content(caller)
- except PermissionError:
- self.send_permission_error(iq, 'Permission')
- else:
- iq.reply()
- iq['alias']['type'] = 'get'
- iq['alias']['node'] = node.hash
- iq['alias']['content'] = content
- iq['alias']['key'] = key
- iq.send()
-
- if iq['alias']['type'] == 'list':
- try:
- list = node.get_children_list(caller)
- except PermissionError:
- self.send_permission_error(iq, 'Permission')
- else:
- iq.reply()
- iq['alias']['type'] = 'content'
- iq['alias']['node'] = node.hash
- iq['alias']['content'] = content
- iq['alias']['key'] = key
- iq.send() \ No newline at end of file
diff --git a/server/component.py b/server/component.py
deleted file mode 100644
index 2ae12d7..0000000
--- a/server/component.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import sys
-import logging
-logger = logging.getLogger(__name__)
-from sleekxmpp.componentxmpp import ComponentXMPP
-from sleekxmpp.xmlstream.xmlstream import XMLStream
-
-from user import UserHandler
-
-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('xep_0077', module="xep_0077")
- 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)
- self.add_event_handler("changed_subscription", self.presence_subscription)
- self.userHandler = UserHandler(root)
-
- def start(self, event):
- for user in self.userHandler.get_user_list():
- self.send_presence(pto = user)
-
- def disconnect(self, reconnect = False):
- for user in self.userHandler.get_user_list():
- self.send_presence(pto = user, ptype = "unavailable")
- XMLStream.disconnect(self, reconnect)
- logger.info('Component {} disconnected'.format(self.boundjid.bare))
-
- def message(self, msg):
- msg.reply("Thanks for sending\n{[body]}".format(msg)).send()
-
- def presence_subscription(self, subscription):
- if subscription["type"] == "subscribe":
- userJID = subscription["from"].full
- if not self.userHandler.registered(userJID):
- self.userHandler.register(userJID)
- logger.info('registering user {}'.format(userJID))
- subscription.reply().send()
- self.send_presence(pto = userJID)
- self.send_presence_subscription(pto = userJID, ptype = "subscribe")
- if subscription["type"] == "unsubscribe":
- userJID = subscription["from"].full
- if self.userHandler.registered(userJID):
- self.userHandler.unregister(userJID)
- logger.info('unregistering user {}'.format(userJID))
-
- #def presence_probe(self, event):
- # self.send_presence(pto = event["from"].full)
-
-
-
diff --git a/server/config.ini.sample b/server/config.ini.sample
deleted file mode 100644
index 66dde3a..0000000
--- a/server/config.ini.sample
+++ /dev/null
@@ -1,9 +0,0 @@
-[component]
-name = testg.alias.im
-secret = Mvdujq06
-host = alias.im
-port = 5349
-root = /var/lib/alias/
-background = True
-logfile = /var/log/alias.log
-pidfile = /var/run/alias.pid
diff --git a/server/config.py b/server/config.py
deleted file mode 100644
index 74befe2..0000000
--- a/server/config.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import ConfigParser
-
-class AliasConfigParser(ConfigParser.SafeConfigParser):
-
- def read(self, filename):
- ConfigParser.SafeConfigParser.read(self, filename)
- self.name = self.get("component", "name")
- self.root = self.get("component", "root")
- self.host = self.get("component", "host")
- self.secret = self.get("component", "secret")
- self.port = self.getint("component", "port")
- self.background = self.getboolean("component", "background")
- if self.has_option("component", "logfile"):
- self.logfile = self.get("component", "logfile")
- if self.has_option("component", "pidfile"):
- self.pidfile = self.get("component", "pidfile")
-
-config = AliasConfigParser()
diff --git a/server/object.py b/server/object.py
deleted file mode 100644
index 8dd91a2..0000000
--- a/server/object.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# -*- coding: utf-8 -*-
-#import StringIO
-import hashlib
-#import sys
-#import os
-import os.path
-#import fileinput
-import logging
-logger = logging.getLogger(__name__)
-
-from permission import *
-from config import config
-
-class ObjectError(Exception):
- pass;
-
-class Object:
- def __init__(self, name, owner, split_name = True):
- self.hash = name
- self.owner = owner
- if split_name:
- self.object_path = os.path.join(config.root, owner, name[:2], name[2:])
- else:
- self.object_path = os.path.join(config.root, owner, name)
-
- def exists(self):
- return os.path.exists(self.object_path)
-
-class ObjectReader(Object):
- def __init__(self, hash, owner, split_name = True):
- Object.__init__(self, hash, owner, split_name)
- if not self.exists():
- logger.error("Object {} can't be found for user {}".format(self.hash,
- self.owner))
- raise ObjectError
-
- def get_permission(self, user):
- with open(os.path.join(self.object_path, 'permissions'), 'r') as file:
- for line in file:
- name, perm, key = line.split()
- if name == user:
- return int(perm)
- return None
-
- def get_key(self, user):
- with open(os.path.join(self.object_path, 'permissions'), 'r') as file:
- for line in file:
- name, perm, key = line.split()
- if name == user:
- return key
- return None
-
- def get_permission_key(self, user):
- with open(os.path.join(self.object_path, 'permissions'), 'r') as file:
- for line in file:
- name, perm, key = line.split()
- if name == user:
- return (int(perm), key)
- return (None, None)
-
- def get_children_list(self, user):
- perm = self.get_permission(user)
- if not perm or (not perm & LIST):
- logger.error("User {} doesn't have the list permission for object {}"
- .format(user, self.hash))
- raise PermissionError
-
- file = open(os.path.join(self.object_path, 'childs'), 'r')
- result = []
- for line in file:
- name = line.rstrip('\n')
- try:
- child = ObjectReader(name, self.owner)
- except ObjectError:
- logger.error('Object {} doesn\'t exist'.format(name))
- else:
- perm, key = child.get_permission_key(user)
- if perm > 0:
- result.append((name, perm, key))
-
- file.close()
- return result
-
- def get_content(self, user):
- """Return object content and the user key to decrypt it."""
- perm, key = self.get_permission_key(user)
- if not perm or (not perm & READ) :
- logger.error("User {} doesn't have read access to object {}"
- .format(user, self.hash))
- raise PermissionError
- with open(os.path.join(self.object_path, 'object'), 'r') as file:
- content = file.read()
-
- return content, key
-
-class ObjectWriter(ObjectReader):
-
- def __init__(self, hash, owner, split_name = True, key = None):
- Object.__init__(self, hash, owner, split_name)
- self.files = ('permissions', 'children', 'object')
- self.__create_skeleton(key)
-
- def __create_skeleton(self, key):
- #new object
- if not self.exists():
- os.makedirs(self.object_path)
- for filename in self.files:
- file = open(os.path.join(self.object_path, filename), "w")
- file.close()
- #give all the permissions to the owner
- ALLPERM = READ + MODIFY + APPEND + LIST
- self.add_user(self.owner, ALLPERM, key)
-
- def write(self, user, content):
- perm = self.get_permission(user)
- if not perm or (not perm & MODIFY):
- logger.error("User {} doesn't have the modify permission for object {}"
- .format(user, self.hash))
- raise PermissionError
- with open(os.path.join(self.object_path, 'object'), "w") as file:
- file.write('{}'.format(content))
-
- def append(self, user, content, parent):
- parent_object = ObjectReader(parent, self.owner)
- perm = parent_object.get_permission(user)
- if not perm or (not perm & APPEND):
- logger.error("User {} doesn't have the modify permission for object {}"
- .format(user, parent))
- raise PermissionError
- with open(os.path.join(self.object_path, 'object'), "w") as file:
- for k, v in content:
- file.write('{} {}\n'.format(k,v))
- #add the child hash to the parent
- with open(os.path.join(parent_object.object_path, 'children'), "a") as file:
- file.write('{} {}\n'.format(self.hash))
-
- def add_user(self, user, perm, key = None):
- with open(os.path.join(self.object_path, 'permissions'), "a") as file:
- if key:
- file.write('{} {} {}\n'.format(user, perm, key))
- else:
- file.write('{} {} None\n'.format(user, perm, key))
-
-if __name__ == '__main__':
- jid = 'thrasibule@alias.im'
- hash = hashlib.sha1(jid).hexdigest()
- config.root = '/var/lib/alias'
- print ObjectReader(hash, jid).get_content(jid)
-
-
-
diff --git a/server/permission.py b/server/permission.py
deleted file mode 100644
index 3ce7323..0000000
--- a/server/permission.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-
-READ = 1 << 0
-MODIFY = 1 << 1
-APPEND = 1 << 2
-LIST = 1 << 3
-
-class PermissionError(Exception):
- pass \ No newline at end of file
diff --git a/server/server.py b/server/server.py
deleted file mode 100644
index 4556fb8..0000000
--- a/server/server.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/python2
-import logging
-from argparse import ArgumentParser
-from config import config
-import daemon
-import daemon.pidfile
-from component import ObjectComponent
-import os.path
-import sys
-
-if sys.version_info < (3, 0):
- reload(sys)
- sys.setdefaultencoding('utf8')
-else:
- raw_input = input
-
-if __name__ == '__main__':
- commandline = ArgumentParser(description = 'Connect the alias \
- component to a given server')
- commandline.add_argument('-p', '--port',
- help = 'Port to connect to',
- type = int)
- commandline.add_argument('-s', '--secret',
- help = 'password')
- commandline.add_argument('-n', '--name',
- help = 'Name the component will have')
- commandline.add_argument('-r', '--root',
- help = 'Root directory of the user files')
- commandline.add_argument('-c', '--config',
- help = 'Name of the config file to use')
- commandline.add_argument('-d', '--debug',
- help = 'Set log level to DEBUG',
- action = 'store_const',
- const = logging.DEBUG,
- default = logging.INFO)
- commandline.add_argument('-o', '--host',
- help = 'Host to connect to')
- commandline.add_argument('-b', '--background',
- help = 'run the server in the background',
- action = 'store_true')
- commandline.add_argument('--logfile',
- help = 'location of the log file (default /var/log/${name}.log')
- commandline.add_argument('--pidfile',
- help = 'location of the pid file (default /var/run/${name}.pid')
- args = commandline.parse_args()
-
- if args.config is None:
- config.name = args.name
- config.port = args.port
- config.secret = args.secret
- config.root = args.root
- config.host = args.host
- config.background = args.background
- config.logfile = args.logfile
- config.pidfile = args.pidfile
- else:
- filename = args.config
- config.read(filename)
- if config.logfile is None:
- config.logfile = os.path.join('/var/log/', config.name + '.log')
- if config.pidfile is None:
- config.pidfile = os.path.join('/var/run/', config.name + '.pid')
-
- #set up the root logger
- logging.getLogger('').setLevel(args.debug)
- formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
- if config.background:
- #save logs in a file
- fh = logging.FileHandler(config.logfile)
- fh.setFormatter(formatter)
- logging.getLogger('').addHandler(fh)
- else:
- #save logs to the console
- ch = logging.StreamHandler()
- ch.setFormatter(formatter)
- logging.getLogger('').addHandler(ch)
-
- if config.background:
- context = daemon.DaemonContext(detach_process = True,
- pidfile = daemon.pidfile.TimeoutPIDLockFile(config.pidfile,10),
- files_preserve=[fh.stream.fileno()],
- working_directory=os.path.abspath(config.root),
- stdout=sys.stdout, stderr=sys.stderr)
- else:
- context = daemon.DaemonContext(detach_process = False,
- stdout=sys.stdout, stderr=sys.stderr,
- working_directory=os.path.abspath(config.root))
-
- with context:
- component = ObjectComponent(config.name, config.secret,
- config.host, config.port,
- config.root)
- if component.connect():
- logging.info('Component {} connected'.format(component.boundjid))
- component.process(block=False)
- else:
- logging.error("Component {} couldn't connect".format(component.boundjid))
diff --git a/server/user.py b/server/user.py
deleted file mode 100644
index f6800f9..0000000
--- a/server/user.py
+++ /dev/null
@@ -1,45 +0,0 @@
-import os
-import os.path
-import shutil
-import hashlib
-import logging
-logger = logging.getLogger(__name__)
-from object import *
-import base64
-
-class User:
-
- def __init__(self, jid):
- self.jid = jid
- self.hash = hashlib.sha256(jid).hexdigest()
- #self.hash = hashlib.md5(jid).hexdigest()
-
- def register(self, registration):
- ObjectWriter('pubkey', self.jid, split_name = False).write(self.jid, registration['pubkey'])
- #everybody can read the pubkey
- ObjectWriter('pubkey', self.jid, split_name = False).add_user('*', READ)
- ObjectWriter('privkey', self.jid, split_name = False).write(self.jid, registration['privkey'])
- ObjectWriter(self.hash, self.jid)
-
- def get_registration(self):
- registration = {}
- registration['pubkey'], ignore = ObjectReader('pubkey',self.jid, split_name = False).get_content(self.jid)
- registration['privkey'], ignore = ObjectReader('privkey',self.jid, split_name = False).get_content(self.jid)
- return registration
-
- def is_registered(self):
- return Object(self.hash, self.jid).exists()
-
- def unregister(self, jid):
- pass
-
-class UserHandler:
-
- def __init__(self, root):
- self.root = root
-
- def get_user_list(self):
- return os.listdir(self.root)
-
-if __name__ == '__main__':
- print UserHandler('/var/lib/alias').get_user_list() \ No newline at end of file
diff --git a/server/version.py b/server/version.py
deleted file mode 100644
index 306cebb..0000000
--- a/server/version.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- coding: utf-8 -*-
-MAJOR=0
-MINOR=1
-TYPE='dev'
-VERSION = str(MAJOR)+'.'+str(MINOR)+TYPE #TODO: add the commit number ?
diff --git a/server/xep_0077.py b/server/xep_0077.py
deleted file mode 100644
index 0608dc5..0000000
--- a/server/xep_0077.py
+++ /dev/null
@@ -1,154 +0,0 @@
-"""
-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 User
-from config import config
-from sleekxmpp.plugins.xep_0004 import Form
-
-import logging
-logger = logging.getLogger(__name__)
-
-class Registration(ElementBase):
- namespace = 'jabber:iq:register'
- name = 'query'
- plugin_attrib = 'register'
- interfaces = set(('registered', 'remove', 'instructions', 'form'))
- sub_interfaces = interfaces
- subitem = (Form,)
-
- def get_registered(self):
- present = self.xml.find('{%s}registered' % self.namespace)
- return present is not None
-
- def get_remove(self):
- present = self.xml.find('{%s}remove' % self.namespace)
- return present is not None
-
- def set_registered(self, registered):
- if registered:
- self.add_field('registered')
- else:
- del self['registered']
-
- def set_remove(self, remove):
- if remove:
- self.addField('remove')
- else:
- del self['remove']
-
- def add_field(self, name):
- itemXML = ET.Element('{%s}%s' % (self.namespace, name))
- self.xml.append(itemXML)
-
- def add_form(self):
- aliasform = Form(None, self)
- aliasform.addField(ftype = "hidden", var = "FORM_TYPE", value = "alias:register")
- aliasform.addField(var = "pubkey", ftype = "text-single", label = "Public Key", required = True)
- aliasform.addField(var = "privkey", ftype = "text-single", label = "Private Key", required = True)
-
- def get_form(self):
- return Form(self.xml.find('{jabber:x:data}x')).getValues()
-
- def set_form(self, values):
- Form(self.xml.find('{jabber:x:data}x')).setValues(values)
-
-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 = ("privkey", "pubkey")
- self.form_instructions = "Please provide the following information to register\
- an alias account"
-
- self.xmpp.register_handler(
- Callback('In-Band Registration',
- MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns),
- self.__handle_registration))
- register_stanza_plugin(Iq, Registration)
-
- def post_init(self):
- base_plugin.post_init(self)
- self.xmpp['xep_0030'].add_feature("jabber:iq:register")
-
- def __handle_registration(self, iq):
- registrant = User(iq['from'].bare)
- logger.info('User {} sent registration iq'.format(iq['from'].bare))
- if iq['type'] == 'get':
- # Registration form requested
- self.send_registration_form(iq, registrant)
- elif iq['type'] == 'set':
- if iq['register']['remove']:
- # Remove an account
- registrant.unregister()
- self.xmpp.event('unregistered_user', iq)
- iq.reply().send()
- return
-
- registration_info = iq['register']['form']
- for field in self.form_fields:
- if not registration_info[field]:
- # Incomplete Registration
- self._send_error(iq, '406', 'modify', 'not-acceptable',
- "Please fill in all fields.")
- return
-
- try:
- registrant.register(registration_info)
- # Successful registration
- #self.xmpp.event('registered_user', iq)
- iq.reply().setPayload(iq['register'].xml)
- iq.send()
- except:
- return
- else:
- # Conflicting registration
- self._send_error(iq, '409', 'cancel', 'conflict',
- "That username is already taken.")
-
- def setForm(self, *fields):
- self.form_fields = fields
-
- def set_instructions(self, instructions):
- self.form_instructions = instructions
-
- def send_registration_form(self, iq, registrant):
- reg = iq['register']
- reg.add_form()
- if self.form_instructions:
- reg['instructions'] = self.form_instructions
- if registrant.is_registered():
- reg['registered'] = True
- reg['form'] = registrant.get_registration()
-
- iq.reply().setPayload(reg.xml)
- iq.send()
-
- def _send_error(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()
-
-if __name__ == '__main__':
- test = Registration()
- test.add_form()
- print '{}\n'.format(test['form'])
- values = {'privkey': 'pomme', 'pubkey': 'poire', 'salt': 'abricot'}
- test['form']=values
- print test