Marco Ricci commited on 2024-08-31 21:24:29
Zeige 2 geänderte Dateien mit 155 Einfügungen und 1 Löschungen.
Further tests are necessary to achieve 100% coverage, but these concern the detection of format errors, so the test files are rather hard to generate.
| ... | ... |
@@ -440,6 +440,51 @@ VAULT_STOREROOM_CONFIG_DATA = {
|
| 440 | 440 |
}, |
| 441 | 441 |
} |
| 442 | 442 |
|
| 443 |
+_VAULT_STOREROOM_BROKEN_DIR_CONFIG_ZIPPED_JAVASCRIPT_SOURCE = """ |
|
| 444 |
+// Executed in the top-level directory of the vault project code, in Node.js. |
|
| 445 |
+const storeroom = require('storeroom')
|
|
| 446 |
+const Store = require('./lib/store.js')
|
|
| 447 |
+let store = new Store(storeroom.createFileAdapter('./broken-dir', 'vault key'))
|
|
| 448 |
+await store._storeroom.put('/services/array/', ['entry1','entry2'])
|
|
| 449 |
+// The resulting "broken-dir" was then zipped manually. |
|
| 450 |
+""" |
|
| 451 |
+VAULT_STOREROOM_BROKEN_DIR_CONFIG_ZIPPED = b""" |
|
| 452 |
+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 |
|
| 486 |
+""" |
|
| 487 |
+ |
|
| 443 | 488 |
CANNOT_LOAD_CRYPTOGRAPHY = ( |
| 444 | 489 |
b'Cannot load the required Python module "cryptography".' |
| 445 | 490 |
) |
| ... | ... |
@@ -11,7 +11,7 @@ import click.testing |
| 11 | 11 |
import pytest |
| 12 | 12 |
|
| 13 | 13 |
import tests |
| 14 |
-from derivepassphrase.exporter import cli |
|
| 14 |
+from derivepassphrase.exporter import cli, storeroom |
|
| 15 | 15 |
|
| 16 | 16 |
cryptography = pytest.importorskip('cryptography', minversion='38.0')
|
| 17 | 17 |
|
| ... | ... |
@@ -194,3 +194,112 @@ class TestCLI: |
| 194 | 194 |
assert result.stderr_bytes |
| 195 | 195 |
assert b'Invalid vault config: ' in result.stderr_bytes |
| 196 | 196 |
assert tests.CANNOT_LOAD_CRYPTOGRAPHY not in result.stderr_bytes |
| 197 |
+ |
|
| 198 |
+ |
|
| 199 |
+class TestStoreroom: |
|
| 200 |
+ @pytest.mark.parametrize( |
|
| 201 |
+ ['path', 'key'], |
|
| 202 |
+ [ |
|
| 203 |
+ ('.vault', tests.VAULT_MASTER_KEY),
|
|
| 204 |
+ ('.vault', None),
|
|
| 205 |
+ (None, tests.VAULT_MASTER_KEY), |
|
| 206 |
+ (None, None), |
|
| 207 |
+ ], |
|
| 208 |
+ ) |
|
| 209 |
+ def test_200_export_data_path_and_keys_type( |
|
| 210 |
+ self, |
|
| 211 |
+ monkeypatch: pytest.MonkeyPatch, |
|
| 212 |
+ path: str | None, |
|
| 213 |
+ key: str | None, |
|
| 214 |
+ ) -> None: |
|
| 215 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
| 216 |
+ with tests.isolated_vault_exporter_config( |
|
| 217 |
+ monkeypatch=monkeypatch, |
|
| 218 |
+ runner=runner, |
|
| 219 |
+ vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED, |
|
| 220 |
+ vault_key=tests.VAULT_MASTER_KEY, |
|
| 221 |
+ ): |
|
| 222 |
+ assert ( |
|
| 223 |
+ storeroom.export_storeroom_data(path, key) |
|
| 224 |
+ == tests.VAULT_STOREROOM_CONFIG_DATA |
|
| 225 |
+ ) |
|
| 226 |
+ |
|
| 227 |
+ def test_400_decrypt_bucket_item_unknown_version(self) -> None: |
|
| 228 |
+ bucket_item = ( |
|
| 229 |
+ b'\xff' + bytes(storeroom.ENCRYPTED_KEYPAIR_SIZE) + bytes(3) |
|
| 230 |
+ ) |
|
| 231 |
+ master_keys: storeroom.MasterKeys = {
|
|
| 232 |
+ 'encryption_key': bytes(storeroom.KEY_SIZE), |
|
| 233 |
+ 'signing_key': bytes(storeroom.KEY_SIZE), |
|
| 234 |
+ 'hashing_key': bytes(storeroom.KEY_SIZE), |
|
| 235 |
+ } |
|
| 236 |
+ with pytest.raises(RuntimeError, match='Cannot handle version 255'): |
|
| 237 |
+ storeroom.decrypt_bucket_item(bucket_item, master_keys) |
|
| 238 |
+ |
|
| 239 |
+ @pytest.mark.parametrize('config', ['xxx', 'null', '{"version": 255}'])
|
|
| 240 |
+ def test_401_decrypt_bucket_file_bad_json_or_version( |
|
| 241 |
+ self, |
|
| 242 |
+ monkeypatch: pytest.MonkeyPatch, |
|
| 243 |
+ config: str, |
|
| 244 |
+ ) -> None: |
|
| 245 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
| 246 |
+ master_keys: storeroom.MasterKeys = {
|
|
| 247 |
+ 'encryption_key': bytes(storeroom.KEY_SIZE), |
|
| 248 |
+ 'signing_key': bytes(storeroom.KEY_SIZE), |
|
| 249 |
+ 'hashing_key': bytes(storeroom.KEY_SIZE), |
|
| 250 |
+ } |
|
| 251 |
+ with ( |
|
| 252 |
+ tests.isolated_vault_exporter_config( |
|
| 253 |
+ monkeypatch=monkeypatch, |
|
| 254 |
+ runner=runner, |
|
| 255 |
+ vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED, |
|
| 256 |
+ ), |
|
| 257 |
+ ): |
|
| 258 |
+ with open('.vault/20', 'w', encoding='UTF-8') as outfile:
|
|
| 259 |
+ print(config, file=outfile) |
|
| 260 |
+ with pytest.raises(RuntimeError, match='Invalid bucket file: '): |
|
| 261 |
+ list(storeroom.decrypt_bucket_file('.vault/20', master_keys))
|
|
| 262 |
+ |
|
| 263 |
+ @pytest.mark.parametrize( |
|
| 264 |
+ ['data', 'err_msg'], |
|
| 265 |
+ [ |
|
| 266 |
+ ('{"version": 255}', 'bad or unsupported keys version header'),
|
|
| 267 |
+ ('{"version": 1}\nAAAA\nAAAA', 'trailing data; cannot make sense'),
|
|
| 268 |
+ ('{"version": 1}\nAAAA', 'cannot handle version 0 encrypted keys'),
|
|
| 269 |
+ ], |
|
| 270 |
+ ) |
|
| 271 |
+ def test_402_export_storeroom_data_bad_master_keys_file( |
|
| 272 |
+ self, |
|
| 273 |
+ monkeypatch: pytest.MonkeyPatch, |
|
| 274 |
+ data: str, |
|
| 275 |
+ err_msg: str, |
|
| 276 |
+ ) -> None: |
|
| 277 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
| 278 |
+ with ( |
|
| 279 |
+ tests.isolated_vault_exporter_config( |
|
| 280 |
+ monkeypatch=monkeypatch, |
|
| 281 |
+ runner=runner, |
|
| 282 |
+ vault_config=tests.VAULT_STOREROOM_CONFIG_ZIPPED, |
|
| 283 |
+ vault_key=tests.VAULT_MASTER_KEY, |
|
| 284 |
+ ), |
|
| 285 |
+ ): |
|
| 286 |
+ with open('.vault/.keys', 'w', encoding='UTF-8') as outfile:
|
|
| 287 |
+ print(data, file=outfile) |
|
| 288 |
+ with pytest.raises(RuntimeError, match=err_msg): |
|
| 289 |
+ storeroom.export_storeroom_data() |
|
| 290 |
+ |
|
| 291 |
+ def test_403_export_storeroom_data_bad_directory_listing( |
|
| 292 |
+ self, |
|
| 293 |
+ monkeypatch: pytest.MonkeyPatch, |
|
| 294 |
+ ) -> None: |
|
| 295 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
| 296 |
+ with ( |
|
| 297 |
+ tests.isolated_vault_exporter_config( |
|
| 298 |
+ monkeypatch=monkeypatch, |
|
| 299 |
+ runner=runner, |
|
| 300 |
+ vault_config=tests.VAULT_STOREROOM_BROKEN_DIR_CONFIG_ZIPPED, |
|
| 301 |
+ vault_key=tests.VAULT_MASTER_KEY, |
|
| 302 |
+ ), |
|
| 303 |
+ pytest.raises(RuntimeError, match='Object key mismatch'), |
|
| 304 |
+ ): |
|
| 305 |
+ storeroom.export_storeroom_data() |
|
| 197 | 306 |