Marco Ricci commited on 2024-12-30 21:34:42
Zeige 3 geänderte Dateien mit 747 Einfügungen und 114 Löschungen.
Add all help texts and metavars as translatable strings. Furthermore, add extra machinery for introspection to the serialized translatable strings class, which will make debugging values in pytest much easier. Add another couple of error messages (and update the manpages as well) for low-level errors while querying the SSH agent for the key list or while requesting a signature. (Previously, we forwarded the internal English exception message directly.) Update the manpage to include these as well.
... | ... |
@@ -50,24 +50,43 @@ |
50 | 50 |
. |
51 | 51 |
.Sh DESCRIPTION |
52 | 52 |
. |
53 |
-Using a master passphrase or a master |
|
54 |
-.Tn SSH |
|
55 |
-key, derive a passphrase for |
|
53 |
+Using a master passphrase, derive a passphrase for |
|
56 | 54 |
.Ar SERVICE , |
57 | 55 |
subject to length, character and character repetition constraints, in a |
58 | 56 |
manner compatible with James Coglan's |
59 | 57 |
.Xr vault 1 . |
60 | 58 |
.Pp |
61 | 59 |
. |
62 |
-The derivation is cryptographically strong, meaning that even if a single |
|
63 |
-passphrase is compromised, guessing the master passphrase or a different |
|
64 |
-service's passphrase is computationally infeasible. |
|
65 |
-The derivation is also deterministic, given the same inputs, thus the |
|
66 |
-resulting passphrase need not be stored explicitly. |
|
60 |
+The derivation is |
|
61 |
+.Em strong : |
|
62 |
+derived passphrases have as much entropy as permitted by the master |
|
63 |
+passphrase and the passphrase constraints (whichever is more restrictive), |
|
64 |
+and even if multiple derived passphrases are compromised, the master |
|
65 |
+passphrase remains cryptographically difficult to discern from theses |
|
66 |
+compromised passphrases. |
|
67 |
+The derivation is also |
|
68 |
+.Em deterministic , |
|
69 |
+given the same inputs, thus the resulting passphrase need not be stored |
|
70 |
+explicitly. |
|
67 | 71 |
.Pp |
68 | 72 |
. |
69 | 73 |
The service name and constraints themselves also need not be kept secret; |
70 |
-the latter are usually stored in a world-readable file. |
|
74 |
+the latter are usually stored in a world-readable file to ease repeated |
|
75 |
+entry of passphrase constraints. |
|
76 |
+.Pp |
|
77 |
+. |
|
78 |
+In lieu of a master passphrase, a master |
|
79 |
+.Tn SSH |
|
80 |
+key can also be used if there is a reachable, running |
|
81 |
+.Tn SSH |
|
82 |
+agent currently holding this key and if the key type is supported. |
|
83 |
+(See |
|
84 |
+.Sx "SSH KEY SUITABILITY" |
|
85 |
+and |
|
86 |
+.Sx BUGS |
|
87 |
+below.) |
|
88 |
+This too is compatible with |
|
89 |
+.Xr vault 1 . |
|
71 | 90 |
. |
72 | 91 |
.Sh OPTIONS |
73 | 92 |
. |
... | ... |
@@ -677,13 +696,37 @@ We cannot connect to the SSH agent indicated by the |
677 | 696 |
environment variable. |
678 | 697 |
Further details are contained in the variable part of the message. |
679 | 698 |
. |
680 |
-.It The SSH agent failed to complete the request |
|
681 |
-The SSH agent \(em while responsive in principle \(em failed to or refused |
|
682 |
-to supply a list of loaded keys. |
|
699 |
+.It The SSH agent failed to or refused to supply a list of loaded keys. |
|
700 |
+The SSH agent \(em while responsive in principle \(em did not fulfill the |
|
701 |
+request. |
|
702 |
+. |
|
703 |
+.It "The SSH agent failed to or refused to" "issue a signature with the selected key," "necessary for deriving a service passphrase." |
|
704 |
+The SSH agent \(em while responsive in principle \(em failed to cooperate with |
|
705 |
+deriving a service passphrase from the selected master |
|
706 |
+.Tn SSH |
|
707 |
+key. |
|
708 |
+. |
|
709 |
+.It The SSH agent contains no keys suitable for derivepassphrase. |
|
710 |
+. |
|
711 |
+None of the keys loaded into the |
|
712 |
+.Tn SSH |
|
713 |
+agent (if any) are suitable for use with |
|
714 |
+.Nm derivepassphrase vault . |
|
715 |
+See the |
|
716 |
+.Sx "SSH KEY SUITABILITY" |
|
717 |
+section for the requirements the |
|
718 |
+.Tn SSH |
|
719 |
+key and the |
|
720 |
+.Tn SSH |
|
721 |
+agent must fulfill to be suitable. |
|
683 | 722 |
. |
684 | 723 |
.It Error communicating with the SSH agent |
685 | 724 |
There was a system error communicating with the SSH agent. |
686 | 725 |
. |
726 |
+.It Cannot understand the SSH agent's response because it violates the communication protocol. |
|
727 |
+. |
|
728 |
+(Exactly what it says.) |
|
729 |
+. |
|
687 | 730 |
.It Not saving any new notes: the user aborted the request. |
688 | 731 |
(Exactly what it says.) |
689 | 732 |
. |
... | ... |
@@ -15,12 +15,14 @@ derivepassphrase-vault – derive a passphrase using the vault derivation scheme |
15 | 15 |
|
16 | 16 |
## DESCRIPTION |
17 | 17 |
|
18 |
-Using a master passphrase or a master SSH key, derive a passphrase for <var>SERVICE</var>, subject to length, character and character repetition constraints, in a manner compatible with James Coglan's <i>vault</i>(1). |
|
18 |
+Using a master passphrase, derive a passphrase for <var>SERVICE</var>, subject to length, character and character repetition constraints, in a manner compatible with James Coglan's <i>vault</i>(1). |
|
19 | 19 |
|
20 |
-The derivation is cryptographically strong, meaning that even if a single passphrase is compromised, guessing the master passphrase or a different service's passphrase is computationally infeasible. |
|
21 |
-The derivation is also deterministic, given the same inputs, thus the resulting passphrase need not be stored explicitly. |
|
20 |
+The derivation is <em>strong</em>: derived passphrases have as much entropy as permitted by the master passphrase and the passphrase constraints (whichever is more restrictive), and even if multiple derived passphrases are compromised, the master passphrase remains cryptographically difficult to discern from these compromised passphrases. |
|
21 |
+The derivation is also <em>deterministic</em>, given the same inputs, thus the resulting passphrase need not be stored explicitly. |
|
22 | 22 |
|
23 |
-The service name and constraints themselves also need not be kept secret; the latter are usually stored in a world-readable file. |
|
23 |
+The service name and constraints themselves also need not be kept secret; the latter are usually stored in a world-readable file to ease repeated entry of passphrase constraints. |
|
24 |
+ |
|
25 |
+In lieu of a master passphrase, a master SSH key can also be used if there is a reachable, running SSH agent currently holding this key and if the key type is supported. (See ["SSH KEY SUITABILITY"](#ssh-key-suitability) and ["BUGS"](#bugs) below.) This too is compatible with <i>vault</i>(1). |
|
24 | 26 |
|
25 | 27 |
## OPTIONS |
26 | 28 |
|
... | ... |
@@ -238,7 +240,7 @@ This is a property specific to the key type, and sometimes the agent used: |
238 | 240 |
|
239 | 241 |
## DIAGNOSTICS |
240 | 242 |
|
241 |
-The derivepassphrase vault utility exits 0 on success, and >0 if an error occurs. |
|
243 |
+The <b>derivepassphrase vault</b> utility exits 0 on success, and >0 if an error occurs. |
|
242 | 244 |
|
243 | 245 |
### Fatal error messsages on standard error |
244 | 246 |
|
... | ... |
@@ -314,14 +316,26 @@ The derivepassphrase vault utility exits 0 on success, and >0 if an error occurs |
314 | 316 |
We cannot connect to the SSH agent indicated by the `SSH_AUTH_SOCK` environment variable. |
315 | 317 |
Further details are contained in the variable part of the message. |
316 | 318 |
|
317 |
-??? failure "`The SSH agent failed to complete the request`" |
|
319 |
+??? failure "`The SSH agent failed to or refused to supply a list of loaded keys.`" |
|
320 |
+ |
|
321 |
+ The SSH agent---while responsive in principle---did not fulfill the request. |
|
322 |
+ |
|
323 |
+??? failure "`The SSH agent failed to or refused to issue a signature with the selected key, necessary for deriving a service passphrase.`" |
|
324 |
+ |
|
325 |
+ The SSH agent---while responsive in principle---failed to cooperate with deriving a service passphrase from the selected master SSH key. |
|
318 | 326 |
|
319 |
- The SSH agent---while responsive in principle---failed to or refused to supply a list of loaded keys. |
|
327 |
+??? failure "`The SSH agent contains no keys suitable for derivepassphrase.`" |
|
328 |
+ |
|
329 |
+ None of the keys loaded into the SSH agent (if any) are suitable for use with <b>derivepassphrase vault</b>. See the ["SSH KEY SUITABILITY"](#ssh-key-suitability) section for the requirements the SSH key and the SSH agent must fulfill to be suitable. |
|
320 | 330 |
|
321 | 331 |
??? failure "`Error communicating with the SSH agent`" |
322 | 332 |
|
323 | 333 |
There was a system error communicating with the SSH agent. |
324 | 334 |
|
335 |
+??? failure "`Cannot understand the SSH agent's response because it violates the communication protocol.`" |
|
336 |
+ |
|
337 |
+ (Exactly what it says.) |
|
338 |
+ |
|
325 | 339 |
??? failure "`Not saving any new notes: the user aborted the request.`" |
326 | 340 |
|
327 | 341 |
(Exactly what it says.) |
... | ... |
@@ -9,8 +9,9 @@ from __future__ import annotations |
9 | 9 |
import enum |
10 | 10 |
import gettext |
11 | 11 |
import inspect |
12 |
+import textwrap |
|
12 | 13 |
import types |
13 |
-from typing import TYPE_CHECKING, NamedTuple |
|
14 |
+from typing import TYPE_CHECKING, NamedTuple, cast |
|
14 | 15 |
|
15 | 16 |
import derivepassphrase as dpp |
16 | 17 |
|
... | ... |
@@ -44,8 +45,26 @@ def _prepare_translatable( |
44 | 45 |
*, |
45 | 46 |
flags: Iterable[str] = (), |
46 | 47 |
) -> TranslatableString: |
47 |
- msg = inspect.cleandoc(msg) |
|
48 |
- plural_msg = inspect.cleandoc(plural_msg) |
|
48 |
+ def maybe_rewrap(string: str) -> str: |
|
49 |
+ string = inspect.cleandoc(string) |
|
50 |
+ if not any(s.strip() == '\b' for s in string.splitlines()): |
|
51 |
+ string = '\n'.join( |
|
52 |
+ textwrap.wrap( |
|
53 |
+ string, |
|
54 |
+ width=float('inf'), # type: ignore[arg-type] |
|
55 |
+ fix_sentence_endings=True, |
|
56 |
+ ) |
|
57 |
+ ) |
|
58 |
+ else: # pragma: no cover |
|
59 |
+ string = ''.join( |
|
60 |
+ s |
|
61 |
+ for s in string.splitlines(True) # noqa: FBT003 |
|
62 |
+ if s.strip() == '\b' |
|
63 |
+ ) |
|
64 |
+ return string |
|
65 |
+ |
|
66 |
+ msg = maybe_rewrap(msg) |
|
67 |
+ plural_msg = maybe_rewrap(plural_msg) |
|
49 | 68 |
context = context.strip() |
50 | 69 |
comments = inspect.cleandoc(comments) |
51 | 70 |
flags = ( |
... | ... |
@@ -53,44 +72,73 @@ def _prepare_translatable( |
53 | 72 |
if not isinstance(flags, str) |
54 | 73 |
else frozenset({flags}) |
55 | 74 |
) |
56 |
- assert ( |
|
57 |
- '{' not in msg |
|
58 |
- or bool(flags & {'python-brace-format', 'no-python-brace-format'}) |
|
75 |
+ assert '{' not in msg or bool( |
|
76 |
+ flags & {'python-brace-format', 'no-python-brace-format'} |
|
59 | 77 |
), f'Missing flag for how to deal with brace in {msg!r}' |
60 |
- assert ( |
|
61 |
- '%' not in msg |
|
62 |
- or bool(flags & {'python-format', 'no-python-format'}) |
|
78 |
+ assert '%' not in msg or bool( |
|
79 |
+ flags & {'python-format', 'no-python-format'} |
|
63 | 80 |
), f'Missing flag for how to deal with percent character in {msg!r}' |
64 | 81 |
return TranslatableString(msg, plural_msg, context, comments, flags) |
65 | 82 |
|
66 | 83 |
|
67 |
-class LogObject: |
|
68 |
- |
|
84 |
+class TranslatedString: |
|
69 | 85 |
def __init__( |
70 | 86 |
self, |
71 |
- template: TranslatableString, |
|
87 |
+ template: ( |
|
88 |
+ str |
|
89 |
+ | TranslatableString |
|
90 |
+ | Label |
|
91 |
+ | InfoMsgTemplate |
|
92 |
+ | WarnMsgTemplate |
|
93 |
+ | ErrMsgTemplate |
|
94 |
+ ), |
|
72 | 95 |
args_dict: Mapping[str, Any] = types.MappingProxyType({}), |
73 | 96 |
/, |
74 | 97 |
**kwargs: Any, # noqa: ANN401 |
75 | 98 |
) -> None: |
99 |
+ if isinstance( |
|
100 |
+ template, (Label, InfoMsgTemplate, WarnMsgTemplate, ErrMsgTemplate) |
|
101 |
+ ): |
|
102 |
+ template = cast(TranslatableString, template.value) |
|
76 | 103 |
self.template = template |
77 | 104 |
self.kwargs = {**args_dict, **kwargs} |
78 | 105 |
self._rendered: str | None = None |
79 | 106 |
|
107 |
+ def __bool__(self) -> bool: |
|
108 |
+ return bool(str(self)) |
|
109 |
+ |
|
110 |
+ def __eq__(self, other: object) -> bool: # pragma: no cover |
|
111 |
+ return str(self) == other |
|
112 |
+ |
|
113 |
+ def __hash__(self) -> int: # pragma: no cover |
|
114 |
+ return hash(str(self)) |
|
115 |
+ |
|
116 |
+ def __repr__(self) -> str: # pragma: no cover |
|
117 |
+ return ( |
|
118 |
+ f'{self.__class__.__name__}({self.template!r}, ' |
|
119 |
+ f'{dict(self.kwargs)!r})' |
|
120 |
+ ) |
|
121 |
+ |
|
80 | 122 |
def __str__(self) -> str: |
81 | 123 |
if self._rendered is None: |
124 |
+ # raw str support is currently unneeded, so excluded from coverage |
|
125 |
+ if isinstance(self.template, str): # pragma: no cover |
|
126 |
+ context = None |
|
127 |
+ template = self.template |
|
128 |
+ else: |
|
82 | 129 |
context = self.template.l10n_context |
83 | 130 |
template = self.template.singular |
84 | 131 |
if context is not None: |
85 | 132 |
template = translation.pgettext(context, template) |
86 |
- else: |
|
133 |
+ else: # pragma: no cover |
|
87 | 134 |
template = translation.gettext(template) |
88 | 135 |
self._rendered = template.format(**self.kwargs) |
89 | 136 |
return self._rendered |
90 | 137 |
|
91 | 138 |
def maybe_without_filename(self) -> Self: |
92 | 139 |
if ( |
93 |
- self.kwargs.get('filename') is None |
|
140 |
+ not isinstance(self.template, str) |
|
141 |
+ and self.kwargs.get('filename') is None |
|
94 | 142 |
and ': {filename!r}' in self.template.singular |
95 | 143 |
): |
96 | 144 |
singular = ''.join( |
... | ... |
@@ -107,35 +155,487 @@ class LogObject: |
107 | 155 |
) |
108 | 156 |
return self |
109 | 157 |
|
110 |
- @classmethod |
|
111 |
- def InfoMsg( # noqa: N802 |
|
112 |
- cls, |
|
113 |
- msg_template: InfoMsgTemplate, |
|
114 |
- args_dict: Mapping[str, Any] = types.MappingProxyType({}), |
|
115 |
- /, |
|
116 |
- **kwargs: Any, # noqa: ANN401 |
|
117 |
- ) -> Self: |
|
118 |
- return cls(msg_template.value, {**args_dict, **kwargs}) |
|
119 | 158 |
|
120 |
- @classmethod |
|
121 |
- def WarnMsg( # noqa: N802 |
|
122 |
- cls, |
|
123 |
- msg_template: WarnMsgTemplate, |
|
124 |
- args_dict: Mapping[str, Any] = types.MappingProxyType({}), |
|
125 |
- /, |
|
126 |
- **kwargs: Any, # noqa: ANN401 |
|
127 |
- ) -> Self: |
|
128 |
- return cls(msg_template.value, {**args_dict, **kwargs}) |
|
159 |
+class Label(enum.Enum): |
|
160 |
+ DEPRECATION_WARNING_LABEL = _prepare_translatable( |
|
161 |
+ 'Deprecation warning', comments='', context='diagnostic label' |
|
162 |
+ ) |
|
163 |
+ WARNING_LABEL = _prepare_translatable( |
|
164 |
+ 'Warning', comments='', context='diagnostic label' |
|
165 |
+ ) |
|
166 |
+ DERIVEPASSPHRASE_01 = _prepare_translatable( |
|
167 |
+ msg=""" |
|
168 |
+ Derive a strong passphrase, deterministically, from a master secret. |
|
169 |
+ """, |
|
170 |
+ comments='', |
|
171 |
+ context='help text (long form)', |
|
172 |
+ ) |
|
173 |
+ DERIVEPASSPHRASE_02 = _prepare_translatable( |
|
174 |
+ msg=""" |
|
175 |
+ The currently implemented subcommands are "vault" (for the |
|
176 |
+ scheme used by vault) and "export" (for exporting foreign |
|
177 |
+ configuration data). See the respective `--help` output for |
|
178 |
+ instructions. If no subcommand is given, we default to "vault". |
|
179 |
+ """, |
|
180 |
+ comments='', |
|
181 |
+ context='help text (long form)', |
|
182 |
+ ) |
|
183 |
+ DERIVEPASSPHRASE_03 = _prepare_translatable( |
|
184 |
+ msg=""" |
|
185 |
+ Deprecation notice: Defaulting to "vault" is deprecated. |
|
186 |
+ Starting in v1.0, the subcommand must be specified explicitly. |
|
187 |
+ """, |
|
188 |
+ comments='', |
|
189 |
+ context='help text (long form)', |
|
190 |
+ ) |
|
191 |
+ DERIVEPASSPHRASE_EPILOG_01 = _prepare_translatable( |
|
192 |
+ msg=r""" |
|
193 |
+ Configuration is stored in a directory according to the |
|
194 |
+ `DERIVEPASSPHRASE_PATH` variable, which defaults to |
|
195 |
+ `~/.derivepassphrase` on UNIX-like systems and |
|
196 |
+ `C:\Users\<user>\AppData\Roaming\Derivepassphrase` on Windows. |
|
197 |
+ """, |
|
198 |
+ comments='', |
|
199 |
+ context='help text (long form)', |
|
200 |
+ ) |
|
201 |
+ DERIVEPASSPHRASE_EXPORT_01 = _prepare_translatable( |
|
202 |
+ msg=""" |
|
203 |
+ Export a foreign configuration to standard output. |
|
204 |
+ """, |
|
205 |
+ comments='', |
|
206 |
+ context='help text (long form)', |
|
207 |
+ ) |
|
208 |
+ DERIVEPASSPHRASE_EXPORT_02 = _prepare_translatable( |
|
209 |
+ msg=""" |
|
210 |
+ The only available subcommand is "vault", which implements the |
|
211 |
+ vault-native configuration scheme. If no subcommand is given, |
|
212 |
+ we default to "vault". |
|
213 |
+ """, |
|
214 |
+ comments='', |
|
215 |
+ context='help text (long form)', |
|
216 |
+ ) |
|
217 |
+ DERIVEPASSPHRASE_EXPORT_03 = DERIVEPASSPHRASE_03 |
|
218 |
+ DERIVEPASSPHRASE_EXPORT_VAULT_01 = _prepare_translatable( |
|
219 |
+ msg=""" |
|
220 |
+ Export a vault-native configuration to standard output. |
|
221 |
+ """, |
|
222 |
+ comments='', |
|
223 |
+ context='help text (long form)', |
|
224 |
+ ) |
|
225 |
+ DERIVEPASSPHRASE_EXPORT_VAULT_02 = _prepare_translatable( |
|
226 |
+ msg=""" |
|
227 |
+ Depending on the configuration format, {path_metavar!s} may |
|
228 |
+ either be a file or a directory. We support the vault "v0.2", |
|
229 |
+ "v0.3" and "storeroom" formats. |
|
230 |
+ """, |
|
231 |
+ comments='', |
|
232 |
+ context='help text (long form)', |
|
233 |
+ flags='python-brace-format', |
|
234 |
+ ) |
|
235 |
+ DERIVEPASSPHRASE_EXPORT_VAULT_03 = _prepare_translatable( |
|
236 |
+ msg=""" |
|
237 |
+ If {path_metavar!s} is explicitly given as `VAULT_PATH`, then |
|
238 |
+ use the `VAULT_PATH` environment variable to determine the |
|
239 |
+ correct path. (Use `./VAULT_PATH` or similar to indicate |
|
240 |
+ a file/directory actually named `VAULT_PATH`.) |
|
241 |
+ """, |
|
242 |
+ comments='', |
|
243 |
+ context='help text (long form)', |
|
244 |
+ flags='python-brace-format', |
|
245 |
+ ) |
|
246 |
+ DERIVEPASSPHRASE_VAULT_01 = _prepare_translatable( |
|
247 |
+ msg=""" |
|
248 |
+ Derive a passphrase using the vault derivation scheme. |
|
249 |
+ """, |
|
250 |
+ comments='', |
|
251 |
+ context='help text (long form)', |
|
252 |
+ ) |
|
253 |
+ DERIVEPASSPHRASE_VAULT_02 = _prepare_translatable( |
|
254 |
+ msg=""" |
|
255 |
+ If operating on global settings, or importing/exporting |
|
256 |
+ settings, then {service_metavar!s} must be omitted. Otherwise |
|
257 |
+ it is required. |
|
258 |
+ """, |
|
259 |
+ comments='', |
|
260 |
+ context='help text (long form)', |
|
261 |
+ flags='python-brace-format', |
|
262 |
+ ) |
|
263 |
+ DERIVEPASSPHRASE_VAULT_EPILOG_01 = _prepare_translatable( |
|
264 |
+ msg=""" |
|
265 |
+ WARNING: There is NO WAY to retrieve the generated passphrases |
|
266 |
+ if the master passphrase, the SSH key, or the exact passphrase |
|
267 |
+ settings are lost, short of trying out all possible |
|
268 |
+ combinations. You are STRONGLY advised to keep independent |
|
269 |
+ backups of the settings and the SSH key, if any. |
|
270 |
+ """, |
|
271 |
+ comments='', |
|
272 |
+ context='help text (long form)', |
|
273 |
+ ) |
|
274 |
+ DERIVEPASSPHRASE_VAULT_EPILOG_02 = _prepare_translatable( |
|
275 |
+ msg=""" |
|
276 |
+ The configuration is NOT encrypted, and you are STRONGLY |
|
277 |
+ discouraged from using a stored passphrase. |
|
278 |
+ """, |
|
279 |
+ comments='', |
|
280 |
+ context='help text (long form)', |
|
281 |
+ ) |
|
282 |
+ DEPRECATED_COMMAND_LABEL = _prepare_translatable( |
|
283 |
+ msg='(Deprecated) {text}', |
|
284 |
+ comments='', |
|
285 |
+ context='help text (long form, label)', |
|
286 |
+ flags='python-brace-format', |
|
287 |
+ ) |
|
288 |
+ DEBUG_OPTION_HELP_TEXT = _prepare_translatable( |
|
289 |
+ 'also emit debug information (implies --verbose)', |
|
290 |
+ comments='', |
|
291 |
+ context='help text (option one-line description)', |
|
292 |
+ ) |
|
293 |
+ EXPORT_VAULT_FORMAT_HELP_TEXT = _prepare_translatable( |
|
294 |
+ comments=r""" |
|
295 |
+ TRANSLATORS: The defaults_hint is the text in |
|
296 |
+ EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT, the metavar is in |
|
297 |
+ EXPORT_VAULT_FORMAT_METAVAR_FMT. |
|
298 |
+ """, |
|
299 |
+ msg=r""" |
|
300 |
+ try the following storage format {metavar!s}; may be |
|
301 |
+ specified multiple times, formats will be tried in order |
|
302 |
+ {defaults_hint!s} |
|
303 |
+ """, |
|
304 |
+ context='help text (option one-line description)', |
|
305 |
+ flags='python-brace-format', |
|
306 |
+ ) |
|
307 |
+ EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT = _prepare_translatable( |
|
308 |
+ comments=r""" |
|
309 |
+ TRANSLATORS: See EXPORT_VAULT_FORMAT_HELP_TEXT. The format |
|
310 |
+ names/labels "v0.3", "v0.2" and "storeroom" should not be |
|
311 |
+ translated. |
|
312 |
+ """, |
|
313 |
+ msg=r""" |
|
314 |
+ (default: v0.3, v0.2, storeroom) |
|
315 |
+ """, |
|
316 |
+ context='help text (option one-line description)', |
|
317 |
+ ) |
|
318 |
+ EXPORT_VAULT_KEY_HELP_TEXT = _prepare_translatable( |
|
319 |
+ comments=r""" |
|
320 |
+ TRANSLATORS: The defaults_hint is the text in |
|
321 |
+ EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT, the metavar is in |
|
322 |
+ EXPORT_VAULT_KEY_METAVAR_K. |
|
323 |
+ """, |
|
324 |
+ msg=r""" |
|
325 |
+ use {metavar!s} as the storage master key {defaults_hint!s} |
|
326 |
+ """, |
|
327 |
+ context='help text (option one-line description)', |
|
328 |
+ flags='python-brace-format', |
|
329 |
+ ) |
|
330 |
+ EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT = _prepare_translatable( |
|
331 |
+ comments=r""" |
|
332 |
+ TRANSLATORS: See EXPORT_VAULT_KEY_HELP_TEXT. |
|
333 |
+ """, |
|
334 |
+ msg=r""" |
|
335 |
+ (default: check the `VAULT_KEY`, `LOGNAME`, `USER`, or |
|
336 |
+ `USERNAME` environment variables) |
|
337 |
+ """, |
|
338 |
+ context='help text (option one-line description)', |
|
339 |
+ ) |
|
340 |
+ QUIET_OPTION_HELP_TEXT = _prepare_translatable( |
|
341 |
+ 'suppress even warnings, emit only errors', |
|
342 |
+ comments='', |
|
343 |
+ context='help text (option one-line description)', |
|
344 |
+ ) |
|
345 |
+ VERBOSE_OPTION_HELP_TEXT = _prepare_translatable( |
|
346 |
+ 'emit extra/progress information to standard error', |
|
347 |
+ comments='', |
|
348 |
+ context='help text (option one-line description)', |
|
349 |
+ ) |
|
129 | 350 |
|
130 |
- @classmethod |
|
131 |
- def ErrMsg( # noqa: N802 |
|
132 |
- cls, |
|
133 |
- msg_template: ErrMsgTemplate, |
|
134 |
- args_dict: Mapping[str, Any] = types.MappingProxyType({}), |
|
135 |
- /, |
|
136 |
- **kwargs: Any, # noqa: ANN401 |
|
137 |
- ) -> Self: |
|
138 |
- return cls(msg_template.value, {**args_dict, **kwargs}) |
|
351 |
+ DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT = _prepare_translatable( |
|
352 |
+ msg='prompt for a master passphrase', |
|
353 |
+ comments='', |
|
354 |
+ context='help text (option one-line description)', |
|
355 |
+ ) |
|
356 |
+ DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT = _prepare_translatable( |
|
357 |
+ msg='select a suitable SSH key from the SSH agent', |
|
358 |
+ comments='', |
|
359 |
+ context='help text (option one-line description)', |
|
360 |
+ ) |
|
361 |
+ DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT = _prepare_translatable( |
|
362 |
+ comments=r""" |
|
363 |
+ TRANSLATORS: The metavar is specified in |
|
364 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
365 |
+ """, |
|
366 |
+ msg='ensure a passphrase length of {metavar!s} characters', |
|
367 |
+ context='help text (option one-line description)', |
|
368 |
+ flags='python-brace-format', |
|
369 |
+ ) |
|
370 |
+ DERIVEPASSPHRASE_VAULT_REPEAT_HELP_TEXT = _prepare_translatable( |
|
371 |
+ comments=r""" |
|
372 |
+ TRANSLATORS: The metavar is specified in |
|
373 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
374 |
+ """, |
|
375 |
+ msg='forbid any run of {metavar!s} identical characters', |
|
376 |
+ context='help text (option one-line description)', |
|
377 |
+ flags='python-brace-format', |
|
378 |
+ ) |
|
379 |
+ DERIVEPASSPHRASE_VAULT_LOWER_HELP_TEXT = _prepare_translatable( |
|
380 |
+ comments=r""" |
|
381 |
+ TRANSLATORS: The metavar is specified in |
|
382 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
383 |
+ """, |
|
384 |
+ msg='ensure at least {metavar!s} lowercase characters', |
|
385 |
+ context='help text (option one-line description)', |
|
386 |
+ flags='python-brace-format', |
|
387 |
+ ) |
|
388 |
+ DERIVEPASSPHRASE_VAULT_UPPER_HELP_TEXT = _prepare_translatable( |
|
389 |
+ comments=r""" |
|
390 |
+ TRANSLATORS: The metavar is specified in |
|
391 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
392 |
+ """, |
|
393 |
+ msg='ensure at least {metavar!s} uppercase characters', |
|
394 |
+ context='help text (option one-line description)', |
|
395 |
+ flags='python-brace-format', |
|
396 |
+ ) |
|
397 |
+ DERIVEPASSPHRASE_VAULT_NUMBER_HELP_TEXT = _prepare_translatable( |
|
398 |
+ comments=r""" |
|
399 |
+ TRANSLATORS: The metavar is specified in |
|
400 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
401 |
+ """, |
|
402 |
+ msg='ensure at least {metavar!s} digits', |
|
403 |
+ context='help text (option one-line description)', |
|
404 |
+ flags='python-brace-format', |
|
405 |
+ ) |
|
406 |
+ DERIVEPASSPHRASE_VAULT_SPACE_HELP_TEXT = _prepare_translatable( |
|
407 |
+ comments=r""" |
|
408 |
+ TRANSLATORS: The metavar is specified in |
|
409 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
410 |
+ """, |
|
411 |
+ msg='ensure at least {metavar!s} spaces', |
|
412 |
+ context='help text (option one-line description)', |
|
413 |
+ flags='python-brace-format', |
|
414 |
+ ) |
|
415 |
+ DERIVEPASSPHRASE_VAULT_DASH_HELP_TEXT = _prepare_translatable( |
|
416 |
+ comments=r""" |
|
417 |
+ TRANSLATORS: The metavar is specified in |
|
418 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
419 |
+ """, |
|
420 |
+ msg='ensure at least {metavar!s} "-" or "_" characters', |
|
421 |
+ context='help text (option one-line description)', |
|
422 |
+ flags='python-brace-format', |
|
423 |
+ ) |
|
424 |
+ DERIVEPASSPHRASE_VAULT_SYMBOL_HELP_TEXT = _prepare_translatable( |
|
425 |
+ comments=r""" |
|
426 |
+ TRANSLATORS: The metavar is specified in |
|
427 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
428 |
+ """, |
|
429 |
+ msg='ensure at least {metavar!s} symbol characters', |
|
430 |
+ context='help text (option one-line description)', |
|
431 |
+ flags='python-brace-format', |
|
432 |
+ ) |
|
433 |
+ |
|
434 |
+ DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT = _prepare_translatable( |
|
435 |
+ msg='spawn an editor to edit notes for {service_metavar!s}', |
|
436 |
+ comments='', |
|
437 |
+ context='help text (option one-line description)', |
|
438 |
+ flags='python-brace-format', |
|
439 |
+ ) |
|
440 |
+ DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT = _prepare_translatable( |
|
441 |
+ msg='save the given settings for {service_metavar!s}, or global', |
|
442 |
+ comments='', |
|
443 |
+ context='help text (option one-line description)', |
|
444 |
+ flags='python-brace-format', |
|
445 |
+ ) |
|
446 |
+ DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT = _prepare_translatable( |
|
447 |
+ msg='delete the settings for {service_metavar!s}', |
|
448 |
+ comments='', |
|
449 |
+ context='help text (option one-line description)', |
|
450 |
+ flags='python-brace-format', |
|
451 |
+ ) |
|
452 |
+ DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT = _prepare_translatable( |
|
453 |
+ msg='delete the global settings', |
|
454 |
+ comments='', |
|
455 |
+ context='help text (option one-line description)', |
|
456 |
+ ) |
|
457 |
+ DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT = _prepare_translatable( |
|
458 |
+ msg='delete all settings', |
|
459 |
+ comments='', |
|
460 |
+ context='help text (option one-line description)', |
|
461 |
+ ) |
|
462 |
+ DERIVEPASSPHRASE_VAULT_EXPORT_HELP_TEXT = _prepare_translatable( |
|
463 |
+ comments=""" |
|
464 |
+ TRANSLATORS: The metavar is specified in |
|
465 |
+ STORAGE_MANAGEMENT_METAVAR_SERVICE. |
|
466 |
+ """, |
|
467 |
+ msg='export all saved settings to {metavar!s}', |
|
468 |
+ context='help text (option one-line description)', |
|
469 |
+ flags='python-brace-format', |
|
470 |
+ ) |
|
471 |
+ DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT = _prepare_translatable( |
|
472 |
+ comments=""" |
|
473 |
+ TRANSLATORS: The metavar is specified in |
|
474 |
+ STORAGE_MANAGEMENT_METAVAR_SERVICE. |
|
475 |
+ """, |
|
476 |
+ msg='import saved settings from {metavar!s}', |
|
477 |
+ context='help text (option one-line description)', |
|
478 |
+ flags='python-brace-format', |
|
479 |
+ ) |
|
480 |
+ DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT = _prepare_translatable( |
|
481 |
+ comments=""" |
|
482 |
+ TRANSLATORS: The corresponding option is displayed as |
|
483 |
+ "--overwrite-existing / --merge-existing", so you may want to |
|
484 |
+ hint that the default (merge) is the second of those options. |
|
485 |
+ """, |
|
486 |
+ msg='overwrite or merge (default) the existing configuration', |
|
487 |
+ context='help text (option one-line description)', |
|
488 |
+ flags='python-brace-format', |
|
489 |
+ ) |
|
490 |
+ DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT = _prepare_translatable( |
|
491 |
+ comments=""" |
|
492 |
+ TRANSLATORS: The corresponding option is displayed as |
|
493 |
+ "--unset=phrase|key|...|symbol", so the "given setting" is |
|
494 |
+ referring to "phrase", "key", "lower", ..., or "symbol", |
|
495 |
+ respectively. "with --config" here means that the user must |
|
496 |
+ also specify "--config" for this option to have any effect. |
|
497 |
+ """, |
|
498 |
+ msg=""" |
|
499 |
+ with --config, also unsets the given setting; may be specified |
|
500 |
+ multiple times |
|
501 |
+ """, |
|
502 |
+ context='help text (option one-line description)', |
|
503 |
+ ) |
|
504 |
+ DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT = _prepare_translatable( |
|
505 |
+ comments=""" |
|
506 |
+ TRANSLATORS: The corresponding option is displayed as |
|
507 |
+ "--export-as=json|sh", so json refers to the JSON format |
|
508 |
+ (default) and sh refers to the POSIX sh format. |
|
509 |
+ """, |
|
510 |
+ msg='when exporting, export as JSON (default) or POSIX sh', |
|
511 |
+ context='help text (option one-line description)', |
|
512 |
+ ) |
|
513 |
+ |
|
514 |
+ EXPORT_VAULT_FORMAT_METAVAR_FMT = _prepare_translatable( |
|
515 |
+ msg='FMT', |
|
516 |
+ comments='', |
|
517 |
+ context='help text, metavar (export vault subcommand)', |
|
518 |
+ ) |
|
519 |
+ EXPORT_VAULT_KEY_METAVAR_K = _prepare_translatable( |
|
520 |
+ comments=r""" |
|
521 |
+ TRANSLATORS: See EXPORT_VAULT_KEY_HELP_TEXT. |
|
522 |
+ """, |
|
523 |
+ msg='K', |
|
524 |
+ context='help text, metavar (export vault subcommand)', |
|
525 |
+ ) |
|
526 |
+ EXPORT_VAULT_METAVAR_PATH = _prepare_translatable( |
|
527 |
+ comments=r""" |
|
528 |
+ TRANSLATORS: This metavar is also used in multiple one-line help |
|
529 |
+ texts, as "path_metavar". |
|
530 |
+ """, |
|
531 |
+ msg='PATH', |
|
532 |
+ context='help text, metavar (export vault subcommand)', |
|
533 |
+ ) |
|
534 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER = _prepare_translatable( |
|
535 |
+ comments=r""" |
|
536 |
+ TRANSLATORS: This metavar is also used in a matching epilog. |
|
537 |
+ """, |
|
538 |
+ msg='NUMBER', |
|
539 |
+ context='help text, metavar (passphrase generation group)', |
|
540 |
+ ) |
|
541 |
+ STORAGE_MANAGEMENT_METAVAR_PATH = _prepare_translatable( |
|
542 |
+ comments=r""" |
|
543 |
+ TRANSLATORS: This metavar is also used in multiple one-line help |
|
544 |
+ texts. |
|
545 |
+ """, |
|
546 |
+ msg='NUMBER', |
|
547 |
+ context='help text, metavar (storage management group)', |
|
548 |
+ ) |
|
549 |
+ VAULT_METAVAR_SERVICE = _prepare_translatable( |
|
550 |
+ comments=r""" |
|
551 |
+ TRANSLATORS: This metavar is also used in multiple one-line help |
|
552 |
+ texts, as "service_metavar". |
|
553 |
+ """, |
|
554 |
+ msg='SERVICE', |
|
555 |
+ context='help text, metavar (vault subcommand)', |
|
556 |
+ ) |
|
557 |
+ CONFIGURATION_EPILOG = _prepare_translatable( |
|
558 |
+ 'Use $VISUAL or $EDITOR to configure the spawned editor.', |
|
559 |
+ comments='', |
|
560 |
+ context='help text, option group epilog (configuration group)', |
|
561 |
+ ) |
|
562 |
+ PASSPHRASE_GENERATION_EPILOG = _prepare_translatable( |
|
563 |
+ comments=r""" |
|
564 |
+ TRANSLATORS: The metavar is specified in |
|
565 |
+ PASSPHRASE_GENERATION_METAVAR_NUMBER. |
|
566 |
+ """, |
|
567 |
+ msg=r""" |
|
568 |
+ Use {metavar!s}=0 to exclude a character type from the output. |
|
569 |
+ """, |
|
570 |
+ context='help text, option group epilog (passphrase generation group)', |
|
571 |
+ flags='python-brace-format', |
|
572 |
+ ) |
|
573 |
+ STORAGE_MANAGEMENT_EPILOG = _prepare_translatable( |
|
574 |
+ comments=r""" |
|
575 |
+ TRANSLATORS: The metavar is specified in |
|
576 |
+ STORAGE_MANAGEMENT_METAVAR_PATH. |
|
577 |
+ """, |
|
578 |
+ msg=r""" |
|
579 |
+ Using "-" as {metavar!s} for standard input/standard output |
|
580 |
+ is supported. |
|
581 |
+ """, |
|
582 |
+ context='help text, option group epilog (storage management group)', |
|
583 |
+ flags='python-brace-format', |
|
584 |
+ ) |
|
585 |
+ COMMANDS_LABEL = _prepare_translatable( |
|
586 |
+ 'Commands', comments='', context='help text, option group name' |
|
587 |
+ ) |
|
588 |
+ COMPATIBILITY_OPTION_LABEL = _prepare_translatable( |
|
589 |
+ 'Compatibility and extension options', |
|
590 |
+ comments='', |
|
591 |
+ context='help text, option group name', |
|
592 |
+ ) |
|
593 |
+ CONFIGURATION_LABEL = _prepare_translatable( |
|
594 |
+ 'Configuration', comments='', context='help text, option group name' |
|
595 |
+ ) |
|
596 |
+ LOGGING_LABEL = _prepare_translatable( |
|
597 |
+ 'Logging', comments='', context='help text, option group name' |
|
598 |
+ ) |
|
599 |
+ OPTIONS_LABEL = _prepare_translatable( |
|
600 |
+ 'Options', comments='', context='help text, option group name' |
|
601 |
+ ) |
|
602 |
+ OTHER_OPTIONS_LABEL = _prepare_translatable( |
|
603 |
+ 'Other options', comments='', context='help text, option group name' |
|
604 |
+ ) |
|
605 |
+ PASSPHRASE_GENERATION_LABEL = _prepare_translatable( |
|
606 |
+ 'Passphrase generation', |
|
607 |
+ comments='', |
|
608 |
+ context='help text, option group name', |
|
609 |
+ ) |
|
610 |
+ STORAGE_MANAGEMENT_LABEL = _prepare_translatable( |
|
611 |
+ 'Storage management', |
|
612 |
+ comments='', |
|
613 |
+ context='help text, option group name', |
|
614 |
+ ) |
|
615 |
+ CONFIRM_THIS_CHOICE_PROMPT_TEXT = _prepare_translatable( |
|
616 |
+ comments=r""" |
|
617 |
+ TRANSLATORS: There is no support for "yes" or "no" in other |
|
618 |
+ languages than English, so it is advised that your translation |
|
619 |
+ makes it clear that only the strings "y", "yes", "n" or "no" are |
|
620 |
+ supported, even if the prompt becomes a bit longer. |
|
621 |
+ """, |
|
622 |
+ msg='Confirm this choice? (y/N)', |
|
623 |
+ context='interactive prompt', |
|
624 |
+ ) |
|
625 |
+ SUITABLE_SSH_KEYS_LABEL = _prepare_translatable( |
|
626 |
+ comments=r""" |
|
627 |
+ TRANSLATORS: This label is the heading of the list of suitable |
|
628 |
+ SSH keys. |
|
629 |
+ """, |
|
630 |
+ msg='Suitable SSH keys:', |
|
631 |
+ context='interactive prompt', |
|
632 |
+ ) |
|
633 |
+ YOUR_SELECTION_PROMPT_TEXT = _prepare_translatable( |
|
634 |
+ 'Your selection? (1-{n}, leave empty to abort)', |
|
635 |
+ comments='', |
|
636 |
+ context='interactive prompt', |
|
637 |
+ flags='python-brace-format', |
|
638 |
+ ) |
|
139 | 639 |
|
140 | 640 |
|
141 | 641 |
class InfoMsgTemplate(enum.Enum): |
... | ... |
@@ -176,20 +676,25 @@ class InfoMsgTemplate(enum.Enum): |
176 | 676 |
|
177 | 677 |
class WarnMsgTemplate(enum.Enum): |
178 | 678 |
EMPTY_SERVICE_NOT_SUPPORTED = _prepare_translatable( |
179 |
- 'An empty SERVICE is not supported by vault(1). ' |
|
180 |
- 'For compatibility, this will be treated as if SERVICE was not ' |
|
181 |
- 'supplied, i.e., it will error out, or operate on global settings.', |
|
182 | 679 |
comments='', |
680 |
+ msg=""" |
|
681 |
+ An empty {service_metavar!s} is not supported by vault(1). |
|
682 |
+ For compatibility, this will be treated as if SERVICE was not |
|
683 |
+ supplied, i.e., it will error out, or operate on global settings. |
|
684 |
+ """, |
|
183 | 685 |
context='warning message', |
686 |
+ flags='python-brace-format', |
|
184 | 687 |
) |
185 | 688 |
EMPTY_SERVICE_SETTINGS_INACCESSIBLE = _prepare_translatable( |
186 |
- f'An empty SERVICE is not supported by vault(1). ' |
|
187 |
- f'The empty-string service settings will be ' |
|
188 |
- f'inaccessible and ineffective. ' |
|
189 |
- f'To ensure that vault(1) and {PROG_NAME!s} see the settings, ' |
|
190 |
- f'move them into the "global" section.', |
|
689 |
+ msg=""" |
|
690 |
+ An empty {service_metavar!s} is not supported by vault(1). |
|
691 |
+ The empty-string service settings will be inaccessible and |
|
692 |
+ ineffective. To ensure that vault(1) and {PROG_NAME!s} see the |
|
693 |
+ settings, move them into the "global" section. |
|
694 |
+ """, |
|
191 | 695 |
comments='', |
192 | 696 |
context='warning message', |
697 |
+ flags='python-brace-format', |
|
193 | 698 |
) |
194 | 699 |
FAILED_TO_MIGRATE_CONFIG = _prepare_translatable( |
195 | 700 |
comments=r""" |
... | ... |
@@ -201,8 +706,10 @@ class WarnMsgTemplate(enum.Enum): |
201 | 706 |
flags='python-brace-format', |
202 | 707 |
) |
203 | 708 |
GLOBAL_PASSPHRASE_INEFFECTIVE = _prepare_translatable( |
204 |
- 'Setting a global passphrase is ineffective ' |
|
205 |
- 'because a key is also set.', |
|
709 |
+ msg=r""" |
|
710 |
+ Setting a global passphrase is ineffective |
|
711 |
+ because a key is also set. |
|
712 |
+ """, |
|
206 | 713 |
comments='', |
207 | 714 |
context='warning message', |
208 | 715 |
) |
... | ... |
@@ -219,11 +726,12 @@ class WarnMsgTemplate(enum.Enum): |
219 | 726 |
any other appropriate way to mark up emphasis of the word |
220 | 727 |
"displays". |
221 | 728 |
""", |
222 |
- msg='The {key!s} passphrase is not {form!s}-normalized. ' |
|
223 |
- 'Its serialization as a byte string may not be what you ' |
|
224 |
- 'expect it to be, even if it *displays* correctly. ' |
|
225 |
- 'Please make sure to double-check any derived ' |
|
226 |
- 'passphrases for unexpected results.', |
|
729 |
+ msg=r""" |
|
730 |
+ The {key!s} passphrase is not {form!s}-normalized. Its |
|
731 |
+ serialization as a byte string may not be what you expect it to |
|
732 |
+ be, even if it *displays* correctly. Please make sure to |
|
733 |
+ double-check any derived passphrases for unexpected results. |
|
734 |
+ """, |
|
227 | 735 |
context='warning message', |
228 | 736 |
flags='python-brace-format', |
229 | 737 |
) |
... | ... |
@@ -232,8 +740,10 @@ class WarnMsgTemplate(enum.Enum): |
232 | 740 |
TRANSLATORS: The key that is set need not necessarily be set at |
233 | 741 |
the service level; it may be a global key as well. |
234 | 742 |
""", |
235 |
- msg='Setting a service passphrase is ineffective ' |
|
236 |
- 'because a key is also set: {service!s}.', |
|
743 |
+ msg=r""" |
|
744 |
+ Setting a service passphrase is ineffective because a key is |
|
745 |
+ also set: {service!s}. |
|
746 |
+ """, |
|
237 | 747 |
context='warning message', |
238 | 748 |
flags='python-brace-format', |
239 | 749 |
) |
... | ... |
@@ -250,9 +760,11 @@ class WarnMsgTemplate(enum.Enum): |
250 | 760 |
flags='python-brace-format', |
251 | 761 |
) |
252 | 762 |
V01_STYLE_CONFIG = _prepare_translatable( |
253 |
- 'Using deprecated v0.1-style config file {old!r}, ' |
|
254 |
- 'instead of v0.2-style {new!r}. ' |
|
255 |
- 'Support for v0.1-style config filenames will be removed in v1.0.', |
|
763 |
+ msg=r""" |
|
764 |
+ Using deprecated v0.1-style config file {old!r}, instead of |
|
765 |
+ v0.2-style {new!r}. Support for v0.1-style config filenames |
|
766 |
+ will be removed in v1.0., |
|
767 |
+ """, |
|
256 | 768 |
comments='', |
257 | 769 |
context='deprecation warning message', |
258 | 770 |
flags='python-brace-format', |
... | ... |
@@ -264,14 +776,36 @@ class WarnMsgTemplate(enum.Enum): |
264 | 776 |
sub-subcommands, or sub-sub-subcommands, etc., which is what the |
265 | 777 |
"here" is supposed to indicate. |
266 | 778 |
""", |
267 |
- msg='A subcommand will be required here in v1.0. ' |
|
268 |
- 'See --help for available subcommands. ' |
|
269 |
- 'Defaulting to subcommand "vault".', |
|
779 |
+ msg=""" |
|
780 |
+ A subcommand will be required here in v1.0. See --help for |
|
781 |
+ available subcommands. Defaulting to subcommand "vault". |
|
782 |
+ """, |
|
270 | 783 |
context='deprecation warning message', |
271 | 784 |
) |
272 | 785 |
|
273 | 786 |
|
274 | 787 |
class ErrMsgTemplate(enum.Enum): |
788 |
+ AGENT_REFUSED_LIST_KEYS = _prepare_translatable( |
|
789 |
+ comments=r""" |
|
790 |
+ TRANSLATORS: "loaded keys" being keys loaded into the agent. |
|
791 |
+ """, |
|
792 |
+ msg=""" |
|
793 |
+ The SSH agent failed to or refused to supply a list of loaded keys. |
|
794 |
+ """, |
|
795 |
+ context='error message', |
|
796 |
+ ) |
|
797 |
+ AGENT_REFUSED_SIGNATURE = _prepare_translatable( |
|
798 |
+ comments=r""" |
|
799 |
+ TRANSLATORS: The message to be signed is the vault UUID, but |
|
800 |
+ there's no space to explain that here, so ideally the error |
|
801 |
+ message does not go into detail. |
|
802 |
+ """, |
|
803 |
+ msg=""" |
|
804 |
+ The SSH agent failed to or refused to issue a signature with the |
|
805 |
+ selected key, necessary for deriving a service passphrase. |
|
806 |
+ """, |
|
807 |
+ context='error message', |
|
808 |
+ ) |
|
275 | 809 |
CANNOT_CONNECT_TO_AGENT = _prepare_translatable( |
276 | 810 |
comments=r""" |
277 | 811 |
TRANSLATORS: The error message is usually supplied by the |
... | ... |
@@ -332,8 +866,10 @@ class ErrMsgTemplate(enum.Enum): |
332 | 866 |
warning message potentially multiple times, and this error |
333 | 867 |
message at the very bottom. |
334 | 868 |
""", |
335 |
- msg='Cannot parse {path!r} as a valid vault-native ' |
|
336 |
- 'configuration file/directory.', |
|
869 |
+ msg=r""" |
|
870 |
+ Cannot parse {path!r} as a valid vault-native configuration |
|
871 |
+ file/directory. |
|
872 |
+ """, |
|
337 | 873 |
context='error message', |
338 | 874 |
flags='python-brace-format', |
339 | 875 |
) |
... | ... |
@@ -346,15 +882,42 @@ class ErrMsgTemplate(enum.Enum): |
346 | 882 |
context='error message', |
347 | 883 |
flags='python-brace-format', |
348 | 884 |
) |
885 |
+ CANNOT_UNDERSTAND_AGENT = _prepare_translatable( |
|
886 |
+ comments=r""" |
|
887 |
+ TRANSLATORS: This error message is used whenever we cannot make |
|
888 |
+ any sense of a response from the SSH agent because the response |
|
889 |
+ is ill-formed (truncated, improperly encoded, etc.) or otherwise |
|
890 |
+ violates the communications protocol. Well-formed responses |
|
891 |
+ that adhere to the protocol, even if they indicate that the |
|
892 |
+ requested operation failed, are handled with a different error |
|
893 |
+ message. |
|
894 |
+ """, |
|
895 |
+ msg=""" |
|
896 |
+ Cannot understand the SSH agent's response because it violates |
|
897 |
+ the communications protocol. |
|
898 |
+ """, |
|
899 |
+ ) |
|
349 | 900 |
CANNOT_UPDATE_SETTINGS_NO_SETTINGS = _prepare_translatable( |
350 |
- msg='Cannot update {settings_type!s} settings ' |
|
351 |
- 'without any given settings. ' |
|
352 |
- 'You must specify at least one of --lower, ..., ' |
|
353 |
- '--symbol, or --phrase or --key.', |
|
901 |
+ msg=r""" |
|
902 |
+ Cannot update {settings_type!s} settings without any given |
|
903 |
+ settings. You must specify at least one of --lower, ..., |
|
904 |
+ --symbol, or --phrase or --key. |
|
905 |
+ """, |
|
354 | 906 |
comments='', |
355 | 907 |
context='error message', |
356 | 908 |
flags='python-brace-format', |
357 | 909 |
) |
910 |
+ INVALID_USER_CONFIG = _prepare_translatable( |
|
911 |
+ comments=r""" |
|
912 |
+ TRANSLATORS: The error message is usually supplied by the |
|
913 |
+ operating system, e.g. ENOENT/"No such file or directory". |
|
914 |
+ """, |
|
915 |
+ msg=r""" |
|
916 |
+ The user configuration file is invalid. {error!s}: {filename!r}. |
|
917 |
+ """, |
|
918 |
+ context='error message', |
|
919 |
+ flags='python-brace-format', |
|
920 |
+ ) |
|
358 | 921 |
INVALID_VAULT_CONFIG = _prepare_translatable( |
359 | 922 |
comments=r""" |
360 | 923 |
TRANSLATORS: This error message is a reaction to a validator |
... | ... |
@@ -373,14 +936,18 @@ class ErrMsgTemplate(enum.Enum): |
373 | 936 |
flags='python-brace-format', |
374 | 937 |
) |
375 | 938 |
NO_AF_UNIX = _prepare_translatable( |
376 |
- 'Cannot connect to an SSH agent because this Python version ' |
|
377 |
- 'does not support UNIX domain sockets.', |
|
939 |
+ msg=r""" |
|
940 |
+ Cannot connect to an SSH agent because this Python version does |
|
941 |
+ not support UNIX domain sockets. |
|
942 |
+ """, |
|
378 | 943 |
comments='', |
379 | 944 |
context='error message', |
380 | 945 |
) |
381 | 946 |
NO_KEY_OR_PHRASE = _prepare_translatable( |
382 |
- 'No passphrase or key was given in the configuration. ' |
|
383 |
- 'In this case, the --phrase or --key argument is required.', |
|
947 |
+ msg=r""" |
|
948 |
+ No passphrase or key was given in the configuration. In this |
|
949 |
+ case, the --phrase or --key argument is required. |
|
950 |
+ """, |
|
384 | 951 |
comments='', |
385 | 952 |
context='error message', |
386 | 953 |
) |
... | ... |
@@ -389,6 +956,14 @@ class ErrMsgTemplate(enum.Enum): |
389 | 956 |
comments='', |
390 | 957 |
context='error message', |
391 | 958 |
) |
959 |
+ NO_SUITABLE_SSH_KEYS = _prepare_translatable( |
|
960 |
+ msg=""" |
|
961 |
+ The SSH agent contains no keys suitable for {PROG_NAME!s}. |
|
962 |
+ """, # noqa: RUF027 |
|
963 |
+ comments='', |
|
964 |
+ context='error message', |
|
965 |
+ flags='python-brace-format', |
|
966 |
+ ) |
|
392 | 967 |
PARAMS_MUTUALLY_EXCLUSIVE = _prepare_translatable( |
393 | 968 |
comments=r""" |
394 | 969 |
TRANSLATORS: The params are long-form command-line option names. |
... | ... |
@@ -401,37 +976,48 @@ class ErrMsgTemplate(enum.Enum): |
401 | 976 |
PARAMS_NEEDS_SERVICE_OR_CONFIG = _prepare_translatable( |
402 | 977 |
comments=r""" |
403 | 978 |
TRANSLATORS: The param is a long-form command-line option name, |
404 |
- and "SERVICE" is the command-line argument for the (sometimes |
|
405 |
- optional) service name. |
|
979 |
+ and the metavar is given in VAULT_METAVAR_SERVICE. |
|
406 | 980 |
""", |
407 |
- msg='{param!s} requires a SERVICE or --config.', |
|
981 |
+ msg='{param!s} requires a {service_metavar!s} or --config.', |
|
408 | 982 |
context='error message', |
409 | 983 |
flags='python-brace-format', |
410 | 984 |
) |
411 | 985 |
PARAMS_NEEDS_SERVICE = _prepare_translatable( |
412 | 986 |
comments=r""" |
413 | 987 |
TRANSLATORS: The param is a long-form command-line option name, |
414 |
- and "SERVICE" is the command-line argument for the (sometimes |
|
415 |
- optional) service name. |
|
988 |
+ and the metavar is given in VAULT_METAVAR_SERVICE. |
|
416 | 989 |
""", |
417 |
- msg='{param!s} requires a SERVICE.', |
|
990 |
+ msg='{param!s} requires a {service_metavar!s}.', |
|
418 | 991 |
context='error message', |
419 | 992 |
flags='python-brace-format', |
420 | 993 |
) |
421 | 994 |
PARAMS_NO_SERVICE = _prepare_translatable( |
422 | 995 |
comments=r""" |
423 | 996 |
TRANSLATORS: The param is a long-form command-line option name, |
424 |
- and "SERVICE" is the command-line argument for the (sometimes |
|
425 |
- optional) service name. |
|
997 |
+ and the metavar is given in VAULT_METAVAR_SERVICE. |
|
426 | 998 |
""", |
427 |
- msg='{param!s} does not take a SERVICE argument.', |
|
999 |
+ msg='{param!s} does not take a {service_metavar!s} argument.', |
|
428 | 1000 |
context='error message', |
429 | 1001 |
flags='python-brace-format', |
430 | 1002 |
) |
431 | 1003 |
SERVICE_REQUIRED = _prepare_translatable( |
432 |
- 'Generating a passphrase requires a SERVICE.', |
|
433 |
- comments='', |
|
1004 |
+ comments=r""" |
|
1005 |
+ TRANSLATORS: The metavar is given in VAULT_METAVAR_SERVICE. |
|
1006 |
+ """, |
|
1007 |
+ msg='Deriving a passphrase requires a {service_metavar!s}.', |
|
1008 |
+ context='error message', |
|
1009 |
+ flags='python-brace-format', |
|
1010 |
+ ) |
|
1011 |
+ SET_AND_UNSET_SAME_SETTING = _prepare_translatable( |
|
1012 |
+ comments=r""" |
|
1013 |
+ TRANSLATORS: The rephrasing "Attempted to unset and set the same |
|
1014 |
+ setting (--unset={setting!s} --{setting!s}=...) at the same |
|
1015 |
+ time." may or may not be more suitable as a basis for |
|
1016 |
+ translation instead. |
|
1017 |
+ """, |
|
1018 |
+ msg='Attempted to unset and set --{setting!s} at the same time.', |
|
434 | 1019 |
context='error message', |
1020 |
+ flags='python-brace-format', |
|
435 | 1021 |
) |
436 | 1022 |
SSH_KEY_NOT_LOADED = _prepare_translatable( |
437 | 1023 |
'The requested SSH key is not loaded into the agent.', |
... | ... |
@@ -453,13 +1039,3 @@ class ErrMsgTemplate(enum.Enum): |
453 | 1039 |
comments='', |
454 | 1040 |
context='error message', |
455 | 1041 |
) |
456 |
- USER_CONFIG_INVALID = _prepare_translatable( |
|
457 |
- comments=r""" |
|
458 |
- TRANSLATORS: The error message is usually supplied by the |
|
459 |
- operating system, e.g. ENOENT/"No such file or directory". |
|
460 |
- """, |
|
461 |
- msg='The user configuration file is invalid. ' |
|
462 |
- '{error!s}: {filename!r}.', |
|
463 |
- context='error message', |
|
464 |
- flags='python-brace-format', |
|
465 |
- ) |
|
466 | 1042 |