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))

Reply via email to