# HG changeset patch # User Goffi # Date 1490809564 -7200 # Node ID 7b267496da1da34841155c206f6c2ef354d5533d # Parent 96a56856d357f6ee02b7c7493314f50b926760eb server: moved session interfaces to session_iface module + added SATGuestSession diff -r 96a56856d357 -r 7b267496da1d src/server/server.py --- a/src/server/server.py Mon Mar 06 00:05:31 2017 +0100 +++ b/src/server/server.py Wed Mar 29 19:46:04 2017 +0200 @@ -49,8 +49,6 @@ import uuid import urlparse import urllib -import shortuuid -from zope.interface import Interface, Attribute, implements from httplib import HTTPS_PORT import libervia @@ -62,25 +60,13 @@ from libervia.server.constants import Const as C from libervia.server.blog import MicroBlog +from libervia.server import session_iface # following value are set from twisted.plugins.libervia_server initialise (see the comment there) DATA_DIR_DEFAULT = OPT_PARAMETERS_BOTH = OPT_PARAMETERS_CFG = coerceDataDir = None -class ISATSession(Interface): - profile = Attribute("Sat profile") - jid = Attribute("JID associated with the profile") - uuid = Attribute("uuid associated with the profile session") - - -class SATSession(object): - implements(ISATSession) - - def __init__(self, session): - self.profile = None - self.jid = None - self.uuid = unicode(shortuuid.uuid()) class LiberviaSession(server.Session): @@ -169,7 +155,7 @@ if not item: raise KeyError except (IndexError, KeyError): - raise NotImplementedError(u"only item for PubSub URI is handler for the moment for url_redirections_dict") + raise NotImplementedError(u"only item for PubSub URI is handled for the moment for url_redirections_dict") location = "/blog/{profile}/{item}".format( profile=urllib.quote(options['url_redirections_profile'].encode('utf-8')), item = urllib.quote_plus(item), @@ -363,7 +349,7 @@ def render(self, request): self.session = request.getSession() - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile if not profile: #user is not identified, we return a jsonrpc fault parsed = jsonrpclib.loads(request.content.read()) @@ -385,40 +371,40 @@ def jsonrpc_disconnect(self): """Disconnect the profile""" - sat_session = ISATSession(self.session) + sat_session = session_iface.ISATSession(self.session) profile = sat_session.profile self.sat_host.bridge.disconnect(profile) def jsonrpc_getContacts(self): """Return all passed args.""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getContacts(profile) def jsonrpc_addContact(self, entity, name, groups): """Subscribe to contact presence, and add it to the given groups""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.addContact(entity, profile) self.sat_host.bridge.updateContact(entity, name, groups, profile) def jsonrpc_delContact(self, entity): """Remove contact from contacts list""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.delContact(entity, profile) def jsonrpc_updateContact(self, entity, name, groups): """Update contact's roster item""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.updateContact(entity, name, groups, profile) def jsonrpc_subscription(self, sub_type, entity): """Confirm (or infirm) subscription, and setup user roster in case of subscription""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.subscription(sub_type, entity, profile) def jsonrpc_getWaitingSub(self): """Return list of room already joined by user""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getWaitingSub(profile) def jsonrpc_setStatus(self, presence, status): @@ -426,12 +412,12 @@ @param presence: value from ("", "chat", "away", "dnd", "xa") @param status: any string to describe your status """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.setPresence('', presence, {'': status}, profile) def jsonrpc_messageSend(self, to_jid, msg, subject, type_, extra={}): """send message""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("messageSend", to_jid, msg, subject, type_, extra, profile) ## PubSub ## @@ -442,7 +428,7 @@ @param service (unicode): service jid @param node (unicode): node to delete """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("psDeleteNode", service, node, profile) # def jsonrpc_psRetractItem(self, service, node, item, notify): @@ -453,7 +439,7 @@ # @param items (iterable): id of item to retract # @param notify (bool): True if notification is required # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # return self.asyncBridgeCall("psRetractItem", service, node, item, notify, profile) # def jsonrpc_psRetractItems(self, service, node, items, notify): @@ -464,7 +450,7 @@ # @param items (iterable): ids of items to retract # @param notify (bool): True if notification is required # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # return self.asyncBridgeCall("psRetractItems", service, node, items, notify, profile) ## microblogging ## @@ -477,7 +463,7 @@ @param mb_data(dict): microblog data @return: a deferred """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("mbSend", service, node, mb_data, profile) def jsonrpc_mbRetract(self, service, node, items): @@ -487,7 +473,7 @@ @param node (unicode): node to delete, empty string for default node @param items (iterable): ids of items to retract """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("mbRetract", service, node, items, profile) def jsonrpc_mbGet(self, service_jid, node, max_items, item_ids, extra): @@ -500,7 +486,7 @@ @param rsm (dict): TODO @return: a deferred couple with the list of items and metadatas. """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("mbGet", service_jid, node, max_items, item_ids, extra, profile) def jsonrpc_mbGetFromMany(self, publishers_type, publishers, max_items, extra): @@ -512,7 +498,7 @@ @param extra (dict): TODO @return (str): RT Deferred session id """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.mbGetFromMany(publishers_type, publishers, max_items, extra, profile) def jsonrpc_mbGetFromManyRTResult(self, rt_session): @@ -520,7 +506,7 @@ @param rt_session (str): RT Deferred session id """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("mbGetFromManyRTResult", rt_session, profile) def jsonrpc_mbGetFromManyWithComments(self, publishers_type, publishers, max_items, max_comments, rsm_dict, rsm_comments_dict): @@ -535,7 +521,7 @@ @param profile_key: profile key @return (str): RT Deferred session id """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.mbGetFromManyWithComments(publishers_type, publishers, max_items, max_comments, rsm_dict, rsm_comments_dict, profile) def jsonrpc_mbGetFromManyWithCommentsRTResult(self, rt_session): @@ -543,7 +529,7 @@ @param rt_session (str): RT Deferred session id """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("mbGetFromManyWithCommentsRTResult", rt_session, profile) @@ -553,7 +539,7 @@ # @param dest (tuple(unicode)): recipient groups (ignored for "PUBLIC") # @param text (unicode): microblog's text # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # extra['allow_comments'] = 'True' # if not type_: # auto-detect @@ -576,7 +562,7 @@ # @param pub_data: a tuple (service, comment node identifier, item identifier) # @param comments: comments node identifier (for main item) or False # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # return self.sat_host.bridge.deleteGroupBlog(pub_data, comments if comments else '', profile) # def jsonrpc_updateMblog(self, pub_data, comments, message, extra={}): @@ -588,7 +574,7 @@ # - allow_comments: True to accept an other level of comments, False else (default: False) # - rich: if present, contain rich text in currently selected syntax # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # if comments: # extra['allow_comments'] = 'True' # return self.sat_host.bridge.updateGroupBlog(pub_data, comments if comments else '', message, extra, profile) @@ -598,7 +584,7 @@ # @param node: url of the comments node # @param text: comment # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # if node and text: # return self.sat_host.bridge.sendGroupBlogComment(node, text, extra, profile) # else: @@ -609,7 +595,7 @@ # @param publisher_jid: jid of the publisher # @param item_ids: list of microblogs items IDs # @return list of microblog data (dict)""" - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # d = self.asyncBridgeCall("getGroupBlogs", publisher_jid, item_ids, {'max_': unicode(max_items)}, False, profile) # return d @@ -618,7 +604,7 @@ # @param publisher_jid: jid of the publisher # @param item_ids: list of microblogs items IDs # @return list of couple (microblog data, list of microblog data)""" - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # d = self.asyncBridgeCall("getGroupBlogsWithComments", publisher_jid, item_ids, {}, max_comments, profile) # return d @@ -632,7 +618,7 @@ # key: publisher's jid # value: list of microblog data (dict) # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # if rsm is None: # rsm = {'max_': unicode(C.RSM_MAX_ITEMS)} # d = self.asyncBridgeCall("getMassiveGroupBlogs", publishers_type, publishers, rsm, profile) @@ -644,7 +630,7 @@ # @param service: jid of the service hosting the node # @param node: comments node # """ - # profile = ISATSession(self.session).profile + # profile = session_iface.ISATSession(self.session).profile # if rsm is None: # rsm = {'max_': unicode(C.RSM_MAX_COMMENTS)} # d = self.asyncBridgeCall("getGroupBlogComments", service, node, rsm, profile) @@ -652,12 +638,12 @@ def jsonrpc_getPresenceStatuses(self): """Get Presence information for connected contacts""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getPresenceStatuses(profile) def jsonrpc_historyGet(self, from_jid, to_jid, size, between, search=''): """Return history for the from_jid/to_jid couple""" - sat_session = ISATSession(self.session) + sat_session = session_iface.ISATSession(self.session) profile = sat_session.profile sat_jid = sat_session.jid if not sat_jid: @@ -685,7 +671,7 @@ @param room_jid (unicode): room JID or empty string to generate a unique name @param nick (unicode): user nick """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile d = self.asyncBridgeCall("joinMUC", room_jid, nick, {}, profile) return d @@ -695,14 +681,14 @@ @param contact_jid (unicode): contact to invite @param room_jid (unicode): room JID or empty string to generate a unique name """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile room_id = room_jid.split("@")[0] service = room_jid.split("@")[1] self.sat_host.bridge.inviteMUC(contact_jid, service, room_id, {}, profile) def jsonrpc_mucLeave(self, room_jid): """Quit a Multi-User Chat room""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile try: room_jid = jid.JID(room_jid) except: @@ -712,7 +698,7 @@ def jsonrpc_mucGetRoomsJoined(self): """Return list of room already joined by user""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.mucGetRoomsJoined(profile) def jsonrpc_mucGetDefaultService(self): @@ -726,7 +712,7 @@ @param other_players (list[unicode]): JIDs of the players to play with @param room_jid (unicode): room JID or empty string to generate a unique name """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.tarotGameLaunch(other_players, room_jid, profile) def jsonrpc_getTarotCardsPaths(self): @@ -737,12 +723,12 @@ def jsonrpc_tarotGameReady(self, player, referee): """Tell to the server that we are ready to start the game""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.tarotGameReady(player, referee, profile) def jsonrpc_tarotGamePlayCards(self, player_nick, referee, cards): """Tell to the server the cards we want to put on the table""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.tarotGamePlayCards(player_nick, referee, cards, profile) def jsonrpc_launchRadioCollective(self, invited, room_jid=""): @@ -751,7 +737,7 @@ @param invited (list[unicode]): JIDs of the contacts to play with @param room_jid (unicode): room JID or empty string to generate a unique name """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.radiocolLaunch(invited, room_jid, profile) def jsonrpc_getEntitiesData(self, jids, keys): @@ -762,7 +748,7 @@ @return: requested data""" if not C.ALLOWED_ENTITY_DATA.issuperset(keys): raise exceptions.PermissionError("Trying to access unallowed data (hack attempt ?)") - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile try: return self.sat_host.bridge.getEntitiesData(jids, keys, profile) except Exception as e: @@ -776,7 +762,7 @@ @return: requested data""" if not C.ALLOWED_ENTITY_DATA.issuperset(keys): raise exceptions.PermissionError("Trying to access unallowed data (hack attempt ?)") - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile try: return self.sat_host.bridge.getEntityData(jid, keys, profile) except Exception as e: @@ -786,12 +772,12 @@ """Get VCard for entiry @param jid_: jid of contact from who we want data @return: id to retrieve the profile""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getCard(jid_, profile) @defer.inlineCallbacks def jsonrpc_avatarGet(self, entity, cache_only, hash_only): - session_data = ISATSession(self.session) + session_data = session_iface.ISATSession(self.session) profile = session_data.profile # profile_uuid = session_data.uuid avatar = yield self.asyncBridgeCall("avatarGet", entity, cache_only, hash_only, profile) @@ -805,17 +791,17 @@ def jsonrpc_getAccountDialogUI(self): """Get the dialog for managing user account @return: XML string of the XMLUI""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getAccountDialogUI(profile) def jsonrpc_getParamsUI(self): """Return the parameters XML for profile""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.asyncBridgeCall("getParamsUI", C.SECURITY_LIMIT, C.APP_NAME, profile) def jsonrpc_asyncGetParamA(self, param, category, attribute="value"): """Return the parameter value for profile""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile if category == "Connection": # we need to manage the followings params here, else SECURITY_LIMIT would block them if param == "JabberID": @@ -826,13 +812,13 @@ return d def jsonrpc_setParam(self, name, value, category): - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.setParam(name, value, category, C.SECURITY_LIMIT, profile) def jsonrpc_launchAction(self, callback_id, data): #FIXME: any action can be launched, this can be a huge security issue if callback_id can be guessed # a security system with authorised callback_id must be implemented, similar to the one for authorised params - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile d = self.asyncBridgeCall("launchAction", callback_id, data, profile) return d @@ -840,7 +826,7 @@ """Call the method to process a "composing" state. @param to_jid_s: contact the user is composing to """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile self.sat_host.bridge.chatStateComposing(to_jid_s, profile) def jsonrpc_getNewAccountDomain(self): @@ -855,22 +841,22 @@ @param syntax_to: dest syntax (e.g.: "XHTML") @param safe: clean resulting XHTML to avoid malicious code if True (forced here) @return: converted text """ - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.syntaxConvert(text, syntax_from, syntax_to, True, profile) def jsonrpc_getLastResource(self, jid_s): """Get the last active resource of that contact.""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getLastResource(jid_s, profile) def jsonrpc_getFeatures(self): """Return the available features in the backend for profile""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.getFeatures(profile) def jsonrpc_skipOTR(self): """Tell the backend to leave OTR handling to Libervia.""" - profile = ISATSession(self.session).profile + profile = session_iface.ISATSession(self.session).profile return self.sat_host.bridge.skipOTR(profile) @@ -940,7 +926,7 @@ method = parsed.get("method") # pylint: disable=E1103 if method not in ['getSessionMetadata', 'registerParams', 'menusGet']: #if we don't call these methods, we need to be identified - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile if not profile: #user is not identified, we return a jsonrpc fault fault = jsonrpclib.Fault(C.ERRNUM_LIBERVIA, C.NOT_ALLOWED) # FIXME: define some standard error codes for libervia @@ -1121,7 +1107,7 @@ register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile) self.waiting_profiles.purgeRequest(profile) _session = request.getSession() - sat_session = ISATSession(_session) + sat_session = session_iface.ISATSession(_session) if sat_session.profile: log.error(_(u'/!\\ Session has already a profile, this should NEVER happen!')) request.write(C.SESSION_ACTIVE) @@ -1154,12 +1140,12 @@ def jsonrpc_isConnected(self): _session = self.request.getSession() - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile return self.sat_host.bridge.isConnected(profile) def jsonrpc_connect(self): _session = self.request.getSession() - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile if self.waiting_profiles.getRequest(profile): raise jsonrpclib.Fault(1, C.ALREADY_WAITING) # FIXME: define some standard error codes for libervia self.waiting_profiles.setRequest(self.request, profile) @@ -1181,7 +1167,7 @@ """ metadata = {} _session = self.request.getSession() - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile if profile: metadata["plugged"] = True else: @@ -1235,7 +1221,7 @@ """Keep the connection alive until a signal is received, then send it @return: (signal, *signal_args)""" _session = self.request.getSession() - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile if profile in self.queue: # if we have signals to send in queue if self.queue[profile]: return self.queue[profile].pop(0) @@ -1332,7 +1318,7 @@ """ _session = request.getSession() parsed = jsonrpclib.loads(request.content.read()) - profile = ISATSession(_session).profile + profile = session_iface.ISATSession(_session).profile if not profile: #user is not identified, we return a jsonrpc fault fault = jsonrpclib.Fault(C.ERRNUM_LIBERVIA, C.NOT_ALLOWED) # FIXME: define some standard error codes for libervia @@ -1412,7 +1398,7 @@ @return: a tuple with the name of the async bridge method to be called followed by its arguments. """ - profile = ISATSession(request.getSession()).profile + profile = session_iface.ISATSession(request.getSession()).profile return ("radiocolSongAdded", request.args['referee'][0], filepath, profile) @@ -1429,7 +1415,7 @@ @return: a tuple with the name of the async bridge method to be called followed by its arguments. """ - profile = ISATSession(request.getSession()).profile + profile = session_iface.ISATSession(request.getSession()).profile return ("setAvatar", filepath, profile) @@ -1785,6 +1771,7 @@ self.initialised.addCallback(initOk) ## URLs ## + def putChild(self, path, resource): """Add a child to the root resource""" # FIXME: check that no information is leaked (c.f. https://twistedmatrix.com/documents/current/web/howto/using-twistedweb.html#request-encoders) @@ -1932,4 +1919,5 @@ return web_util.redirectTo(url, request) -registerAdapter(SATSession, server.Session, ISATSession) +registerAdapter(session_iface.SATSession, server.Session, session_iface.ISATSession) +registerAdapter(session_iface.SATGuestSession, server.Session, session_iface.ISATGuestSession) diff -r 96a56856d357 -r 7b267496da1d src/server/session_iface.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/session_iface.py Wed Mar 29 19:46:04 2017 +0200 @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Libervia: a SAT frontend +# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from zope.interface import Interface, Attribute, implements +import shortuuid + +class ISATSession(Interface): + profile = Attribute("Sat profile") + jid = Attribute("JID associated with the profile") + uuid = Attribute("uuid associated with the profile session") + + +class SATSession(object): + implements(ISATSession) + + def __init__(self, session): + self.profile = None + self.jid = None + self.uuid = unicode(shortuuid.uuid()) + + +class ISATGuestSession(Interface): + id = Attribute("UUID of the guest") + data = Attribute("data associated with the guest") + + +class SATGuestSession(object): + implements(ISATGuestSession) + + def __init__(self, session): + self.id = None + self.data = None