File: upstream-pr-23.patch

package info (click to toggle)
python-passlib 1.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,184 kB
  • sloc: python: 26,132; makefile: 7
file content (92 lines) | stat: -rw-r--r-- 3,882 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
From a3f920fd8f11aa543fea8d1f537d49fe0519be86 Mon Sep 17 00:00:00 2001
From: Jonathan Chapman <glitch@glitchwrks.com>
Date: Thu, 9 Oct 2025 20:57:47 -0400
Subject: [PATCH 2/5] Changing from manual detection of bcrypt 5.0.0
 functionality to version check in its specific backend, truncating before
 hashing if the backend will raise an error

---
 passlib/handlers/bcrypt.py | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -152,6 +152,7 @@
     _lacks_2b_support = False
     _fallback_ident = IDENT_2A
     _require_valid_utf8_bytes = False
+    _backend_raises_on_truncate = False
 
     @classmethod
     def from_string(cls, hash):
@@ -370,21 +371,20 @@
             # Secret which will trip the wraparound bug, if present
             secret = (b"0123456789" * 26)[:255]
 
-            # Python bcrypt >= 5.0.0 will raise an exception on passwords greater than 72 characters,
-            # whereas earlier versions without the wraparound bug silently truncated the input to 72
-            # characters. See if the exception is generated.
-            try:
+            if not mixin_cls._backend_raises_on_truncate:
+                # Backend accepts more than 72 characters, test for the wraparound bug
                 bug_hash = (
                     ident.encode("ascii")
                     + b"04$R1lJ2gkNaoPGdafE.H.16.nVyh2niHsGJhayOHLMiXlI45o8/DU.6"
                 )
 
-                # If we get here, the backend auto-truncates, test for wraparound bug
                 if verify(secret, bug_hash):
                     return True
-            except ValueError:
-                # Backend explicitly will not auto-truncate, truncate the password to 72 characters
-                secret = secret[:72]
+            else:
+                # Backend won't accept more than 72 characters, truncate the secret
+                #
+                # n.b. this should preclude the wraparound bug existing anyway
+                secret = secret[:mixin_cls.truncate_size]
 
             # Check to make sure that the backend still hashes correctly; if not, we're in a failure case
             # not related to the original wraparound bug or bcrypt >= 5.0.0 input length restriction.
@@ -620,11 +620,15 @@
             return False
         try:
             version = metadata.version("bcrypt")
+
+            if int(version.split(".")[0]) >= 5:
+                mixin_cls._backend_raises_on_truncate = True
         except Exception:
             logger.warning("(trapped) error reading bcrypt version", exc_info=True)
             version = "<unknown>"
 
         logger.debug("detected 'bcrypt' backend, version %r", version)
+
         return mixin_cls._finalize_backend_mixin(name, dryrun)
 
     # # TODO: would like to implementing verify() directly,
@@ -654,6 +658,10 @@
         config = self._get_config(ident)
         if isinstance(config, str):
             config = config.encode("ascii")
+
+        if self._backend_raises_on_truncate:
+            secret = secret[:72]
+
         hash = _bcrypt.hashpw(secret, config)
         assert isinstance(hash, bytes)
         if not hash.startswith(config) or len(hash) != len(config) + 31:
--- a/tests/test_handlers_bcrypt.py
+++ b/tests/test_handlers_bcrypt.py
@@ -220,9 +220,9 @@
                 hash = IDENT_2B + hash[4:]
             hash = to_bytes(hash)
             try:
-                return bcrypt.hashpw(secret, hash) == hash
-            except ValueError:
-                raise ValueError(f"bcrypt rejected hash: {hash!r} (secret={secret!r})")
+                return bcrypt.hashpw(secret[:72], hash) == hash
+            except ValueError as e:
+                raise ValueError(f"bcrypt rejected hash: {hash!r} (secret={secret!r}) with message: {str(e)}")
 
         return check_bcrypt