0e31ed481bf84684233c909ae8f559c360386fb1
Marco Ricci Change the author e-mail ad...

Marco Ricci authored 4 months ago

1) # SPDX-FileCopyrightText: 2024 Marco Ricci <software@the13thletter.info>
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2) #
3) # SPDX-License-Identifier: MIT
4) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

5) # ruff: noqa: TRY400
6) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

7) """Command-line interface for derivepassphrase."""
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

8) 
9) from __future__ import annotations
10) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

11) import base64
12) import collections
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

13) import copy
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

14) import enum
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

15) import functools
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

16) import importlib
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

17) import inspect
18) import json
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

19) import logging
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

20) import os
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

21) import shlex
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

22) import sys
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

23) import unicodedata
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

24) import warnings
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

25) from typing import (
26)     TYPE_CHECKING,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

27)     Callable,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

28)     Literal,
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

29)     NoReturn,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

30)     TextIO,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

31)     TypeVar,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

32)     cast,
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

33) )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

34) 
35) import click
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

36) from typing_extensions import (
37)     Any,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

38)     ParamSpec,
39)     Self,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

40)     assert_never,
41) )
42) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

43) import derivepassphrase as dpp
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

44) from derivepassphrase import _cli_msg as _msg
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

45) from derivepassphrase import _types, exporter, ssh_agent, vault
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

46) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

47) if sys.version_info >= (3, 11):
48)     import tomllib
49) else:
50)     import tomli as tomllib
51) 
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

52) if TYPE_CHECKING:
53)     import pathlib
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

54)     import socket
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

55)     import types
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

56)     from collections.abc import (
57)         Iterator,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

58)         MutableSequence,
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

59)         Sequence,
60)     )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

61) 
62) __author__ = dpp.__author__
63) __version__ = dpp.__version__
64) 
65) __all__ = ('derivepassphrase',)
66) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

67) PROG_NAME = _msg.PROG_NAME
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

68) KEY_DISPLAY_LENGTH = 50
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

69) 
70) # Error messages
71) _INVALID_VAULT_CONFIG = 'Invalid vault config'
72) _AGENT_COMMUNICATION_ERROR = 'Error communicating with the SSH agent'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

73) _NO_SUITABLE_KEYS = 'No suitable SSH keys were found'
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

74) _EMPTY_SELECTION = 'Empty selection'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

75) _NOT_AN_INTEGER = 'not an integer'
76) _NOT_A_NONNEGATIVE_INTEGER = 'not a non-negative integer'
77) _NOT_A_POSITIVE_INTEGER = 'not a positive integer'
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

78) 
79) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

80) # Logging
81) # =======
82) 
83) 
84) class ClickEchoStderrHandler(logging.Handler):
85)     """A [`logging.Handler`][] for `click` applications.
86) 
87)     Outputs log messages to [`sys.stderr`][] via [`click.echo`][].
88) 
89)     """
90) 
91)     def emit(self, record: logging.LogRecord) -> None:
92)         """Emit a log record.
93) 
94)         Format the log record, then emit it via [`click.echo`][] to
95)         [`sys.stderr`][].
96) 
97)         """
98)         click.echo(self.format(record), err=True)
99) 
100) 
101) class CLIofPackageFormatter(logging.Formatter):
102)     """A [`logging.LogRecord`][] formatter for the CLI of a Python package.
103) 
104)     Assuming a package `PKG` and loggers within the same hierarchy
105)     `PKG`, format all log records from that hierarchy for proper user
106)     feedback on the console.  Intended for use with [`click`][CLICK] and
107)     when `PKG` provides a command-line tool `PKG` and when logs from
108)     that package should show up as output of the command-line tool.
109) 
110)     Essentially, this prepends certain short strings to the log message
111)     lines to make them readable as standard error output.
112) 
113)     Because this log output is intended to be displayed on standard
114)     error as high-level diagnostic output, you are strongly discouraged
115)     from changing the output format to include more tokens besides the
116)     log message.  Use a dedicated log file handler instead, without this
117)     formatter.
118) 
119)     [CLICK]: https://pypi.org/projects/click/
120) 
121)     """
122) 
123)     def __init__(
124)         self,
125)         *,
126)         prog_name: str = PROG_NAME,
127)         package_name: str | None = None,
128)     ) -> None:
129)         self.prog_name = prog_name
130)         self.package_name = (
131)             package_name
132)             if package_name is not None
133)             else prog_name.lower().replace(' ', '_').replace('-', '_')
134)         )
135) 
136)     def format(self, record: logging.LogRecord) -> str:
137)         """Format a log record suitably for standard error console output.
138) 
139)         Prepend the formatted string `"PROG_NAME: LABEL"` to each line
140)         of the message, where `PROG_NAME` is the program name, and
141)         `LABEL` depends on the record's level and on the logger name as
142)         follows:
143) 
144)           * For records at level [`logging.DEBUG`][], `LABEL` is
145)             `"Debug: "`.
146)           * For records at level [`logging.INFO`][], `LABEL` is the
147)             empty string.
148)           * For records at level [`logging.WARNING`][], `LABEL` is
149)             `"Deprecation warning: "` if the logger is named
150)             `PKG.deprecation` (where `PKG` is the package name), else
151)             `"Warning: "`.
152)           * For records at level [`logging.ERROR`][] and
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

153)             [`logging.CRITICAL`][] `"Error: "`, `LABEL` is the empty
154)             string.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

155) 
156)         The level indication strings at level `WARNING` or above are
157)         highlighted.  Use [`click.echo`][] to output them and remove
158)         color output if necessary.
159) 
160)         Args:
161)             record: A log record.
162) 
163)         Returns:
164)             A formatted log record.
165) 
166)         Raises:
167)             AssertionError:
168)                 The log level is not supported.
169) 
170)         """
171)         preliminary_result = record.getMessage()
172)         prefix = f'{self.prog_name}: '
173)         if record.levelname == 'DEBUG':  # pragma: no cover
174)             level_indicator = 'Debug: '
175)         elif record.levelname == 'INFO':
176)             level_indicator = ''
177)         elif record.levelname == 'WARNING':
178)             level_indicator = (
179)                 f'{click.style("Deprecation warning", bold=True)}: '
180)                 if record.name.endswith('.deprecation')
181)                 else f'{click.style("Warning", bold=True)}: '
182)             )
183)         elif record.levelname in {'ERROR', 'CRITICAL'}:
184)             level_indicator = ''
185)         else:  # pragma: no cover
186)             msg = f'Unsupported logging level: {record.levelname}'
187)             raise AssertionError(msg)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

188)         parts = [
189)             ''.join(
190)                 prefix + level_indicator + line
191)                 for line in preliminary_result.splitlines(True)  # noqa: FBT003
192)             )
193)         ]
194)         if record.exc_info:
195)             parts.append(self.formatException(record.exc_info) + '\n')
196)         return ''.join(parts)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

197) 
198) 
199) class StandardCLILogging:
200)     """Set up CLI logging handlers upon instantiation."""
201) 
202)     prog_name = PROG_NAME
203)     package_name = PROG_NAME.lower().replace(' ', '_').replace('-', '_')
204)     cli_formatter = CLIofPackageFormatter(
205)         prog_name=prog_name, package_name=package_name
206)     )
207)     cli_handler = ClickEchoStderrHandler()
208)     cli_handler.addFilter(logging.Filter(name=package_name))
209)     cli_handler.setFormatter(cli_formatter)
210)     cli_handler.setLevel(logging.WARNING)
211)     warnings_handler = ClickEchoStderrHandler()
212)     warnings_handler.addFilter(logging.Filter(name='py.warnings'))
213)     warnings_handler.setFormatter(cli_formatter)
214)     warnings_handler.setLevel(logging.WARNING)
215) 
216)     @classmethod
217)     def ensure_standard_logging(cls) -> StandardLoggingContextManager:
218)         """Return a context manager to ensure standard logging is set up."""
219)         return StandardLoggingContextManager(
220)             handler=cls.cli_handler,
221)             root_logger=cls.package_name,
222)         )
223) 
224)     @classmethod
225)     def ensure_standard_warnings_logging(
226)         cls,
227)     ) -> StandardWarningsLoggingContextManager:
228)         """Return a context manager to ensure warnings logging is set up."""
229)         return StandardWarningsLoggingContextManager(
230)             handler=cls.warnings_handler,
231)         )
232) 
233) 
234) class StandardLoggingContextManager:
235)     """A reentrant context manager setting up standard CLI logging.
236) 
237)     Ensures that the given handler (defaulting to the CLI logging
238)     handler) is added to the named logger (defaulting to the root
239)     logger), and if it had to be added, then that it will be removed
240)     upon exiting the context.
241) 
242)     Reentrant, but not thread safe, because it temporarily modifies
243)     global state.
244) 
245)     """
246) 
247)     def __init__(
248)         self,
249)         handler: logging.Handler,
250)         root_logger: str | None = None,
251)     ) -> None:
252)         self.handler = handler
253)         self.root_logger_name = root_logger
254)         self.base_logger = logging.getLogger(self.root_logger_name)
255)         self.action_required: MutableSequence[bool] = collections.deque()
256) 
257)     def __enter__(self) -> Self:
258)         self.action_required.append(
259)             self.handler not in self.base_logger.handlers
260)         )
261)         if self.action_required[-1]:
262)             self.base_logger.addHandler(self.handler)
263)         return self
264) 
265)     def __exit__(
266)         self,
267)         exc_type: type[BaseException] | None,
268)         exc_value: BaseException | None,
269)         exc_tb: types.TracebackType | None,
270)     ) -> Literal[False]:
271)         if self.action_required[-1]:
272)             self.base_logger.removeHandler(self.handler)
273)         self.action_required.pop()
274)         return False
275) 
276) 
277) class StandardWarningsLoggingContextManager(StandardLoggingContextManager):
278)     """A reentrant context manager setting up standard warnings logging.
279) 
280)     Ensures that warnings are being diverted to the logging system, and
281)     that the given handler (defaulting to the CLI logging handler) is
282)     added to the warnings logger. If the handler had to be added, then
283)     it will be removed upon exiting the context.
284) 
285)     Reentrant, but not thread safe, because it temporarily modifies
286)     global state.
287) 
288)     """
289) 
290)     def __init__(
291)         self,
292)         handler: logging.Handler,
293)     ) -> None:
294)         super().__init__(handler=handler, root_logger='py.warnings')
295)         self.stack: MutableSequence[
296)             tuple[
297)                 Callable[
298)                     [
299)                         type[BaseException] | None,
300)                         BaseException | None,
301)                         types.TracebackType | None,
302)                     ],
303)                     None,
304)                 ],
305)                 Callable[
306)                     [
307)                         str | Warning,
308)                         type[Warning],
309)                         str,
310)                         int,
311)                         TextIO | None,
312)                         str | None,
313)                     ],
314)                     None,
315)                 ],
316)             ]
317)         ] = collections.deque()
318) 
319)     def __enter__(self) -> Self:
320)         def showwarning(  # noqa: PLR0913,PLR0917
321)             message: str | Warning,
322)             category: type[Warning],
323)             filename: str,
324)             lineno: int,
325)             file: TextIO | None = None,
326)             line: str | None = None,
327)         ) -> None:
328)             if file is not None:  # pragma: no cover
329)                 self.stack[0][1](
330)                     message, category, filename, lineno, file, line
331)                 )
332)             else:
333)                 logging.getLogger('py.warnings').warning(
334)                     str(
335)                         warnings.formatwarning(
336)                             message, category, filename, lineno, line
337)                         )
338)                     )
339)                 )
340) 
341)         ctx = warnings.catch_warnings()
342)         exit_func = ctx.__exit__
343)         ctx.__enter__()
344)         self.stack.append((exit_func, warnings.showwarning))
345)         warnings.showwarning = showwarning
346)         return super().__enter__()
347) 
348)     def __exit__(
349)         self,
350)         exc_type: type[BaseException] | None,
351)         exc_value: BaseException | None,
352)         exc_tb: types.TracebackType | None,
353)     ) -> Literal[False]:
354)         ret = super().__exit__(exc_type, exc_value, exc_tb)
355)         val = self.stack.pop()[0](exc_type, exc_value, exc_tb)
356)         assert not val
357)         return ret
358) 
359) 
360) P = ParamSpec('P')
361) R = TypeVar('R')
362) 
363) 
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

364) def adjust_logging_level(
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

365)     ctx: click.Context,
366)     /,
367)     param: click.Parameter | None = None,
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

368)     value: int | None = None,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

369) ) -> None:
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

370)     """Change the logs that are emitted to standard error.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

371) 
372)     This modifies the [`StandardCLILogging`][] settings such that log
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

373)     records at the respective level are emitted, based on the `param`
374)     and the `value`.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

375) 
376)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

377)     # Note: If multiple options use this callback, then we will be
378)     # called multiple times.  Ensure the runs are idempotent.
379)     if param is None or value is None or ctx.resilient_parsing:
380)         return
381)     StandardCLILogging.cli_handler.setLevel(value)
382)     logging.getLogger(StandardCLILogging.package_name).setLevel(value)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

383) 
384) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

385) # Option parsing and grouping
386) # ===========================
387) 
388) 
389) class OptionGroupOption(click.Option):
390)     """A [`click.Option`][] with an associated group name and group epilog.
391) 
392)     Used by [`CommandWithHelpGroups`][] to print help sections.  Each
393)     subclass contains its own group name and epilog.
394) 
395)     Attributes:
396)         option_group_name:
397)             The name of the option group.  Used as a heading on the help
398)             text for options in this section.
399)         epilog:
400)             An epilog to print after listing the options in this
401)             section.
402) 
403)     """
404) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

405)     option_group_name: object = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

406)     """"""
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

407)     epilog: object = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

408)     """"""
409) 
410)     def __init__(self, *args: Any, **kwargs: Any) -> None:  # noqa: ANN401
411)         if self.__class__ == __class__:  # type: ignore[name-defined]
412)             raise NotImplementedError
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

413)         # Though click 8.1 mostly defers help text processing until the
414)         # `BaseCommand.format_*` methods are called, the Option
415)         # constructor still preprocesses the help text, and asserts that
416)         # the help text is a string.  Work around this by removing the
417)         # help text from the constructor arguments and re-adding it,
418)         # unprocessed, after constructor finishes.
419)         unset = object()
420)         help = kwargs.pop('help', unset)  # noqa: A001
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

421)         super().__init__(*args, **kwargs)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

422)         if help is not unset:  # pragma: no branch
423)             self.help = help
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

424) 
425) 
426) class CommandWithHelpGroups(click.Command):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

427)     """A [`click.Command`][] with support for some help text customizations.
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

428) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

429)     Supports help/option groups, group epilogs, and help text objects
430)     (objects that stringify to help texts).  The latter is primarily
431)     used to implement translations.
432) 
433)     Inspired by [a comment on `pallets/click#373`][CLICK_ISSUE] for
434)     help/option group support, and further modified to include group
435)     epilogs and help text objects.
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

436) 
437)     [CLICK_ISSUE]: https://github.com/pallets/click/issues/373#issuecomment-515293746
438) 
439)     """
440) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

441)     @staticmethod
442)     def _text(text: object, /) -> str:
443)         if isinstance(text, (list, tuple)):
444)             return '\n\n'.join(str(x) for x in text)
445)         return str(text)
446) 
447)     def collect_usage_pieces(self, ctx: click.Context) -> list[str]:
448)         """Return the pieces for the usage string.
449) 
450)         Based on code from click 8.1.  Subject to the following license
451)         (3-clause BSD license):
452) 
453)             Copyright 2024 Pallets
454) 
455)             Redistribution and use in source and binary forms, with or
456)             without modification, are permitted provided that the
457)             following conditions are met:
458) 
459)              1. Redistributions of source code must retain the above
460)                 copyright notice, this list of conditions and the
461)                 following disclaimer.
462) 
463)              2. Redistributions in binary form must reproduce the above
464)                 copyright notice, this list of conditions and the
465)                 following disclaimer in the documentation and/or other
466)                 materials provided with the distribution.
467) 
468)              3. Neither the name of the copyright holder nor the names
469)                 of its contributors may be used to endorse or promote
470)                 products derived from this software without specific
471)                 prior written permission.
472) 
473)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
474)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
475)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
476)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
477)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
478)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
479)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
480)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
481)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
482)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
483)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
484)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
485)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
486) 
487)         Modifications are marked with respective comments.  They too are
488)         released under the same license above.  The original code did
489)         not contain any "noqa" or "pragma" comments.
490) 
491)         Args:
492)             ctx:
493)                 The click context.
494) 
495)         """
496)         rv = [str(self.options_metavar)] if self.options_metavar else []
497)         for param in self.get_params(ctx):
498)             rv.extend(str(x) for x in param.get_usage_pieces(ctx))
499)         return rv
500) 
501)     def get_short_help_str(
502)         self,
503)         limit: int = 45,
504)     ) -> str:
505)         """Return the short help string for a command.
506) 
507)         If only a long help string is given, shorten it.
508) 
509)         Based on code from click 8.1.  Subject to the following license
510)         (3-clause BSD license):
511) 
512)             Copyright 2024 Pallets
513) 
514)             Redistribution and use in source and binary forms, with or
515)             without modification, are permitted provided that the
516)             following conditions are met:
517) 
518)              1. Redistributions of source code must retain the above
519)                 copyright notice, this list of conditions and the
520)                 following disclaimer.
521) 
522)              2. Redistributions in binary form must reproduce the above
523)                 copyright notice, this list of conditions and the
524)                 following disclaimer in the documentation and/or other
525)                 materials provided with the distribution.
526) 
527)              3. Neither the name of the copyright holder nor the names
528)                 of its contributors may be used to endorse or promote
529)                 products derived from this software without specific
530)                 prior written permission.
531) 
532)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
533)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
534)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
535)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
536)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
537)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
538)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
539)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
540)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
541)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
542)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
543)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
544)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
545) 
546)         Modifications are marked with respective comments.  They too are
547)         released under the same license above.  The original code did
548)         not contain any "noqa" or "pragma" comments.
549) 
550)         Args:
551)             limit:
552)                 The maximum width of the short help string.
553) 
554)         """
555)         # Modification against click 8.1: Call `_text()` on `self.help`
556)         # to allow help texts to be general objects, not just strings.
557)         # Used to implement translatable strings, as objects that
558)         # stringify to the translation.
559)         if self.short_help:  # pragma: no cover
560)             text = inspect.cleandoc(self._text(self.short_help))
561)         elif self.help:
562)             text = click.utils.make_default_short_help(
563)                 self._text(self.help), limit
564)             )
565)         else:  # pragma: no cover
566)             text = ''
567)         if self.deprecated:  # pragma: no cover
568)             # Modification against click 8.1: The translated string is
569)             # looked up in the derivepassphrase message domain, not the
570)             # gettext default domain.
571)             text = str(
572)                 _msg.TranslatedString(_msg.Label.DEPRECATED_COMMAND_LABEL)
573)             ).format(text=text)
574)         return text.strip()
575) 
576)     def format_help_text(
577)         self,
578)         ctx: click.Context,
579)         formatter: click.HelpFormatter,
580)     ) -> None:
581)         """Format the help text prologue, if any.
582) 
583)         Based on code from click 8.1.  Subject to the following license
584)         (3-clause BSD license):
585) 
586)             Copyright 2024 Pallets
587) 
588)             Redistribution and use in source and binary forms, with or
589)             without modification, are permitted provided that the
590)             following conditions are met:
591) 
592)              1. Redistributions of source code must retain the above
593)                 copyright notice, this list of conditions and the
594)                 following disclaimer.
595) 
596)              2. Redistributions in binary form must reproduce the above
597)                 copyright notice, this list of conditions and the
598)                 following disclaimer in the documentation and/or other
599)                 materials provided with the distribution.
600) 
601)              3. Neither the name of the copyright holder nor the names
602)                 of its contributors may be used to endorse or promote
603)                 products derived from this software without specific
604)                 prior written permission.
605) 
606)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
607)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
608)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
609)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
610)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
611)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
612)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
613)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
614)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
615)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
616)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
617)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
618)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
619) 
620)         Modifications are marked with respective comments.  They too are
621)         released under the same license above.  The original code did
622)         not contain any "noqa" or "pragma" comments.
623) 
624)         Args:
625)             ctx:
626)                 The click context.
627)             formatter:
628)                 The formatter for the `--help` listing.
629) 
630)         """
631)         del ctx
632)         # Modification against click 8.1: Call `_text()` on `self.help`
633)         # to allow help texts to be general objects, not just strings.
634)         # Used to implement translatable strings, as objects that
635)         # stringify to the translation.
636)         text = (
637)             inspect.cleandoc(self._text(self.help).partition('\f')[0])
638)             if self.help is not None
639)             else ''
640)         )
641)         if self.deprecated:  # pragma: no cover
642)             # Modification against click 8.1: The translated string is
643)             # looked up in the derivepassphrase message domain, not the
644)             # gettext default domain.
645)             text = str(
646)                 _msg.TranslatedString(_msg.Label.DEPRECATED_COMMAND_LABEL)
647)             ).format(text=text)
648)         if text:  # pragma: no branch
649)             formatter.write_paragraph()
650)             with formatter.indentation():
651)                 formatter.write_text(text)
652) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

653)     def format_options(
654)         self,
655)         ctx: click.Context,
656)         formatter: click.HelpFormatter,
657)     ) -> None:
658)         r"""Format options on the help listing, grouped into sections.
659) 
660)         This is a callback for [`click.Command.get_help`][] that
661)         implements the `--help` listing, by calling appropriate methods
662)         of the `formatter`.  We list all options (like the base
663)         implementation), but grouped into sections according to the
664)         concrete [`click.Option`][] subclass being used.  If the option
665)         is an instance of some subclass of [`OptionGroupOption`][], then
666)         the section heading and the epilog are taken from the
667)         [`option_group_name`] [OptionGroupOption.option_group_name] and
668)         [`epilog`] [OptionGroupOption.epilog] attributes; otherwise, the
669)         section heading is "Options" (or "Other options" if there are
670)         other option groups) and the epilog is empty.
671) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

672)         We unconditionally call [`format_commands`][], and rely on it to
673)         act as a no-op if we aren't actually a [`click.MultiCommand`][].
674) 
675)         Based on code from click 8.1.  Subject to the following license
676)         (3-clause BSD license):
677) 
678)             Copyright 2024 Pallets
679) 
680)             Redistribution and use in source and binary forms, with or
681)             without modification, are permitted provided that the
682)             following conditions are met:
683) 
684)              1. Redistributions of source code must retain the above
685)                 copyright notice, this list of conditions and the
686)                 following disclaimer.
687) 
688)              2. Redistributions in binary form must reproduce the above
689)                 copyright notice, this list of conditions and the
690)                 following disclaimer in the documentation and/or other
691)                 materials provided with the distribution.
692) 
693)              3. Neither the name of the copyright holder nor the names
694)                 of its contributors may be used to endorse or promote
695)                 products derived from this software without specific
696)                 prior written permission.
697) 
698)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
699)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
700)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
701)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
702)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
703)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
704)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
705)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
706)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
707)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
708)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
709)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
710)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
711) 
712)         Modifications are released under the same license above.
713) 
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

714)         Args:
715)             ctx:
716)                 The click context.
717)             formatter:
718)                 The formatter for the `--help` listing.
719) 
720)         """
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

721)         default_group_name = ''
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

722)         help_records: dict[str, list[tuple[str, str]]] = {}
723)         epilogs: dict[str, str] = {}
724)         params = self.params[:]
725)         if (  # pragma: no branch
726)             (help_opt := self.get_help_option(ctx)) is not None
727)             and help_opt not in params
728)         ):
729)             params.append(help_opt)
730)         for param in params:
731)             rec = param.get_help_record(ctx)
732)             if rec is not None:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

733)                 rec = (rec[0], self._text(rec[1]))
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

734)                 if isinstance(param, OptionGroupOption):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

735)                     group_name = self._text(param.option_group_name)
736)                     epilogs.setdefault(group_name, self._text(param.epilog))
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

737)                 else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

738)                     group_name = default_group_name
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

739)                 help_records.setdefault(group_name, []).append(rec)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

740)         if default_group_name in help_records:  # pragma: no branch
741)             default_group = help_records.pop(default_group_name)
742)             default_group_label = (
743)                 _msg.Label.OTHER_OPTIONS_LABEL
744)                 if len(default_group) > 1
745)                 else _msg.Label.OPTIONS_LABEL
746)             )
747)             default_group_name = self._text(
748)                 _msg.TranslatedString(default_group_label)
749)             )
750)             help_records[default_group_name] = default_group
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

751)         for group_name, records in help_records.items():
752)             with formatter.section(group_name):
753)                 formatter.write_dl(records)
754)             epilog = inspect.cleandoc(epilogs.get(group_name, ''))
755)             if epilog:
756)                 formatter.write_paragraph()
757)                 with formatter.indentation():
758)                     formatter.write_text(epilog)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

759)         self.format_commands(ctx, formatter)
760) 
761)     def format_commands(
762)         self,
763)         ctx: click.Context,
764)         formatter: click.HelpFormatter,
765)     ) -> None:
766)         """Format the subcommands, if any.
767) 
768)         If called on a command object that isn't derived from
769)         [`click.MultiCommand`][], then do nothing.
770) 
771)         Based on code from click 8.1.  Subject to the following license
772)         (3-clause BSD license):
773) 
774)             Copyright 2024 Pallets
775) 
776)             Redistribution and use in source and binary forms, with or
777)             without modification, are permitted provided that the
778)             following conditions are met:
779) 
780)              1. Redistributions of source code must retain the above
781)                 copyright notice, this list of conditions and the
782)                 following disclaimer.
783) 
784)              2. Redistributions in binary form must reproduce the above
785)                 copyright notice, this list of conditions and the
786)                 following disclaimer in the documentation and/or other
787)                 materials provided with the distribution.
788) 
789)              3. Neither the name of the copyright holder nor the names
790)                 of its contributors may be used to endorse or promote
791)                 products derived from this software without specific
792)                 prior written permission.
793) 
794)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
795)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
796)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
797)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
798)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
799)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
800)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
801)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
802)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
803)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
804)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
805)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
806)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
807) 
808)         Modifications are marked with respective comments.  They too are
809)         released under the same license above.  The original code did
810)         not contain any "noqa" or "pragma" comments.
811) 
812)         Args:
813)             ctx:
814)                 The click context.
815)             formatter:
816)                 The formatter for the `--help` listing.
817) 
818)         """
819)         if not isinstance(self, click.MultiCommand):
820)             return
821)         commands: list[tuple[str, click.Command]] = []
822)         for subcommand in self.list_commands(ctx):
823)             cmd = self.get_command(ctx, subcommand)
824)             if cmd is None or cmd.hidden:  # pragma: no cover
825)                 continue
826)             commands.append((subcommand, cmd))
827)         if commands:  # pragma: no branch
828)             longest_command = max((cmd[0] for cmd in commands), key=len)
829)             limit = formatter.width - 6 - len(longest_command)
830)             rows: list[tuple[str, str]] = []
831)             for subcommand, cmd in commands:
832)                 help_str = self._text(cmd.get_short_help_str(limit) or '')
833)                 rows.append((subcommand, help_str))
834)             if rows:  # pragma: no branch
835)                 commands_label = self._text(
836)                     _msg.TranslatedString(_msg.Label.COMMANDS_LABEL)
837)                 )
838)                 with formatter.section(commands_label):
839)                     formatter.write_dl(rows)
840) 
841)     def format_epilog(
842)         self,
843)         ctx: click.Context,
844)         formatter: click.HelpFormatter,
845)     ) -> None:
846)         """Format the epilog, if any.
847) 
848)         Based on code from click 8.1.  Subject to the following license
849)         (3-clause BSD license):
850) 
851)             Copyright 2024 Pallets
852) 
853)             Redistribution and use in source and binary forms, with or
854)             without modification, are permitted provided that the
855)             following conditions are met:
856) 
857)              1. Redistributions of source code must retain the above
858)                 copyright notice, this list of conditions and the
859)                 following disclaimer.
860) 
861)              2. Redistributions in binary form must reproduce the above
862)                 copyright notice, this list of conditions and the
863)                 following disclaimer in the documentation and/or other
864)                 materials provided with the distribution.
865) 
866)              3. Neither the name of the copyright holder nor the names
867)                 of its contributors may be used to endorse or promote
868)                 products derived from this software without specific
869)                 prior written permission.
870) 
871)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
872)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
873)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
874)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
875)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
876)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
877)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
878)             NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
879)             LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
880)             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
881)             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
882)             OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
883)             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
884) 
885)         Modifications are marked with respective comments.  They too are
886)         released under the same license above.
887) 
888)         Args:
889)             ctx:
890)                 The click context.
891)             formatter:
892)                 The formatter for the `--help` listing.
893) 
894)         """
895)         del ctx
896)         if self.epilog:  # pragma: no branch
897)             # Modification against click 8.1: Call `str()` on
898)             # `self.epilog` to allow help texts to be general objects,
899)             # not just strings.  Used to implement translatable strings,
900)             # as objects that stringify to the translation.
901)             epilog = inspect.cleandoc(self._text(self.epilog))
902)             formatter.write_paragraph()
903)             with formatter.indentation():
904)                 formatter.write_text(epilog)
Marco Ricci Shift option parsing and gr...

Marco Ricci authored 1 month ago

905) 
906) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

907) class LoggingOption(OptionGroupOption):
908)     """Logging options for the CLI."""
909) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

910)     option_group_name = _msg.TranslatedString(_msg.Label.LOGGING_LABEL)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

911)     epilog = ''
912) 
913) 
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

914) debug_option = click.option(
915)     '--debug',
916)     'logging_level',
917)     is_flag=True,
918)     flag_value=logging.DEBUG,
919)     expose_value=False,
920)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

921)     help=_msg.TranslatedString(_msg.Label.DEBUG_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

922)     cls=LoggingOption,
923) )
924) verbose_option = click.option(
925)     '-v',
926)     '--verbose',
927)     'logging_level',
928)     is_flag=True,
929)     flag_value=logging.INFO,
930)     expose_value=False,
931)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

932)     help=_msg.TranslatedString(_msg.Label.VERBOSE_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

933)     cls=LoggingOption,
934) )
935) quiet_option = click.option(
936)     '-q',
937)     '--quiet',
938)     'logging_level',
939)     is_flag=True,
940)     flag_value=logging.ERROR,
941)     expose_value=False,
942)     callback=adjust_logging_level,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

943)     help=_msg.TranslatedString(_msg.Label.QUIET_OPTION_HELP_TEXT),
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

944)     cls=LoggingOption,
945) )
946) 
947) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

948) def standard_logging_options(f: Callable[P, R]) -> Callable[P, R]:
949)     """Decorate the function with standard logging click options.
950) 
951)     Adds the three click options `-v`/`--verbose`, `-q`/`--quiet` and
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

952)     `--debug`, which calls back into the [`adjust_logging_level`][]
953)     function (with different argument values).
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

954) 
955)     Args:
956)         f: A callable to decorate.
957) 
958)     Returns:
959)         The decorated callable.
960) 
961)     """
Marco Ricci Fix usage of `--debug`, `--...

Marco Ricci authored 3 weeks ago

962)     return debug_option(verbose_option(quiet_option(f)))
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

963) 
964) 
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

965) # Top-level
966) # =========
967) 
968) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

969) class _DefaultToVaultGroup(CommandWithHelpGroups, click.Group):
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

970)     """A helper class to implement the default-to-"vault"-subcommand behavior.
971) 
972)     Modifies internal [`click.MultiCommand`][] methods, and thus is both
973)     an implementation detail and a kludge.
974) 
975)     """
976) 
977)     def resolve_command(
978)         self, ctx: click.Context, args: list[str]
979)     ) -> tuple[str | None, click.Command | None, list[str]]:
980)         """Resolve a command, but default to "vault" instead of erroring out.
981) 
982)         Based on code from click 8.1, which appears to be essentially
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

983)         untouched since at least click 3.2.  Subject to the following
984)         license (3-clause BSD license):
985) 
986)             Copyright 2024 Pallets
987) 
988)             Redistribution and use in source and binary forms, with or
989)             without modification, are permitted provided that the following
990)             conditions are met:
991) 
992)              1. Redistributions of source code must retain the above
993)                 copyright notice, this list of conditions and the following
994)                 disclaimer.
995) 
996)              2. Redistributions in binary form must reproduce the above
997)                 copyright notice, this list of conditions and the following
998)                 disclaimer in the documentation and/or other materials
999)                 provided with the distribution.
1000) 
1001)              3. Neither the name of the copyright holder nor the names of
1002)                 its contributors may be used to endorse or promote products
1003)                 derived from this software without specific prior written
1004)                 permission.
1005) 
1006)             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
1007)             CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
1008)             INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1009)             MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1010)             DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
1011)             CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1012)             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1013)             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1014)             USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
1015)             AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1016)             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
1017)             IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1018)             THE POSSIBILITY OF SUCH DAMAGE.
1019) 
1020)         Modifications to this routine are marked with "modifications for
1021)         derivepassphrase".  Furthermore, all "pragma" and "noqa" comments
1022)         are also modifications for derivepassphrase.
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1023) 
1024)         """
1025)         cmd_name = click.utils.make_str(args[0])
1026) 
1027)         # Get the command
1028)         cmd = self.get_command(ctx, cmd_name)
1029) 
1030)         # If we can't find the command but there is a normalization
1031)         # function available, we try with that one.
1032)         if (  # pragma: no cover
1033)             cmd is None and ctx.token_normalize_func is not None
1034)         ):
1035)             cmd_name = ctx.token_normalize_func(cmd_name)
1036)             cmd = self.get_command(ctx, cmd_name)
1037) 
1038)         # If we don't find the command we want to show an error message
1039)         # to the user that it was not provided.  However, there is
1040)         # something else we should do: if the first argument looks like
1041)         # an option we want to kick off parsing again for arguments to
1042)         # resolve things like --help which now should go to the main
1043)         # place.
1044)         if cmd is None and not ctx.resilient_parsing:
1045)             if click.parser.split_opt(cmd_name)[0]:
1046)                 self.parse_args(ctx, ctx.args)
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1047)             ####
1048)             # BEGIN modifications for derivepassphrase
1049)             #
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1050)             # Instead of calling ctx.fail here, default to "vault", and
1051)             # issue a deprecation warning.
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1052)             deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
1053)             deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1054)                 _msg.TranslatedString(
1055)                     _msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED
1056)                 )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1057)             )
1058)             cmd_name = 'vault'
1059)             cmd = self.get_command(ctx, cmd_name)
1060)             assert cmd is not None, 'Mandatory subcommand "vault" missing!'
1061)             args = [cmd_name, *args]
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1062)             #
1063)             # END modifications for derivepassphrase
1064)             ####
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1065)         return cmd_name if cmd else None, cmd, args[1:]  # noqa: DOC201
1066) 
1067) 
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1068) class _TopLevelCLIEntryPoint(_DefaultToVaultGroup):
1069)     """A minor variation of _DefaultToVaultGroup for the top-level command.
1070) 
1071)     When called as a function, this sets up the environment properly
1072)     before invoking the actual callbacks.  Currently, this means setting
1073)     up the logging subsystem and the delegation of Python warnings to
1074)     the logging subsystem.
1075) 
1076)     The environment setup can be bypassed by calling the `.main` method
1077)     directly.
1078) 
1079)     """
1080) 
1081)     def __call__(  # pragma: no cover
1082)         self,
1083)         *args: Any,  # noqa: ANN401
1084)         **kwargs: Any,  # noqa: ANN401
1085)     ) -> Any:  # noqa: ANN401
1086)         """"""  # noqa: D419
1087)         # Coverage testing is done with the `click.testing` module,
1088)         # which does not use the `__call__` shortcut.  So it is normal
1089)         # that this function is never called, and thus should be
1090)         # excluded from coverage.
1091)         with (
1092)             StandardCLILogging.ensure_standard_logging(),
1093)             StandardCLILogging.ensure_standard_warnings_logging(),
1094)         ):
1095)             return self.main(*args, **kwargs)
1096) 
1097) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1098) @click.group(
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1099)     context_settings={
1100)         'help_option_names': ['-h', '--help'],
1101)         'ignore_unknown_options': True,
1102)         'allow_interspersed_args': False,
1103)     },
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1104)     epilog=_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EPILOG_01),
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1105)     invoke_without_command=True,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1106)     cls=_TopLevelCLIEntryPoint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1107)     help=(
1108)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_01),
1109)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_02),
1110)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_03),
1111)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1112) )
1113) @click.version_option(version=dpp.__version__, prog_name=PROG_NAME)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1114) @standard_logging_options
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1115) @click.pass_context
1116) def derivepassphrase(ctx: click.Context, /) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1117)     """Derive a strong passphrase, deterministically, from a master secret.
1118) 
1119)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1120)     and not intended for programmatic use.  See the derivepassphrase(1)
1121)     manpage for full documentation of the interface.  (See also
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1122)     [`click.testing.CliRunner`][] for controlled, programmatic
1123)     invocation.)
1124) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

1125)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1126) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1127)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1128)     deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1129)     if ctx.invoked_subcommand is None:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1130)         deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1131)             _msg.TranslatedString(_msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1132)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1133)         # See definition of click.Group.invoke, non-chained case.
1134)         with ctx:
1135)             sub_ctx = derivepassphrase_vault.make_context(
1136)                 'vault', ctx.args, parent=ctx
1137)             )
1138)             with sub_ctx:
1139)                 return derivepassphrase_vault.invoke(sub_ctx)
1140)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1141) 
1142) 
1143) # Exporter
1144) # ========
1145) 
1146) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1147) @derivepassphrase.group(
1148)     'export',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1149)     context_settings={
1150)         'help_option_names': ['-h', '--help'],
1151)         'ignore_unknown_options': True,
1152)         'allow_interspersed_args': False,
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1153)     },
1154)     invoke_without_command=True,
1155)     cls=_DefaultToVaultGroup,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1156)     help=(
1157)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_01),
1158)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_02),
1159)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_03),
1160)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1161) )
1162) @click.version_option(version=dpp.__version__, prog_name=PROG_NAME)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1163) @standard_logging_options
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1164) @click.pass_context
1165) def derivepassphrase_export(ctx: click.Context, /) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1166)     """Export a foreign configuration to standard output.
1167) 
1168)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1169)     and not intended for programmatic use.  See the
1170)     derivepassphrase-export(1) manpage for full documentation of the
1171)     interface.  (See also [`click.testing.CliRunner`][] for controlled,
1172)     programmatic invocation.)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1173) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

1174)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1175) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1176)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1177)     deprecation = logging.getLogger(f'{PROG_NAME}.deprecation')
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1178)     if ctx.invoked_subcommand is None:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1179)         deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1180)             _msg.TranslatedString(_msg.WarnMsgTemplate.V10_SUBCOMMAND_REQUIRED)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1181)         )
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1182)         # See definition of click.Group.invoke, non-chained case.
1183)         with ctx:
1184)             sub_ctx = derivepassphrase_export_vault.make_context(
1185)                 'vault', ctx.args, parent=ctx
1186)             )
1187)             # Constructing the subcontext above will usually already
1188)             # lead to a click.UsageError, so this block typically won't
1189)             # actually be called.
1190)             with sub_ctx:  # pragma: no cover
1191)                 return derivepassphrase_export_vault.invoke(sub_ctx)
1192)     return None
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1193) 
1194) 
1195) def _load_data(
1196)     fmt: Literal['v0.2', 'v0.3', 'storeroom'],
1197)     path: str | bytes | os.PathLike[str],
1198)     key: bytes,
1199) ) -> Any:  # noqa: ANN401
1200)     contents: bytes
1201)     module: types.ModuleType
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1202)     # Use match/case here once Python 3.9 becomes unsupported.
1203)     if fmt == 'v0.2':
1204)         module = importlib.import_module(
1205)             'derivepassphrase.exporter.vault_native'
1206)         )
1207)         if module.STUBBED:
1208)             raise ModuleNotFoundError
1209)         with open(path, 'rb') as infile:
1210)             contents = base64.standard_b64decode(infile.read())
1211)         return module.export_vault_native_data(
1212)             contents, key, try_formats=['v0.2']
1213)         )
1214)     elif fmt == 'v0.3':  # noqa: RET505
1215)         module = importlib.import_module(
1216)             'derivepassphrase.exporter.vault_native'
1217)         )
1218)         if module.STUBBED:
1219)             raise ModuleNotFoundError
1220)         with open(path, 'rb') as infile:
1221)             contents = base64.standard_b64decode(infile.read())
1222)         return module.export_vault_native_data(
1223)             contents, key, try_formats=['v0.3']
1224)         )
1225)     elif fmt == 'storeroom':
1226)         module = importlib.import_module('derivepassphrase.exporter.storeroom')
1227)         if module.STUBBED:
1228)             raise ModuleNotFoundError
1229)         return module.export_storeroom_data(path, key)
1230)     else:  # pragma: no cover
1231)         assert_never(fmt)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1232) 
1233) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1234) class StandardOption(OptionGroupOption):
1235)     pass
1236) 
1237) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

1238) @derivepassphrase_export.command(
1239)     'vault',
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1240)     context_settings={'help_option_names': ['-h', '--help']},
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1241)     cls=CommandWithHelpGroups,
1242)     help=(
1243)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_01),
1244)         _msg.TranslatedString(
1245)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_02,
1246)             path_metavar=_msg.TranslatedString(
1247)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1248)             ),
1249)         ),
1250)         _msg.TranslatedString(
1251)             _msg.Label.DERIVEPASSPHRASE_EXPORT_VAULT_03,
1252)             path_metavar=_msg.TranslatedString(
1253)                 _msg.Label.EXPORT_VAULT_METAVAR_PATH,
1254)             ),
1255)         ),
1256)     ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1257) )
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1258) @standard_logging_options
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1259) @click.option(
1260)     '-f',
1261)     '--format',
1262)     'formats',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1263)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1264)     multiple=True,
1265)     default=('v0.3', 'v0.2', 'storeroom'),
1266)     type=click.Choice(['v0.2', 'v0.3', 'storeroom']),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1267)     help=_msg.TranslatedString(
1268)         _msg.Label.EXPORT_VAULT_FORMAT_HELP_TEXT,
1269)         defaults_hint=_msg.TranslatedString(
1270)             _msg.Label.EXPORT_VAULT_FORMAT_DEFAULTS_HELP_TEXT,
1271)         ),
1272)         metavar=_msg.TranslatedString(
1273)             _msg.Label.EXPORT_VAULT_FORMAT_METAVAR_FMT,
1274)         ),
1275)     ),
1276)     cls=StandardOption,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1277) )
1278) @click.option(
1279)     '-k',
1280)     '--key',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1281)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1282)     help=_msg.TranslatedString(
1283)         _msg.Label.EXPORT_VAULT_KEY_HELP_TEXT,
1284)         metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_KEY_METAVAR_K),
1285)         defaults_hint=_msg.TranslatedString(
1286)             _msg.Label.EXPORT_VAULT_KEY_DEFAULTS_HELP_TEXT,
1287)         ),
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1288)     ),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1289)     cls=StandardOption,
1290) )
1291) @click.argument(
1292)     'path',
1293)     metavar=_msg.TranslatedString(_msg.Label.EXPORT_VAULT_METAVAR_PATH),
1294)     required=True,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1295) )
1296) @click.pass_context
1297) def derivepassphrase_export_vault(
1298)     ctx: click.Context,
1299)     /,
1300)     *,
1301)     path: str | bytes | os.PathLike[str],
1302)     formats: Sequence[Literal['v0.2', 'v0.3', 'storeroom']] = (),
1303)     key: str | bytes | None = None,
1304) ) -> None:
1305)     """Export a vault-native configuration to standard output.
1306) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1307)     This is a [`click`][CLICK]-powered command-line interface function,
1308)     and not intended for programmatic use.  See the
1309)     derivepassphrase-export-vault(1) manpage for full documentation of
1310)     the interface.  (See also [`click.testing.CliRunner`][] for
1311)     controlled, programmatic invocation.)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1312) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1313)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1314) 
1315)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1316)     logger = logging.getLogger(PROG_NAME)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1317)     if path in {'VAULT_PATH', b'VAULT_PATH'}:
1318)         path = exporter.get_vault_path()
1319)     if key is None:
1320)         key = exporter.get_vault_key()
1321)     elif isinstance(key, str):  # pragma: no branch
1322)         key = key.encode('utf-8')
1323)     for fmt in formats:
1324)         try:
1325)             config = _load_data(fmt, path, key)
1326)         except (
1327)             IsADirectoryError,
1328)             NotADirectoryError,
1329)             ValueError,
1330)             RuntimeError,
1331)         ):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1332)             logger.info('Cannot load as %s: %s', fmt, path)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1333)             continue
1334)         except OSError as exc:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1335)             logger.error(
1336)                 'Cannot parse %r as a valid config: %s: %r',
1337)                 path,
1338)                 exc.strerror,
1339)                 exc.filename,
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1340)             )
1341)             ctx.exit(1)
1342)         except ModuleNotFoundError:
1343)             # TODO(the-13th-letter): Use backslash continuation.
1344)             # https://github.com/nedbat/coveragepy/issues/1836
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1345)             logger.error(
1346)                 'Cannot load the required Python module "cryptography".'
1347)             )
1348)             logger.info('pip users: see the "export" extra.')
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1349)             ctx.exit(1)
1350)         else:
1351)             if not _types.is_vault_config(config):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1352)                 logger.error('Invalid vault config: %r', config)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1353)                 ctx.exit(1)
1354)             click.echo(json.dumps(config, indent=2, sort_keys=True))
1355)             break
1356)     else:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1357)         logger.error('Cannot parse %r as a valid config.', path)
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

1358)         ctx.exit(1)
1359) 
1360) 
1361) # Vault
1362) # =====
1363) 
1364) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1365) def _config_filename(
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1366)     subsystem: str | None = 'old settings.json',
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1367) ) -> str | bytes | pathlib.Path:
1368)     """Return the filename of the configuration file for the subsystem.
1369) 
1370)     The (implicit default) file is currently named `settings.json`,
1371)     located within the configuration directory as determined by the
1372)     `DERIVEPASSPHRASE_PATH` environment variable, or by
1373)     [`click.get_app_dir`][] in POSIX mode.  Depending on the requested
1374)     subsystem, this will usually be a different file within that
1375)     directory.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1376) 
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1377)     Args:
1378)         subsystem:
1379)             Name of the configuration subsystem whose configuration
1380)             filename to return.  If not given, return the old filename
1381)             from before the subcommand migration.  If `None`, return the
1382)             configuration directory instead.
1383) 
1384)     Raises:
1385)         AssertionError:
1386)             An unknown subsystem was passed.
1387) 
1388)     Deprecated:
1389)         Since v0.2.0: The implicit default subsystem and the old
1390)         configuration filename are deprecated, and will be removed in v1.0.
1391)         The subsystem will be mandatory to specify.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1392) 
1393)     """
1394)     path: str | bytes | pathlib.Path
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1395)     path = os.getenv(PROG_NAME.upper() + '_PATH') or click.get_app_dir(
1396)         PROG_NAME, force_posix=True
1397)     )
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1398)     # Use match/case here once Python 3.9 becomes unsupported.
1399)     if subsystem is None:
1400)         return path
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1401)     elif subsystem == 'vault':  # noqa: RET505
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1402)         filename = f'{subsystem}.json'
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

1403)     elif subsystem == 'user configuration':
1404)         filename = 'config.toml'
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1405)     elif subsystem == 'old settings.json':
1406)         filename = 'settings.json'
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

1407)     else:  # pragma: no cover
1408)         msg = f'Unknown configuration subsystem: {subsystem!r}'
1409)         raise AssertionError(msg)
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1410)     return os.path.join(path, filename)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1411) 
1412) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1413) def _load_config() -> _types.VaultConfig:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1414)     """Load a vault(1)-compatible config from the application directory.
1415) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1416)     The filename is obtained via [`_config_filename`][].  This must be
1417)     an unencrypted JSON file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1418) 
1419)     Returns:
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1420)         The vault settings.  See [`_types.VaultConfig`][] for details.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1421) 
1422)     Raises:
1423)         OSError:
1424)             There was an OS error accessing the file.
1425)         ValueError:
1426)             The data loaded from the file is not a vault(1)-compatible
1427)             config.
1428) 
1429)     """
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1430)     filename = _config_filename(subsystem='vault')
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1431)     with open(filename, 'rb') as fileobj:
1432)         data = json.load(fileobj)
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1433)     if not _types.is_vault_config(data):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1434)         raise ValueError(_INVALID_VAULT_CONFIG)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1435)     return data
1436) 
1437) 
Marco Ricci Permit one flaky test and f...

Marco Ricci authored 3 months ago

1438) def _migrate_and_load_old_config() -> tuple[
1439)     _types.VaultConfig, OSError | None
1440) ]:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1441)     """Load and migrate a vault(1)-compatible config.
1442) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1443)     The (old) filename is obtained via [`_config_filename`][].  This
1444)     must be an unencrypted JSON file.  After loading, the file is
1445)     migrated to the new standard filename.
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1446) 
1447)     Returns:
1448)         The vault settings, and an optional exception encountered during
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1449)         migration.  See [`_types.VaultConfig`][] for details on the
1450)         former.
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1451) 
1452)     Raises:
1453)         OSError:
1454)             There was an OS error accessing the old file.
1455)         ValueError:
1456)             The data loaded from the file is not a vault(1)-compatible
1457)             config.
1458) 
1459)     """
1460)     new_filename = _config_filename(subsystem='vault')
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

1461)     old_filename = _config_filename(subsystem='old settings.json')
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1462)     with open(old_filename, 'rb') as fileobj:
1463)         data = json.load(fileobj)
1464)     if not _types.is_vault_config(data):
1465)         raise ValueError(_INVALID_VAULT_CONFIG)
1466)     try:
1467)         os.replace(old_filename, new_filename)
1468)     except OSError as exc:
1469)         return data, exc
1470)     else:
1471)         return data, None
1472) 
1473) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1474) def _save_config(config: _types.VaultConfig, /) -> None:
Marco Ricci Create the configuration di...

Marco Ricci authored 5 months ago

1475)     """Save a vault(1)-compatible config to the application directory.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1476) 
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1477)     The filename is obtained via [`_config_filename`][].  The config
1478)     will be stored as an unencrypted JSON file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1479) 
1480)     Args:
1481)         config:
1482)             vault configuration to save.
1483) 
1484)     Raises:
1485)         OSError:
1486)             There was an OS error accessing or writing the file.
1487)         ValueError:
1488)             The data cannot be stored as a vault(1)-compatible config.
1489) 
1490)     """
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1491)     if not _types.is_vault_config(config):
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1492)         raise ValueError(_INVALID_VAULT_CONFIG)
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

1493)     filename = _config_filename(subsystem='vault')
Marco Ricci Create the configuration di...

Marco Ricci authored 5 months ago

1494)     filedir = os.path.dirname(os.path.abspath(filename))
1495)     try:
1496)         os.makedirs(filedir, exist_ok=False)
1497)     except FileExistsError:
1498)         if not os.path.isdir(filedir):
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1499)             raise  # noqa: DOC501
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1500)     with open(filename, 'w', encoding='UTF-8') as fileobj:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1501)         json.dump(config, fileobj)
1502) 
1503) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

1504) def _load_user_config() -> dict[str, Any]:
1505)     """Load the user config from the application directory.
1506) 
1507)     The filename is obtained via [`_config_filename`][].
1508) 
1509)     Returns:
1510)         The user configuration, as a nested `dict`.
1511) 
1512)     Raises:
1513)         OSError:
1514)             There was an OS error accessing the file.
1515)         ValueError:
1516)             The data loaded from the file is not a valid configuration
1517)             file.
1518) 
1519)     """
1520)     filename = _config_filename(subsystem='user configuration')
1521)     with open(filename, 'rb') as fileobj:
1522)         return tomllib.load(fileobj)
1523) 
1524) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1525) def _get_suitable_ssh_keys(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

1526)     conn: ssh_agent.SSHAgentClient | socket.socket | None = None, /
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

1527) ) -> Iterator[_types.KeyCommentPair]:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1528)     """Yield all SSH keys suitable for passphrase derivation.
1529) 
1530)     Suitable SSH keys are queried from the running SSH agent (see
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1531)     [`ssh_agent.SSHAgentClient.list_keys`][]).
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1532) 
1533)     Args:
1534)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1535)             An optional connection hint to the SSH agent.  See
1536)             [`ssh_agent.SSHAgentClient.ensure_agent_subcontext`][].
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1537) 
1538)     Yields:
Marco Ricci Convert old syntax for Yiel...

Marco Ricci authored 3 months ago

1539)         Every SSH key from the SSH agent that is suitable for passphrase
1540)         derivation.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1541) 
1542)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1543)         KeyError:
1544)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1545)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

1546)         NotImplementedError:
1547)             `conn` was `None`, and this Python does not support
1548)             [`socket.AF_UNIX`][], so the SSH agent client cannot be
1549)             automatically set up.
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1550)         OSError:
1551)             `conn` was a socket or `None`, and there was an error
1552)             setting up a socket connection to the agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1553)         LookupError:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1554)             No keys usable for passphrase derivation are loaded into the
1555)             SSH agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1556)         RuntimeError:
1557)             There was an error communicating with the SSH agent.
Marco Ricci Fix miscellaneous small doc...

Marco Ricci authored 3 months ago

1558)         ssh_agent.SSHAgentFailedError:
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

1559)             The agent failed to supply a list of loaded keys.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1560) 
1561)     """
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1562)     with ssh_agent.SSHAgentClient.ensure_agent_subcontext(conn) as client:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1563)         try:
1564)             all_key_comment_pairs = list(client.list_keys())
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1565)         except EOFError as exc:  # pragma: no cover
1566)             raise RuntimeError(_AGENT_COMMUNICATION_ERROR) from exc
Marco Ricci Publish polished `is_suitab...

Marco Ricci authored 1 month ago

1567)         suitable_keys = copy.copy(all_key_comment_pairs)
1568)         for pair in all_key_comment_pairs:
1569)             key, _comment = pair
1570)             if vault.Vault.is_suitable_ssh_key(key, client=client):
1571)                 yield pair
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1572)     if not suitable_keys:  # pragma: no cover
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1573)         raise LookupError(_NO_SUITABLE_KEYS)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1574) 
1575) 
1576) def _prompt_for_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1577)     items: Sequence[str | bytes],
1578)     heading: str = 'Possible choices:',
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1579)     single_choice_prompt: str = 'Confirm this choice?',
1580) ) -> int:
1581)     """Prompt user for a choice among the given items.
1582) 
1583)     Print the heading, if any, then present the items to the user.  If
1584)     there are multiple items, prompt the user for a selection, validate
1585)     the choice, then return the list index of the selected item.  If
1586)     there is only a single item, request confirmation for that item
1587)     instead, and return the correct index.
1588) 
1589)     Args:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1590)         items:
1591)             The list of items to choose from.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1592)         heading:
1593)             A heading for the list of items, to print immediately
1594)             before.  Defaults to a reasonable standard heading.  If
1595)             explicitly empty, print no heading.
1596)         single_choice_prompt:
1597)             The confirmation prompt if there is only a single possible
1598)             choice.  Defaults to a reasonable standard prompt.
1599) 
1600)     Returns:
1601)         An index into the items sequence, indicating the user's
1602)         selection.
1603) 
1604)     Raises:
1605)         IndexError:
1606)             The user made an invalid or empty selection, or requested an
1607)             abort.
1608) 
1609)     """
1610)     n = len(items)
1611)     if heading:
1612)         click.echo(click.style(heading, bold=True))
1613)     for i, x in enumerate(items, start=1):
1614)         click.echo(click.style(f'[{i}]', bold=True), nl=False)
1615)         click.echo(' ', nl=False)
1616)         click.echo(x)
1617)     if n > 1:
1618)         choices = click.Choice([''] + [str(i) for i in range(1, n + 1)])
1619)         choice = click.prompt(
1620)             f'Your selection? (1-{n}, leave empty to abort)',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1621)             err=True,
1622)             type=choices,
1623)             show_choices=False,
1624)             show_default=False,
1625)             default='',
1626)         )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1627)         if not choice:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1628)             raise IndexError(_EMPTY_SELECTION)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1629)         return int(choice) - 1
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1630)     prompt_suffix = (
1631)         ' ' if single_choice_prompt.endswith(tuple('?.!')) else ': '
1632)     )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1633)     try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1634)         click.confirm(
1635)             single_choice_prompt,
1636)             prompt_suffix=prompt_suffix,
1637)             err=True,
1638)             abort=True,
1639)             default=False,
1640)             show_default=False,
1641)         )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1642)     except click.Abort:
1643)         raise IndexError(_EMPTY_SELECTION) from None
1644)     return 0
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1645) 
1646) 
1647) def _select_ssh_key(
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

1648)     conn: ssh_agent.SSHAgentClient | socket.socket | None = None, /
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1649) ) -> bytes | bytearray:
1650)     """Interactively select an SSH key for passphrase derivation.
1651) 
1652)     Suitable SSH keys are queried from the running SSH agent (see
Marco Ricci Generate nicer documentatio...

Marco Ricci authored 3 months ago

1653)     [`ssh_agent.SSHAgentClient.list_keys`][]), then the user is prompted
1654)     interactively (see [`click.prompt`][]) for a selection.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1655) 
1656)     Args:
1657)         conn:
Marco Ricci Support one-off SSH agent c...

Marco Ricci authored 1 month ago

1658)             An optional connection hint to the SSH agent.  See
1659)             [`ssh_agent.SSHAgentClient.ensure_agent_subcontext`][].
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1660) 
1661)     Returns:
1662)         The selected SSH key.
1663) 
1664)     Raises:
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1665)         KeyError:
1666)             `conn` was `None`, and the `SSH_AUTH_SOCK` environment
1667)             variable was not found.
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

1668)         NotImplementedError:
1669)             `conn` was `None`, and this Python does not support
1670)             [`socket.AF_UNIX`][], so the SSH agent client cannot be
1671)             automatically set up.
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

1672)         OSError:
1673)             `conn` was a socket or `None`, and there was an error
1674)             setting up a socket connection to the agent.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1675)         IndexError:
1676)             The user made an invalid or empty selection, or requested an
1677)             abort.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1678)         LookupError:
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1679)             No keys usable for passphrase derivation are loaded into the
1680)             SSH agent.
Marco Ricci Distinguish between a key l...

Marco Ricci authored 6 months ago

1681)         RuntimeError:
1682)             There was an error communicating with the SSH agent.
Marco Ricci Add a specific error class...

Marco Ricci authored 4 months ago

1683)         SSHAgentFailedError:
1684)             The agent failed to supply a list of loaded keys.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1685)     """
1686)     suitable_keys = list(_get_suitable_ssh_keys(conn))
1687)     key_listing: list[str] = []
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

1688)     unstring_prefix = ssh_agent.SSHAgentClient.unstring_prefix
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1689)     for key, comment in suitable_keys:
1690)         keytype = unstring_prefix(key)[0].decode('ASCII')
1691)         key_str = base64.standard_b64encode(key).decode('ASCII')
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

1692)         remaining_key_display_length = KEY_DISPLAY_LENGTH - 1 - len(keytype)
1693)         key_extract = min(
1694)             key_str,
1695)             '...' + key_str[-remaining_key_display_length:],
1696)             key=len,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1697)         )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1698)         comment_str = comment.decode('UTF-8', errors='replace')
Marco Ricci Make suitable SSH key listi...

Marco Ricci authored 1 month ago

1699)         key_listing.append(f'{keytype} {key_extract}  {comment_str}')
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1700)     choice = _prompt_for_selection(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1701)         key_listing,
1702)         heading='Suitable SSH keys:',
1703)         single_choice_prompt='Use this key?',
1704)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1705)     return suitable_keys[choice].key
1706) 
1707) 
1708) def _prompt_for_passphrase() -> str:
1709)     """Interactively prompt for the passphrase.
1710) 
1711)     Calls [`click.prompt`][] internally.  Moved into a separate function
1712)     mainly for testing/mocking purposes.
1713) 
1714)     Returns:
1715)         The user input.
1716) 
1717)     """
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

1718)     return cast(
1719)         str,
1720)         click.prompt(
1721)             'Passphrase',
1722)             default='',
1723)             hide_input=True,
1724)             show_default=False,
1725)             err=True,
1726)         ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1727)     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

1728) 
1729) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1730) def _toml_key(*parts: str) -> str:
1731)     """Return a formatted TOML key, given its parts."""
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

1732) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1733)     def escape(string: str) -> str:
1734)         translated = string.translate({
1735)             0: r'\u0000',
1736)             1: r'\u0001',
1737)             2: r'\u0002',
1738)             3: r'\u0003',
1739)             4: r'\u0004',
1740)             5: r'\u0005',
1741)             6: r'\u0006',
1742)             7: r'\u0007',
1743)             8: r'\b',
1744)             9: r'\t',
1745)             10: r'\n',
1746)             11: r'\u000B',
1747)             12: r'\f',
1748)             13: r'\r',
1749)             14: r'\u000E',
1750)             15: r'\u000F',
1751)             ord('"'): r'\"',
1752)             ord('\\'): r'\\',
1753)             127: r'\u007F',
1754)         })
1755)         return f'"{translated}"' if translated != string else string
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

1756) 
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1757)     return '.'.join(map(escape, parts))
1758) 
1759) 
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

1760) class _ORIGIN(enum.Enum):
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1761)     INTERACTIVE: str = 'interactive input'
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

1762) 
1763) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1764) def _check_for_misleading_passphrase(
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

1765)     key: tuple[str, ...] | _ORIGIN,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1766)     value: dict[str, Any],
1767)     *,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1768)     main_config: dict[str, Any],
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1769) ) -> None:
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1770)     form_key = 'unicode-normalization-form'
1771)     default_form: str = main_config.get('vault', {}).get(
1772)         f'default-{form_key}', 'NFC'
1773)     )
1774)     form_dict: dict[str, dict] = main_config.get('vault', {}).get(form_key, {})
1775)     form: Any = (
1776)         default_form
1777)         if isinstance(key, _ORIGIN) or key == ('global',)
1778)         else form_dict.get(key[1], default_form)
1779)     )
1780)     config_key = (
1781)         _toml_key('vault', key[1], form_key)
1782)         if isinstance(key, tuple) and len(key) > 1 and key[1] in form_dict
1783)         else f'vault.default-{form_key}'
1784)     )
1785)     if form not in {'NFC', 'NFD', 'NFKC', 'NFKD'}:
1786)         msg = f'Invalid value {form!r} for config key {config_key}'
1787)         raise AssertionError(msg)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1788)     logger = logging.getLogger(PROG_NAME)
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1789)     formatted_key = (
1790)         key.value if isinstance(key, _ORIGIN) else _types.json_path(key)
1791)     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1792)     if 'phrase' in value:
1793)         phrase = value['phrase']
1794)         if not unicodedata.is_normalized(form, phrase):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1795)             logger.warning(
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1796)                 (
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1797)                     'The %s passphrase is not %s-normalized.  Its '
1798)                     'serialization as a byte string may not be what you '
1799)                     'expect it to be, even if it *displays* correctly.  '
1800)                     'Please make sure to double-check any derived '
1801)                     'passphrases for unexpected results.'
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1802)                 ),
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

1803)                 formatted_key,
1804)                 form,
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

1805)                 stacklevel=2,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

1806)             )
1807) 
1808) 
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1809) def _key_to_phrase(
1810)     key_: str | bytes | bytearray,
1811)     /,
1812)     *,
1813)     error_callback: Callable[..., NoReturn] = sys.exit,
1814) ) -> bytes | bytearray:
1815)     key = base64.standard_b64decode(key_)
1816)     try:
1817)         with ssh_agent.SSHAgentClient.ensure_agent_subcontext() as client:
1818)             try:
1819)                 return vault.Vault.phrase_from_key(key, conn=client)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1820)             except ssh_agent.SSHAgentFailedError as exc:
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1821)                 try:
1822)                     keylist = client.list_keys()
1823)                 except ssh_agent.SSHAgentFailedError:
1824)                     pass
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1825)                 except Exception as exc2:  # noqa: BLE001
1826)                     exc.__context__ = exc2
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1827)                 else:
1828)                     if not any(  # pragma: no branch
1829)                         k == key for k, _ in keylist
1830)                     ):
1831)                         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1832)                             _msg.TranslatedString(
1833)                                 _msg.ErrMsgTemplate.SSH_KEY_NOT_LOADED
1834)                             )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1835)                         )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1836)                 error_callback(
1837)                     _msg.TranslatedString(
1838)                         _msg.ErrMsgTemplate.AGENT_REFUSED_SIGNATURE
1839)                     ),
1840)                     exc_info=exc,
1841)                 )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1842)     except KeyError:
1843)         error_callback(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1844)             _msg.TranslatedString(_msg.ErrMsgTemplate.NO_SSH_AGENT_FOUND)
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1845)         )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1846)     except NotImplementedError:
1847)         error_callback(_msg.TranslatedString(_msg.ErrMsgTemplate.NO_AF_UNIX))
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

1848)     except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1849)         error_callback(
1850)             _msg.TranslatedString(
1851)                 _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
1852)                 error=exc.strerror,
1853)                 filename=exc.filename,
1854)             ).maybe_without_filename()
1855)         )
1856)     except RuntimeError as exc:
1857)         error_callback(
1858)             _msg.TranslatedString(_msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT),
1859)             exc_info=exc,
1860)         )
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

1861) 
1862) 
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

1863) def _print_config_as_sh_script(
1864)     config: _types.VaultConfig,
1865)     /,
1866)     *,
1867)     outfile: TextIO,
1868)     prog_name_list: Sequence[str],
1869) ) -> None:
1870)     service_keys = (
1871)         'length',
1872)         'repeat',
1873)         'lower',
1874)         'upper',
1875)         'number',
1876)         'space',
1877)         'dash',
1878)         'symbol',
1879)     )
1880)     print('#!/bin/sh -e', file=outfile)
1881)     print(file=outfile)
1882)     print(shlex.join([*prog_name_list, '--clear']), file=outfile)
1883)     sv_obj_pairs: list[
1884)         tuple[
1885)             str | None,
1886)             _types.VaultConfigGlobalSettings
1887)             | _types.VaultConfigServicesSettings,
1888)         ],
1889)     ] = list(config['services'].items())
1890)     if config.get('global', {}):
1891)         sv_obj_pairs.insert(0, (None, config['global']))
1892)     for sv, sv_obj in sv_obj_pairs:
1893)         this_service_keys = tuple(k for k in service_keys if k in sv_obj)
1894)         this_other_keys = tuple(k for k in sv_obj if k not in service_keys)
1895)         if this_other_keys:
1896)             other_sv_obj = {k: sv_obj[k] for k in this_other_keys}  # type: ignore[literal-required]
1897)             dumped_config = json.dumps(
1898)                 (
1899)                     {'services': {sv: other_sv_obj}}
1900)                     if sv is not None
1901)                     else {'global': other_sv_obj, 'services': {}}
1902)                 ),
1903)                 ensure_ascii=False,
1904)                 indent=None,
1905)             )
1906)             print(
1907)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
1908)                 dumped_config,
1909)                 'HERE',
1910)                 sep='\n',
1911)                 file=outfile,
1912)             )
1913)         if not this_service_keys and not this_other_keys and sv:
1914)             dumped_config = json.dumps(
1915)                 {'services': {sv: {}}},
1916)                 ensure_ascii=False,
1917)                 indent=None,
1918)             )
1919)             print(
1920)                 shlex.join([*prog_name_list, '--import', '-']) + " <<'HERE'",
1921)                 dumped_config,
1922)                 'HERE',
1923)                 sep='\n',
1924)                 file=outfile,
1925)             )
1926)         elif this_service_keys:
1927)             tokens = [*prog_name_list, '--config']
1928)             for key in this_service_keys:
1929)                 tokens.extend([f'--{key}', str(sv_obj[key])])  # type: ignore[literal-required]
1930)             if sv is not None:
1931)                 tokens.extend(['--', sv])
1932)             print(shlex.join(tokens), file=outfile)
1933) 
1934) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

1935) # Concrete option groups used by this command-line interface.
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

1936) class PassphraseGenerationOption(OptionGroupOption):
1937)     """Passphrase generation options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1938) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1939)     option_group_name = _msg.TranslatedString(
1940)         _msg.Label.PASSPHRASE_GENERATION_LABEL
1941)     )
1942)     epilog = _msg.TranslatedString(
1943)         _msg.Label.PASSPHRASE_GENERATION_EPILOG,
1944)         metavar=_msg.TranslatedString(
1945)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
1946)         ),
1947)     )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1948) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

1949) 
1950) class ConfigurationOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1951)     """Configuration options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1952) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1953)     option_group_name = _msg.TranslatedString(_msg.Label.CONFIGURATION_LABEL)
1954)     epilog = _msg.TranslatedString(_msg.Label.CONFIGURATION_EPILOG)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1955) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

1956) 
1957) class StorageManagementOption(OptionGroupOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1958)     """Storage management options for the CLI."""
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1959) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1960)     option_group_name = _msg.TranslatedString(
1961)         _msg.Label.STORAGE_MANAGEMENT_LABEL
1962)     )
1963)     epilog = _msg.TranslatedString(
1964)         _msg.Label.STORAGE_MANAGEMENT_EPILOG,
1965)         metavar=_msg.TranslatedString(
1966)             _msg.Label.STORAGE_MANAGEMENT_METAVAR_PATH
1967)         ),
1968)     )
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1969) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

1970) 
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

1971) class CompatibilityOption(OptionGroupOption):
1972)     """Compatibility and incompatibility options for the CLI."""
1973) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

1974)     option_group_name = _msg.TranslatedString(
1975)         _msg.Label.COMPATIBILITY_OPTION_LABEL
1976)     )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

1977) 
1978) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

1979) def _validate_occurrence_constraint(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1980)     ctx: click.Context,
1981)     param: click.Parameter,
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1982)     value: Any,  # noqa: ANN401
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

1983) ) -> int | None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

1984)     """Check that the occurrence constraint is valid (int, 0 or larger).
1985) 
1986)     Args:
1987)         ctx: The `click` context.
1988)         param: The current command-line parameter.
1989)         value: The parameter value to be checked.
1990) 
1991)     Returns:
1992)         The parsed parameter value.
1993) 
1994)     Raises:
1995)         click.BadParameter: The parameter value is invalid.
1996) 
1997)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

1998)     del ctx  # Unused.
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

1999)     del param  # Unused.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2000)     if value is None:
2001)         return value
2002)     if isinstance(value, int):
2003)         int_value = value
2004)     else:
2005)         try:
2006)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2007)         except ValueError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2008)             raise click.BadParameter(_NOT_AN_INTEGER) from exc
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2009)     if int_value < 0:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2010)         raise click.BadParameter(_NOT_A_NONNEGATIVE_INTEGER)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2011)     return int_value
2012) 
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2013) 
2014) def _validate_length(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2015)     ctx: click.Context,
2016)     param: click.Parameter,
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2017)     value: Any,  # noqa: ANN401
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2018) ) -> int | None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2019)     """Check that the length is valid (int, 1 or larger).
2020) 
2021)     Args:
2022)         ctx: The `click` context.
2023)         param: The current command-line parameter.
2024)         value: The parameter value to be checked.
2025) 
2026)     Returns:
2027)         The parsed parameter value.
2028) 
2029)     Raises:
2030)         click.BadParameter: The parameter value is invalid.
2031) 
2032)     """
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2033)     del ctx  # Unused.
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

2034)     del param  # Unused.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2035)     if value is None:
2036)         return value
2037)     if isinstance(value, int):
2038)         int_value = value
2039)     else:
2040)         try:
2041)             int_value = int(value, 10)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2042)         except ValueError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2043)             raise click.BadParameter(_NOT_AN_INTEGER) from exc
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2044)     if int_value < 1:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2045)         raise click.BadParameter(_NOT_A_POSITIVE_INTEGER)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2046)     return int_value
2047) 
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2048) 
2049) DEFAULT_NOTES_TEMPLATE = """\
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2050) # Enter notes below the line with the cut mark (ASCII scissors and
2051) # dashes).  Lines above the cut mark (such as this one) will be ignored.
2052) #
2053) # If you wish to clear the notes, leave everything beyond the cut mark
2054) # blank.  However, if you leave the *entire* file blank, also removing
2055) # the cut mark, then the edit is aborted, and the old notes contents are
2056) # retained.
2057) #
2058) # - - - - - >8 - - - - - >8 - - - - - >8 - - - - - >8 - - - - -
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2059) """
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2060) DEFAULT_NOTES_MARKER = '# - - - - - >8 - - - - -'
2061) 
2062) 
Marco Ricci Reimplement deprecated subc...

Marco Ricci authored 1 month ago

2063) @derivepassphrase.command(
2064)     'vault',
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2065)     context_settings={'help_option_names': ['-h', '--help']},
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2066)     cls=CommandWithHelpGroups,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2067)     help=(
2068)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_01),
2069)         _msg.TranslatedString(
2070)             _msg.Label.DERIVEPASSPHRASE_VAULT_02,
2071)             service_metavar=_msg.TranslatedString(
2072)                 _msg.Label.VAULT_METAVAR_SERVICE
2073)             ),
2074)         ),
2075)     ),
2076)     epilog=(
2077)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_01),
2078)         _msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_VAULT_EPILOG_02),
2079)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2080) )
2081) @click.option(
2082)     '-p',
2083)     '--phrase',
2084)     'use_phrase',
2085)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2086)     help=_msg.TranslatedString(
2087)         _msg.Label.DERIVEPASSPHRASE_VAULT_PHRASE_HELP_TEXT
2088)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2089)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2090) )
2091) @click.option(
2092)     '-k',
2093)     '--key',
2094)     'use_key',
2095)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2096)     help=_msg.TranslatedString(
2097)         _msg.Label.DERIVEPASSPHRASE_VAULT_KEY_HELP_TEXT
2098)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2099)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2100) )
2101) @click.option(
2102)     '-l',
2103)     '--length',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2104)     metavar=_msg.TranslatedString(
2105)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2106)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2107)     callback=_validate_length,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2108)     help=_msg.TranslatedString(
2109)         _msg.Label.DERIVEPASSPHRASE_VAULT_LENGTH_HELP_TEXT,
2110)         metavar=_msg.TranslatedString(
2111)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2112)         ),
2113)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2114)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2115) )
2116) @click.option(
2117)     '-r',
2118)     '--repeat',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2119)     metavar=_msg.TranslatedString(
2120)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2121)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2122)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2123)     help=_msg.TranslatedString(
2124)         _msg.Label.DERIVEPASSPHRASE_VAULT_REPEAT_HELP_TEXT,
2125)         metavar=_msg.TranslatedString(
2126)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2127)         ),
2128)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2129)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2130) )
2131) @click.option(
2132)     '--lower',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2133)     metavar=_msg.TranslatedString(
2134)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2135)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2136)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2137)     help=_msg.TranslatedString(
2138)         _msg.Label.DERIVEPASSPHRASE_VAULT_LOWER_HELP_TEXT,
2139)         metavar=_msg.TranslatedString(
2140)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2141)         ),
2142)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2143)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2144) )
2145) @click.option(
2146)     '--upper',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2147)     metavar=_msg.TranslatedString(
2148)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2149)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2150)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2151)     help=_msg.TranslatedString(
2152)         _msg.Label.DERIVEPASSPHRASE_VAULT_UPPER_HELP_TEXT,
2153)         metavar=_msg.TranslatedString(
2154)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2155)         ),
2156)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2157)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2158) )
2159) @click.option(
2160)     '--number',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2161)     metavar=_msg.TranslatedString(
2162)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2163)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2164)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2165)     help=_msg.TranslatedString(
2166)         _msg.Label.DERIVEPASSPHRASE_VAULT_NUMBER_HELP_TEXT,
2167)         metavar=_msg.TranslatedString(
2168)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2169)         ),
2170)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2171)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2172) )
2173) @click.option(
2174)     '--space',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2175)     metavar=_msg.TranslatedString(
2176)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2177)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2178)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2179)     help=_msg.TranslatedString(
2180)         _msg.Label.DERIVEPASSPHRASE_VAULT_SPACE_HELP_TEXT,
2181)         metavar=_msg.TranslatedString(
2182)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2183)         ),
2184)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2185)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2186) )
2187) @click.option(
2188)     '--dash',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2189)     metavar=_msg.TranslatedString(
2190)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2191)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2192)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2193)     help=_msg.TranslatedString(
2194)         _msg.Label.DERIVEPASSPHRASE_VAULT_DASH_HELP_TEXT,
2195)         metavar=_msg.TranslatedString(
2196)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2197)         ),
2198)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2199)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2200) )
2201) @click.option(
2202)     '--symbol',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2203)     metavar=_msg.TranslatedString(
2204)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2205)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2206)     callback=_validate_occurrence_constraint,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2207)     help=_msg.TranslatedString(
2208)         _msg.Label.DERIVEPASSPHRASE_VAULT_SYMBOL_HELP_TEXT,
2209)         metavar=_msg.TranslatedString(
2210)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2211)         ),
2212)     ),
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2213)     cls=PassphraseGenerationOption,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2214) )
2215) @click.option(
2216)     '-n',
2217)     '--notes',
2218)     'edit_notes',
2219)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2220)     help=_msg.TranslatedString(
2221)         _msg.Label.DERIVEPASSPHRASE_VAULT_NOTES_HELP_TEXT,
2222)         service_metavar=_msg.TranslatedString(
2223)             _msg.Label.VAULT_METAVAR_SERVICE
2224)         ),
2225)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2226)     cls=ConfigurationOption,
2227) )
2228) @click.option(
2229)     '-c',
2230)     '--config',
2231)     'store_config_only',
2232)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2233)     help=_msg.TranslatedString(
2234)         _msg.Label.DERIVEPASSPHRASE_VAULT_CONFIG_HELP_TEXT,
2235)         service_metavar=_msg.TranslatedString(
2236)             _msg.Label.VAULT_METAVAR_SERVICE
2237)         ),
2238)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2239)     cls=ConfigurationOption,
2240) )
2241) @click.option(
2242)     '-x',
2243)     '--delete',
2244)     'delete_service_settings',
2245)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2246)     help=_msg.TranslatedString(
2247)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_HELP_TEXT,
2248)         service_metavar=_msg.TranslatedString(
2249)             _msg.Label.VAULT_METAVAR_SERVICE
2250)         ),
2251)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2252)     cls=ConfigurationOption,
2253) )
2254) @click.option(
2255)     '--delete-globals',
2256)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2257)     help=_msg.TranslatedString(
2258)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_GLOBALS_HELP_TEXT,
2259)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2260)     cls=ConfigurationOption,
2261) )
2262) @click.option(
2263)     '-X',
2264)     '--clear',
2265)     'clear_all_settings',
2266)     is_flag=True,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2267)     help=_msg.TranslatedString(
2268)         _msg.Label.DERIVEPASSPHRASE_VAULT_DELETE_ALL_HELP_TEXT,
2269)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2270)     cls=ConfigurationOption,
2271) )
2272) @click.option(
2273)     '-e',
2274)     '--export',
2275)     'export_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2276)     metavar=_msg.TranslatedString(
2277)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2278)     ),
2279)     help=_msg.TranslatedString(
2280)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_HELP_TEXT,
2281)         metavar=_msg.TranslatedString(
2282)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2283)         ),
2284)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2285)     cls=StorageManagementOption,
2286) )
2287) @click.option(
2288)     '-i',
2289)     '--import',
2290)     'import_settings',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2291)     metavar=_msg.TranslatedString(
2292)         _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2293)     ),
2294)     help=_msg.TranslatedString(
2295)         _msg.Label.DERIVEPASSPHRASE_VAULT_IMPORT_HELP_TEXT,
2296)         metavar=_msg.TranslatedString(
2297)             _msg.Label.PASSPHRASE_GENERATION_METAVAR_NUMBER
2298)         ),
2299)     ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2300)     cls=StorageManagementOption,
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2301) )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2302) @click.option(
2303)     '--overwrite-existing/--merge-existing',
2304)     'overwrite_config',
2305)     default=False,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2306)     help=_msg.TranslatedString(
2307)         _msg.Label.DERIVEPASSPHRASE_VAULT_OVERWRITE_HELP_TEXT
2308)     ),
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2309)     cls=CompatibilityOption,
2310) )
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2311) @click.option(
2312)     '--unset',
2313)     'unset_settings',
2314)     multiple=True,
2315)     type=click.Choice([
2316)         'phrase',
2317)         'key',
2318)         'length',
2319)         'repeat',
2320)         'lower',
2321)         'upper',
2322)         'number',
2323)         'space',
2324)         'dash',
2325)         'symbol',
2326)     ]),
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2327)     help=_msg.TranslatedString(
2328)         _msg.Label.DERIVEPASSPHRASE_VAULT_UNSET_HELP_TEXT
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2329)     ),
2330)     cls=CompatibilityOption,
2331) )
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2332) @click.option(
2333)     '--export-as',
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2334)     type=click.Choice(['json', 'sh']),
2335)     default='json',
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2336)     help=_msg.TranslatedString(
2337)         _msg.Label.DERIVEPASSPHRASE_VAULT_EXPORT_AS_HELP_TEXT
2338)     ),
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2339)     cls=CompatibilityOption,
2340) )
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

2341) @click.version_option(version=dpp.__version__, prog_name=PROG_NAME)
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2342) @standard_logging_options
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2343) @click.argument(
2344)     'service',
2345)     metavar=_msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE),
2346)     required=False,
2347)     default=None,
2348) )
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2349) @click.pass_context
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

2350) def derivepassphrase_vault(  # noqa: C901,PLR0912,PLR0913,PLR0914,PLR0915
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2351)     ctx: click.Context,
2352)     /,
2353)     *,
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2354)     service: str | None = None,
2355)     use_phrase: bool = False,
2356)     use_key: bool = False,
2357)     length: int | None = None,
2358)     repeat: int | None = None,
2359)     lower: int | None = None,
2360)     upper: int | None = None,
2361)     number: int | None = None,
2362)     space: int | None = None,
2363)     dash: int | None = None,
2364)     symbol: int | None = None,
2365)     edit_notes: bool = False,
2366)     store_config_only: bool = False,
2367)     delete_service_settings: bool = False,
2368)     delete_globals: bool = False,
2369)     clear_all_settings: bool = False,
2370)     export_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
2371)     import_settings: TextIO | pathlib.Path | os.PathLike[str] | None = None,
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2372)     overwrite_config: bool = False,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2373)     unset_settings: Sequence[str] = (),
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2374)     export_as: Literal['json', 'sh'] = 'json',
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2375) ) -> None:
Marco Ricci Reintegrate all functionali...

Marco Ricci authored 3 months ago

2376)     """Derive a passphrase using the vault(1) derivation scheme.
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2377) 
2378)     This is a [`click`][CLICK]-powered command-line interface function,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2379)     and not intended for programmatic use.  See the
2380)     derivepassphrase-vault(1) manpage for full documentation of the
2381)     interface.  (See also [`click.testing.CliRunner`][] for controlled,
2382)     programmatic invocation.)
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2383) 
Marco Ricci Update all URLs to stable a...

Marco Ricci authored 3 months ago

2384)     [CLICK]: https://pypi.org/package/click/
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2385) 
2386)     Parameters:
2387)         ctx (click.Context):
2388)             The `click` context.
2389) 
2390)     Other Parameters:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2391)         service:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2392)             A service name.  Required, unless operating on global
2393)             settings or importing/exporting settings.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2394)         use_phrase:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2395)             Command-line argument `-p`/`--phrase`.  If given, query the
2396)             user for a passphrase instead of an SSH key.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2397)         use_key:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2398)             Command-line argument `-k`/`--key`.  If given, query the
2399)             user for an SSH key instead of a passphrase.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2400)         length:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2401)             Command-line argument `-l`/`--length`.  Override the default
2402)             length of the generated passphrase.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2403)         repeat:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2404)             Command-line argument `-r`/`--repeat`.  Override the default
2405)             repetition limit if positive, or disable the repetition
2406)             limit if 0.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2407)         lower:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2408)             Command-line argument `--lower`.  Require a given amount of
2409)             ASCII lowercase characters if positive, else forbid ASCII
2410)             lowercase characters if 0.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2411)         upper:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2412)             Command-line argument `--upper`.  Same as `lower`, but for
2413)             ASCII uppercase characters.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2414)         number:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2415)             Command-line argument `--number`.  Same as `lower`, but for
2416)             ASCII digits.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2417)         space:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2418)             Command-line argument `--space`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2419)             the space character.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2420)         dash:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2421)             Command-line argument `--dash`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2422)             the hyphen-minus and underscore characters.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2423)         symbol:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2424)             Command-line argument `--symbol`.  Same as `lower`, but for
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2425)             all other ASCII printable characters (except backquote).
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2426)         edit_notes:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2427)             Command-line argument `-n`/`--notes`.  If given, spawn an
2428)             editor to edit notes for `service`.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2429)         store_config_only:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2430)             Command-line argument `-c`/`--config`.  If given, saves the
2431)             other given settings (`--key`, ..., `--symbol`) to the
2432)             configuration file, either specifically for `service` or as
2433)             global settings.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2434)         delete_service_settings:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2435)             Command-line argument `-x`/`--delete`.  If given, removes
2436)             the settings for `service` from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2437)         delete_globals:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2438)             Command-line argument `--delete-globals`.  If given, removes
2439)             the global settings from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2440)         clear_all_settings:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2441)             Command-line argument `-X`/`--clear`.  If given, removes all
2442)             settings from the configuration file.
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2443)         export_settings:
2444)             Command-line argument `-e`/`--export`.  If a file object,
2445)             then it must be open for writing and accept `str` inputs.
2446)             Otherwise, a filename to open for writing.  Using `-` for
2447)             standard output is supported.
2448)         import_settings:
2449)             Command-line argument `-i`/`--import`.  If a file object, it
2450)             must be open for reading and yield `str` values.  Otherwise,
2451)             a filename to open for reading.  Using `-` for standard
2452)             input is supported.
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2453)         overwrite_config:
2454)             Command-line arguments `--overwrite-existing` (True) and
2455)             `--merge-existing` (False).  Controls whether config saving
2456)             and config importing overwrite existing configurations, or
2457)             merge them section-wise instead.
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

2458)         unset_settings:
2459)             Command-line argument `--unset`.  If given together with
2460)             `--config`, unsets the specified settings (in addition to
2461)             any other changes requested).
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2462)         export_as:
2463)             Command-line argument `--export-as`.  If given together with
2464)             `--export`, selects the format to export the current
2465)             configuration as: JSON ("json", default) or POSIX sh ("sh").
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2466) 
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2467)     """
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2468)     logger = logging.getLogger(PROG_NAME)
2469)     deprecation = logging.getLogger(PROG_NAME + '.deprecation')
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2470)     service_metavar = _msg.TranslatedString(_msg.Label.VAULT_METAVAR_SERVICE)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2471)     options_in_group: dict[type[click.Option], list[click.Option]] = {}
2472)     params_by_str: dict[str, click.Parameter] = {}
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2473)     for param in ctx.command.params:
2474)         if isinstance(param, click.Option):
2475)             group: type[click.Option]
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2476)             # Use match/case here once Python 3.9 becomes unsupported.
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2477)             if isinstance(param, PassphraseGenerationOption):
2478)                 group = PassphraseGenerationOption
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2479)             elif isinstance(param, ConfigurationOption):
2480)                 group = ConfigurationOption
2481)             elif isinstance(param, StorageManagementOption):
2482)                 group = StorageManagementOption
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2483)             elif isinstance(param, LoggingOption):
2484)                 group = LoggingOption
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2485)             elif isinstance(param, CompatibilityOption):
2486)                 group = CompatibilityOption
Marco Ricci Add support for Python 3.9

Marco Ricci authored 3 months ago

2487)             elif isinstance(param, OptionGroupOption):
2488)                 raise AssertionError(  # noqa: DOC501,TRY003,TRY004
2489)                     f'Unknown option group for {param!r}'  # noqa: EM102
2490)                 )
2491)             else:
2492)                 group = click.Option
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2493)             options_in_group.setdefault(group, []).append(param)
2494)         params_by_str[param.human_readable_name] = param
2495)         for name in param.opts + param.secondary_opts:
2496)             params_by_str[name] = param
2497) 
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2498)     @functools.cache
Marco Ricci Fix typing issues in mypy s...

Marco Ricci authored 5 months ago

2499)     def is_param_set(param: click.Parameter) -> bool:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2500)         return bool(ctx.params.get(param.human_readable_name))
2501) 
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2502)     def option_name(param: click.Parameter | str) -> str:
2503)         # Annoyingly, `param.human_readable_name` contains the *function*
2504)         # parameter name, not the list of option names.  *Those* are
2505)         # stashed in the `.opts` and `.secondary_opts` attributes, which
2506)         # are visible in the `.to_info_dict()` output, but not otherwise
2507)         # documented.
2508)         param = params_by_str[param] if isinstance(param, str) else param
2509)         names = [param.human_readable_name, *param.opts, *param.secondary_opts]
2510)         option_names = [n for n in names if n.startswith('--')]
2511)         return min(option_names, key=len)
2512) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2513)     def check_incompatible_options(
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2514)         param1: click.Parameter | str,
2515)         param2: click.Parameter | str,
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2516)     ) -> None:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2517)         param1 = params_by_str[param1] if isinstance(param1, str) else param1
2518)         param2 = params_by_str[param2] if isinstance(param2, str) else param2
2519)         if param1 == param2:
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2520)             return
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2521)         if not is_param_set(param1):
2522)             return
2523)         if is_param_set(param2):
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2524)             param1_str = option_name(param1)
2525)             param2_str = option_name(param2)
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2526)             raise click.BadOptionUsage(
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2527)                 param1_str,
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2528)                 str(
2529)                     _msg.TranslatedString(
2530)                         _msg.ErrMsgTemplate.PARAMS_MUTUALLY_EXCLUSIVE,
2531)                         param1=param1_str,
2532)                         param2=param2_str,
2533)                     )
2534)                 ),
Marco Ricci Make the mutually exclusive...

Marco Ricci authored 2 weeks ago

2535)                 ctx=ctx,
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2536)             )
2537)         return
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2538) 
Marco Ricci Force logging calls in erro...

Marco Ricci authored 1 week ago

2539)     def err(msg: Any, /, **kwargs: Any) -> NoReturn:  # noqa: ANN401
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2540)         stacklevel = kwargs.pop('stacklevel', 1)
2541)         stacklevel += 1
Marco Ricci Force logging calls in erro...

Marco Ricci authored 1 week ago

2542)         logger.error(msg, stacklevel=stacklevel, **kwargs)
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2543)         ctx.exit(1)
2544) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

2545)     def get_config() -> _types.VaultConfig:
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2546)         try:
2547)             return _load_config()
2548)         except FileNotFoundError:
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2549)             try:
2550)                 backup_config, exc = _migrate_and_load_old_config()
2551)             except FileNotFoundError:
2552)                 return {'services': {}}
Marco Ricci Make obtaining the compatib...

Marco Ricci authored 3 weeks ago

2553)             old_name = os.path.basename(
2554)                 _config_filename(subsystem='old settings.json')
2555)             )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2556)             new_name = os.path.basename(_config_filename(subsystem='vault'))
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2557)             deprecation.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2558)                 _msg.TranslatedString(
2559)                     _msg.WarnMsgTemplate.V01_STYLE_CONFIG,
2560)                     old=old_name,
2561)                     new=new_name,
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2562)                 ),
2563)             )
2564)             if isinstance(exc, OSError):
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2565)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2566)                     _msg.TranslatedString(
2567)                         _msg.WarnMsgTemplate.FAILED_TO_MIGRATE_CONFIG,
2568)                         path=new_name,
2569)                         error=exc.strerror,
2570)                         filename=exc.filename,
2571)                     ).maybe_without_filename(),
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2572)                 )
2573)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2574)                 deprecation.info(
2575)                     _msg.TranslatedString(
2576)                         _msg.InfoMsgTemplate.SUCCESSFULLY_MIGRATED,
2577)                         path=new_name,
2578)                     ),
2579)                 )
Marco Ricci Rename the configuration fi...

Marco Ricci authored 3 months ago

2580)             return backup_config
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2581)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2582)             err(
2583)                 _msg.TranslatedString(
2584)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2585)                     error=exc.strerror,
2586)                     filename=exc.filename,
2587)                 ).maybe_without_filename(),
2588)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2589)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2590)             err(
2591)                 _msg.TranslatedString(
2592)                     _msg.ErrMsgTemplate.CANNOT_LOAD_VAULT_SETTINGS,
2593)                     error=str(exc),
2594)                     filename=None,
2595)                 ).maybe_without_filename(),
2596)                 exc_info=exc,
2597)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2598) 
2599)     def put_config(config: _types.VaultConfig, /) -> None:
2600)         try:
2601)             _save_config(config)
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

2602)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2603)             err(
2604)                 _msg.TranslatedString(
2605)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2606)                     error=exc.strerror,
2607)                     filename=exc.filename,
2608)                 ).maybe_without_filename(),
2609)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2610)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2611)             err(
2612)                 _msg.TranslatedString(
2613)                     _msg.ErrMsgTemplate.CANNOT_STORE_VAULT_SETTINGS,
2614)                     error=str(exc),
2615)                     filename=None,
2616)                 ).maybe_without_filename(),
2617)                 exc_info=exc,
2618)             )
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2619) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

2620)     def get_user_config() -> dict[str, Any]:
2621)         try:
2622)             return _load_user_config()
2623)         except FileNotFoundError:
2624)             return {}
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2625)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2626)             err(
2627)                 _msg.TranslatedString(
2628)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2629)                     error=exc.strerror,
2630)                     filename=exc.filename,
2631)                 ).maybe_without_filename(),
2632)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2633)         except Exception as exc:  # noqa: BLE001
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2634)             err(
2635)                 _msg.TranslatedString(
2636)                     _msg.ErrMsgTemplate.CANNOT_LOAD_USER_CONFIG,
2637)                     error=str(exc),
2638)                     filename=None,
2639)                 ).maybe_without_filename(),
2640)                 exc_info=exc,
2641)             )
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

2642) 
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

2643)     configuration: _types.VaultConfig
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2644) 
2645)     check_incompatible_options('--phrase', '--key')
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2646)     for group in (ConfigurationOption, StorageManagementOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2647)         for opt in options_in_group[group]:
2648)             if opt != params_by_str['--config']:
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2649)                 for other_opt in options_in_group[PassphraseGenerationOption]:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2650)                     check_incompatible_options(opt, other_opt)
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2651) 
Marco Ricci Add prototype command-line...

Marco Ricci authored 6 months ago

2652)     for group in (ConfigurationOption, StorageManagementOption):
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2653)         for opt in options_in_group[group]:
Marco Ricci Rewrite incompatible option...

Marco Ricci authored 3 weeks ago

2654)             for other_opt in options_in_group[ConfigurationOption]:
2655)                 check_incompatible_options(opt, other_opt)
2656)             for other_opt in options_in_group[StorageManagementOption]:
2657)                 check_incompatible_options(opt, other_opt)
Marco Ricci Add an actual derivepassphr...

Marco Ricci authored 2 weeks ago

2658)     sv_or_global_options = options_in_group[PassphraseGenerationOption]
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

2659)     for param in sv_or_global_options:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2660)         if is_param_set(param) and not (
2661)             service or is_param_set(params_by_str['--config'])
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2662)         ):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2663)             err_msg = _msg.TranslatedString(
2664)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE_OR_CONFIG,
2665)                 param=param.opts[0],
2666)                 service_metavar=service_metavar,
2667)             )
2668)             raise click.UsageError(str(err_msg))  # noqa: DOC501
Marco Ricci Correctly model vault globa...

Marco Ricci authored 2 months ago

2669)     sv_options = [params_by_str['--notes'], params_by_str['--delete']]
2670)     for param in sv_options:
2671)         if is_param_set(param) and not service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2672)             err_msg = _msg.TranslatedString(
2673)                 _msg.ErrMsgTemplate.PARAMS_NEEDS_SERVICE,
2674)                 param=param.opts[0],
2675)                 service_metavar=service_metavar,
2676)             )
2677)             raise click.UsageError(str(err_msg))
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2678)     no_sv_options = [
2679)         params_by_str['--delete-globals'],
2680)         params_by_str['--clear'],
2681)         *options_in_group[StorageManagementOption],
2682)     ]
Marco Ricci Fortify the argument parsin...

Marco Ricci authored 6 months ago

2683)     for param in no_sv_options:
2684)         if is_param_set(param) and service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2685)             err_msg = _msg.TranslatedString(
2686)                 _msg.ErrMsgTemplate.PARAMS_NO_SERVICE,
2687)                 param=param.opts[0],
2688)                 service_metavar=service_metavar,
2689)             )
2690)             raise click.UsageError(str(err_msg))
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2691) 
Marco Ricci Introduce a central user co...

Marco Ricci authored 3 weeks ago

2692)     user_config = get_user_config()
2693) 
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2694)     if service == '':  # noqa: PLC1901
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2695)         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2696)             _msg.TranslatedString(
2697)                 _msg.WarnMsgTemplate.EMPTY_SERVICE_NOT_SUPPORTED,
2698)                 service_metavar=service_metavar,
2699)             )
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2700)         )
2701) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2702)     if edit_notes:
2703)         assert service is not None
2704)         configuration = get_config()
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2705)         text = DEFAULT_NOTES_TEMPLATE + configuration['services'].get(
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

2706)             service, cast(_types.VaultConfigServicesSettings, {})
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2707)         ).get('notes', '')
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2708)         notes_value = click.edit(text=text)
2709)         if notes_value is not None:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2710)             notes_lines = collections.deque(notes_value.splitlines(True))  # noqa: FBT003
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2711)             while notes_lines:
2712)                 line = notes_lines.popleft()
2713)                 if line.startswith(DEFAULT_NOTES_MARKER):
2714)                     notes_value = ''.join(notes_lines)
2715)                     break
2716)             else:
2717)                 if not notes_value.strip():
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2718)                     err(
2719)                         _msg.TranslatedString(
2720)                             _msg.ErrMsgTemplate.USER_ABORTED_EDIT
2721)                         )
2722)                     )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2723)             configuration['services'].setdefault(service, {})['notes'] = (
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2724)                 notes_value.strip('\n')
2725)             )
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2726)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2727)     elif delete_service_settings:
2728)         assert service is not None
2729)         configuration = get_config()
2730)         if service in configuration['services']:
2731)             del configuration['services'][service]
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2732)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2733)     elif delete_globals:
2734)         configuration = get_config()
2735)         if 'global' in configuration:
2736)             del configuration['global']
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2737)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2738)     elif clear_all_settings:
Marco Ricci Use better error message ha...

Marco Ricci authored 4 months ago

2739)         put_config({'services': {}})
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2740)     elif import_settings:
2741)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2742)             # TODO(the-13th-letter): keep track of auto-close; try
2743)             # os.dup if feasible
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

2744)             infile = cast(
2745)                 TextIO,
2746)                 (
2747)                     import_settings
2748)                     if hasattr(import_settings, 'close')
2749)                     else click.open_file(os.fspath(import_settings), 'rt')
2750)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2751)             )
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

2752)             # Don't specifically catch TypeError or ValueError here if
2753)             # the passed-in fileobj is not a readable text stream.  This
2754)             # will never happen on the command-line (thanks to `click`),
2755)             # and for programmatic use, our caller may want accurate
2756)             # error information.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2757)             with infile:
2758)                 maybe_config = json.load(infile)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2759)         except json.JSONDecodeError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2760)             err(
2761)                 _msg.TranslatedString(
2762)                     _msg.ErrMsgTemplate.CANNOT_DECODEIMPORT_VAULT_SETTINGS,
2763)                     error=exc,
2764)                 )
2765)             )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2766)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2767)             err(
2768)                 _msg.TranslatedString(
2769)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
2770)                     error=exc.strerror,
2771)                     filename=exc.filename,
2772)                 ).maybe_without_filename()
2773)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2774)         cleaned = _types.clean_up_falsy_vault_config_values(maybe_config)
2775)         if not _types.is_vault_config(maybe_config):
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2776)             err(
2777)                 _msg.TranslatedString(
2778)                     _msg.ErrMsgTemplate.CANNOT_IMPORT_VAULT_SETTINGS,
2779)                     error=_msg.TranslatedString(
2780)                         _msg.ErrMsgTemplate.INVALID_VAULT_CONFIG,
2781)                         config=maybe_config,
2782)                     ),
2783)                     filename=None,
2784)                 ).maybe_without_filename()
2785)             )
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2786)         assert cleaned is not None
2787)         for step in cleaned:
2788)             # These are never fatal errors, because the semantics of
2789)             # vault upon encountering these settings are ill-specified,
2790)             # but not ill-defined.
2791)             if step.action == 'replace':
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2792)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2793)                     _msg.TranslatedString(
2794)                         _msg.WarnMsgTemplate.STEP_REPLACE_INVALID_VALUE,
2795)                         old=json.dumps(step.old_value),
2796)                         path=_types.json_path(step.path),
2797)                         new=json.dumps(step.new_value),
2798)                     ),
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2799)                 )
2800)             else:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2801)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2802)                     _msg.TranslatedString(
2803)                         _msg.WarnMsgTemplate.STEP_REMOVE_INEFFECTIVE_VALUE,
2804)                         path=_types.json_path(step.path),
2805)                         old=json.dumps(step.old_value),
2806)                     ),
Marco Ricci Signal and list falsy value...

Marco Ricci authored 3 months ago

2807)                 )
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2808)         if '' in maybe_config['services']:
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2809)             logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2810)                 _msg.TranslatedString(
2811)                     _msg.WarnMsgTemplate.EMPTY_SERVICE_SETTINGS_INACCESSIBLE,
2812)                     service_metavar=service_metavar,
2813)                     PROG_NAME=PROG_NAME,
Marco Ricci Use the logging system to e...

Marco Ricci authored 1 month ago

2814)                 ),
Marco Ricci Warn the user upon supplyin...

Marco Ricci authored 2 months ago

2815)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2816)         try:
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2817)             _check_for_misleading_passphrase(
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2818)                 ('global',),
2819)                 cast(dict[str, Any], maybe_config.get('global', {})),
2820)                 main_config=user_config,
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

2821)             )
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

2822)             for key, value in maybe_config['services'].items():
2823)                 _check_for_misleading_passphrase(
2824)                     ('services', key),
2825)                     cast(dict[str, Any], value),
2826)                     main_config=user_config,
2827)                 )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2828)         except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2829)             err(
2830)                 _msg.TranslatedString(
2831)                     _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
2832)                     error=exc,
2833)                     filename=None,
2834)                 ).maybe_without_filename(),
2835)             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2836)         global_obj = maybe_config.get('global', {})
2837)         has_key = _types.js_truthiness(global_obj.get('key'))
2838)         has_phrase = _types.js_truthiness(global_obj.get('phrase'))
2839)         if has_key and has_phrase:
2840)             logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2841)                 _msg.TranslatedString(
2842)                     _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE,
2843)                 )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2844)             )
2845)         for service_name, service_obj in maybe_config['services'].items():
2846)             has_key = _types.js_truthiness(
2847)                 service_obj.get('key')
2848)             ) or _types.js_truthiness(global_obj.get('key'))
2849)             has_phrase = _types.js_truthiness(
2850)                 service_obj.get('phrase')
2851)             ) or _types.js_truthiness(global_obj.get('phrase'))
2852)             if has_key and has_phrase:
2853)                 logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2854)                     _msg.TranslatedString(
2855)                         _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
2856)                         service=json.dumps(service_name),
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

2857)                     ),
2858)                 )
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

2859)         if overwrite_config:
2860)             put_config(maybe_config)
2861)         else:
2862)             configuration = get_config()
2863)             merged_config: collections.ChainMap[str, Any] = (
2864)                 collections.ChainMap(
2865)                     {
2866)                         'services': collections.ChainMap(
2867)                             maybe_config['services'],
2868)                             configuration['services'],
2869)                         ),
2870)                     },
2871)                     {'global': maybe_config['global']}
2872)                     if 'global' in maybe_config
2873)                     else {},
2874)                     {'global': configuration['global']}
2875)                     if 'global' in configuration
2876)                     else {},
2877)                 )
2878)             )
2879)             new_config: Any = {
2880)                 k: dict(v) if isinstance(v, collections.ChainMap) else v
2881)                 for k, v in sorted(merged_config.items())
2882)             }
2883)             assert _types.is_vault_config(new_config)
2884)             put_config(new_config)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2885)     elif export_settings:
2886)         configuration = get_config()
2887)         try:
Marco Ricci Apply new ruff ruleset to c...

Marco Ricci authored 4 months ago

2888)             # TODO(the-13th-letter): keep track of auto-close; try
2889)             # os.dup if feasible
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

2890)             outfile = cast(
2891)                 TextIO,
2892)                 (
2893)                     export_settings
2894)                     if hasattr(export_settings, 'close')
2895)                     else click.open_file(os.fspath(export_settings), 'wt')
2896)                 ),
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2897)             )
Marco Ricci Document handling of file o...

Marco Ricci authored 3 weeks ago

2898)             # Don't specifically catch TypeError or ValueError here if
2899)             # the passed-in fileobj is not a writable text stream.  This
2900)             # will never happen on the command-line (thanks to `click`),
2901)             # and for programmatic use, our caller may want accurate
2902)             # error information.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2903)             with outfile:
Marco Ricci Support exporting the `vaul...

Marco Ricci authored 2 weeks ago

2904)                 if export_as == 'sh':
2905)                     this_ctx = ctx
2906)                     prog_name_pieces = collections.deque([
2907)                         this_ctx.info_name or 'vault',
2908)                     ])
2909)                     while (
2910)                         this_ctx.parent is not None
2911)                         and this_ctx.parent.info_name is not None
2912)                     ):
2913)                         prog_name_pieces.appendleft(this_ctx.parent.info_name)
2914)                         this_ctx = this_ctx.parent
2915)                     _print_config_as_sh_script(
2916)                         configuration,
2917)                         outfile=outfile,
2918)                         prog_name_list=prog_name_pieces,
2919)                     )
2920)                 else:
2921)                     json.dump(configuration, outfile)
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2922)         except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2923)             err(
2924)                 _msg.TranslatedString(
2925)                     _msg.ErrMsgTemplate.CANNOT_EXPORT_VAULT_SETTINGS,
2926)                     error=exc.strerror,
2927)                     filename=exc.filename,
2928)                 ).maybe_without_filename(),
2929)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2930)     else:
2931)         configuration = get_config()
2932)         # This block could be type checked more stringently, but this
2933)         # would probably involve a lot of code repetition.  Since we
2934)         # have a type guarding function anyway, assert that we didn't
2935)         # make any mistakes at the end instead.
2936)         global_keys = {'key', 'phrase'}
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2937)         service_keys = {
2938)             'key',
2939)             'phrase',
2940)             'length',
2941)             'repeat',
2942)             'lower',
2943)             'upper',
2944)             'number',
2945)             'space',
2946)             'dash',
2947)             'symbol',
2948)         }
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2949)         settings: collections.ChainMap[str, Any] = collections.ChainMap(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2950)             {
2951)                 k: v
2952)                 for k, v in locals().items()
2953)                 if k in service_keys and v is not None
2954)             },
2955)             cast(
2956)                 dict[str, Any],
2957)                 configuration['services'].get(service or '', {}),
2958)             ),
2959)             cast(dict[str, Any], configuration.get('global', {})),
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2960)         )
2961)         if use_key:
2962)             try:
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

2963)                 key = base64.standard_b64encode(_select_ssh_key()).decode(
2964)                     'ASCII'
2965)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

2966)             except IndexError:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2967)                 err(
2968)                     _msg.TranslatedString(
2969)                         _msg.ErrMsgTemplate.USER_ABORTED_SSH_KEY_SELECTION
2970)                     ),
2971)                 )
Marco Ricci Document and handle other e...

Marco Ricci authored 4 months ago

2972)             except KeyError:
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

2973)                 err(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2974)                     _msg.TranslatedString(
2975)                         _msg.ErrMsgTemplate.NO_SSH_AGENT_FOUND
2976)                     ),
2977)                 )
2978)             except LookupError:
2979)                 err(
2980)                     _msg.TranslatedString(
2981)                         _msg.ErrMsgTemplate.NO_SUITABLE_SSH_KEYS,
2982)                         PROG_NAME=PROG_NAME,
2983)                     )
Marco Ricci Fail gracefully if UNIX dom...

Marco Ricci authored 3 months ago

2984)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2985)             except NotImplementedError:
2986)                 err(_msg.TranslatedString(_msg.ErrMsgTemplate.NO_AF_UNIX))
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

2987)             except OSError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

2988)                 err(
2989)                     _msg.TranslatedString(
2990)                         _msg.ErrMsgTemplate.CANNOT_CONNECT_TO_AGENT,
2991)                         error=exc.strerror,
2992)                         filename=exc.filename,
2993)                     ).maybe_without_filename(),
2994)                 )
2995)             except ssh_agent.SSHAgentFailedError as exc:
2996)                 err(
2997)                     _msg.TranslatedString(
2998)                         _msg.ErrMsgTemplate.AGENT_REFUSED_LIST_KEYS
2999)                     ),
3000)                     exc_info=exc,
3001)                 )
3002)             except RuntimeError as exc:
3003)                 err(
3004)                     _msg.TranslatedString(
3005)                         _msg.ErrMsgTemplate.CANNOT_UNDERSTAND_AGENT
3006)                     ),
3007)                     exc_info=exc,
3008)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3009)         elif use_phrase:
3010)             maybe_phrase = _prompt_for_passphrase()
3011)             if not maybe_phrase:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3012)                 err(
3013)                     _msg.TranslatedString(
3014)                         _msg.ErrMsgTemplate.USER_ABORTED_PASSPHRASE
3015)                     )
3016)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3017)             else:
3018)                 phrase = maybe_phrase
3019)         if store_config_only:
3020)             view: collections.ChainMap[str, Any]
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3021)             view = (
3022)                 collections.ChainMap(*settings.maps[:2])
3023)                 if service
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3024)                 else collections.ChainMap(settings.maps[0], settings.maps[2])
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3025)             )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3026)             if use_key:
3027)                 view['key'] = key
3028)             elif use_phrase:
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3029)                 view['phrase'] = phrase
3030)                 settings_type = 'service' if service else 'global'
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3031)                 try:
3032)                     _check_for_misleading_passphrase(
3033)                         ('services', service) if service else ('global',),
3034)                         {'phrase': phrase},
3035)                         main_config=user_config,
3036)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3037)                 except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3038)                     err(
3039)                         _msg.TranslatedString(
3040)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3041)                             error=exc,
3042)                             filename=None,
3043)                         ).maybe_without_filename(),
3044)                     )
Marco Ricci Fix missing consideration o...

Marco Ricci authored 2 months ago

3045)                 if 'key' in settings:
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

3046)                     if service:
3047)                         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3048)                             _msg.TranslatedString(
3049)                                 _msg.WarnMsgTemplate.SERVICE_PASSPHRASE_INEFFECTIVE,
3050)                                 service=json.dumps(service),
3051)                             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

3052)                         )
3053)                     else:
3054)                         logger.warning(
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3055)                             _msg.TranslatedString(
3056)                                 _msg.WarnMsgTemplate.GLOBAL_PASSPHRASE_INEFFECTIVE
3057)                             )
Marco Ricci Fix empty key handling in `...

Marco Ricci authored 3 weeks ago

3058)                         )
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3059)             if not view.maps[0] and not unset_settings:
Marco Ricci Fix style issues with ruff...

Marco Ricci authored 5 months ago

3060)                 settings_type = 'service' if service else 'global'
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3061)                 err_msg = _msg.TranslatedString(
3062)                     _msg.ErrMsgTemplate.CANNOT_UPDATE_SETTINGS_NO_SETTINGS,
3063)                     settings_type=settings_type,
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3064)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3065)                 raise click.UsageError(str(err_msg))
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3066)             for setting in unset_settings:
3067)                 if setting in view.maps[0]:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3068)                     err_msg = _msg.TranslatedString(
3069)                         _msg.ErrMsgTemplate.SET_AND_UNSET_SAME_SETTING,
3070)                         setting=setting,
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3071)                     )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3072)                     raise click.UsageError(str(err_msg))
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3073)             subtree: dict[str, Any] = (
3074)                 configuration['services'].setdefault(service, {})  # type: ignore[assignment]
3075)                 if service
3076)                 else configuration.setdefault('global', {})
3077)             )
3078)             if overwrite_config:
3079)                 subtree.clear()
Marco Ricci Allow unsetting settings wh...

Marco Ricci authored 2 weeks ago

3080)             else:
3081)                 for setting in unset_settings:
3082)                     subtree.pop(setting, None)
Marco Ricci Allow the user to overwrite...

Marco Ricci authored 4 weeks ago

3083)             subtree.update(view)
Marco Ricci Consolidate `types` submodu...

Marco Ricci authored 5 months ago

3084)             assert _types.is_vault_config(
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3085)                 configuration
Marco Ricci Fix error message capitaliz...

Marco Ricci authored 4 months ago

3086)             ), f'Invalid vault configuration: {configuration!r}'
Marco Ricci Fix error bubbling in outda...

Marco Ricci authored 4 months ago

3087)             put_config(configuration)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3088)         else:
3089)             if not service:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3090)                 err_msg = _msg.TranslatedString(
3091)                     _msg.ErrMsgTemplate.SERVICE_REQUIRED,
3092)                     service_metavar=_msg.TranslatedString(
3093)                         _msg.Label.VAULT_METAVAR_SERVICE
3094)                     ),
3095)                 )
3096)                 raise click.UsageError(str(err_msg))
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3097)             kwargs: dict[str, Any] = {
3098)                 k: v
3099)                 for k, v in settings.items()
3100)                 if k in service_keys and v is not None
3101)             }
3102) 
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3103)             if use_phrase:
Marco Ricci Turn Unicode normalization...

Marco Ricci authored 3 weeks ago

3104)                 try:
3105)                     _check_for_misleading_passphrase(
3106)                         _ORIGIN.INTERACTIVE,
3107)                         {'phrase': phrase},
3108)                         main_config=user_config,
3109)                     )
Marco Ricci Add small fixes to changelo...

Marco Ricci authored 2 weeks ago

3110)                 except AssertionError as exc:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3111)                     err(
3112)                         _msg.TranslatedString(
3113)                             _msg.ErrMsgTemplate.INVALID_USER_CONFIG,
3114)                             error=exc,
3115)                             filename=None,
3116)                         ).maybe_without_filename(),
3117)                     )
Marco Ricci Allow all textual strings,...

Marco Ricci authored 4 months ago

3118) 
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3119)             # If either --key or --phrase are given, use that setting.
3120)             # Otherwise, if both key and phrase are set in the config,
Marco Ricci Align behavior with vault c...

Marco Ricci authored 3 months ago

3121)             # use the key.  Otherwise, if only one of key and phrase is
3122)             # set in the config, use that one.  In all these above
3123)             # cases, set the phrase via vault.Vault.phrase_from_key if
3124)             # a key is given.  Finally, if nothing is set, error out.
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3125)             if use_key or use_phrase:
Marco Ricci Fix formatting, some covera...

Marco Ricci authored 2 weeks ago

3126)                 kwargs['phrase'] = (
3127)                     _key_to_phrase(key, error_callback=err)
3128)                     if use_key
3129)                     else phrase
3130)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3131)             elif kwargs.get('key'):
Marco Ricci Hoist and add tests for int...

Marco Ricci authored 3 weeks ago

3132)                 kwargs['phrase'] = _key_to_phrase(
3133)                     kwargs['key'], error_callback=err
3134)                 )
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3135)             elif kwargs.get('phrase'):
3136)                 pass
3137)             else:
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3138)                 err_msg = _msg.TranslatedString(
3139)                     _msg.ErrMsgTemplate.NO_KEY_OR_PHRASE
Marco Ricci Reformat everything with ruff

Marco Ricci authored 5 months ago

3140)                 )
Marco Ricci Update the CLI to use the t...

Marco Ricci authored 1 week ago

3141)                 raise click.UsageError(str(err_msg))
Marco Ricci Avoid crashing when overrid...

Marco Ricci authored 5 months ago

3142)             kwargs.pop('key', '')
Marco Ricci Move `sequin` and `ssh_agen...

Marco Ricci authored 5 months ago

3143)             result = vault.Vault(**kwargs).generate(service)
Marco Ricci Add finished command-line i...

Marco Ricci authored 6 months ago

3144)             click.echo(result.decode('ASCII'))