From 739e212782622e36c60d8ced703753fa2b4e07ce Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 18 Apr 2020 13:50:36 +0200 Subject: [PATCH 1/2] Parse booleans according to the xs:boolean spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'True', 'False' or '' aren’t valid values. Also use this helper in more locations. --- nbxmpp/modules/bookmarks.py | 4 ++-- nbxmpp/modules/dataforms.py | 14 ++++++-------- nbxmpp/modules/muc.py | 3 ++- nbxmpp/smacks.py | 3 ++- nbxmpp/util.py | 12 ++++++++---- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/nbxmpp/modules/bookmarks.py b/nbxmpp/modules/bookmarks.py index 143748a..34bd0da 100644 --- a/nbxmpp/modules/bookmarks.py +++ b/nbxmpp/modules/bookmarks.py @@ -134,7 +134,7 @@ class Bookmarks(BaseModule): autojoin = False else: try: - autojoin = from_xs_boolean(autojoin) + autojoin = from_xs_boolean(autojoin, default=False) except ValueError as error: self._log.warning(error) self._log.warning(storage) @@ -176,7 +176,7 @@ class Bookmarks(BaseModule): self._log.warning(item) return None - autojoin = conference.getAttr('autojoin') in ('True', 'true', '1') + autojoin = from_xs_boolean(conference.getAttr('autojoin'), default=False) name = conference.getAttr('name') nick = conference.getTagData('nick') diff --git a/nbxmpp/modules/dataforms.py b/nbxmpp/modules/dataforms.py index 4eda96a..b685ad7 100644 --- a/nbxmpp/modules/dataforms.py +++ b/nbxmpp/modules/dataforms.py @@ -22,6 +22,7 @@ from nbxmpp.namespaces import Namespace from nbxmpp.protocol import JID from nbxmpp.simplexml import Node +from nbxmpp.util import from_xs_boolean # exceptions used in this module @@ -309,17 +310,14 @@ class BooleanField(DataField): Value of field. May contain True, False or None """ value = self.getTagData('value') - if value in ('0', 'false'): - return False - if value in ('1', 'true'): - return True - if value is None: - return False # default value is False - raise WrongFieldValue + try: + return from_xs_boolean(value, default=False) + except ValueError: + raise WrongFieldValue @value.setter def value(self, value): - self.setTagData('value', value and '1' or '0') + self.setTagData('value', '1' if value else '0') @value.deleter def value(self): diff --git a/nbxmpp/modules/muc.py b/nbxmpp/modules/muc.py index 0b02904..bb8fdc4 100644 --- a/nbxmpp/modules/muc.py +++ b/nbxmpp/modules/muc.py @@ -44,6 +44,7 @@ from nbxmpp.structs import MucDestroyed from nbxmpp.util import call_on_response from nbxmpp.util import callback from nbxmpp.util import raise_error +from nbxmpp.util import from_xs_boolean from nbxmpp.modules.dataforms import extend_form from nbxmpp.modules.base import BaseModule @@ -250,7 +251,7 @@ class MUC(BaseModule): data['from_'] = properties.jid data['reason'] = direct.getAttr('reason') data['password'] = direct.getAttr('password') - data['continued'] = direct.getAttr('continue') == 'true' + data['continued'] = from_xs_boolean(direct.getAttr('continue'), default=False) data['thread'] = direct.getAttr('thread') data['type'] = InviteType.DIRECT properties.muc_invite = InviteData(**data) diff --git a/nbxmpp/smacks.py b/nbxmpp/smacks.py index d75cb19..5dd6ff8 100644 --- a/nbxmpp/smacks.py +++ b/nbxmpp/smacks.py @@ -22,6 +22,7 @@ from nbxmpp.namespaces import Namespace from nbxmpp.simplexml import Node from nbxmpp.const import StreamState from nbxmpp.util import LogAdapter +from nbxmpp.util import from_xs_boolean from nbxmpp.structs import StanzaHandler @@ -112,7 +113,7 @@ class Smacks: self._log.error('Received "enabled", but SM is already enabled') return resume = stanza.getAttr('resume') - if resume in ('true', 'True', '1'): + if from_xs_boolean(resume, default=False): self.resume_supported = True self._session_id = stanza.getAttr('id') diff --git a/nbxmpp/util.py b/nbxmpp/util.py index 1884df4..eae3dce 100644 --- a/nbxmpp/util.py +++ b/nbxmpp/util.py @@ -25,6 +25,7 @@ import re import logging from logging import LoggerAdapter from collections import defaultdict +from typing import Optional from functools import wraps from functools import lru_cache @@ -124,17 +125,20 @@ def callback(func): return func_wrapper -def from_xs_boolean(value): - if value in ('1', 'true', 'True'): +def from_xs_boolean(value: Optional[str], *, default: Optional[bool] = None) -> bool: + if value in ('1', 'true'): return True - if value in ('0', 'false', 'False', ''): + if value in ('0', 'false'): return False + if value is None and default is not None: + return default + raise ValueError('Cant convert %s to python boolean' % value) -def to_xs_boolean(value): +def to_xs_boolean(value: Optional[bool]) -> str: # Convert to xs:boolean ('true', 'false') # from a python boolean (True, False) or None if value is True: -- GitLab From 7b1a6faa59ab091963661638b130d4308b3c3198 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 20 Apr 2020 18:55:25 +0200 Subject: [PATCH 2/2] Util: Fix circular import by moving get_form() to the dataforms module --- nbxmpp/modules/dataforms.py | 16 ++++++++++++++++ nbxmpp/modules/register.py | 2 +- nbxmpp/util.py | 17 ----------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/nbxmpp/modules/dataforms.py b/nbxmpp/modules/dataforms.py index b685ad7..1d368c9 100644 --- a/nbxmpp/modules/dataforms.py +++ b/nbxmpp/modules/dataforms.py @@ -105,6 +105,22 @@ def extend_form(node): return SimpleDataForm(extend=node) +def get_form(node, form_type): + forms = node.getTags('x', namespace=Namespace.DATA) + if not forms: + return None + + for form in forms: + form = extend_form(node=form) + field = form.vars.get('FORM_TYPE') + if field is None: + continue + + if field.value == form_type: + return form + return None + + class DataField(ExtendedNode): """ Keeps data about one field - var, field type, labels, instructions... Base diff --git a/nbxmpp/modules/register.py b/nbxmpp/modules/register.py index 45104c8..5d1e973 100644 --- a/nbxmpp/modules/register.py +++ b/nbxmpp/modules/register.py @@ -25,9 +25,9 @@ from nbxmpp.structs import ChangePasswordResult from nbxmpp.util import call_on_response from nbxmpp.util import callback from nbxmpp.util import raise_error -from nbxmpp.util import get_form from nbxmpp.const import REGISTER_FIELDS from nbxmpp.modules.bits_of_binary import parse_bob_data +from nbxmpp.modules.dataforms import get_form from nbxmpp.modules.dataforms import extend_form from nbxmpp.modules.dataforms import create_field from nbxmpp.modules.dataforms import SimpleDataForm diff --git a/nbxmpp/util.py b/nbxmpp/util.py index eae3dce..361f3a0 100644 --- a/nbxmpp/util.py +++ b/nbxmpp/util.py @@ -46,7 +46,6 @@ 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 log = logging.getLogger('nbxmpp.util') @@ -342,22 +341,6 @@ def generate_id(): return str(uuid.uuid4()) -def get_form(stanza, form_type): - forms = stanza.getTags('x', namespace=Namespace.DATA) - if not forms: - return None - - for form in forms: - form = extend_form(node=form) - field = form.vars.get('FORM_TYPE') - if field is None: - continue - - if field.value == form_type: - return form - return None - - def validate_stream_header(stanza, domain, is_websocket): attrs = stanza.getAttrs() if attrs.get('from') != domain: -- GitLab