Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-py-vapid for openSUSE:Factory 
checked in at 2025-10-21 11:15:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-py-vapid (Old)
 and      /work/SRC/openSUSE:Factory/.python-py-vapid.new.18484 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-py-vapid"

Tue Oct 21 11:15:23 2025 rev:7 rq:1312273 version:1.9.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-py-vapid/python-py-vapid.changes  
2025-06-10 09:10:47.669099994 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-py-vapid.new.18484/python-py-vapid.changes   
    2025-10-21 11:16:24.046743509 +0200
@@ -1,0 +2,10 @@
+Mon Oct 20 03:08:23 UTC 2025 - Steve Kowalik <[email protected]>
+
+- Update to 1.9.2:
+  * Move project metadata to pyproject.toml
+- Add patch remove-mock.patch:
+  * Prefer built-in unittest.mock
+- Add patch support-new-cryptography.patch:
+  * Support new cryprtography changes.
+
+-------------------------------------------------------------------

Old:
----
  py-vapid-1.9.0.tar.gz

New:
----
  py_vapid-1.9.2.tar.gz
  remove-mock.patch
  support-new-cryptography.patch

----------(New B)----------
  New:  * Move project metadata to pyproject.toml
- Add patch remove-mock.patch:
  * Prefer built-in unittest.mock
  New:  * Prefer built-in unittest.mock
- Add patch support-new-cryptography.patch:
  * Support new cryprtography changes.
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-py-vapid.spec ++++++
--- /var/tmp/diff_new_pack.vyJviQ/_old  2025-10-21 11:16:25.186791420 +0200
+++ /var/tmp/diff_new_pack.vyJviQ/_new  2025-10-21 11:16:25.190791588 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-py-vapid
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,12 +18,16 @@
 
 %bcond_without libalternatives
 Name:           python-py-vapid
-Version:        1.9.0
+Version:        1.9.2
 Release:        0
 Summary:        VAPID header generation library
 License:        MPL-2.0
 URL:            https://github.com/mozilla-services/vapid
-Source:         
https://files.pythonhosted.org/packages/source/p/py-vapid/py-vapid-%{version}.tar.gz
+Source:         
https://files.pythonhosted.org/packages/source/p/py-vapid/py_vapid-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM Based on gh#web-push-libs/vapid#108
+Patch0:         remove-mock.patch
+# PATCH-FIX-UPSTREAM Based on gh#web-push-libs/vapid#110
+Patch1:         support-new-cryptography.patch
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module wheel}
@@ -43,8 +47,7 @@
 VAPID header generation library.
 
 %prep
-%setup -q -n py-vapid-%{version}
-sed -i 's/from mock import/from unittest.mock import/' 
py_vapid/tests/test_vapid.py
+%autosetup -p1 -n py_vapid-%{version}
 
 %build
 %pyproject_wheel
@@ -65,5 +68,5 @@
 %license LICENSE
 %python_alternative %{_bindir}/vapid
 %{python_sitelib}/py[-_]vapid
-%{python_sitelib}/py[-_]vapid-%{version}*-info
+%{python_sitelib}/py[-_]vapid-%{version}.dist-info
 

++++++ remove-mock.patch ++++++
>From 87e8fa3b251145f8f996e64974134921c8d06bb3 Mon Sep 17 00:00:00 2001
From: Alexandre Detiste <[email protected]>
Date: Sun, 30 Mar 2025 12:11:35 +0200
Subject: [PATCH] prefer newer unittest.mock from standard library

---
 python/py_vapid/tests/test_vapid.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

Index: py_vapid-1.9.2/py_vapid/tests/test_vapid.py
===================================================================
--- py_vapid-1.9.2.orig/py_vapid/tests/test_vapid.py
+++ py_vapid-1.9.2/py_vapid/tests/test_vapid.py
@@ -5,7 +5,10 @@ import os
 import json
 import unittest
 from cryptography.hazmat.primitives import serialization
-from mock import patch, Mock
+try:
+    from unittest.mock import patch, Mock
+except ImportError:
+    from mock import patch, Mock
 
 from py_vapid import Vapid01, Vapid02, VapidException, _check_sub
 from py_vapid.jwt import decode

++++++ support-new-cryptography.patch ++++++
>From 4898bb4d418c4b3b3a0bb3620cb4cb13a481e0ba Mon Sep 17 00:00:00 2001
From: jrconlin <[email protected]>
Date: Thu, 2 Oct 2025 10:29:35 -0700
Subject: [PATCH 1/2] feat: Update to latest EC recommendations

Closes #105
---
 python/py_vapid/__init__.py | 116 +++++++++++++++++-------------------
 python/pyproject.toml       |   2 +-
 2 files changed, 57 insertions(+), 61 deletions(-)

diff --git a/py_vapid/__init__.py b/py_vapid/__init__.py
index 4a6eff2..94d1113 100644
--- a/py_vapid/__init__.py
+++ b/py_vapid/__init__.py
@@ -25,6 +25,7 @@
 
 class VapidException(Exception):
     """An exception wrapper for Vapid."""
+
     pass
 
 
@@ -34,6 +35,7 @@ class Vapid01(object):
     https://tools.ietf.org/html/draft-ietf-webpush-vapid-01
 
     """
+
     _private_key = None
     _public_key = None
     _schema = "WebPush"
@@ -65,14 +67,14 @@ def from_raw(cls, private_raw):
         key = ec.derive_private_key(
             int(binascii.hexlify(b64urldecode(private_raw)), 16),
             curve=ec.SECP256R1(),
-            backend=default_backend())
+            backend=default_backend(),
+        )
         return cls(key)
 
     @classmethod
     def from_raw_public(cls, public_raw):
         key = ec.EllipticCurvePublicKey.from_encoded_point(
-            curve=ec.SECP256R1(),
-            data=b64urldecode(public_raw)
+            curve=ec.SECP256R1(), data=b64urldecode(public_raw)
         )
         ss = cls()
         ss._public_key = key
@@ -87,8 +89,7 @@ def from_pem(cls, private_key):
 
         """
         # not sure why, but load_pem_private_key fails to deserialize
-        return cls.from_der(
-            b''.join(private_key.splitlines()[1:-1]))
+        return cls.from_der(b"".join(private_key.splitlines()[1:-1]))
 
     @classmethod
     def from_der(cls, private_key):
@@ -98,9 +99,9 @@ def from_der(cls, private_key):
         :type private_key: bytes
 
         """
-        key = serialization.load_der_private_key(b64urldecode(private_key),
-                                                 password=None,
-                                                 backend=default_backend())
+        key = serialization.load_der_private_key(
+            b64urldecode(private_key), password=None, backend=default_backend()
+        )
         return cls(key)
 
     @classmethod
@@ -118,13 +119,13 @@ def from_file(cls, private_key_file=None):
             vapid.generate_keys()
             vapid.save_key(private_key_file)
             return vapid
-        with open(private_key_file, 'r') as file:
+        with open(private_key_file, "r") as file:
             private_key = file.read()
         try:
             if "-----BEGIN" in private_key:
-                vapid = cls.from_pem(private_key.encode('utf8'))
+                vapid = cls.from_pem(private_key.encode("utf8"))
             else:
-                vapid = cls.from_der(private_key.encode('utf8'))
+                vapid = cls.from_der(private_key.encode("utf8"))
             return vapid
         except Exception as exc:
             logging.error("Could not open private key file: %s", repr(exc))
@@ -156,11 +157,10 @@ def verify(cls, key, auth):
         type key: str
 
         """
-        tokens = auth.rsplit(' ', 1)[1].rsplit('.', 1)
+        tokens = auth.rsplit(" ", 1)[1].rsplit(".", 1)
         kp = cls().from_raw_public(key.encode())
         return kp.verify_token(
-            validation_token=tokens[0].encode(),
-            verification_token=tokens[1]
+            validation_token=tokens[0].encode(), verification_token=tokens[1]
         )
 
     @property
@@ -197,20 +197,19 @@ def public_key(self):
 
     def generate_keys(self):
         """Generate a valid ECDSA Key Pair."""
-        self.private_key = ec.generate_private_key(ec.SECP256R1,
-                                                   default_backend())
+        self.private_key = ec.generate_private_key(ec.SECP256R1(), 
default_backend())
 
     def private_pem(self):
         return self.private_key.private_bytes(
             encoding=serialization.Encoding.PEM,
             format=serialization.PrivateFormat.PKCS8,
-            encryption_algorithm=serialization.NoEncryption()
+            encryption_algorithm=serialization.NoEncryption(),
         )
 
     def public_pem(self):
         return self.public_key.public_bytes(
             encoding=serialization.Encoding.PEM,
-            format=serialization.PublicFormat.SubjectPublicKeyInfo
+            format=serialization.PublicFormat.SubjectPublicKeyInfo,
         )
 
     def save_key(self, key_file):
@@ -245,14 +244,14 @@ def verify_token(self, validation_token, 
verification_token):
         :rtype: boolean
 
         """
-        hsig = b64urldecode(verification_token.encode('utf8'))
+        hsig = b64urldecode(verification_token.encode("utf8"))
         r = int(binascii.hexlify(hsig[:32]), 16)
         s = int(binascii.hexlify(hsig[32:]), 16)
         try:
             self.public_key.verify(
                 ecutils.encode_dss_signature(r, s),
                 validation_token,
-                signature_algorithm=ec.ECDSA(hashes.SHA256())
+                signature_algorithm=ec.ECDSA(hashes.SHA256()),
             )
             return True
         except InvalidSignature:
@@ -260,23 +259,25 @@ def verify_token(self, validation_token, 
verification_token):
 
     def _base_sign(self, claims):
         cclaims = copy.deepcopy(claims)
-        if not cclaims.get('exp'):
-            cclaims['exp'] = int(time.time()) + 86400
-        if not self.conf.get('no-strict', False):
-            valid = _check_sub(cclaims.get('sub', ''))
+        if not cclaims.get("exp"):
+            cclaims["exp"] = int(time.time()) + 86400
+        if not self.conf.get("no-strict", False):
+            valid = _check_sub(cclaims.get("sub", ""))
         else:
-            valid = cclaims.get('sub') is not None
+            valid = cclaims.get("sub") is not None
         if not valid:
             raise VapidException(
                 "Missing 'sub' from claims. "
-                "'sub' is your admin email as a mailto: link.")
-        if not re.match(r"^https?://[^/:]+(:\d+)?$",
-                        cclaims.get("aud", ""),
-                        re.IGNORECASE):
+                "'sub' is your admin email as a mailto: link."
+            )
+        if not re.match(
+            r"^https?://[^/:]+(:\d+)?$", cclaims.get("aud", ""), re.IGNORECASE
+        ):
             raise VapidException(
                 "Missing 'aud' from claims. "
                 "'aud' is the scheme, host and optional port for this "
-                "transaction e.g. https://example.com:8080";)
+                "transaction e.g. https://example.com:8080";
+            )
         return cclaims
 
     def sign(self, claims, crypto_key=None):
@@ -292,19 +293,22 @@ def sign(self, claims, crypto_key=None):
 
         """
         sig = sign(self._base_sign(claims), self.private_key)
-        pkey = 'p256ecdsa='
+        pkey = "p256ecdsa="
         pkey += b64urlencode(
             self.public_key.public_bytes(
                 serialization.Encoding.X962,
-                serialization.PublicFormat.UncompressedPoint
-            ))
+                serialization.PublicFormat.UncompressedPoint,
+            )
+        )
         if crypto_key:
-            crypto_key = crypto_key + ';' + pkey
+            crypto_key = crypto_key + ";" + pkey
         else:
             crypto_key = pkey
 
-        return {"Authorization": "{} {}".format(self._schema, sig.strip('=')),
-                "Crypto-Key": crypto_key}
+        return {
+            "Authorization": "{} {}".format(self._schema, sig.strip("=")),
+            "Crypto-Key": crypto_key,
+        }
 
 
 class Vapid02(Vapid01):
@@ -313,6 +317,7 @@ class Vapid02(Vapid01):
     https://tools.ietf.org/html/rfc8292
 
     """
+
     _schema = "vapid"
 
     def sign(self, claims, crypto_key=None):
@@ -329,14 +334,11 @@ def sign(self, claims, crypto_key=None):
         """
         sig = sign(self._base_sign(claims), self.private_key)
         pkey = self.public_key.public_bytes(
-                serialization.Encoding.X962,
-                serialization.PublicFormat.UncompressedPoint
-            )
-        return{
+            serialization.Encoding.X962, 
serialization.PublicFormat.UncompressedPoint
+        )
+        return {
             "Authorization": "{schema} t={t},k={k}".format(
-                schema=self._schema,
-                t=sig,
-                k=b64urlencode(pkey)
+                schema=self._schema, t=sig, k=b64urlencode(pkey)
             )
         }
 
@@ -349,27 +351,23 @@ def verify(cls, auth):
         :rtype: bool
 
         """
-        pref_tok = auth.rsplit(' ', 1)
-        assert pref_tok[0].lower() == cls._schema, (
-                "Incorrect schema specified")
+        pref_tok = auth.rsplit(" ", 1)
+        assert pref_tok[0].lower() == cls._schema, "Incorrect schema specified"
         parts = {}
-        for tok in pref_tok[1].split(','):
-            kv = tok.split('=', 1)
+        for tok in pref_tok[1].split(","):
+            kv = tok.split("=", 1)
             parts[kv[0]] = kv[1]
-        assert 'k' in parts.keys(), (
-                "Auth missing public key 'k' value")
-        assert 't' in parts.keys(), (
-                "Auth missing token set 't' value")
-        kp = cls().from_raw_public(parts['k'].encode())
-        tokens = parts['t'].rsplit('.', 1)
+        assert "k" in parts.keys(), "Auth missing public key 'k' value"
+        assert "t" in parts.keys(), "Auth missing token set 't' value"
+        kp = cls().from_raw_public(parts["k"].encode())
+        tokens = parts["t"].rsplit(".", 1)
         return kp.verify_token(
-            validation_token=tokens[0].encode(),
-            verification_token=tokens[1]
+            validation_token=tokens[0].encode(), verification_token=tokens[1]
         )
 
 
 def _check_sub(sub):
-    """ Check to see if the `sub` is a properly formatted `mailto:`
+    """Check to see if the `sub` is a properly formatted `mailto:`
 
     a `mailto:` should be a SMTP mail address. Mind you, since I run
     YouFailAtEmail.com, you have every right to yell about how terrible
@@ -382,9 +380,7 @@ def _check_sub(sub):
     :rtype: bool
 
     """
-    pattern = (
-        
r"^(mailto:.+@((localhost|[%\w-]+(\.[%\w-]+)+|([0-9a-f]{1,4}):+([0-9a-f]{1,4})?)))|https:\/\/(localhost|[\w-]+\.[\w\.-]+|([0-9a-f]{1,4}:+)+([0-9a-f]{1,4})?)$"
 # noqa
-        )
+    pattern = 
r"^(mailto:.+@((localhost|[%\w-]+(\.[%\w-]+)+|([0-9a-f]{1,4}):+([0-9a-f]{1,4})?)))|https:\/\/(localhost|[\w-]+\.[\w\.-]+|([0-9a-f]{1,4}:+)+([0-9a-f]{1,4})?)$"
  # noqa
     return re.match(pattern, sub, re.IGNORECASE) is not None
 

Reply via email to