Repository: hynek/argon2-cffi

Issue:
Make PasswordHasher.check_needs_rehash() accept bytes hash
`PasswordHasher.check_needs_rehash()` should also accept bytes hashes to be consistent with the rest of the API.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3fe7fb..46c0765 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,12 @@ What explicitly *may* change over time are the default hashing parameters and th
 
 ## [Unreleased](https://github.com/hynek/argon2-cffi/compare/23.1.0...HEAD)
 
+### Changed
+
+- `argon2.PasswordHasher.check_needs_rehash()` now also accepts bytes like the rest of the API.
+  [#174](https://github.com/hynek/argon2-cffi/pull/174)
+
+
 ## [23.1.0](https://github.com/hynek/argon2-cffi/compare/21.3.0...23.1.0) - 2023-08-15
 
 ### Removed
diff --git a/src/argon2/_password_hasher.py b/src/argon2/_password_hasher.py
index 125149b..ef940b3 100644
--- a/src/argon2/_password_hasher.py
+++ b/src/argon2/_password_hasher.py
@@ -244,7 +244,7 @@ class PasswordHasher:
             hash, _ensure_bytes(password, self.encoding), hash_type
         )
 
-    def check_needs_rehash(self, hash: str) -> bool:
+    def check_needs_rehash(self, hash: str | bytes) -> bool:
         """
         Check whether *hash* was created using the instance's parameters.
 
@@ -264,5 +264,9 @@ class PasswordHasher:
             Whether *hash* was created using the instance's parameters.
 
         .. versionadded:: 18.2.0
+        .. versionchanged:: 24.1.0 Accepts bytes for *hash*.
         """
+        if isinstance(hash, bytes):
+            hash = hash.decode("ascii")
+
         return self._parameters != extract_parameters(hash)


Test patch:
diff --git a/tests/test_password_hasher.py b/tests/test_password_hasher.py
index d6fa626..17f9410 100644
--- a/tests/test_password_hasher.py
+++ b/tests/test_password_hasher.py
@@ -109,22 +109,32 @@ class TestPasswordHasher:
         with pytest.raises(InvalidHash):
             PasswordHasher().verify("tiger", "does not matter")
 
-    def test_check_needs_rehash_no(self):
+    @pytest.mark.parametrize("use_bytes", [True, False])
+    def test_check_needs_rehash_no(self, use_bytes):
         """
         Return False if the hash has the correct parameters.
         """
         ph = PasswordHasher(1, 8, 1, 16, 16)
 
-        assert not ph.check_needs_rehash(ph.hash("foo"))
+        hash = ph.hash("foo")
+        if use_bytes:
+            hash = hash.encode()
 
-    def test_check_needs_rehash_yes(self):
+        assert not ph.check_needs_rehash(hash)
+
+    @pytest.mark.parametrize("use_bytes", [True, False])
+    def test_check_needs_rehash_yes(self, use_bytes):
         """
         Return True if any of the parameters changes.
         """
         ph = PasswordHasher(1, 8, 1, 16, 16)
         ph_old = PasswordHasher(1, 8, 1, 8, 8)
 
-        assert ph.check_needs_rehash(ph_old.hash("foo"))
+        hash = ph_old.hash("foo")
+        if use_bytes:
+            hash = hash.encode()
+
+        assert ph.check_needs_rehash(hash)
 
     def test_type_is_configurable(self):
         """