Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-nbxmpp for openSUSE:Factory checked in at 2022-09-15 22:57:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-nbxmpp (Old) and /work/SRC/openSUSE:Factory/.python-nbxmpp.new.2083 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-nbxmpp" Thu Sep 15 22:57:57 2022 rev:33 rq:1003578 version:3.2.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-nbxmpp/python-nbxmpp.changes 2022-08-30 14:49:38.444145031 +0200 +++ /work/SRC/openSUSE:Factory/.python-nbxmpp.new.2083/python-nbxmpp.changes 2022-09-15 22:58:11.693046752 +0200 @@ -1,0 +2,12 @@ +Tue Sep 13 19:30:23 UTC 2022 - Alexei Sorokin <sor.ale...@meowr.ru> + +- Update to version 3.2.2: + * Expose TLS version and ciphersuite. + * Add stringprep implementation. + * Add packaging as dependency. + * Use stringprep instead of precis for JID validation. + * Add missing __init__.py to examples. + * You can set the env variable NBXMPP_USE_PRECIS to revert back + to the old behaviour. + +------------------------------------------------------------------- Old: ---- python-nbxmpp-3.2.1.tar.bz2 New: ---- python-nbxmpp-3.2.2.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-nbxmpp.spec ++++++ --- /var/tmp/diff_new_pack.yjgEXK/_old 2022-09-15 22:58:12.161048073 +0200 +++ /var/tmp/diff_new_pack.yjgEXK/_new 2022-09-15 22:58:12.165048084 +0200 @@ -22,7 +22,7 @@ %define skip_python38 1 %define _name nbxmpp Name: python-nbxmpp -Version: 3.2.1 +Version: 3.2.2 Release: 0 Summary: XMPP library by Gajim team License: GPL-3.0-or-later @@ -36,6 +36,7 @@ # For testing BuildRequires: %{python_module gobject-Gdk} BuildRequires: %{python_module idna} +BuildRequires: %{python_module packaging} BuildRequires: %{python_module precis-i18n} BuildRequires: typelib(Soup) = 2.4 Recommends: python-gssapi ++++++ python-nbxmpp-3.2.1.tar.bz2 -> python-nbxmpp-3.2.2.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/.chglog/CHANGELOG.tpl.md new/python-nbxmpp-3.2.2/.chglog/CHANGELOG.tpl.md --- old/python-nbxmpp-3.2.1/.chglog/CHANGELOG.tpl.md 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/.chglog/CHANGELOG.tpl.md 2022-09-13 21:15:44.000000000 +0200 @@ -13,7 +13,7 @@ {{ range .NoteGroups -}} {{ .Title }} {{ range .Notes }} -{{ .Body }} + * {{ .Body }} {{ end }} {{ end -}} {{ end -}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/.chglog/config.yml new/python-nbxmpp-3.2.2/.chglog/config.yml --- old/python-nbxmpp-3.2.1/.chglog/config.yml 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/.chglog/config.yml 2022-09-13 21:15:44.000000000 +0200 @@ -39,4 +39,4 @@ - Fixes notes: keywords: - - NOTES + - Notes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/.ci/pylint-test.py new/python-nbxmpp-3.2.2/.ci/pylint-test.py --- old/python-nbxmpp-3.2.1/.ci/pylint-test.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/.ci/pylint-test.py 2022-09-13 21:15:44.000000000 +0200 @@ -32,7 +32,8 @@ cmd = [ 'pylint', 'nbxmpp', - f'--disable={",".join(DISABLED_CHECKS)}' + f'--disable={",".join(DISABLED_CHECKS)}', + '--ignore=examples' ] try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/ChangeLog new/python-nbxmpp-3.2.2/ChangeLog --- old/python-nbxmpp-3.2.1/ChangeLog 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/ChangeLog 2022-09-13 21:15:44.000000000 +0200 @@ -1,3 +1,24 @@ +nbxmpp 3.2.2 (13 Sep 2022) + + New + + * Expose TLS version and ciphersuite + * Add stringprep implementation + + Change + + * Add packaging as dependency + * Use stringprep instead of precis for JID validation + + Bug Fixes + + * Add missing __init__.py to examples + + Notes + + * You can set the env variable NBXMPP_USE_PRECIS to revert back + to the old behavior. + nbxmpp 3.2.1 (29 Aug 2022) Bug Fixes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/README.md new/python-nbxmpp-3.2.2/README.md --- old/python-nbxmpp-3.2.1/README.md 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/README.md 2022-09-13 21:15:44.000000000 +0200 @@ -9,6 +9,7 @@ - GLib >= 2.60 - libsoup - precis-i18n +- packaging - idna ## Optional Runtime Requirements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/debian/control new/python-nbxmpp-3.2.2/debian/control --- old/python-nbxmpp-3.2.1/debian/control 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/debian/control 2022-09-13 21:15:44.000000000 +0200 @@ -1,15 +1,16 @@ Source: python3-nbxmpp-nightly -Section: python +Section: net Priority: optional Maintainer: Gajim Maintainers <c...@gajim.org> -Build-Depends: debhelper-compat (= 13), +Build-Depends: + debhelper-compat (= 13), dh-python, libglib2.0-0 (>= 2.60), gir1.2-soup-2.4, python3-all, python3-gi, - python3-gssapi, python3-idna, + python3-packaging, python3-precis-i18n, python3-setuptools, Standards-Version: 4.1.4 @@ -22,10 +23,14 @@ Architecture: all Depends: ${misc:Depends}, ${python3:Depends}, + libglib2.0-0 (>= 2.60), gir1.2-soup-2.4, - python3-gi + python3-gi, + python3-idna, + python3-packaging, + python3-precis-i18n, Recommends: python3-gssapi, Breaks: gajim (<< 1.4~) Description: Non blocking XMPP Python library - nbxmpp is a Python library that provides a way for Python applications - to use the XMPP network. This library was initially a fork of xmpppy. + python-nbxmpp is a Python library that provides a way for Python applications + to use the XMPP network. This library was initially a fork of xmpppy. \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/__init__.py new/python-nbxmpp-3.2.2/nbxmpp/__init__.py --- old/python-nbxmpp-3.2.1/nbxmpp/__init__.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/__init__.py 2022-09-13 21:15:44.000000000 +0200 @@ -4,4 +4,4 @@ gi.require_version('Soup', '2.4') -__version__: str = '3.2.1' +__version__: str = '3.2.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/client.py new/python-nbxmpp-3.2.2/nbxmpp/client.py --- old/python-nbxmpp-3.2.1/nbxmpp/client.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/client.py 2022-09-13 21:15:44.000000000 +0200 @@ -212,6 +212,14 @@ def ignore_tls_errors(self): return self._ignore_tls_errors + @property + def tls_version(self): + return self._con.tls_version + + @property + def ciphersuite(self): + return self._con.ciphersuite + def set_ignore_tls_errors(self, ignore): self._ignore_tls_errors = ignore diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/connection.py new/python-nbxmpp-3.2.2/nbxmpp/connection.py --- old/python-nbxmpp-3.2.1/nbxmpp/connection.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/connection.py 2022-09-13 21:15:44.000000000 +0200 @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with this program; If not, see <http://www.gnu.org/licenses/>. +from typing import Optional + import logging from gi.repository import Gio @@ -66,6 +68,14 @@ self._ignored_tls_errors = ignored_tls_errors @property + def tls_version(self) -> Optional[int]: + return None + + @property + def ciphersuite(self) -> Optional[int]: + return None + + @property def local_address(self): return self._local_address diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/const.py new/python-nbxmpp-3.2.2/nbxmpp/const.py --- old/python-nbxmpp-3.2.1/nbxmpp/const.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/const.py 2022-09-13 21:15:44.000000000 +0200 @@ -19,7 +19,14 @@ from enum import IntEnum from functools import total_ordering +from packaging.version import Version + from gi.repository import Gio +from gi.repository import GLib + + +GLIB_VERSION = Version( + f'{GLib.MAJOR_VERSION}.{GLib.MINOR_VERSION}.{GLib.MICRO_VERSION}') class IqType(Enum): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/precis.py new/python-nbxmpp-3.2.2/nbxmpp/precis.py --- old/python-nbxmpp-3.2.1/nbxmpp/precis.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-nbxmpp-3.2.2/nbxmpp/precis.py 2022-09-13 21:15:44.000000000 +0200 @@ -0,0 +1,19 @@ + + +from precis_i18n import get_profile + + +_localpart_disallowed_chars = set('"&\'/:<>@') + + +def enforce_precis_username(localpart: str) -> str: + if _localpart_disallowed_chars & set(localpart): + raise ValueError('Input contains prohibited codepoint: %s' % localpart) + + username = get_profile('UsernameCaseMapped') + return username.enforce(localpart) + + +def enforce_precis_opaque(resourcepart: str) -> str: + opaque = get_profile('OpaqueString') + return opaque.enforce(resourcepart) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/protocol.py new/python-nbxmpp-3.2.2/nbxmpp/protocol.py --- old/python-nbxmpp-3.2.1/nbxmpp/protocol.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/protocol.py 2022-09-13 21:15:44.000000000 +0200 @@ -25,6 +25,7 @@ from typing import Optional from typing import cast +import os import time import hashlib import functools @@ -36,13 +37,18 @@ from gi.repository import GLib import idna -from precis_i18n import get_profile from nbxmpp.simplexml import Node from nbxmpp.namespaces import Namespace +from nbxmpp.stringprep import nodeprep +from nbxmpp.stringprep import resourceprep +from nbxmpp.precis import enforce_precis_username +from nbxmpp.precis import enforce_precis_opaque + def ascii_upper(s): return s.upper() + SASL_AUTH_MECHS = [ 'SCRAM-SHA-512-PLUS', 'SCRAM-SHA-512', @@ -251,7 +257,6 @@ } -_localpart_disallowed_chars = set('"&\'/:<>@') _localpart_escape_chars = ' "&\'/:<>@' @@ -482,12 +487,17 @@ if not localpart or len(localpart.encode()) > 1023: raise LocalpartByteLimit - if _localpart_disallowed_chars & set(localpart): - raise LocalpartNotAllowedChar + if os.environ.get('NBXMPP_ENFORCE_PRECIS') is None: + try: + return nodeprep(localpart) + except Exception: + try: + return enforce_precis_username(localpart) + except Exception: + raise LocalpartNotAllowedChar try: - username = get_profile('UsernameCaseMapped') - return username.enforce(localpart) + return enforce_precis_username(localpart) except Exception: raise LocalpartNotAllowedChar @@ -497,9 +507,17 @@ if not resourcepart or len(resourcepart.encode()) > 1023: raise ResourcepartByteLimit + if os.environ.get('NBXMPP_ENFORCE_PRECIS') is None: + try: + return resourceprep(resourcepart) + except Exception: + try: + return enforce_precis_opaque(resourcepart) + except Exception: + raise ResourcepartNotAllowedChar + try: - opaque = get_profile('OpaqueString') - return opaque.enforce(resourcepart) + return enforce_precis_opaque(resourcepart) except Exception: raise ResourcepartNotAllowedChar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/stringprep.py new/python-nbxmpp-3.2.2/nbxmpp/stringprep.py --- old/python-nbxmpp-3.2.1/nbxmpp/stringprep.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-nbxmpp-3.2.2/nbxmpp/stringprep.py 2022-09-13 21:15:44.000000000 +0200 @@ -0,0 +1,243 @@ +# 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/>. + +# Initial version taken from https://github.com/horazont/aioxmpp +# Modified on 30-AUG-2022 + +from __future__ import annotations + +from typing import Optional +from typing import Callable + +import stringprep + +from unicodedata import ucd_3_2_0 + + +_nodeprep_prohibited = frozenset('"&\'/:<>@') + + +def is_RandALCat(c: str) -> bool: + return ucd_3_2_0.bidirectional(c) in ('R', 'AL') + + +def is_LCat(c: str) -> bool: + return ucd_3_2_0.bidirectional(c) == 'L' + + +def check_nodeprep_prohibited(char: str) -> bool: + return char in _nodeprep_prohibited + + +def _check_against_tables(chars: list[str], + tables: tuple[Callable[[str], bool]] + ) -> Optional[str]: + ''' + Perform a check against the table predicates in `tables`. `tables` must be + a reusable iterable containing characteristic functions of character sets, + that is, functions which return :data:`True` if the character is in the + table. + The function returns the first character occuring in any of the tables or + :data:`None` if no character matches. + ''' + + for c in chars: + if any(in_table(c) for in_table in tables): + return c + + return None + + +def do_normalization(chars: list[str]) -> None: + ''' + Perform the stringprep normalization. Operates in-place on a list of + unicode characters provided in `chars`. + ''' + chars[:] = list(ucd_3_2_0.normalize('NFKC', ''.join(chars))) + + +def check_bidi(chars: list[str]) -> None: + ''' + Check proper bidirectionality as per stringprep. Operates on a list of + unicode characters provided in `chars`. + ''' + + # the empty string is valid, as it cannot violate the RandALCat constraints + if not chars: + return + + # first_is_RorAL = ucd_3_2_0.bidirectional(chars[0]) in {"R", "AL"} + # if first_is_RorAL: + + has_RandALCat = any(is_RandALCat(c) for c in chars) + if not has_RandALCat: + return + + has_LCat = any(is_LCat(c) for c in chars) + if has_LCat: + raise ValueError('L and R/AL characters must not occur in the same' + ' string') + + if not is_RandALCat(chars[0]) or not is_RandALCat(chars[-1]): + raise ValueError('R/AL string must start and end with R/AL character.') + + +def check_against_tables(chars: list[str], + bad_tables: tuple[Callable[[str], bool], ...] + ) -> None: + ''' + Check against tables, by checking whether any of the characters + from `chars` are in any of the `bad_tables`. + Operates in-place on a list of code points from `chars`. + ''' + violator = _check_against_tables(chars, bad_tables) + if violator is not None: + raise ValueError('Input contains prohibited or unassigned codepoint: ' + 'U+{:04x}'.format(ord(violator))) + + +def _nodeprep_do_mapping(chars: list[str]) -> None: + i = 0 + while i < len(chars): + c = chars[i] + if stringprep.in_table_b1(c): + del chars[i] + else: + replacement = stringprep.map_table_b2(c) + if replacement != c: + chars[i:(i + 1)] = list(replacement) + i += len(replacement) + + +def nodeprep(string: str, allow_unassigned: bool = False) -> str: + ''' + Process the given `string` using the Nodeprep (`RFC 6122`_) profile. In the + error cases defined in `RFC 3454`_ (stringprep), a :class:`ValueError` is + raised. + ''' + + chars = list(string) + _nodeprep_do_mapping(chars) + do_normalization(chars) + check_against_tables( + chars, + ( + stringprep.in_table_c11, + stringprep.in_table_c12, + stringprep.in_table_c21, + stringprep.in_table_c22, + stringprep.in_table_c3, + stringprep.in_table_c4, + stringprep.in_table_c5, + stringprep.in_table_c6, + stringprep.in_table_c7, + stringprep.in_table_c8, + stringprep.in_table_c9, + check_nodeprep_prohibited, + )) + check_bidi(chars) + + if not allow_unassigned: + check_against_tables( + chars, + ( + stringprep.in_table_a1, + ) + ) + + return ''.join(chars) + + +def _resourceprep_do_mapping(chars: list[str]) -> None: + i = 0 + while i < len(chars): + c = chars[i] + if stringprep.in_table_b1(c): + del chars[i] + continue + i += 1 + + +def resourceprep(string: str, allow_unassigned: bool = False) -> str: + ''' + Process the given `string` using the Resourceprep (`RFC 6122`_) profile. In + the error cases defined in `RFC 3454`_ (stringprep), a :class:`ValueError` + is raised. + ''' + + chars = list(string) + _resourceprep_do_mapping(chars) + do_normalization(chars) + check_against_tables( + chars, + ( + stringprep.in_table_c12, + stringprep.in_table_c21, + stringprep.in_table_c22, + stringprep.in_table_c3, + stringprep.in_table_c4, + stringprep.in_table_c5, + stringprep.in_table_c6, + stringprep.in_table_c7, + stringprep.in_table_c8, + stringprep.in_table_c9, + )) + check_bidi(chars) + + if not allow_unassigned: + check_against_tables( + chars, + ( + stringprep.in_table_a1, + ) + ) + + return ''.join(chars) + + +def nameprep(string: str, allow_unassigned: bool = False) -> str: + ''' + Process the given `string` using the Nameprep (`RFC 3491`_) profile. In the + error cases defined in `RFC 3454`_ (stringprep), a :class:`ValueError` is + raised. + ''' + + chars = list(string) + _nodeprep_do_mapping(chars) + do_normalization(chars) + check_against_tables( + chars, + ( + stringprep.in_table_c12, + stringprep.in_table_c22, + stringprep.in_table_c3, + stringprep.in_table_c4, + stringprep.in_table_c5, + stringprep.in_table_c6, + stringprep.in_table_c7, + stringprep.in_table_c8, + stringprep.in_table_c9, + )) + check_bidi(chars) + + if not allow_unassigned: + check_against_tables( + chars, + ( + stringprep.in_table_a1, + ) + ) + + return ''.join(chars) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/tcp.py new/python-nbxmpp-3.2.2/nbxmpp/tcp.py --- old/python-nbxmpp-3.2.1/nbxmpp/tcp.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/tcp.py 2022-09-13 21:15:44.000000000 +0200 @@ -17,6 +17,7 @@ import logging from collections import deque +from typing import Optional from gi.repository import GLib from gi.repository import Gio @@ -26,6 +27,7 @@ from nbxmpp.const import ConnectionType from nbxmpp.util import utf8_decode from nbxmpp.util import convert_tls_error_flags +from nbxmpp.util import min_version from nbxmpp.connection import Connection log = logging.getLogger('nbxmpp.tcp') @@ -62,6 +64,28 @@ self._keepalive_id = None + @property + def tls_version(self) -> Optional[int]: + if self._con is None: + return None + + if not min_version('GLib', '2.69.0'): + return None + + tls_con = self._con.get_base_io_stream() + return tls_con.get_protocol_version() + + @property + def ciphersuite(self) -> Optional[int]: + if self._con is None: + return None + + if not min_version('GLib', '2.69.0'): + return None + + tls_con = self._con.get_base_io_stream() + return tls_con.get_ciphersuite_name() + def connect(self): self.state = TCPState.CONNECTING diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/nbxmpp/util.py new/python-nbxmpp-3.2.2/nbxmpp/util.py --- old/python-nbxmpp-3.2.1/nbxmpp/util.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/nbxmpp/util.py 2022-09-13 21:15:44.000000000 +0200 @@ -31,13 +31,15 @@ from logging import LoggerAdapter from collections import defaultdict import xml.etree.ElementTree as ET - from functools import lru_cache +from packaging.version import Version + from gi.repository import Gio from nbxmpp.protocol import DiscoInfoMalformed from nbxmpp.const import GIO_TLS_ERRORS +from nbxmpp.const import GLIB_VERSION from nbxmpp.namespaces import Namespace from nbxmpp.protocol import StanzaMalformed from nbxmpp.protocol import StreamHeader @@ -405,6 +407,12 @@ stanza.getNamespace() == Namespace.STREAMS) +def min_version(name: str, min_version: str) -> bool: + if name == 'GLib': + return GLIB_VERSION >= Version(min_version) + raise ValueError('Unknown library name') + + class Observable: def __init__(self, log_: logging.Logger): self._log = log_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/setup.cfg new/python-nbxmpp-3.2.2/setup.cfg --- old/python-nbxmpp-3.2.1/setup.cfg 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/setup.cfg 2022-09-13 21:15:44.000000000 +0200 @@ -1,6 +1,6 @@ [metadata] name = nbxmpp -version = 3.2.1 +version = 3.2.2 description = XMPP Library author = Yann Leboulanger, Philipp Hoerist author_email = gajim-de...@gajim.org @@ -18,6 +18,7 @@ packages = find: install_requires = precis-i18n>=1.0.0 + packaging idna [options.extras_require] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/test/unit/test_jid_parsing.py new/python-nbxmpp-3.2.2/test/unit/test_jid_parsing.py --- old/python-nbxmpp-3.2.1/test/unit/test_jid_parsing.py 2022-08-29 18:13:36.000000000 +0200 +++ new/python-nbxmpp-3.2.2/test/unit/test_jid_parsing.py 2022-09-13 21:15:44.000000000 +0200 @@ -1,3 +1,4 @@ +import os import unittest from nbxmpp.protocol import LocalpartByteLimit @@ -8,6 +9,7 @@ from nbxmpp.protocol import DomainpartNotAllowedChar from nbxmpp.protocol import JID + class JIDParsing(unittest.TestCase): def test_valid_jids(self): @@ -36,11 +38,9 @@ tests = [ ('"juliet"@example.com', LocalpartNotAllowedChar), ('foo b...@example.com', LocalpartNotAllowedChar), - ('henry\u00002...@example.com', LocalpartNotAllowedChar), ('@example.com', LocalpartByteLimit), ('u...@example.com/', ResourcepartByteLimit), ('u...@example.com/\U00000001', ResourcepartNotAllowedChar), - ('\u00002...@example.com', LocalpartNotAllowedChar), ('user@h...@example.com', DomainpartNotAllowedChar), ('juliet@', DomainpartByteLimit), ('/foobar', DomainpartByteLimit), @@ -50,6 +50,19 @@ with self.assertRaises(exception): JID.from_string(jid) + def test_invalid_precis_jids(self): + os.environ['NBXMPP_ENFORCE_PRECIS'] = 'true' + tests = [ + ('henry\u00002...@example.com', LocalpartNotAllowedChar), + ('\u00002...@example.com', LocalpartNotAllowedChar), + ] + + for jid, exception in tests: + with self.assertRaises(exception): + JID.from_string(jid) + + del os.environ['NBXMPP_ENFORCE_PRECIS'] + def test_ip_literals(self): tests = [ ('juliet@[2002:4559:1FE2::4559:1FE2]/res'), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-nbxmpp-3.2.1/test/unit/test_stringprep.py new/python-nbxmpp-3.2.2/test/unit/test_stringprep.py --- old/python-nbxmpp-3.2.1/test/unit/test_stringprep.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-nbxmpp-3.2.2/test/unit/test_stringprep.py 2022-09-13 21:15:44.000000000 +0200 @@ -0,0 +1,203 @@ +import unittest + +from nbxmpp.stringprep import nodeprep +from nbxmpp.stringprep import resourceprep +from nbxmpp.stringprep import nameprep +from nbxmpp.stringprep import check_bidi + + +class TestBidi(unittest.TestCase): + def test_empty_string(self): + check_bidi('') + + def test_L_RAL_violation(self): + with self.assertRaises(ValueError): + check_bidi('\u05be\u0041') + + +class TestNodeprep(unittest.TestCase): + def test_map_to_nothing(self): + self.assertEqual( + 'ix', + nodeprep('I\u00ADX'), + 'Nodeprep requirement: map SOFT HYPHEN to nothing') + + def test_case_fold(self): + self.assertEqual( + 'ssa', + nodeprep('??A'), + 'Nodeprep requirement: map ?? to ss, A to a') + + def test_nfkc(self): + self.assertEqual( + 'a', + nodeprep('\u00AA'), + 'Nodeprep requirement: NFKC') + self.assertEqual( + 'ix', + nodeprep('\u2168'), + 'Nodeprep requirement: NFKC') + + def test_prohibited_character(self): + with self.assertRaisesRegex( + ValueError, + r'U\+0007', + msg='Nodeprep requirement: prohibited character (C.2.1)'): + nodeprep('\u0007') + + with self.assertRaisesRegex( + ValueError, + r'U\+200e', + msg='Nodeprep requirement: prohibited character (C.8)'): + nodeprep('\u200E') + + with self.assertRaisesRegex( + ValueError, + r'U\+003e', + msg='Nodeprep requirement: prohibited character (custom)'): + nodeprep('>') + + def test_unassigned(self): + with self.assertRaises( + ValueError, + msg='Nodeprep requirement: unassigned'): + nodeprep('\u0221', allow_unassigned=False) + + with self.assertRaises( + ValueError, + msg='enforce no unassigned by default'): + nodeprep('\u0221') + + self.assertEqual( + '\u0221', + nodeprep('\u0221', allow_unassigned=True)) + + +class TestNameprep(unittest.TestCase): + def test_map_to_nothing(self): + self.assertEqual( + 'ix', + nameprep('I\u00ADX'), + 'Nameprep requirement: map SOFT HYPHEN to nothing') + + def test_case_fold(self): + self.assertEqual( + 'ssa', + nameprep('??A'), + 'Nameprep requirement: map ?? to ss, A to a') + + def test_nfkc(self): + self.assertEqual( + 'a', + nodeprep('\u00AA'), + 'Nameprep requirement: NFKC') + self.assertEqual( + 'ix', + nodeprep('\u2168'), + 'Nameprep requirement: NFKC') + + def test_prohibited_character(self): + with self.assertRaisesRegex( + ValueError, + r'U\+06dd', + msg='Nameprep requirement: prohibited character (C.2.2)'): + nameprep('\u06DD') + + with self.assertRaisesRegex( + ValueError, + r'U\+e000', + msg='Nameprep requirement: prohibited character (C.3)'): + nameprep('\uE000') + + with self.assertRaisesRegex( + ValueError, + r'U\+1fffe', + msg='Nameprep requirement: prohibited character (C.4)'): + nameprep('\U0001FFFE') + + with self.assertRaisesRegex( + ValueError, + r'U\+d800', + msg='Nameprep requirement: prohibited character (C.5)'): + nameprep('\uD800') + + with self.assertRaisesRegex( + ValueError, + r'U\+fff9', + msg='Nameprep requirement: prohibited character (C.6)'): + nameprep('\uFFF9') + + with self.assertRaisesRegex( + ValueError, + r'U\+2ff0', + msg='Nameprep requirement: prohibited character (C.7)'): + nameprep('\u2FF0') + + with self.assertRaisesRegex( + ValueError, + r'U\+e0001', + msg='Nameprep requirement: prohibited character (C.9)'): + nameprep('\U000E0001') + + def test_unassigned(self): + with self.assertRaises( + ValueError, + msg='Nameprep requirement: unassigned'): + nameprep('\u0221', allow_unassigned=False) + + with self.assertRaises( + ValueError, + msg='enforce no unassigned by default'): + nameprep('\u0221') + + self.assertEqual( + '\u0221', + nameprep('\u0221', allow_unassigned=True)) + + +class TestResourceprep(unittest.TestCase): + def test_map_to_nothing(self): + self.assertEqual( + 'IX', + resourceprep('I\u00ADX'), + 'Resourceprep requirement: map SOFT HYPHEN to nothing') + + def test_nfkc(self): + self.assertEqual( + 'a', + resourceprep('\u00AA'), + 'Resourceprep requirement: NFKC') + self.assertEqual( + 'IX', + resourceprep('\u2168'), + 'Resourceprep requirement: NFKC') + + def test_prohibited_character(self): + with self.assertRaisesRegex( + ValueError, + r'U\+0007', + msg='Resourceprep requirement: ' + 'prohibited character (C.2.1)'): + resourceprep('\u0007') + + with self.assertRaisesRegex( + ValueError, + r'U\+200e', + msg='Resourceprep requirement: ' + 'prohibited character (C.8)'): + resourceprep('\u200E') + + def test_unassigned(self): + with self.assertRaises( + ValueError, + msg='Resourceprep requirement: unassigned'): + resourceprep('\u0221', allow_unassigned=False) + + with self.assertRaises( + ValueError, + msg='enforce no unassigned by default'): + resourceprep('\u0221') + + self.assertEqual( + '\u0221', + resourceprep('\u0221', allow_unassigned=True))