Marco Ricci commited on 2025-01-27 15:23:35
Zeige 1 geänderte Dateien mit 83 Einfügungen und 0 Löschungen.
As part of a larger quality assurance effort, explicitly test that derived passphrases depend on the service name. The obvious counterpart, that derived passphrases depend on the master passphrase, it not quite so straightforward, and will be tackled in a later commit.
... | ... |
@@ -39,6 +39,29 @@ class TestVault: |
39 | 39 |
<i>vault</i>(1)'s test suite. |
40 | 40 |
""" |
41 | 41 |
|
42 |
+ @hypothesis.given( |
|
43 |
+ phrase=strategies.text( |
|
44 |
+ strategies.characters(min_codepoint=32, max_codepoint=126), |
|
45 |
+ min_size=1, |
|
46 |
+ max_size=32, |
|
47 |
+ ), |
|
48 |
+ services=strategies.lists( |
|
49 |
+ strategies.binary(min_size=1, max_size=32), |
|
50 |
+ min_size=2, |
|
51 |
+ max_size=2, |
|
52 |
+ unique=True, |
|
53 |
+ ), |
|
54 |
+ ) |
|
55 |
+ def test_101_create_hash_service_name_dependence( |
|
56 |
+ self, |
|
57 |
+ phrase: str, |
|
58 |
+ services: list[bytes], |
|
59 |
+ ) -> None: |
|
60 |
+ """The internal hash is dependent on the service name.""" |
|
61 |
+ assert Vault.create_hash( |
|
62 |
+ phrase=phrase, service=services[0] |
|
63 |
+ ) != Vault.create_hash(phrase=phrase, service=services[1]) |
|
64 |
+ |
|
42 | 65 |
@pytest.mark.parametrize( |
43 | 66 |
['service', 'expected'], |
44 | 67 |
[ |
... | ... |
@@ -96,6 +119,66 @@ class TestVault: |
96 | 119 |
phrase=phrase |
97 | 120 |
).generate(bytearray(service.encode('utf-8'))) |
98 | 121 |
|
122 |
+ @hypothesis.given( |
|
123 |
+ phrase=strategies.text( |
|
124 |
+ strategies.characters(min_codepoint=32, max_codepoint=126), |
|
125 |
+ min_size=1, |
|
126 |
+ max_size=32, |
|
127 |
+ ), |
|
128 |
+ services=strategies.lists( |
|
129 |
+ strategies.binary(min_size=1, max_size=32), |
|
130 |
+ min_size=2, |
|
131 |
+ max_size=2, |
|
132 |
+ unique=True, |
|
133 |
+ ), |
|
134 |
+ ) |
|
135 |
+ def test_203a_service_name_dependence( |
|
136 |
+ self, |
|
137 |
+ phrase: str, |
|
138 |
+ services: list[bytes], |
|
139 |
+ ) -> None: |
|
140 |
+ """The derived passphrase is dependent on the service name.""" |
|
141 |
+ assert Vault(phrase=phrase).generate( |
|
142 |
+ services[0] |
|
143 |
+ ) != Vault(phrase=phrase).generate(services[1]) |
|
144 |
+ |
|
145 |
+ @tests.hypothesis_settings_coverage_compatible |
|
146 |
+ @hypothesis.given( |
|
147 |
+ phrase=strategies.text( |
|
148 |
+ strategies.characters(min_codepoint=32, max_codepoint=126), |
|
149 |
+ min_size=1, |
|
150 |
+ max_size=32, |
|
151 |
+ ), |
|
152 |
+ config=tests.vault_full_service_config(), |
|
153 |
+ services=strategies.lists( |
|
154 |
+ strategies.binary(min_size=1, max_size=32), |
|
155 |
+ min_size=2, |
|
156 |
+ max_size=2, |
|
157 |
+ unique=True, |
|
158 |
+ ), |
|
159 |
+ ) |
|
160 |
+ def test_203b_service_name_dependence_with_config( |
|
161 |
+ self, |
|
162 |
+ phrase: str, |
|
163 |
+ config: dict[str, int], |
|
164 |
+ services: list[bytes], |
|
165 |
+ ) -> None: |
|
166 |
+ """The derived passphrase is dependent on the service name.""" |
|
167 |
+ try: |
|
168 |
+ assert Vault(phrase=phrase, **config).generate( |
|
169 |
+ services[0] |
|
170 |
+ ) != Vault(phrase=phrase, **config).generate(services[1]) |
|
171 |
+ except ValueError as exc: |
|
172 |
+ # The service configuration strategy attempts to only |
|
173 |
+ # generate satisfiable configurations. It is possible, |
|
174 |
+ # though rare, that this fails, and that unsatisfiability is |
|
175 |
+ # only recognized when actually deriving a passphrase. In |
|
176 |
+ # that case, reject the generated configuration. |
|
177 |
+ hypothesis.assume('no allowed characters left' not in exc.args) |
|
178 |
+ # Otherwise it's a genuine bug in the test case or the |
|
179 |
+ # implementation, and should be raised. |
|
180 |
+ raise # pragma: no cover |
|
181 |
+ |
|
99 | 182 |
def test_210_nonstandard_length(self) -> None: |
100 | 183 |
"""Deriving a passphrase adheres to imposed length limits.""" |
101 | 184 |
assert ( |
102 | 185 |