Le formateur de ce dépôt est ruff depuis qu'il remplace black, qui ne connaît aucune cible au-delà de py313 ; ce passage applique sa norme à l'arbre entier, d'un coup, pour qu'aucun commit de fond n'ait à porter du style. L'écart tient presque entièrement aux chaînes coupées à la main que ruff recolle quand elles tiennent sur une ligne, et aux « with » multiples qu'il regroupe : aucune valeur ne change, et les clés de traduction non plus. Vérifié : la suite unitaire reste verte après le passage, et le contrôle de syntaxe ne signale rien. --- EN --- This repository's formatter is ruff since it replaced black, which knows no target beyond py313; this pass applies its standard to the whole tree at once, so that no substantive commit has to carry style. The difference is almost entirely the hand-split strings ruff joins back when they fit on one line, and the multiple "with" it merges: no value changes, nor do the translation keys. Checked: the unit suite stays green after the pass, and the syntax check reports nothing. Assisted-by: Claude Opus 5
63 lines
2.5 KiB
Python
63 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
"""La logique d'ajout de compte et de mise en place du coffre, sans UI.
|
|
|
|
`menu._add_account` et `menu._ensure_kdbx` mêlaient cette logique — pas
|
|
triviale, elle annule l'écriture du secret si la sauvegarde du compte échoue
|
|
— à des `input()`/`getpass.getpass()`. Le CLI et le TUI ont chacun leur façon
|
|
de demander l'information, mais doivent appeler exactement le même code une
|
|
fois qu'ils l'ont : sinon les deux copies dérivent. Ce module ne connaît ni
|
|
`input`, ni Textual, ni aucune bibliothèque d'interface.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from script.todo.mail import accounts as mail_accounts
|
|
from script.todo.mail.accounts import AccountError
|
|
from script.todo.mail.secrets import SecretError, create_kdbx
|
|
from script.todo.todo_i18n import t
|
|
|
|
# Chemin proposé par défaut pour un kdbx nouvellement créé. `private/` est un
|
|
# dossier versionné, mais `private/.gitignore` y ignore déjà `*.kdbx` : c'est
|
|
# la convention du dépôt pour les fichiers de coffre.
|
|
DEFAULT_KDBX_PATH = "private/erplibre.kdbx"
|
|
|
|
|
|
def save_new_account(secret_store, accounts, account, password) -> None:
|
|
"""Écrit le mot de passe puis sauvegarde `accounts` (qui doit déjà
|
|
contenir `account`, à la place voulue par l'appelant).
|
|
|
|
Si la sauvegarde échoue, le secret est retiré du coffre avant que
|
|
l'exception ne remonte : l'y laisser sous une référence qu'aucune
|
|
configuration ne désigne en ferait un déchet invisible.
|
|
"""
|
|
secret_store.set(account.secret_ref, password)
|
|
try:
|
|
mail_accounts.save(accounts)
|
|
except (AccountError, OSError):
|
|
try:
|
|
secret_store.delete(account.secret_ref)
|
|
except SecretError:
|
|
pass
|
|
raise
|
|
|
|
|
|
def kdbx_is_configured(config_file) -> bool:
|
|
"""Vrai si un kdbx est déjà désigné dans la configuration."""
|
|
return bool(config_file.get_config_value(["kdbx", "path"]))
|
|
|
|
|
|
def create_vault(config_file, path: str, password: str) -> None:
|
|
"""Crée un nouveau kdbx à `path`, puis l'enregistre comme coffre actif."""
|
|
create_kdbx(path, password)
|
|
config_file.set_config_value(["kdbx", "path"], path)
|
|
|
|
|
|
def use_existing_vault(config_file, path: str) -> None:
|
|
"""Adopte un kdbx déjà présent sur disque comme coffre actif."""
|
|
if not path or not os.path.isfile(path):
|
|
raise SecretError(f"{t('mail_kdbx_path_not_found')} {path}")
|
|
config_file.set_config_value(["kdbx", "path"], path)
|