Esempio n. 1
0
    def request_command_list(self, jid=None):
        _task = yield

        if jid is None:
            jid = self._client.get_bound_jid().bare
        response = yield get_disco_request(Namespace.DISCO_ITEMS,
                                           jid,
                                           node=Namespace.COMMANDS)
        if response.isError():
            raise StanzaError(response)

        payload = response.getQueryPayload()
        if payload is None:
            raise MalformedStanzaError('query payload missing', response)

        command_list = []
        for item in payload:
            if item.getName() != 'item':
                continue
            try:
                command_list.append(AdHocCommand(**item.getAttrs()))
            except Exception as error:
                raise MalformedStanzaError(f'invalid item attributes: {error}',
                                           response)

        yield command_list
Esempio n. 2
0
    def make_query(self,
                   jid,
                   queryid=None,
                   start=None,
                   end=None,
                   with_=None,
                   after=None,
                   max_=70):

        _task = yield

        response = yield _make_request(jid, queryid,
                                       start, end, with_, after, max_)
        if response.isError():
            raise StanzaError(response)

        jid = response.getFrom()
        fin = response.getTag('fin', namespace=Namespace.MAM_2)
        if fin is None:
            raise MalformedStanzaError('fin node missing', response)

        rsm = parse_rsm(fin)
        if rsm is None:
            raise MalformedStanzaError('rsm set missing', response)

        complete = fin.getAttr('complete') == 'true'
        if not complete:
            if rsm.first is None or rsm.last is None:
                raise MalformedStanzaError('first or last element missing',
                                           response)

        yield MAMQueryData(jid=jid,
                           complete=complete,
                           rsm=rsm)
Esempio n. 3
0
    def request_slot(self, jid, filename, size, content_type):
        _task = yield

        response = yield _make_request(jid, filename, size, content_type)
        if response.isError():
            raise HTTPUploadStanzaError(response)

        slot = response.getTag('slot', namespace=Namespace.HTTPUPLOAD_0)
        if slot is None:
            raise MalformedStanzaError('slot node missing', response)

        put_uri = slot.getTagAttr('put', 'url')
        if put_uri is None:
            raise MalformedStanzaError('put uri missing', response)

        get_uri = slot.getTagAttr('get', 'url')
        if get_uri is None:
            raise MalformedStanzaError('get uri missing', response)

        headers = {}
        for header in slot.getTag('put').getTags('header'):
            name = header.getAttr('name')
            if name not in ALLOWED_HEADERS:
                raise MalformedStanzaError(
                    'not allowed header found: %s' % name, response)

            data = header.getData()
            if '\n' in data:
                raise MalformedStanzaError('newline in header data found',
                                           response)

            headers[name] = data

        yield HTTPUploadData(put_uri=put_uri, get_uri=get_uri, headers=headers)
Esempio n. 4
0
    def request_preferences(self):
        _task = yield

        response = yield _make_pref_request()
        if response.isError():
            raise StanzaError(response)

        prefs = response.getTag('prefs', namespace=Namespace.MAM_2)
        if prefs is None:
            raise MalformedStanzaError('prefs node missing', response)

        default = prefs.getAttr('default')
        if default is None:
            raise MalformedStanzaError('default attr missing', response)

        always_node = prefs.getTag('always')
        if always_node is None:
            raise MalformedStanzaError('always node missing', response)

        always = _get_preference_jids(always_node)

        never_node = prefs.getTag('never')
        if never_node is None:
            raise MalformedStanzaError('never node missing', response)

        never = _get_preference_jids(never_node)
        yield MAMPreferencesData(default=default,
                                 always=always,
                                 never=never)
Esempio n. 5
0
def parse_disco_info(stanza, timestamp=None):
    idenities = []
    features = []
    dataforms = []

    if timestamp is None:
        timestamp = time.time()

    query = stanza.getQuery()
    for node in query.getTags('identity'):
        attrs = node.getAttrs()
        try:
            idenities.append(
                DiscoIdentity(category=attrs['category'],
                              type=attrs['type'],
                              name=attrs.get('name'),
                              lang=attrs.get('xml:lang')))
        except Exception:
            raise MalformedStanzaError('invalid attributes', stanza)

    for node in query.getTags('feature'):
        try:
            features.append(node.getAttr('var'))
        except Exception:
            raise MalformedStanzaError('invalid attributes', stanza)

    for node in query.getTags('x', namespace=Namespace.DATA):
        dataforms.append(extend_form(node))

    return DiscoInfo(stanza=stanza,
                     identities=idenities,
                     features=features,
                     dataforms=dataforms,
                     timestamp=timestamp)
Esempio n. 6
0
def _get_published_item_id(response, node, id_):
    pubsub = response.getTag('pubsub', namespace=Namespace.PUBSUB)
    if pubsub is None:
        # https://xmpp.org/extensions/xep-0060.html#publisher-publish-success
        # If the publish request did not include an ItemID,
        # the IQ-result SHOULD include an empty <item/> element
        # that specifies the ItemID of the published item.
        #
        # If the server did not add a payload we assume the item was
        # published with the id we requested
        return id_

    publish = pubsub.getTag('publish')
    if publish is None:
        raise MalformedStanzaError('publish node missing', response)

    if node != publish.getAttr('node'):
        raise MalformedStanzaError('invalid node attribute', response)

    item = publish.getTag('item')
    if item is None:
        raise MalformedStanzaError('item node missing', response)

    item_id = item.getAttr('id')
    if id_ is not None and item_id != id_:
        raise MalformedStanzaError('invalid item id', response)

    return item_id
Esempio n. 7
0
    def set_search(self, jid, dataform, items_per_page=50, after=None):
        _task = yield

        response = yield _make_search_query(jid, dataform, items_per_page,
                                            after)
        if response.isError():
            raise StanzaError(response)

        result = response.getTag('result', namespace=Namespace.MUCLUMBUS)
        if result is None:
            raise MalformedStanzaError('result node missing', response)

        items = result.getTags('item')
        if not items:
            yield MuclumbusResult(first=None,
                                  last=None,
                                  max=None,
                                  end=True,
                                  items=[])

        set_ = result.getTag('set', namespace=Namespace.RSM)
        if set_ is None:
            raise MalformedStanzaError('set node missing', response)

        first = set_.getTagData('first')
        last = set_.getTagData('last')
        try:
            max_ = int(set_.getTagData('max'))
        except Exception:
            raise MalformedStanzaError('invalid max value', response)

        results = []
        for item in items:
            jid = item.getAttr('address')
            name = item.getTagData('name')
            nusers = item.getTagData('nusers')
            description = item.getTagData('description')
            language = item.getTagData('language')
            is_open = item.getTag('is-open') is not None

            try:
                anonymity_mode = AnonymityMode(
                    item.getTagData('anonymity-mode'))
            except ValueError:
                anonymity_mode = AnonymityMode.UNKNOWN
            results.append(
                MuclumbusItem(jid=jid,
                              name=name or '',
                              nusers=nusers or '',
                              description=description or '',
                              language=language or '',
                              is_open=is_open,
                              anonymity_mode=anonymity_mode))
        yield MuclumbusResult(first=first,
                              last=last,
                              max=max_,
                              end=len(items) < max_,
                              items=results)
Esempio n. 8
0
def _get_vcard(item):
    vcard = item.getTag('vcard', namespace=Namespace.VCARD4)
    if vcard is None:
        raise MalformedStanzaError('vcard node missing', item)

    try:
        vcard = VCard.from_node(vcard)
    except Exception as error:
        raise MalformedStanzaError('invalid vcard: %s' % error, item)

    return vcard
Esempio n. 9
0
def _get_pubsub_items(response, node):
    pubsub_node = response.getTag('pubsub', namespace=Namespace.PUBSUB)
    if pubsub_node is None:
        raise MalformedStanzaError('pubsub node missing', response)

    items_node = pubsub_node.getTag('items')
    if items_node is None:
        raise MalformedStanzaError('items node missing', response)

    if items_node.getAttr('node') != node:
        raise MalformedStanzaError('invalid node attr', response)

    return items_node.getTags('item')
Esempio n. 10
0
def _get_pubsub_item(response, node, id_):
    items = _get_pubsub_items(response, node)

    if len(items) > 1:
        raise MalformedStanzaError('multiple items found', response)

    if not items:
        return None

    item = items[0]
    if item.getAttr('id') != id_:
        raise MalformedStanzaError('invalid item id', response)

    return item
Esempio n. 11
0
def _parse_devicelist(item):
    '''
    <items node='eu.siacs.conversations.axolotl.devicelist'>
      <item id='current'>
        <list xmlns='eu.siacs.conversations.axolotl'>
          <device id='12345' />
          <device id='4223' />
        </list>
      </item>
    </items>
    '''
    list_node = item.getTag('list', namespace=Namespace.OMEMO_TEMP)
    if list_node is None:
        raise MalformedStanzaError('No list node found', item)

    if not list_node.getChildren():
        return []

    result = []
    devices_nodes = list_node.getChildren()
    for dn in devices_nodes:
        _id = dn.getAttr('id')
        if _id:
            result.append(int(_id))

    return result
def _parse_info(stanza):
    try:
        name = stanza.getQueryChild('name').getData()
    except Exception:
        raise MalformedStanzaError('name node missing', stanza)

    try:
        version = stanza.getQueryChild('version').getData()
    except Exception:
        raise MalformedStanzaError('version node missing', stanza)

    os_info = stanza.getQueryChild('os')
    if os_info is not None:
        os_info = os_info.getData()

    return SoftwareVersionResult(name, version, os_info)
Esempio n. 13
0
def parse_private_bookmarks(response, log):
    query = response.getQuery()
    storage_node = query.getTag('storage', namespace=Namespace.BOOKMARKS)
    if storage_node is None:
        raise MalformedStanzaError('storage node missing', response)

    return parse_storage_node(storage_node, log)
Esempio n. 14
0
    def request_parameters(self, jid):
        task = yield

        response = yield _make_parameter_request(jid)
        if response.isError():
            raise StanzaError(response)

        search = response.getTag('search', namespace=Namespace.MUCLUMBUS)
        if search is None:
            raise MalformedStanzaError('search node missing', response)

        dataform = search.getTag('x', namespace=Namespace.DATA)
        if dataform is None:
            raise MalformedStanzaError('dataform node missing', response)

        self._log.info('Muclumbus parameters received')
        yield finalize(task, extend_form(node=dataform))
Esempio n. 15
0
def _parse_response(response):
    query = response.getQuery()
    seconds = query.getAttr('seconds')

    try:
        seconds = int(seconds)
    except Exception:
        raise MalformedStanzaError('seconds attribute invalid', response)

    return LastActivityData(seconds=seconds, status=query.getData())
Esempio n. 16
0
def _get_avatar_data(item, id_):
    data_node = item.getTag('data', namespace=Namespace.AVATAR_DATA)
    if data_node is None:
        raise MalformedStanzaError('data node missing', item)

    data = data_node.getData()
    if not data:
        raise MalformedStanzaError('data node empty', item)

    try:
        avatar = b64decode(data, return_type=bytes)
    except Exception as error:
        raise MalformedStanzaError(f'decoding error: {error}', item)

    avatar_sha = hashlib.sha1(avatar).hexdigest()
    if avatar_sha != id_:
        raise MalformedStanzaError(f'avatar does not match sha', item)

    return AvatarData(data=avatar, sha=avatar_sha)
Esempio n. 17
0
    def execute_command(self, command, action=None, dataform=None):
        _task = yield

        if action is None:
            action = AdHocAction.EXECUTE
        attrs = {
            'node': command.node,
            'xmlns': Namespace.COMMANDS,
            'action': action.value
        }
        if command.sessionid is not None:
            attrs['sessionid'] = command.sessionid

        response = yield _make_command(command, attrs, dataform)
        if response.isError():
            raise StanzaError(response)

        command = response.getTag('command', namespace=Namespace.COMMANDS)
        if command is None:
            raise MalformedStanzaError('command node missing', response)

        node = command.getAttr('node')
        if node is None:
            raise MalformedStanzaError('node attribute missing', response)

        sessionid = command.getAttr('sessionid')
        if sessionid is None:
            raise MalformedStanzaError('sessionid attribute missing', response)

        status = command.getAttr('status')
        if status is None:
            raise MalformedStanzaError('status attribute missing', response)

        if status not in ('executing', 'completed', 'canceled'):
            raise MalformedStanzaError('invalid status attribute %s' % status,
                                       response)

        status = AdHocStatus(status)

        try:
            notes = _parse_notes(command)
        except ValueError as error:
            raise MalformedStanzaError(error, response)

        try:
            actions, default = _parse_actions(command)
        except ValueError as error:
            raise MalformedStanzaError(error, response)

        yield AdHocCommand(jid=response.getFrom(),
                           name=None,
                           node=node,
                           sessionid=sessionid,
                           status=status,
                           data=command.getTag('x', namespace=Namespace.DATA),
                           actions=actions,
                           default=default,
                           notes=notes)
Esempio n. 18
0
def _get_configure_form(response, node):
    pubsub = response.getTag('pubsub', namespace=Namespace.PUBSUB_OWNER)
    if pubsub is None:
        raise MalformedStanzaError('pubsub node missing', response)

    configure = pubsub.getTag('configure')
    if configure is None:
        raise MalformedStanzaError('configure node missing', response)

    if node != configure.getAttr('node'):
        raise MalformedStanzaError('invalid node attribute', response)

    forms = configure.getTags('x', namespace=Namespace.DATA)
    for form in forms:
        dataform = extend_form(node=form)
        form_type = dataform.vars.get('FORM_TYPE')
        if form_type is None or form_type.value != Namespace.PUBSUB_CONFIG:
            continue

        return dataform

    raise MalformedStanzaError('no valid form type found', response)
Esempio n. 19
0
def _parse_response(response):
    time_ = response.getTag('time')
    if not time_:
        raise MalformedStanzaError('time node missing', response)

    tzo = time_.getTagData('tzo')
    if not tzo:
        raise MalformedStanzaError('tzo node or data missing', response)

    remote_tz = create_tzinfo(tz_string=tzo)
    if remote_tz is None:
        raise MalformedStanzaError('invalid tzo data', response)

    utc_time = time_.getTagData('utc')
    if not utc_time:
        raise MalformedStanzaError('utc node or data missing', response)

    date_time = parse_datetime(utc_time, check_utc=True)
    if date_time is None:
        raise MalformedStanzaError('invalid timezone definition', response)

    date_time = date_time.astimezone(remote_tz)
    return date_time.strftime('%c %Z')
Esempio n. 20
0
def parse_bookmark(item):
    conference = item.getTag('conference', namespace=Namespace.BOOKMARKS_1)
    if conference is None:
        raise MalformedStanzaError('conference node missing', item)

    try:
        jid = JID.from_string(item.getAttr('id'))
    except Exception as error:
        raise MalformedStanzaError('invalid jid: %s' % error, item)

    if jid.localpart is None or jid.resource is not None:
        raise MalformedStanzaError('invalid jid', item)

    autojoin = parse_autojoin(conference.getAttr('autojoin'))
    nick = parse_nickname(conference.getTagData('nick'))
    name = conference.getAttr('name') or None
    password = conference.getTagData('password') or None

    return BookmarkData(jid=jid,
                        name=name,
                        autojoin=autojoin,
                        password=password,
                        nick=nick)
Esempio n. 21
0
    def request_secret_key(self):
        task = yield

        items = yield self.request_items(Namespace.OPENPGP_SK, max_items=1)

        raise_if_error(items)

        if not items:
            yield task.set_result(None)

        try:
            secret_key = _parse_secret_key(items[0])
        except ValueError as error:
            raise MalformedStanzaError(str(error), items)

        yield secret_key
Esempio n. 22
0
def parse_disco_items(stanza):
    items = []

    query = stanza.getQuery()
    for node in query.getTags('item'):
        attrs = node.getAttrs()
        try:
            items.append(
                DiscoItem(jid=attrs['jid'],
                          name=attrs.get('name'),
                          node=attrs.get('node')))
        except Exception:
            raise MalformedStanzaError('invalid attributes', stanza)

    return DiscoItems(jid=stanza.getFrom(),
                      node=query.getAttr('node'),
                      items=items)
Esempio n. 23
0
    def request_public_key(self, jid, fingerprint):
        task = yield

        items = yield self.request_items(
            f'{Namespace.OPENPGP_PK}:{fingerprint}', max_items=1, jid=jid)

        raise_if_error(items)

        if not items:
            yield task.set_result(None)

        try:
            key = _parse_public_key(jid, items[0])
        except ValueError as error:
            raise MalformedStanzaError(str(error), items)

        yield key
Esempio n. 24
0
def _parse_register_data(response):
    query = response.getTag('query', namespace=Namespace.REGISTER)
    if query is None:
        raise StanzaError(response)

    instructions = query.getTagData('instructions') or None

    data = RegisterData(instructions=instructions,
                        form=_parse_form(response),
                        fields_form=_parse_fields_form(query),
                        oob_url=_parse_oob_url(query),
                        bob_data=parse_bob_data(query))

    if (data.form is None and data.fields_form is None
            and data.oob_url is None):
        raise MalformedStanzaError('invalid register response', response)

    return data
Esempio n. 25
0
    def request_keylist(self, jid=None):
        task = yield

        items = yield self.request_items(Namespace.OPENPGP_PK,
                                         max_items=1,
                                         jid=jid)

        raise_if_error(items)

        if not items:
            yield task.set_result(None)

        try:
            keylist = _parse_keylist(jid, items[0])
        except ValueError as error:
            raise MalformedStanzaError(str(error), items)

        self._log.info('Received keylist: %s', keylist)
        yield keylist
Esempio n. 26
0
    def request_avatar_metadata(self, jid=None):
        task = yield

        items = yield self.request_items(Namespace.AVATAR_METADATA,
                                         max_items=1,
                                         jid=jid)

        raise_if_error(items)

        if not items:
            yield task.set_result(None)

        item = items[0]
        metadata = item.getTag('metadata', namespace=Namespace.AVATAR_METADATA)
        if metadata is None:
            raise MalformedStanzaError('metadata node missing', item)

        if not metadata.getChildren():
            yield task.set_result(None)

        yield AvatarMetaData.from_node(metadata, item.getAttr('id'))
Esempio n. 27
0
    def _parse_push(self, stanza, ver_support):
        query = stanza.getTag('query', namespace=Namespace.ROSTER)

        version = None
        if ver_support:
            version = query.getAttr('ver')
            if version is None:
                raise MalformedStanzaError('ver attribute missing', stanza)

        pushed_items = []
        for item in query.getTags('item'):
            try:
                roster_item = RosterItem.from_node(item)
            except Exception:
                self._log.warning('Invalid roster item')
                self._log.warning(stanza)
                continue

            pushed_items.append(roster_item)

        return pushed_items, version
Esempio n. 28
0
    def request_blocking_list(self):
        _task = yield

        result = yield _make_blocking_list_request()
        if result.isError():
            raise StanzaError(result)

        blocklist = result.getTag('blocklist', namespace=Namespace.BLOCKING)
        if blocklist is None:
            raise MalformedStanzaError('blocklist node missing', result)

        blocked = set()
        for item in blocklist.getTags('item'):
            try:
                jid = JID.from_string(item.getAttr('jid'))
            except Exception:
                self._log.info('Invalid JID: %s', item.getAttr('jid'))
                continue

            blocked.add(jid)

        self._log.info('Received blocking list: %s', blocked)
        yield blocked
Esempio n. 29
0
    def request_roster(self, version=None):
        _task = yield

        ver_support = self._client.features.has_roster_version()
        if not ver_support:
            version = None

        if ver_support and version is None:
            version = ''

        self._log.info('Roster versioning supported: %s', ver_support)

        response = yield _make_request(version, ver_support)
        if response.isError():
            raise StanzaError(response)

        query = response.getTag('query', namespace=Namespace.ROSTER)
        if query is None:
            if not ver_support:
                raise MalformedStanzaError('query node missing', response)
            yield RosterData(None, version)

        pushed_items, version = self._parse_push(response, ver_support)
        yield RosterData(pushed_items, version)
Esempio n. 30
0
def _get_vcard_node(response):
    vcard_node = response.getTag('vCard', namespace=Namespace.VCARD)
    if vcard_node is None:
        raise MalformedStanzaError('vCard node missing', response)
    return vcard_node