Marco Ricci commited on 2024-09-29 23:27:27
Zeige 8 geänderte Dateien mit 67 Einfügungen und 85 Löschungen.
Now that (some) versions of `mkdocstrings-python` have support for [scoped crossreferences] [SCOPED], references to documented objects can be named like they would be in code. This leads to (Markdown) docstrings that are much more readable in source form than when having to type or re-type the fully qualified identifier name. [SCOPED]: https://github.com/mkdocstrings/python/issues/166
... | ... |
@@ -190,11 +190,10 @@ class SSH_AGENTC(enum.Enum): # noqa: N801 |
190 | 190 |
|
191 | 191 |
Attributes: |
192 | 192 |
REQUEST_IDENTITIES: |
193 |
- List identities. Expecting [`SSH_AGENT.IDENTITIES_ANSWER`] |
|
194 |
- [derivepassphrase._types.SSH_AGENT]. |
|
193 |
+ List identities. Expecting |
|
194 |
+ [`SSH_AGENT.IDENTITIES_ANSWER`][]. |
|
195 | 195 |
SIGN_REQUEST: |
196 |
- Sign data. Expecting [`SSH_AGENT.SIGN_RESPONSE`] |
|
197 |
- [derivepassphrase._types.SSH_AGENT]. |
|
196 |
+ Sign data. Expecting [`SSH_AGENT.SIGN_RESPONSE`][]. |
|
198 | 197 |
ADD_IDENTITY: |
199 | 198 |
Add an (SSH2) identity. |
200 | 199 |
REMOVE_IDENTITY: |
... | ... |
@@ -225,11 +224,9 @@ class SSH_AGENT(enum.Enum): # noqa: N801 |
225 | 224 |
SUCCESS: |
226 | 225 |
Generic success code. |
227 | 226 |
IDENTITIES_ANSWER: |
228 |
- Successful answer to [`SSH_AGENTC.REQUEST_IDENTITIES`] |
|
229 |
- [derivepassphrase._types.SSH_AGENTC]. |
|
227 |
+ Successful answer to [`SSH_AGENTC.REQUEST_IDENTITIES`][]. |
|
230 | 228 |
SIGN_RESPONSE: |
231 |
- Successful answer to [`SSH_AGENTC.SIGN_REQUEST`] |
|
232 |
- [derivepassphrase._types.SSH_AGENTC]. |
|
229 |
+ Successful answer to [`SSH_AGENTC.SIGN_REQUEST`][]. |
|
233 | 230 |
|
234 | 231 |
""" |
235 | 232 |
|
... | ... |
@@ -387,13 +387,11 @@ def _config_filename( |
387 | 387 |
def _load_config() -> _types.VaultConfig: |
388 | 388 |
"""Load a vault(1)-compatible config from the application directory. |
389 | 389 |
|
390 |
- The filename is obtained via |
|
391 |
- [`derivepassphrase.cli._config_filename`][]. This must be an |
|
392 |
- unencrypted JSON file. |
|
390 |
+ The filename is obtained via [`_config_filename`][]. This must be |
|
391 |
+ an unencrypted JSON file. |
|
393 | 392 |
|
394 | 393 |
Returns: |
395 |
- The vault settings. See |
|
396 |
- [`derivepassphrase._types.VaultConfig`][] for details. |
|
394 |
+ The vault settings. See [`_types.VaultConfig`][] for details. |
|
397 | 395 |
|
398 | 396 |
Raises: |
399 | 397 |
OSError: |
... | ... |
@@ -416,15 +414,14 @@ def _migrate_and_load_old_config() -> ( |
416 | 414 |
): |
417 | 415 |
"""Load and migrate a vault(1)-compatible config. |
418 | 416 |
|
419 |
- The (old) filename is obtained via |
|
420 |
- [`derivepassphrase.cli._config_filename`][]. This must be an |
|
421 |
- unencrypted JSON file. After loading, the file is migrated to the new |
|
422 |
- standard filename. |
|
417 |
+ The (old) filename is obtained via [`_config_filename`][]. This |
|
418 |
+ must be an unencrypted JSON file. After loading, the file is |
|
419 |
+ migrated to the new standard filename. |
|
423 | 420 |
|
424 | 421 |
Returns: |
425 | 422 |
The vault settings, and an optional exception encountered during |
426 |
- migration. See [`derivepassphrase._types.VaultConfig`][] for |
|
427 |
- details on the former. |
|
423 |
+ migration. See [`_types.VaultConfig`][] for details on the |
|
424 |
+ former. |
|
428 | 425 |
|
429 | 426 |
Raises: |
430 | 427 |
OSError: |
... | ... |
@@ -451,9 +448,8 @@ def _migrate_and_load_old_config() -> ( |
451 | 448 |
def _save_config(config: _types.VaultConfig, /) -> None: |
452 | 449 |
"""Save a vault(1)-compatible config to the application directory. |
453 | 450 |
|
454 |
- The filename is obtained via |
|
455 |
- [`derivepassphrase.cli._config_filename`][]. The config will be |
|
456 |
- stored as an unencrypted JSON file. |
|
451 |
+ The filename is obtained via [`_config_filename`][]. The config |
|
452 |
+ will be stored as an unencrypted JSON file. |
|
457 | 453 |
|
458 | 454 |
Args: |
459 | 455 |
config: |
... | ... |
@@ -485,7 +481,7 @@ def _get_suitable_ssh_keys( |
485 | 481 |
"""Yield all SSH keys suitable for passphrase derivation. |
486 | 482 |
|
487 | 483 |
Suitable SSH keys are queried from the running SSH agent (see |
488 |
- [`derivepassphrase.ssh_agent.SSHAgentClient.list_keys`][]). |
|
484 |
+ [`ssh_agent.SSHAgentClient.list_keys`][]). |
|
489 | 485 |
|
490 | 486 |
Args: |
491 | 487 |
conn: |
... | ... |
@@ -628,9 +624,8 @@ def _select_ssh_key( |
628 | 624 |
"""Interactively select an SSH key for passphrase derivation. |
629 | 625 |
|
630 | 626 |
Suitable SSH keys are queried from the running SSH agent (see |
631 |
- [`derivepassphrase.ssh_agent.SSHAgentClient.list_keys`][]), then the |
|
632 |
- user is prompted interactively (see [`click.prompt`][]) for |
|
633 |
- a selection. |
|
627 |
+ [`ssh_agent.SSHAgentClient.list_keys`][]), then the user is prompted |
|
628 |
+ interactively (see [`click.prompt`][]) for a selection. |
|
634 | 629 |
|
635 | 630 |
Args: |
636 | 631 |
conn: |
... | ... |
@@ -744,9 +739,8 @@ def _check_for_misleading_passphrase( |
744 | 739 |
class OptionGroupOption(click.Option): |
745 | 740 |
"""A [`click.Option`][] with an associated group name and group epilog. |
746 | 741 |
|
747 |
- Used by [`derivepassphrase.cli.CommandWithHelpGroups`][] to print |
|
748 |
- help sections. Each subclass contains its own group name and |
|
749 |
- epilog. |
|
742 |
+ Used by [`CommandWithHelpGroups`][] to print help sections. Each |
|
743 |
+ subclass contains its own group name and epilog. |
|
750 | 744 |
|
751 | 745 |
Attributes: |
752 | 746 |
option_group_name: |
... | ... |
@@ -759,7 +753,9 @@ class OptionGroupOption(click.Option): |
759 | 753 |
""" |
760 | 754 |
|
761 | 755 |
option_group_name: str = '' |
756 |
+ """""" |
|
762 | 757 |
epilog: str = '' |
758 |
+ """""" |
|
763 | 759 |
|
764 | 760 |
def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401 |
765 | 761 |
if self.__class__ == __class__: # type: ignore[name-defined] |
... | ... |
@@ -789,12 +785,12 @@ class CommandWithHelpGroups(click.Command): |
789 | 785 |
of the `formatter`. We list all options (like the base |
790 | 786 |
implementation), but grouped into sections according to the |
791 | 787 |
concrete [`click.Option`][] subclass being used. If the option |
792 |
- is an instance of some subclass `X` of |
|
793 |
- [`derivepassphrase.cli.OptionGroupOption`][], then the section |
|
794 |
- heading and the epilog are taken from `X.option_group_name` and |
|
795 |
- `X.epilog`; otherwise, the section heading is "Options" (or |
|
796 |
- "Other options" if there are other option groups) and the epilog |
|
797 |
- is empty. |
|
788 |
+ is an instance of some subclass of [`OptionGroupOption`][], then |
|
789 |
+ the section heading and the epilog are taken from the |
|
790 |
+ [`option_group_name`] [OptionGroupOption.option_group_name] and |
|
791 |
+ [`epilog`] [OptionGroupOption.epilog] attributes; otherwise, the |
|
792 |
+ section heading is "Options" (or "Other options" if there are |
|
793 |
+ other option groups) and the epilog is empty. |
|
798 | 794 |
|
799 | 795 |
Args: |
800 | 796 |
ctx: |
... | ... |
@@ -12,12 +12,11 @@ table entry is separately encrypted and authenticated. James Coglan |
12 | 12 |
designed this format to avoid concurrent write issues when updating or |
13 | 13 |
synchronizing the vault configuration with e.g. a cloud service. |
14 | 14 |
|
15 |
-The public interface is the |
|
16 |
-[`derivepassphrase.exporter.storeroom.export_storeroom_data`][] |
|
17 |
-function. Multiple *non-public* functions are additionally documented |
|
18 |
-here for didactical and educational reasons, but they are not part of |
|
19 |
-the module API, are subject to change without notice (including |
|
20 |
-removal), and should *not* be used or relied on. |
|
15 |
+The public interface is the [`export_storeroom_data`][] function. |
|
16 |
+Multiple *non-public* functions are additionally documented here for |
|
17 |
+didactical and educational reasons, but they are not part of the module |
|
18 |
+API, are subject to change without notice (including removal), and |
|
19 |
+should *not* be used or relied on. |
|
21 | 20 |
|
22 | 21 |
""" |
23 | 22 |
|
... | ... |
@@ -209,8 +208,7 @@ def decrypt_master_keys_data(data: bytes, keys: KeyPair) -> MasterKeys: |
209 | 208 |
keys: |
210 | 209 |
The encryption and signing keys for the master keys data. |
211 | 210 |
These should have previously been derived via the |
212 |
- [`derivepassphrase.exporter.storeroom.derive_master_keys_keys`][] |
|
213 |
- function. |
|
211 |
+ [`derive_master_keys_keys`][] function. |
|
214 | 212 |
|
215 | 213 |
Returns: |
216 | 214 |
The master encryption, signing and hashing keys. |
... | ... |
@@ -303,9 +301,7 @@ def decrypt_session_keys(data: bytes, master_keys: MasterKeys) -> KeyPair: |
303 | 301 |
The encrypted bucket item session key data. |
304 | 302 |
master_keys: |
305 | 303 |
The master keys. Presumably these have previously been |
306 |
- obtained via the |
|
307 |
- [`derivepassphrase.exporter.storeroom.decrypt_master_keys_data`][] |
|
308 |
- function. |
|
304 |
+ obtained via the [`decrypt_master_keys_data`][] function. |
|
309 | 305 |
|
310 | 306 |
Returns: |
311 | 307 |
The bucket item's encryption and signing keys. |
... | ... |
@@ -414,8 +410,7 @@ def decrypt_contents(data: bytes, session_keys: KeyPair) -> bytes: |
414 | 410 |
The encrypted bucket item payload data. |
415 | 411 |
session_keys: |
416 | 412 |
The bucket item's session keys. Presumably these have |
417 |
- previously been obtained via the |
|
418 |
- [`derivepassphrase.exporter.storeroom.decrypt_session_keys`][] |
|
413 |
+ previously been obtained via the [`decrypt_session_keys`][] |
|
419 | 414 |
function. |
420 | 415 |
|
421 | 416 |
Returns: |
... | ... |
@@ -494,9 +489,7 @@ def decrypt_bucket_item(bucket_item: bytes, master_keys: MasterKeys) -> bytes: |
494 | 489 |
The encrypted bucket item. |
495 | 490 |
master_keys: |
496 | 491 |
The master keys. Presumably these have previously been |
497 |
- obtained via the |
|
498 |
- [`derivepassphrase.exporter.storeroom.decrypt_master_keys_data`][] |
|
499 |
- function. |
|
492 |
+ obtained via the [`decrypt_master_keys_data`][] function. |
|
500 | 493 |
|
501 | 494 |
Returns: |
502 | 495 |
The decrypted bucket item. |
... | ... |
@@ -553,9 +546,7 @@ def decrypt_bucket_file( |
553 | 546 |
The bucket file's filename. |
554 | 547 |
master_keys: |
555 | 548 |
The master keys. Presumably these have previously been |
556 |
- obtained via the |
|
557 |
- [`derivepassphrase.exporter.storeroom.decrypt_master_keys_data`][] |
|
558 |
- function. |
|
549 |
+ obtained via the [`decrypt_master_keys_data`][] function. |
|
559 | 550 |
root_dir: |
560 | 551 |
The root directory of the data store. The filename is |
561 | 552 |
interpreted relatively to this directory. |
... | ... |
@@ -635,13 +626,12 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
635 | 626 |
Args: |
636 | 627 |
storeroom_path: |
637 | 628 |
Path to the storeroom; usually `~/.vault`. If not given, |
638 |
- then query [`derivepassphrase.exporter.get_vault_path`][] |
|
639 |
- for the value. |
|
629 |
+ then query [`exporter.get_vault_path`][] for the value. |
|
640 | 630 |
master_keys_key: |
641 | 631 |
Encryption key/password for the master keys, usually the |
642 | 632 |
username, or passed via the `VAULT_KEY` environment |
643 | 633 |
variable. If not given, then query |
644 |
- [`derivepassphrase.exporter.get_vault_key`][] for the value. |
|
634 |
+ [`exporter.get_vault_key`][] for the value. |
|
645 | 635 |
|
646 | 636 |
Returns: |
647 | 637 |
The full configuration, as stored in the storeroom. |
... | ... |
@@ -13,12 +13,11 @@ cryptographic weaknesses (API misuse of a key derivation function, and |
13 | 13 |
a low-entropy method of generating initialization vectors for CBC block |
14 | 14 |
encryption mode) and should thus be avoided if possible. |
15 | 15 |
|
16 |
-The public interface is the |
|
17 |
-[`derivepassphrase.exporter.vault_native.export_vault_native_data`][] |
|
18 |
-function. Multiple *non-public* classes are additionally documented |
|
19 |
-here for didactical and educational reasons, but they are not part of |
|
20 |
-the module API, are subject to change without notice (including |
|
21 |
-removal), and should *not* be used or relied on. |
|
16 |
+The public interface is the [`export_vault_native_data`][] function. |
|
17 |
+Multiple *non-public* classes are additionally documented here for |
|
18 |
+didactical and educational reasons, but they are not part of the module |
|
19 |
+API, are subject to change without notice (including removal), and |
|
20 |
+should *not* be used or relied on. |
|
22 | 21 |
|
23 | 22 |
""" |
24 | 23 |
|
... | ... |
@@ -108,8 +107,7 @@ class VaultNativeConfigParser(abc.ABC): |
108 | 107 |
password: |
109 | 108 |
The vault master key/master passphrase the file is |
110 | 109 |
encrypted with. Must be non-empty. See |
111 |
- [`derivepassphrase.exporter.get_vault_key`][] for |
|
112 |
- details. |
|
110 |
+ [`exporter.get_vault_key`][] for details. |
|
113 | 111 |
|
114 | 112 |
If this is a text string, then the UTF-8 encoding of the |
115 | 113 |
string is used as the binary password. |
... | ... |
@@ -403,8 +401,8 @@ def export_vault_native_data( |
403 | 401 |
contents: |
404 | 402 |
The binary encrypted contents of the vault configuration |
405 | 403 |
file. If not given, then query |
406 |
- [`derivepassphrase.exporter.get_vault_path`][] for the |
|
407 |
- correct filename and read the contents from there. |
|
404 |
+ [`exporter.get_vault_path`][] for the correct filename and |
|
405 |
+ read the contents from there. |
|
408 | 406 |
|
409 | 407 |
Note: On disk, these are usually stored in base64-encoded |
410 | 408 |
form, not in the "raw" form as needed here. |
... | ... |
@@ -412,7 +410,7 @@ def export_vault_native_data( |
412 | 410 |
Encryption key/password for the configuration file, usually |
413 | 411 |
the username, or passed via the `VAULT_KEY` environment |
414 | 412 |
variable. If not given, then query |
415 |
- [`derivepassphrase.exporter.get_vault_key`][] for the value. |
|
413 |
+ [`exporter.get_vault_key`][] for the value. |
|
416 | 414 |
try_formats: |
417 | 415 |
A sequence of formats to try out, in order. Each key must |
418 | 416 |
be one of `v0.2` or `v0.3`. |
... | ... |
@@ -14,8 +14,7 @@ deterministic, stateless password manager that recomputes passwords |
14 | 14 |
instead of storing them), and this reimplementation is used for |
15 | 15 |
a similar purpose. |
16 | 16 |
|
17 |
-The main API is the [`Sequin`] [derivepassphrase.sequin.Sequin] class, |
|
18 |
-which is thoroughly documented. |
|
17 |
+The main API is the [`Sequin`][] class, which is thoroughly documented. |
|
19 | 18 |
|
20 | 19 |
""" |
21 | 20 |
|
... | ... |
@@ -61,11 +61,13 @@ class SSHAgentClient: |
61 | 61 |
The main use case is requesting the agent sign some data, after |
62 | 62 |
checking that the necessary key is already loaded. |
63 | 63 |
|
64 |
- The main fleshed out methods are `list_keys` and `sign`, which |
|
65 |
- implement the `REQUEST_IDENTITIES` and `SIGN_REQUEST` requests. If |
|
66 |
- you *really* wanted to, there is enough infrastructure in place to |
|
67 |
- issue other requests as defined in the protocol---it's merely the |
|
68 |
- wrapper functions and the protocol numbers table that are missing. |
|
64 |
+ The main fleshed out methods are [`list_keys`][] and [`sign`][], |
|
65 |
+ which implement the [`REQUEST_IDENTITIES`] |
|
66 |
+ [_types.SSH_AGENTC.REQUEST_IDENTITIES] and [`SIGN_REQUEST`] |
|
67 |
+ [_types.SSH_AGENTC.SIGN_REQUEST] requests. If you *really* wanted |
|
68 |
+ to, there is enough infrastructure in place to issue other requests |
|
69 |
+ as defined in the protocol---it's merely the wrapper functions and |
|
70 |
+ the protocol numbers table that are missing. |
|
69 | 71 |
|
70 | 72 |
""" |
71 | 73 |
|
... | ... |
@@ -433,7 +435,7 @@ class SSHAgentClient: |
433 | 435 |
Args: |
434 | 436 |
key: |
435 | 437 |
The public SSH key to sign the payload with, in the same |
436 |
- format as returned by, e.g., the `list_keys` method. |
|
438 |
+ format as returned by, e.g., the [`list_keys`][] method. |
|
437 | 439 |
The corresponding private key must have previously been |
438 | 440 |
loaded into the agent to successfully issue a signature. |
439 | 441 |
payload: |
... | ... |
@@ -445,7 +447,7 @@ class SSHAgentClient: |
445 | 447 |
algorithms when signing with RSA keys. (No such |
446 | 448 |
real-world usage is currently implemented.) |
447 | 449 |
check_if_key_loaded: |
448 |
- If true, check beforehand (via `list_keys`) if the |
|
450 |
+ If true, check beforehand (via [`list_keys`][]) if the |
|
449 | 451 |
corresponding key has been loaded into the agent. |
450 | 452 |
|
451 | 453 |
Returns: |
... | ... |
@@ -34,10 +34,9 @@ class Vault: |
34 | 34 |
detail][ALGORITHM] in his blog post on said topic: A principally |
35 | 35 |
infinite bit stream is obtained by running a key-derivation function |
36 | 36 |
on the master passphrase and the service name, then this bit stream |
37 |
- is fed into a [Sequin][derivepassphrase.sequin.Sequin] to generate |
|
38 |
- random numbers in the correct range, and finally these random |
|
39 |
- numbers select passphrase characters until the desired length is |
|
40 |
- reached. |
|
37 |
+ is fed into a [sequin.Sequin][] to generate random numbers in the |
|
38 |
+ correct range, and finally these random numbers select passphrase |
|
39 |
+ characters until the desired length is reached. |
|
41 | 40 |
|
42 | 41 |
[vault]: https://www.npmjs.com/package/vault |
43 | 42 |
[ALGORITHM]: https://blog.jcoglan.com/2012/07/16/designing-vaults-generator-algorithm/ |
... | ... |
@@ -219,10 +218,10 @@ class Vault: |
219 | 218 |
) -> int: |
220 | 219 |
"""Estimate the sufficient hash length, given the current settings. |
221 | 220 |
|
222 |
- Using the entropy (via `_entropy`) and a safety factor, give an |
|
223 |
- initial estimate of the length to use for `create_hash` such |
|
224 |
- that using a `Sequin` with this hash will not exhaust it during |
|
225 |
- passphrase generation. |
|
221 |
+ Using the entropy (via [`_entropy`][]) and a safety factor, give |
|
222 |
+ an initial estimate of the length to use for [`create_hash`][] |
|
223 |
+ such that using a [`sequin.Sequin`][] with this hash will not |
|
224 |
+ exhaust it during passphrase generation. |
|
226 | 225 |
|
227 | 226 |
Args: |
228 | 227 |
safety_factor: The safety factor. Must be at least 1. |
229 | 228 |