Fix repeated character detection logic in passphrase generation
Marco Ricci

Marco Ricci commited on 2024-06-08 19:06:56
Zeige 2 geänderte Dateien mit 24 Einfügungen und 12 Löschungen.


The prototype implementation is based off a JavaScript program, and is
clumsy to read and hard to verify if translated directly to Python.  (It
also interacts badly with type checking.)  Rewrite the check in
a pythonic manner, from scratch, that is much easier to verify.
... ...
@@ -257,18 +257,11 @@ class Vault:
257 257
                     # (where r is the repeat limit that must not be
258 258
                     # reached), and if so, remove this same character
259 259
                     # from the current character's allowed set.
260
-                    previous = result[-1] if result else None
261
-                    i = self._repeat - 1
262
-                    same = (i >= 0) if previous is not None else False
263
-                    while same and i > 0:
264
-                        i -= 1
265
-                        if same:
266
-                            other_pos = -(self._repeat - i)
267
-                            same = (result[other_pos] == previous)
268
-                    if same:
269
-                        assert previous is not None  # for the type checker
270
-                        charset = self._subtract(bytes([previous]), charset)
271
-                    # End checking for repeated characters.
260
+                    if self._repeat and result:
261
+                        bad_suffix = bytes(result[-1:]) * (self._repeat - 1)
262
+                        if result.endswith(bad_suffix):
263
+                            charset = self._subtract(bytes(result[-1:]),
264
+                                                     charset)
272 265
                     pos = seq.generate(len(charset))
273 266
                     result.extend(charset[pos:pos+1])
274 267
             except sequin.SequinExhaustedException:
... ...
@@ -94,3 +94,22 @@ def test_218_all_character_classes():
94 94
               space=3, dash=2, symbol=1).generate('google') ==
95 95
         b': : fv_wqt>a-4w1S  R'
96 96
     )
97
+
98
+def test_219_only_numbers_and_very_high_repetition_limit():
99
+    generated = Vault(phrase=b'', length=40, lower=0, upper=0, space=0,
100
+                      dash=0, symbol=0, repeat=4).generate('abcdef')
101
+    assert b'0000' not in generated
102
+    assert b'1111' not in generated
103
+    assert b'2222' not in generated
104
+    assert b'3333' not in generated
105
+    assert b'4444' not in generated
106
+    assert b'5555' not in generated
107
+    assert b'6666' not in generated
108
+    assert b'7777' not in generated
109
+    assert b'8888' not in generated
110
+    assert b'9999' not in generated
111
+
112
+def test_220_very_limited_character_set():
113
+    generated = Vault(phrase=b'', length=24, lower=0, upper=0,
114
+                      space=0, symbol=0).generate('testing')
115
+    assert b'763252593304946694588866' == generated
97 116