diff options
-rw-r--r-- | nbxmpp/dispatcher.py | 2 | ||||
-rw-r--r-- | nbxmpp/modules/http_upload.py | 85 | ||||
-rw-r--r-- | nbxmpp/structs.py | 23 | ||||
-rw-r--r-- | nbxmpp/util.py | 6 |
4 files changed, 115 insertions, 1 deletions
diff --git a/nbxmpp/dispatcher.py b/nbxmpp/dispatcher.py index e2862b1..1249252 100644 --- a/nbxmpp/dispatcher.py +++ b/nbxmpp/dispatcher.py @@ -79,6 +79,7 @@ from nbxmpp.modules.attention import Attention from nbxmpp.modules.security_labels import SecurityLabels from nbxmpp.modules.chatstates import Chatstates from nbxmpp.modules.register import Register +from nbxmpp.modules.http_upload import HTTPUpload from nbxmpp.modules.misc import unwrap_carbon from nbxmpp.modules.misc import unwrap_mam from nbxmpp.util import get_properties_struct @@ -225,6 +226,7 @@ class XMPPDispatcher(PlugIn): self._modules['SecurityLabels'] = SecurityLabels(self._owner) self._modules['Chatstates'] = Chatstates(self._owner) self._modules['Register'] = Register(self._owner) + self._modules['HTTPUpload'] = HTTPUpload(self._owner) for instance in self._modules.values(): for handler in instance.handlers: diff --git a/nbxmpp/modules/http_upload.py b/nbxmpp/modules/http_upload.py new file mode 100644 index 0000000..f912923 --- /dev/null +++ b/nbxmpp/modules/http_upload.py @@ -0,0 +1,85 @@ +# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com> +# +# This file is part of nbxmpp. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; If not, see <http://www.gnu.org/licenses/>. + +import logging + +from nbxmpp.protocol import NS_HTTPUPLOAD_0 +from nbxmpp.protocol import Iq +from nbxmpp.protocol import isResultNode +from nbxmpp.structs import HTTPUploadData +from nbxmpp.util import call_on_response +from nbxmpp.util import callback +from nbxmpp.util import raise_error + + +ALLOWED_HEADERS = ['Authorization', 'Cookie', 'Expires'] + +log = logging.getLogger('nbxmpp.m.http_upload') + + +class HTTPUpload: + def __init__(self, client): + self._client = client + self.handlers = [] + + @call_on_response('_received_slot') + def request_slot(self, jid, filename, size, content_type): + iq = Iq(typ='get', to=jid) + attr = {'filename': filename, + 'size': size, + 'content-type': content_type} + iq.setTag(name="request", + namespace=NS_HTTPUPLOAD_0, + attrs=attr) + return iq + + @callback + def _received_slot(self, stanza): + if not isResultNode(stanza): + return raise_error(log.info, stanza) + + slot = stanza.getTag('slot', namespace=NS_HTTPUPLOAD_0) + if slot is None: + return raise_error(log.warning, stanza, 'stanza-malformed', + 'No slot node found') + + put_uri = slot.getTagAttr('put', 'url') + if put_uri is None: + return raise_error(log.warning, stanza, 'stanza-malformed', + 'No put uri found') + + get_uri = slot.getTagAttr('get', 'url') + if get_uri is None: + return raise_error(log.warning, stanza, 'stanza-malformed', + 'No get uri found') + + headers = {} + for header in slot.getTag('put').getTags('header'): + name = header.getAttr('name') + if name not in ALLOWED_HEADERS: + return raise_error(log.warning, stanza, 'stanza-malformed', + 'Not allowed header found: %s' % name) + data = header.getData() + if '\n' in data: + return raise_error(log.warning, stanza, 'stanza-malformed', + 'NNewline in header data found') + + headers[name] = data + + return HTTPUploadData(put_uri=put_uri, + get_uri=get_uri, + headers=headers) diff --git a/nbxmpp/structs.py b/nbxmpp/structs.py index 347d4b1..252ef3f 100644 --- a/nbxmpp/structs.py +++ b/nbxmpp/structs.py @@ -136,6 +136,10 @@ RegisterData = namedtuple('RegisterData', 'instructions form fields_form oob_url ChangePasswordResult = namedtuple('ChangePasswordResult', 'successful form') ChangePasswordResult.__new__.__defaults__ = (None,) +HTTPUploadData = namedtuple('HTTPUploadData', 'put_uri get_uri headers') +HTTPUploadData.__new__.__defaults__ = (None,) + + class DiscoInfo(namedtuple('DiscoInfo', 'stanza identities features dataforms timestamp')): __slots__ = [] @@ -449,6 +453,25 @@ class CommonError: payload=self._error_node)) +class HTTPUploadError(CommonError): + def __init__(self, stanza): + CommonError.__init__(self, stanza) + + def get_max_file_size(self): + if not self.app_condition == 'file-too-large': + return None + node = self._error_node.getTag(self.app_condition) + try: + return float(node.getTagData('max-file-size')) + except Exception: + return None + + def get_retry_date(self): + if not self.app_condition == 'retry': + return None + return self._error_node.getTagAttr('stamp') + + class StanzaMalformedError(CommonError): def __init__(self, stanza, text): self._error_node = None diff --git a/nbxmpp/util.py b/nbxmpp/util.py index 885885c..47f1d86 100644 --- a/nbxmpp/util.py +++ b/nbxmpp/util.py @@ -28,11 +28,13 @@ import precis_i18n.codec from nbxmpp.protocol import DiscoInfoMalformed from nbxmpp.protocol import isErrorNode from nbxmpp.protocol import NS_DATA +from nbxmpp.protocol import NS_HTTPUPLOAD_0 from nbxmpp.structs import Properties from nbxmpp.structs import IqProperties from nbxmpp.structs import MessageProperties from nbxmpp.structs import PresenceProperties from nbxmpp.structs import CommonError +from nbxmpp.structs import HTTPUploadError from nbxmpp.structs import StanzaMalformedError from nbxmpp.modules.dataforms import extend_form from nbxmpp.third_party.hsluv import hsluv_to_rgb @@ -139,7 +141,9 @@ def to_xs_boolean(value): 'Cant convert %s to xs:boolean' % value) -error_classes = {} +error_classes = { + NS_HTTPUPLOAD_0: HTTPUploadError +} def error_factory(stanza, condition=None, text=None): if condition == 'stanza-malformed': |