Mercurial > libervia-backend
diff sat/plugins/plugin_xep_0234.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 3e4e78de9cca |
children | 378188abe941 |
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0234.py Wed Jun 27 07:51:29 2018 +0200 +++ b/sat/plugins/plugin_xep_0234.py Wed Jun 27 20:14:46 2018 +0200 @@ -20,6 +20,7 @@ from sat.core.i18n import _ from sat.core.constants import Const as C from sat.core.log import getLogger + log = getLogger(__name__) from sat.core import exceptions from wokkel import disco, iwokkel @@ -40,7 +41,7 @@ import mimetypes -NS_JINGLE_FT = 'urn:xmpp:jingle:apps:file-transfer:5' +NS_JINGLE_FT = "urn:xmpp:jingle:apps:file-transfer:5" PLUGIN_INFO = { C.PI_NAME: "Jingle File Transfer", @@ -51,11 +52,11 @@ C.PI_DEPENDENCIES: ["XEP-0166", "XEP-0300", "FILE"], C.PI_MAIN: "XEP_0234", C.PI_HANDLER: "yes", - C.PI_DESCRIPTION: _("""Implementation of Jingle File Transfer""") + C.PI_DESCRIPTION: _("""Implementation of Jingle File Transfer"""), } -EXTRA_ALLOWED = {u'path', u'namespace', u'file_desc', u'file_hash'} -Range = namedtuple('Range', ('offset', 'length')) +EXTRA_ALLOWED = {u"path", u"namespace", u"file_desc", u"file_hash"} +Range = namedtuple("Range", ("offset", "length")) class XEP_0234(object): @@ -66,14 +67,30 @@ def __init__(self, host): log.info(_("plugin Jingle File Transfer initialization")) self.host = host - host.registerNamespace('jingle-ft', NS_JINGLE_FT) - self._j = host.plugins["XEP-0166"] # shortcut to access jingle + host.registerNamespace("jingle-ft", NS_JINGLE_FT) + self._j = host.plugins["XEP-0166"] # shortcut to access jingle self._j.registerApplication(NS_JINGLE_FT, self) self._f = host.plugins["FILE"] - self._f.register(NS_JINGLE_FT, self.fileJingleSend, priority = 10000, method_name=u"Jingle") + self._f.register( + NS_JINGLE_FT, self.fileJingleSend, priority=10000, method_name=u"Jingle" + ) self._hash = self.host.plugins["XEP-0300"] - host.bridge.addMethod("fileJingleSend", ".plugin", in_sign='ssssa{ss}s', out_sign='', method=self._fileJingleSend, async=True) - host.bridge.addMethod("fileJingleRequest", ".plugin", in_sign='sssssa{ss}s', out_sign='s', method=self._fileJingleRequest, async=True) + host.bridge.addMethod( + "fileJingleSend", + ".plugin", + in_sign="ssssa{ss}s", + out_sign="", + method=self._fileJingleSend, + async=True, + ) + host.bridge.addMethod( + "fileJingleRequest", + ".plugin", + in_sign="sssssa{ss}s", + out_sign="s", + method=self._fileJingleRequest, + async=True, + ) def getHandler(self, client): return XEP_0234_handler() @@ -85,12 +102,25 @@ @param content_name(unicode): name of the content @return (unicode): unique progress id """ - return u'{}_{}'.format(session['id'], content_name) + return u"{}_{}".format(session["id"], content_name) # generic methods - def buildFileElement(self, name, file_hash=None, hash_algo=None, size=None, mime_type=None, desc=None, - modified=None, transfer_range=None, path=None, namespace=None, file_elt=None, **kwargs): + def buildFileElement( + self, + name, + file_hash=None, + hash_algo=None, + size=None, + mime_type=None, + desc=None, + modified=None, + transfer_range=None, + path=None, + namespace=None, + file_elt=None, + **kwargs + ): """Generate a <file> element with available metadata @param file_hash(unicode, None): hash of the file @@ -109,26 +139,32 @@ @trigger XEP-0234_buildFileElement(file_elt, extra_args): can be used to extend elements to add """ if file_elt is None: - file_elt = domish.Element((NS_JINGLE_FT, u'file')) - for name, value in ((u'name', name), (u'size', size), ('media-type', mime_type), - (u'desc', desc), (u'path', path), (u'namespace', namespace)): + file_elt = domish.Element((NS_JINGLE_FT, u"file")) + for name, value in ( + (u"name", name), + (u"size", size), + ("media-type", mime_type), + (u"desc", desc), + (u"path", path), + (u"namespace", namespace), + ): if value is not None: file_elt.addElement(name, content=unicode(value)) if modified is not None: if isinstance(modified, int): - file_elt.addElement(u'date', utils.xmpp_date(modified or None)) + file_elt.addElement(u"date", utils.xmpp_date(modified or None)) else: - file_elt.addElement(u'date', modified) - elif 'created' in kwargs: - file_elt.addElement(u'date', utils.xmpp_date(kwargs.pop('created'))) + file_elt.addElement(u"date", modified) + elif "created" in kwargs: + file_elt.addElement(u"date", utils.xmpp_date(kwargs.pop("created"))) - range_elt = file_elt.addElement(u'range') + range_elt = file_elt.addElement(u"range") if transfer_range is not None: if transfer_range.offset is not None: - range_elt[u'offset'] = transfer_range.offset + range_elt[u"offset"] = transfer_range.offset if transfer_range.length is not None: - range_elt[u'length'] = transfer_range.length + range_elt[u"length"] = transfer_range.length if file_hash is not None: if not file_hash: file_elt.addChild(self._hash.buildHashUsedElt()) @@ -136,10 +172,10 @@ file_elt.addChild(self._hash.buildHashElt(file_hash, hash_algo)) elif hash_algo is not None: file_elt.addChild(self._hash.buildHashUsedElt(hash_algo)) - self.host.trigger.point(u'XEP-0234_buildFileElement', file_elt, extra_args=kwargs) + self.host.trigger.point(u"XEP-0234_buildFileElement", file_elt, extra_args=kwargs) if kwargs: for kw in kwargs: - log.debug('ignored keyword: {}'.format(kw)) + log.debug("ignored keyword: {}".format(kw)) return file_elt def buildFileElementFromDict(self, file_data, **kwargs): @@ -151,10 +187,16 @@ if kwargs: file_data = file_data.copy() file_data.update(kwargs) - return self. buildFileElement(**file_data) + return self.buildFileElement(**file_data) - - def parseFileElement(self, file_elt, file_data=None, given=False, parent_elt=None, keep_empty_range=False): + def parseFileElement( + self, + file_elt, + file_data=None, + given=False, + parent_elt=None, + keep_empty_range=False, + ): """Parse a <file> element and file dictionary accordingly @param file_data(dict, None): dict where the data will be set @@ -173,77 +215,105 @@ """ if parent_elt is not None: if file_elt is not None: - raise exceptions.InternalError(u'file_elt must be None if parent_elt is set') + raise exceptions.InternalError( + u"file_elt must be None if parent_elt is set" + ) try: - file_elt = next(parent_elt.elements(NS_JINGLE_FT, u'file')) + file_elt = next(parent_elt.elements(NS_JINGLE_FT, u"file")) except StopIteration: raise exceptions.NotFound() else: if not file_elt or file_elt.uri != NS_JINGLE_FT: - raise exceptions.DataError(u'invalid <file> element: {stanza}'.format(stanza = file_elt.toXml())) + raise exceptions.DataError( + u"invalid <file> element: {stanza}".format(stanza=file_elt.toXml()) + ) if file_data is None: file_data = {} - for name in (u'name', u'desc', u'path', u'namespace'): + for name in (u"name", u"desc", u"path", u"namespace"): try: file_data[name] = unicode(next(file_elt.elements(NS_JINGLE_FT, name))) except StopIteration: pass - - name = file_data.get(u'name') - if name == u'..': + name = file_data.get(u"name") + if name == u"..": # we don't want to go to parent dir when joining to a path - name = u'--' - file_data[u'name'] = name - elif name is not None and u'/' in name or u'\\' in name: - file_data[u'name'] = regex.pathEscape(name) + name = u"--" + file_data[u"name"] = name + elif name is not None and u"/" in name or u"\\" in name: + file_data[u"name"] = regex.pathEscape(name) try: - file_data[u'mime_type'] = unicode(next(file_elt.elements(NS_JINGLE_FT, u'media-type'))) + file_data[u"mime_type"] = unicode( + next(file_elt.elements(NS_JINGLE_FT, u"media-type")) + ) except StopIteration: pass try: - file_data[u'size'] = int(unicode(next(file_elt.elements(NS_JINGLE_FT, u'size')))) + file_data[u"size"] = int( + unicode(next(file_elt.elements(NS_JINGLE_FT, u"size"))) + ) except StopIteration: pass try: - file_data[u'modified'] = date_utils.date_parse(next(file_elt.elements(NS_JINGLE_FT, u'date'))) + file_data[u"modified"] = date_utils.date_parse( + next(file_elt.elements(NS_JINGLE_FT, u"date")) + ) except StopIteration: pass try: - range_elt = file_elt.elements(NS_JINGLE_FT, u'range').next() + range_elt = file_elt.elements(NS_JINGLE_FT, u"range").next() except StopIteration: pass else: - offset = range_elt.getAttribute('offset') - length = range_elt.getAttribute('length') + offset = range_elt.getAttribute("offset") + length = range_elt.getAttribute("length") if offset or length or keep_empty_range: - file_data[u'transfer_range'] = Range(offset=offset, length=length) + file_data[u"transfer_range"] = Range(offset=offset, length=length) - prefix = u'given_' if given else u'' - hash_algo_key, hash_key = u'hash_algo', prefix + u'file_hash' + prefix = u"given_" if given else u"" + hash_algo_key, hash_key = u"hash_algo", prefix + u"file_hash" try: - file_data[hash_algo_key], file_data[hash_key] = self._hash.parseHashElt(file_elt) + file_data[hash_algo_key], file_data[hash_key] = self._hash.parseHashElt( + file_elt + ) except exceptions.NotFound: pass - self.host.trigger.point(u'XEP-0234_parseFileElement', file_elt, file_data) + self.host.trigger.point(u"XEP-0234_parseFileElement", file_elt, file_data) return file_data # bridge methods - def _fileJingleSend(self, peer_jid, filepath, name="", file_desc="", extra=None, profile=C.PROF_KEY_NONE): + def _fileJingleSend( + self, + peer_jid, + filepath, + name="", + file_desc="", + extra=None, + profile=C.PROF_KEY_NONE, + ): client = self.host.getClient(profile) - return self.fileJingleSend(client, jid.JID(peer_jid), filepath, name or None, file_desc or None, extra or None) + return self.fileJingleSend( + client, + jid.JID(peer_jid), + filepath, + name or None, + file_desc or None, + extra or None, + ) @defer.inlineCallbacks - def fileJingleSend(self, client, peer_jid, filepath, name, file_desc=None, extra=None): + def fileJingleSend( + self, client, peer_jid, filepath, name, file_desc=None, extra=None + ): """Send a file using jingle file transfer @param peer_jid(jid.JID): destinee jid @@ -256,25 +326,58 @@ if extra is None: extra = {} if file_desc is not None: - extra['file_desc'] = file_desc - yield self._j.initiate(client, - peer_jid, - [{'app_ns': NS_JINGLE_FT, - 'senders': self._j.ROLE_INITIATOR, - 'app_kwargs': {'filepath': filepath, - 'name': name, - 'extra': extra, - 'progress_id_d': progress_id_d}, - }]) + extra["file_desc"] = file_desc + yield self._j.initiate( + client, + peer_jid, + [ + { + "app_ns": NS_JINGLE_FT, + "senders": self._j.ROLE_INITIATOR, + "app_kwargs": { + "filepath": filepath, + "name": name, + "extra": extra, + "progress_id_d": progress_id_d, + }, + } + ], + ) progress_id = yield progress_id_d defer.returnValue(progress_id) - def _fileJingleRequest(self, peer_jid, filepath, name="", file_hash="", hash_algo="", extra=None, profile=C.PROF_KEY_NONE): + def _fileJingleRequest( + self, + peer_jid, + filepath, + name="", + file_hash="", + hash_algo="", + extra=None, + profile=C.PROF_KEY_NONE, + ): client = self.host.getClient(profile) - return self.fileJingleRequest(client, jid.JID(peer_jid), filepath, name or None, file_hash or None, hash_algo or None, extra or None) + return self.fileJingleRequest( + client, + jid.JID(peer_jid), + filepath, + name or None, + file_hash or None, + hash_algo or None, + extra or None, + ) @defer.inlineCallbacks - def fileJingleRequest(self, client, peer_jid, filepath, name=None, file_hash=None, hash_algo=None, extra=None): + def fileJingleRequest( + self, + client, + peer_jid, + filepath, + name=None, + file_hash=None, + hash_algo=None, + extra=None, + ): """Request a file using jingle file transfer @param peer_jid(jid.JID): destinee jid @@ -289,122 +392,152 @@ if file_hash is not None: if hash_algo is None: raise ValueError(_(u"hash_algo must be set if file_hash is set")) - extra['file_hash'] = file_hash - extra['hash_algo'] = hash_algo + extra["file_hash"] = file_hash + extra["hash_algo"] = hash_algo else: if hash_algo is not None: raise ValueError(_(u"file_hash must be set if hash_algo is set")) - yield self._j.initiate(client, - peer_jid, - [{'app_ns': NS_JINGLE_FT, - 'senders': self._j.ROLE_RESPONDER, - 'app_kwargs': {'filepath': filepath, - 'name': name, - 'extra': extra, - 'progress_id_d': progress_id_d}, - }]) + yield self._j.initiate( + client, + peer_jid, + [ + { + "app_ns": NS_JINGLE_FT, + "senders": self._j.ROLE_RESPONDER, + "app_kwargs": { + "filepath": filepath, + "name": name, + "extra": extra, + "progress_id_d": progress_id_d, + }, + } + ], + ) progress_id = yield progress_id_d defer.returnValue(progress_id) # jingle callbacks - def jingleSessionInit(self, client, session, content_name, filepath, name, extra, progress_id_d): + def jingleSessionInit( + self, client, session, content_name, filepath, name, extra, progress_id_d + ): if extra is None: extra = {} else: if not EXTRA_ALLOWED.issuperset(extra): - raise ValueError(_(u"only the following keys are allowed in extra: {keys}").format( - keys=u', '.join(EXTRA_ALLOWED))) + raise ValueError( + _(u"only the following keys are allowed in extra: {keys}").format( + keys=u", ".join(EXTRA_ALLOWED) + ) + ) progress_id_d.callback(self.getProgressId(session, content_name)) - content_data = session['contents'][content_name] - application_data = content_data['application_data'] - assert 'file_path' not in application_data - application_data['file_path'] = filepath - file_data = application_data['file_data'] = {} - desc_elt = domish.Element((NS_JINGLE_FT, 'description')) + content_data = session["contents"][content_name] + application_data = content_data["application_data"] + assert "file_path" not in application_data + application_data["file_path"] = filepath + file_data = application_data["file_data"] = {} + desc_elt = domish.Element((NS_JINGLE_FT, "description")) file_elt = desc_elt.addElement("file") - if content_data[u'senders'] == self._j.ROLE_INITIATOR: + if content_data[u"senders"] == self._j.ROLE_INITIATOR: # we send a file if name is None: name = os.path.basename(filepath) - file_data[u'date'] = utils.xmpp_date() - file_data[u'desc'] = extra.pop(u'file_desc', u'') - file_data[u'name'] = name + file_data[u"date"] = utils.xmpp_date() + file_data[u"desc"] = extra.pop(u"file_desc", u"") + file_data[u"name"] = name mime_type = mimetypes.guess_type(name, strict=False)[0] if mime_type is not None: - file_data[u'mime_type'] = mime_type - file_data[u'size'] = os.path.getsize(filepath) - if u'namespace' in extra: - file_data[u'namespace'] = extra[u'namespace'] - if u'path' in extra: - file_data[u'path'] = extra[u'path'] - self.buildFileElementFromDict(file_data, file_elt=file_elt, file_hash=u'') + file_data[u"mime_type"] = mime_type + file_data[u"size"] = os.path.getsize(filepath) + if u"namespace" in extra: + file_data[u"namespace"] = extra[u"namespace"] + if u"path" in extra: + file_data[u"path"] = extra[u"path"] + self.buildFileElementFromDict(file_data, file_elt=file_elt, file_hash=u"") else: # we request a file - file_hash = extra.pop(u'file_hash', u'') + file_hash = extra.pop(u"file_hash", u"") if not name and not file_hash: - raise ValueError(_(u'you need to provide at least name or file hash')) + raise ValueError(_(u"you need to provide at least name or file hash")) if name: - file_data[u'name'] = name + file_data[u"name"] = name if file_hash: - file_data[u'file_hash'] = file_hash - file_data[u'hash_algo'] = extra[u'hash_algo'] + file_data[u"file_hash"] = file_hash + file_data[u"hash_algo"] = extra[u"hash_algo"] else: - file_data[u'hash_algo'] = self._hash.getDefaultAlgo() - if u'namespace' in extra: - file_data[u'namespace'] = extra[u'namespace'] - if u'path' in extra: - file_data[u'path'] = extra[u'path'] + file_data[u"hash_algo"] = self._hash.getDefaultAlgo() + if u"namespace" in extra: + file_data[u"namespace"] = extra[u"namespace"] + if u"path" in extra: + file_data[u"path"] = extra[u"path"] self.buildFileElementFromDict(file_data, file_elt=file_elt) return desc_elt def jingleRequestConfirmation(self, client, action, session, content_name, desc_elt): """This method request confirmation for a jingle session""" - content_data = session['contents'][content_name] - senders = content_data[u'senders'] + content_data = session["contents"][content_name] + senders = content_data[u"senders"] if senders not in (self._j.ROLE_INITIATOR, self._j.ROLE_RESPONDER): log.warning(u"Bad sender, assuming initiator") - senders = content_data[u'senders'] = self._j.ROLE_INITIATOR + senders = content_data[u"senders"] = self._j.ROLE_INITIATOR # first we grab file informations try: - file_elt = desc_elt.elements(NS_JINGLE_FT, 'file').next() + file_elt = desc_elt.elements(NS_JINGLE_FT, "file").next() except StopIteration: raise failure.Failure(exceptions.DataError) - file_data = {'progress_id': self.getProgressId(session, content_name)} + file_data = {"progress_id": self.getProgressId(session, content_name)} if senders == self._j.ROLE_RESPONDER: # we send the file - return self._fileSendingRequestConf(client, session, content_data, content_name, file_data, file_elt) + return self._fileSendingRequestConf( + client, session, content_data, content_name, file_data, file_elt + ) else: # we receive the file - return self._fileReceivingRequestConf(client, session, content_data, content_name, file_data, file_elt) + return self._fileReceivingRequestConf( + client, session, content_data, content_name, file_data, file_elt + ) @defer.inlineCallbacks - def _fileSendingRequestConf(self, client, session, content_data, content_name, file_data, file_elt): + def _fileSendingRequestConf( + self, client, session, content_data, content_name, file_data, file_elt + ): """parse file_elt, and handle file retrieving/permission checking""" self.parseFileElement(file_elt, file_data) - content_data['application_data']['file_data'] = file_data - finished_d = content_data['finished_d'] = defer.Deferred() + content_data["application_data"]["file_data"] = file_data + finished_d = content_data["finished_d"] = defer.Deferred() # confirmed_d is a deferred returning confimed value (only used if cont is False) - cont, confirmed_d = self.host.trigger.returnPoint("XEP-0234_fileSendingRequest", client, session, content_data, content_name, file_data, file_elt) + cont, confirmed_d = self.host.trigger.returnPoint( + "XEP-0234_fileSendingRequest", + client, + session, + content_data, + content_name, + file_data, + file_elt, + ) if not cont: confirmed = yield confirmed_d if confirmed: args = [client, session, content_name, content_data] - finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) + finished_d.addCallbacks( + self._finishedCb, self._finishedEb, args, None, args + ) defer.returnValue(confirmed) - log.warning(_(u'File continue is not implemented yet')) + log.warning(_(u"File continue is not implemented yet")) defer.returnValue(False) - def _fileReceivingRequestConf(self, client, session, content_data, content_name, file_data, file_elt): + def _fileReceivingRequestConf( + self, client, session, content_data, content_name, file_data, file_elt + ): """parse file_elt, and handle user permission/file opening""" self.parseFileElement(file_elt, file_data, given=True) try: - hash_algo, file_data['given_file_hash'] = self._hash.parseHashElt(file_elt) + hash_algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) except exceptions.NotFound: try: hash_algo = self._hash.parseHashUsedElt(file_elt) @@ -412,88 +545,94 @@ raise failure.Failure(exceptions.DataError) if hash_algo is not None: - file_data['hash_algo'] = hash_algo - file_data['hash_hasher'] = hasher = self._hash.getHasher(hash_algo) - file_data['data_cb'] = lambda data: hasher.update(data) + file_data["hash_algo"] = hash_algo + file_data["hash_hasher"] = hasher = self._hash.getHasher(hash_algo) + file_data["data_cb"] = lambda data: hasher.update(data) try: - file_data['size'] = int(file_data['size']) + file_data["size"] = int(file_data["size"]) except ValueError: raise failure.Failure(exceptions.DataError) - name = file_data['name'] - if '/' in name or '\\' in name: - log.warning(u"File name contain path characters, we replace them: {}".format(name)) - file_data['name'] = name.replace('/', '_').replace('\\', '_') + name = file_data["name"] + if "/" in name or "\\" in name: + log.warning( + u"File name contain path characters, we replace them: {}".format(name) + ) + file_data["name"] = name.replace("/", "_").replace("\\", "_") - content_data['application_data']['file_data'] = file_data + content_data["application_data"]["file_data"] = file_data # now we actualy request permission to user def gotConfirmation(confirmed): if confirmed: args = [client, session, content_name, content_data] - finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) + finished_d.addCallbacks( + self._finishedCb, self._finishedEb, args, None, args + ) return confirmed # deferred to track end of transfer - finished_d = content_data['finished_d'] = defer.Deferred() - d = self._f.getDestDir(client, session['peer_jid'], content_data, file_data, stream_object=True) + finished_d = content_data["finished_d"] = defer.Deferred() + d = self._f.getDestDir( + client, session["peer_jid"], content_data, file_data, stream_object=True + ) d.addCallback(gotConfirmation) return d def jingleHandler(self, client, action, session, content_name, desc_elt): - content_data = session['contents'][content_name] - application_data = content_data['application_data'] + content_data = session["contents"][content_name] + application_data = content_data["application_data"] if action in (self._j.A_ACCEPTED_ACK,): pass elif action == self._j.A_SESSION_INITIATE: - file_elt = desc_elt.elements(NS_JINGLE_FT, 'file').next() + file_elt = desc_elt.elements(NS_JINGLE_FT, "file").next() try: - file_elt.elements(NS_JINGLE_FT, 'range').next() + file_elt.elements(NS_JINGLE_FT, "range").next() except StopIteration: # initiator doesn't manage <range>, but we do so we advertise it - # FIXME: to be checked + # FIXME: to be checked log.debug("adding <range> element") - file_elt.addElement('range') + file_elt.addElement("range") elif action == self._j.A_SESSION_ACCEPT: - assert not 'stream_object' in content_data - file_data = application_data['file_data'] - file_path = application_data['file_path'] - senders = content_data[u'senders'] - if senders != session[u'role']: + assert not "stream_object" in content_data + file_data = application_data["file_data"] + file_path = application_data["file_path"] + senders = content_data[u"senders"] + if senders != session[u"role"]: # we are receiving the file try: # did the responder specified the size of the file? - file_elt = next(desc_elt.elements(NS_JINGLE_FT, u'file')) - size_elt = next(file_elt.elements(NS_JINGLE_FT, u'size')) + file_elt = next(desc_elt.elements(NS_JINGLE_FT, u"file")) + size_elt = next(file_elt.elements(NS_JINGLE_FT, u"size")) size = int(unicode(size_elt)) except (StopIteration, ValueError): size = None # XXX: hash security is not critical here, so we just take the higher mandatory one - hasher = file_data['hash_hasher'] = self._hash.getHasher() - content_data['stream_object'] = stream.FileStreamObject( + hasher = file_data["hash_hasher"] = self._hash.getHasher() + content_data["stream_object"] = stream.FileStreamObject( self.host, client, file_path, - mode='wb', + mode="wb", uid=self.getProgressId(session, content_name), size=size, data_cb=lambda data: hasher.update(data), - ) + ) else: # we are sending the file - size = file_data['size'] + size = file_data["size"] # XXX: hash security is not critical here, so we just take the higher mandatory one - hasher = file_data['hash_hasher'] = self._hash.getHasher() - content_data['stream_object'] = stream.FileStreamObject( + hasher = file_data["hash_hasher"] = self._hash.getHasher() + content_data["stream_object"] = stream.FileStreamObject( self.host, client, file_path, uid=self.getProgressId(session, content_name), size=size, data_cb=lambda data: hasher.update(data), - ) - finished_d = content_data['finished_d'] = defer.Deferred() + ) + finished_d = content_data["finished_d"] = defer.Deferred() args = [client, session, content_name, content_data] finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) else: @@ -506,33 +645,42 @@ manage checksum, and ignore <received/> element """ # TODO: manage <received/> element - content_data = session['contents'][content_name] + content_data = session["contents"][content_name] elts = [elt for elt in jingle_elt.elements() if elt.uri == NS_JINGLE_FT] if not elts: return for elt in elts: - if elt.name == 'received': + if elt.name == "received": pass - elif elt.name == 'checksum': + elif elt.name == "checksum": # we have received the file hash, we need to parse it - if content_data['senders'] == session['role']: - log.warning(u"unexpected checksum received while we are the file sender") + if content_data["senders"] == session["role"]: + log.warning( + u"unexpected checksum received while we are the file sender" + ) raise exceptions.DataError - info_content_name = elt['name'] + info_content_name = elt["name"] if info_content_name != content_name: # it was for an other content... return - file_data = content_data['application_data']['file_data'] + file_data = content_data["application_data"]["file_data"] try: - file_elt = elt.elements((NS_JINGLE_FT, 'file')).next() + file_elt = elt.elements((NS_JINGLE_FT, "file")).next() except StopIteration: raise exceptions.DataError - algo, file_data['given_file_hash'] = self._hash.parseHashElt(file_elt) - if algo != file_data.get('hash_algo'): - log.warning(u"Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]" - .format(peer_algo=algo, our_algo=file_data.get('hash_algo'), profile=client.profile)) + algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) + if algo != file_data.get("hash_algo"): + log.warning( + u"Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]".format( + peer_algo=algo, + our_algo=file_data.get("hash_algo"), + profile=client.profile, + ) + ) else: - self._receiverTryTerminate(client, session, content_name, content_data) + self._receiverTryTerminate( + client, session, content_name, content_data + ) else: raise NotImplementedError @@ -540,23 +688,27 @@ if jingle_elt.decline: # progress is the only way to tell to frontends that session has been declined progress_id = self.getProgressId(session, content_name) - self.host.bridge.progressError(progress_id, C.PROGRESS_ERROR_DECLINED, client.profile) + self.host.bridge.progressError( + progress_id, C.PROGRESS_ERROR_DECLINED, client.profile + ) def _sendCheckSum(self, client, session, content_name, content_data): """Send the session-info with the hash checksum""" - file_data = content_data['application_data']['file_data'] - hasher = file_data['hash_hasher'] + file_data = content_data["application_data"]["file_data"] + hasher = file_data["hash_hasher"] hash_ = hasher.hexdigest() log.debug(u"Calculated hash: {}".format(hash_)) iq_elt, jingle_elt = self._j.buildSessionInfo(client, session) - checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, 'checksum')) - checksum_elt['creator'] = content_data['creator'] - checksum_elt['name'] = content_name - file_elt = checksum_elt.addElement('file') + checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, "checksum")) + checksum_elt["creator"] = content_data["creator"] + checksum_elt["name"] = content_name + file_elt = checksum_elt.addElement("file") file_elt.addChild(self._hash.buildHashElt(hash_)) iq_elt.send() - def _receiverTryTerminate(self, client, session, content_name, content_data, last_try=False): + def _receiverTryTerminate( + self, client, session, content_name, content_data, last_try=False + ): """Try to terminate the session This method must only be used by the receiver. @@ -565,70 +717,85 @@ @param last_try(bool): if True this mean than session must be terminated even given hash is not available @return (bool): True if session was terminated """ - if not content_data.get('transfer_finished', False): + if not content_data.get("transfer_finished", False): return False - file_data = content_data['application_data']['file_data'] - given_hash = file_data.get('given_file_hash') + file_data = content_data["application_data"]["file_data"] + given_hash = file_data.get("given_file_hash") if given_hash is None: if last_try: - log.warning(u"sender didn't sent hash checksum, we can't check the file [{profile}]".format(profile=client.profile)) + log.warning( + u"sender didn't sent hash checksum, we can't check the file [{profile}]".format( + profile=client.profile + ) + ) self._j.delayedContentTerminate(client, session, content_name) - content_data['stream_object'].close() + content_data["stream_object"].close() return True return False - hasher = file_data['hash_hasher'] + hasher = file_data["hash_hasher"] hash_ = hasher.hexdigest() if hash_ == given_hash: log.info(u"Hash checked, file was successfully transfered: {}".format(hash_)) - progress_metadata = {'hash': hash_, - 'hash_algo': file_data['hash_algo'], - 'hash_verified': C.BOOL_TRUE - } + progress_metadata = { + "hash": hash_, + "hash_algo": file_data["hash_algo"], + "hash_verified": C.BOOL_TRUE, + } error = None else: log.warning(u"Hash mismatch, the file was not transfered correctly") - progress_metadata=None + progress_metadata = None error = u"Hash mismatch: given={algo}:{given}, calculated={algo}:{our}".format( - algo = file_data['hash_algo'], - given = given_hash, - our = hash_) + algo=file_data["hash_algo"], given=given_hash, our=hash_ + ) self._j.delayedContentTerminate(client, session, content_name) - content_data['stream_object'].close(progress_metadata, error) + content_data["stream_object"].close(progress_metadata, error) # we may have the last_try timer still active, so we try to cancel it try: - content_data['last_try_timer'].cancel() + content_data["last_try_timer"].cancel() except (KeyError, internet_error.AlreadyCalled): pass return True def _finishedCb(self, dummy, client, session, content_name, content_data): log.info(u"File transfer terminated") - if content_data['senders'] != session['role']: + if content_data["senders"] != session["role"]: # we terminate the session only if we are the receiver, # as recommanded in XEP-0234 §2 (after example 6) - content_data['transfer_finished'] = True - if not self._receiverTryTerminate(client, session, content_name, content_data): + content_data["transfer_finished"] = True + if not self._receiverTryTerminate( + client, session, content_name, content_data + ): # we have not received the hash yet, we wait 5 more seconds - content_data['last_try_timer'] = reactor.callLater( - 5, self._receiverTryTerminate, client, session, content_name, content_data, last_try=True) + content_data["last_try_timer"] = reactor.callLater( + 5, + self._receiverTryTerminate, + client, + session, + content_name, + content_data, + last_try=True, + ) else: # we are the sender, we send the checksum self._sendCheckSum(client, session, content_name, content_data) - content_data['stream_object'].close() + content_data["stream_object"].close() def _finishedEb(self, failure, client, session, content_name, content_data): log.warning(u"Error while streaming file: {}".format(failure)) - content_data['stream_object'].close() - self._j.contentTerminate(client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT) + content_data["stream_object"].close() + self._j.contentTerminate( + client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT + ) class XEP_0234_handler(XMPPHandler): implements(iwokkel.IDisco) - def getDiscoInfo(self, requestor, target, nodeIdentifier=''): + def getDiscoInfo(self, requestor, target, nodeIdentifier=""): return [disco.DiscoFeature(NS_JINGLE_FT)] - def getDiscoItems(self, requestor, target, nodeIdentifier=''): + def getDiscoItems(self, requestor, target, nodeIdentifier=""): return []