mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-15 03:37:03 -04:00
Digital IDs added through Sign with a Digital ID (imported .p12/.pfx files or new self-signed ones) are saved with the app settings, but nothing ever took one off the list, so an old or mistakenly imported certificate stayed there for good (#1396). Sign with a Digital ID now has Remove next to Configure New Digital ID. It acts on the selected file-based ID, asks first ("Remove "<name>" from this list? The file itself is not deleted."), and takes the entry off the saved list. The .p12 file stays on disk. Keychain and Windows store IDs can't be removed here: the OS manages them and they are listed again on every signing. - sign_ui: PdfCraftApp::remove_digital_id refuses OS store IDs and stale indexes, keeps the dialog's selection on the same ID (or the first usable one), and goes to Configure when no IDs are left. - SignDraft::confirm_remove holds the entry awaiting confirmation; clicking another row cancels the question. - i18n: the confirmation is translated in all 21 catalogs; ATTRIBUTION.toml hashes updated. - Tests: a unit test for the list, the selection and persist/restore, and a real-shell test that imports a .p12, cancels, then removes it. Co-authored-by: Brandon Thomas <[email protected]>
This commit is contained in:
1 parent
e88dd728cb
commit
7739685796
24 files changed
+170
-21
No files matched your search
+21
-21
@@ -7,7 +7,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Greek UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "28141072a01326a59e873958c20780688da68bbce6fee6d8a0598b3b2eaf64c8"
|
||||
sha256 = "a05bbd3b58f64e8c2a06cb7803009c81de049716ef089fdd0abc56c7d0eb394b"
|
||||
|
||||
# ATTRIBUTION.toml: one entry per asset (AGENTS.md §1). The source of truth for provenance and licences.
|
||||
# ATTRIBUTION.md is generated from this file: `cargo xtask assets --write`. Checked by `cargo xtask assets` (part of `xtask ci`).
|
||||
@@ -30,7 +30,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "55741bc14dd319319db883308cee6400a95cc86a11e54ddcf84921b07d7aa5b6"
|
||||
sha256 = "30f26c55038c23956d79b6b85821890a55c82bc99108a0c982b679fccf918eeb"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/zh-hant.tsv"
|
||||
@@ -41,7 +41,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "77a0c98f38aceee0a2b63002a0348bc10fb6982ac76fe80d020d030c640c7dfb"
|
||||
sha256 = "c92d6c1b4f92fe6cc0dda954da593e7c22821f524bff77c2cdf71796ba0ea8e3"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/cs.tsv"
|
||||
@@ -52,7 +52,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "b29359b5f0b2be96cdb9c1600187aa738d789db13d74afda26de8d7efbe71d5f"
|
||||
sha256 = "2a9b1347fe5eec8cf144c315592adb2999206c91c6be3c96115fa8871d2d18b0"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/pt-br.tsv"
|
||||
@@ -63,7 +63,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "69623423479cb67f011a7725d6174385285cc1e6e7f46785d6c2cd1c403f5f71"
|
||||
sha256 = "b267b363ffd9a3d0b610f14ecf505543d53ce08c0603b78306be9a70a77d15ef"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/es.tsv"
|
||||
@@ -74,7 +74,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "b5c78c84b6b4d418e77b1b106f88fbbe4dad8e3faf06e5d134f069d4eeaff49c"
|
||||
sha256 = "6ed7cd84692db0c02b322207206f9f1b79b47825c247e6bc4ea8e8231e3bdda2"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/fr.tsv"
|
||||
@@ -85,7 +85,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "e891fcdfa020a94d129f5f56a27a85841153311afd45c1b066895927e24468e0"
|
||||
sha256 = "bc7823dca413e745370b5fb1640cfd80c8633dac959e3f9766a4e10271b323b7"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/de.tsv"
|
||||
@@ -96,7 +96,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "5f8bca9c22a5a7f0015b3ef4bbc173c3040f23789a145e51119e38419a3e476a"
|
||||
sha256 = "a0d155d28ea5784bcd0bff539e3282e394ae74d08ee9ee2c156c3340009f74a8"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/te.tsv"
|
||||
@@ -107,7 +107,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "bbc72e480ee0b22da792a95643b851c0752d69543472d79c2edc7978c9afc4fb"
|
||||
sha256 = "ef3e873eadfaf5367e19834dcc892487b0eae1d089b11c0913835e0e24e9bd83"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/it.tsv"
|
||||
@@ -118,7 +118,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "ea26a00d59bca609e44eb2d59e493da0aa41f49c3e206f3a9ba9a4d0886d263c"
|
||||
sha256 = "980062f140bbfe78ea077d1bc6ff66ea856c7e267d444054319d91b9b1fb915b"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/pl.tsv"
|
||||
@@ -129,7 +129,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8f45e60c676b33c2c8298274c44311900364e5ed96258bf86d4cc371a84d65ad"
|
||||
sha256 = "1433b66e2b40b590b6be1089d4201d6f74aac8116f67b79caca9048bfec444bf"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ru.tsv"
|
||||
@@ -140,7 +140,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "527b6f96e54741387ded3d94484c6f70bd75246a83873beeaad284531cabf710"
|
||||
sha256 = "fa5ecd1eb447cce1255098829a03af6909cd48fdaf3d4853c3ec322746b6f367"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/hu.tsv"
|
||||
@@ -151,7 +151,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "c4d0cae1401ac1aae2eb50f426c9ba0361aaeef3ea56835eeada9632b0ba4101"
|
||||
sha256 = "20ef278f871692830b2021996bd7038bf7ed5bfae959d8aaaddbdfb573a33d98"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/bg.tsv"
|
||||
@@ -162,7 +162,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "64912fc6c3e232d8a90c6b2fe476a5a383178aeba5f1d32cc27602d5e65f141b"
|
||||
sha256 = "38f753d18d4bac285d8b4eeb4cf5f84e97ae5fabbe7b63502fe46c4fe9cbdbde"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/kk.tsv"
|
||||
@@ -173,7 +173,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Kazakh UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "f669ad8797a518ad8e849b2332043367b0e04479d4d8de03f7e565dddb53a123"
|
||||
sha256 = "aae6a9f14b7b5d4ad702aaf2dc07046216ab1b4366c65215f52ff0cbb682ff04"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ja.tsv"
|
||||
@@ -184,7 +184,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "e57905062cc7d54185120c66435be590cd778a98b91d158fe8f40acf17636787"
|
||||
sha256 = "42fe836106db7bce7a8e492b9642569df942a0695b330f8701cb85e0d6ea93ea"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/uk.tsv"
|
||||
@@ -195,7 +195,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "24b37ec8b7c16eee4347c3b3e45c574d339a097dc24aad2c35524c2dbf589c40"
|
||||
sha256 = "8c9d7fc2e7c040b40a4efbdad38183cc6e40adc5936f8faa1b23580b9adce704"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ar.tsv"
|
||||
@@ -206,7 +206,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "7d3f5fbc9016ad86441bd8b6858627f64971facc8c5bbbcb339521007669fdb1"
|
||||
sha256 = "a18e085d8d9797a50d37bcb06daef2ce9675a2450d4db86c77faeeb6a66fd644"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/tr.tsv"
|
||||
@@ -217,7 +217,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Turkish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "bcfe8940ac0f1887b4b2692a7796bbe79048a414891c16159f09040948619a21"
|
||||
sha256 = "448606a33ff4e953579ac38f7d614d2193b06771141b5cba005a35f6926a1d01"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/lt.tsv"
|
||||
@@ -228,7 +228,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8982df2065edb0aaa98e7e3606521ced403a0cc6e5ff1f70ba0e272dd5dc74e5"
|
||||
sha256 = "8e2d2bf1ec678cbdaf25a8c7f952b5bfb88d162a75bf8b627a742d823b131df7"
|
||||
|
||||
[[asset]]
|
||||
path = "assets/icons/accessibility.svg"
|
||||
@@ -3351,4 +3351,4 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Slovene UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "649ead1e9be5f868571144e9964856077aa769e5bdb0b8d3c530d6bce0e29219"
|
||||
sha256 = "fef63bd8be5ab43be8e48add9719b8418ddeb483f766408b34d280cdc08a3018"
|
||||
@@ -855,6 +855,7 @@
|
||||
, Expires: ، تنتهي:
|
||||
No digital IDs yet. لا توجد معرّفات رقمية بعد.
|
||||
Configure New Digital ID إعداد معرّف رقمي جديد
|
||||
Remove "{name}" from this list? The file itself is not deleted. إزالة "{name}" من هذه القائمة؟ لن يُحذف الملف نفسه.
|
||||
Continue متابعة
|
||||
Configure a Digital ID for Signing إعداد معرّف رقمي للتوقيع
|
||||
Use a Digital ID from a file استخدام معرّف رقمي من ملف
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -530,6 +530,7 @@
|
||||
, Expires: , валиден до:
|
||||
No digital IDs yet. Все още няма цифрови идентификатори.
|
||||
Configure New Digital ID Конфигурирай нов цифров идентификатор
|
||||
Remove "{name}" from this list? The file itself is not deleted. Да се премахне ли „{name}“ от този списък? Самият файл няма да бъде изтрит.
|
||||
Continue Продължи
|
||||
Configure a Digital ID for Signing Конфигуриране на цифров идентификатор за подписване
|
||||
Use a Digital ID from a file Използвай цифров идентификатор от файл
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 16.
|
@@ -929,6 +929,7 @@ key Space Mezerník
|
||||
, Expires: , platnost do:
|
||||
No digital IDs yet. Zatím žádná digitální ID.
|
||||
Configure New Digital ID Nastavit nové digitální ID
|
||||
Remove "{name}" from this list? The file itself is not deleted. Odebrat „{name}“ z tohoto seznamu? Samotný soubor se nesmaže.
|
||||
Continue Pokračovat
|
||||
Configure a Digital ID for Signing Nastavení digitálního ID pro podepisování
|
||||
Use a Digital ID from a file Použít digitální ID ze souboru
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -833,6 +833,7 @@
|
||||
, Expires: , läuft ab:
|
||||
No digital IDs yet. Noch keine digitalen IDs.
|
||||
Configure New Digital ID Neue digitale ID einrichten
|
||||
Remove "{name}" from this list? The file itself is not deleted. „{name}“ aus dieser Liste entfernen? Die Datei selbst wird nicht gelöscht.
|
||||
Continue Weiter
|
||||
Configure a Digital ID for Signing Digitale ID zum Signieren einrichten
|
||||
Use a Digital ID from a file Digitale ID aus einer Datei verwenden
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 51.
|
@@ -464,6 +464,7 @@
|
||||
, Expires: , Λήξη:
|
||||
No digital IDs yet. Δεν υπάρχουν ακόμη ψηφιακές ταυτότητες.
|
||||
Configure New Digital ID Ρύθμιση νέας ψηφιακής ταυτότητας
|
||||
Remove "{name}" from this list? The file itself is not deleted. Αφαίρεση του «{name}» από αυτή τη λίστα; Το ίδιο το αρχείο δεν διαγράφεται.
|
||||
Configure a Digital ID for Signing Ρύθμιση ψηφιακής ταυτότητας για υπογραφή
|
||||
Use a Digital ID from a file Χρήση ψηφιακής ταυτότητας από αρχείο
|
||||
Create a new Digital ID (self-signed, saved to a password-protected file) Δημιουργία νέας ψηφιακής ταυτότητας (αυτοϋπογεγραμμένης, αποθηκευμένης σε αρχείο με κωδικό πρόσβασης)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 467 and column 9.
|
@@ -849,6 +849,7 @@
|
||||
, Expires: , caduca:
|
||||
No digital IDs yet. Aún no hay ningún ID digital.
|
||||
Configure New Digital ID Configurar un nuevo ID digital
|
||||
Remove "{name}" from this list? The file itself is not deleted. ¿Quitar «{name}» de esta lista? El archivo en sí no se elimina.
|
||||
Continue Continuar
|
||||
Configure a Digital ID for Signing Configurar un ID digital para firmar
|
||||
Use a Digital ID from a file Usar un ID digital de un archivo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 60.
|
@@ -829,6 +829,7 @@
|
||||
, Expires: , expire :
|
||||
No digital IDs yet. Aucun ID numérique pour l'instant.
|
||||
Configure New Digital ID Configurer un nouvel ID numérique
|
||||
Remove "{name}" from this list? The file itself is not deleted. Retirer « {name} » de cette liste ? Le fichier lui-même n’est pas supprimé.
|
||||
Continue Continuer
|
||||
Configure a Digital ID for Signing Configurer un ID numérique pour signer
|
||||
Use a Digital ID from a file Utiliser un ID numérique provenant d'un fichier
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 39.
|
@@ -826,6 +826,7 @@
|
||||
, Expires: , lejár:
|
||||
No digital IDs yet. Még nincs digitális azonosító.
|
||||
Configure New Digital ID Új digitális azonosító beállítása
|
||||
Remove "{name}" from this list? The file itself is not deleted. Eltávolítja a(z) „{name}” elemet erről a listáról? Maga a fájl nem törlődik.
|
||||
Continue Tovább
|
||||
Configure a Digital ID for Signing Digitális azonosító beállítása aláíráshoz
|
||||
Use a Digital ID from a file Digitális azonosító használata fájlból
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 44.
|
@@ -852,6 +852,7 @@
|
||||
, Expires: , Scadenza:
|
||||
No digital IDs yet. Ancora nessun ID digitale.
|
||||
Configure New Digital ID Configura nuovo ID digitale
|
||||
Remove "{name}" from this list? The file itself is not deleted. Rimuovere "{name}" da questo elenco? Il file non viene eliminato.
|
||||
Continue Continua
|
||||
Configure a Digital ID for Signing Configura un ID digitale per la firma
|
||||
Use a Digital ID from a file Usa un ID digitale da file
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -856,6 +856,7 @@
|
||||
, Expires: 、有効期限:
|
||||
No digital IDs yet. デジタル ID はまだありません。
|
||||
Configure New Digital ID 新しいデジタル ID を設定
|
||||
Remove "{name}" from this list? The file itself is not deleted. 「{name}」をこの一覧から削除しますか?ファイル自体は削除されません。
|
||||
Continue 続行
|
||||
Configure a Digital ID for Signing 署名用のデジタル ID を設定
|
||||
Use a Digital ID from a file ファイルのデジタル ID を使用
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -811,6 +811,7 @@
|
||||
, Expires: , Жарамдылық мерзімі:
|
||||
No digital IDs yet. Әзірге цифрлық ID жоқ.
|
||||
Configure New Digital ID Жаңа цифрлық ID теңшеу
|
||||
Remove "{name}" from this list? The file itself is not deleted. «{name}» осы тізімнен алып тасталсын ба? Файлдың өзі жойылмайды.
|
||||
Continue Жалғастыру
|
||||
Configure a Digital ID for Signing Қол қоюға арналған цифрлық ID теңшеу
|
||||
Use a Digital ID from a file Файлдағы цифрлық ID-ді пайдалану
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 814 and column 9.
|
@@ -390,6 +390,7 @@
|
||||
Compress document structure (object streams) Suglaudinti dokumento struktūrą (objektų srautus)
|
||||
Compression Glaudinimas
|
||||
Configure New Digital ID Konfigūruoti naują skaitmeninį ID
|
||||
Remove "{name}" from this list? The file itself is not deleted. Pašalinti „{name}“ iš šio sąrašo? Pats failas nebus ištrintas.
|
||||
Confirm Password Patvirtinti slaptažodį
|
||||
Conformance level: Atitikties lygis:
|
||||
Continue Tęsti
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 393 and column 9.
|
@@ -847,6 +847,7 @@
|
||||
, Expires: , Wygasa:
|
||||
No digital IDs yet. Brak identyfikatorów cyfrowych.
|
||||
Configure New Digital ID Skonfiguruj nowy identyfikator cyfrowy
|
||||
Remove "{name}" from this list? The file itself is not deleted. Usunąć „{name}” z tej listy? Sam plik nie zostanie usunięty.
|
||||
Continue Kontynuuj
|
||||
Configure a Digital ID for Signing Skonfiguruj identyfikator cyfrowy do podpisywania
|
||||
Use a Digital ID from a file Użyj identyfikatora cyfrowego z pliku
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -484,6 +484,7 @@
|
||||
, Expires: , Expira em:
|
||||
No digital IDs yet. Nenhuma ID digital ainda.
|
||||
Configure New Digital ID Configurar nova ID digital
|
||||
Remove "{name}" from this list? The file itself is not deleted. Remover "{name}" desta lista? O arquivo em si não é excluído.
|
||||
Continue Continuar
|
||||
Configure a Digital ID for Signing Configurar uma ID digital para assinatura
|
||||
Use a Digital ID from a file Usar uma ID digital de um arquivo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -849,6 +849,7 @@
|
||||
, Expires: , Истекает:
|
||||
No digital IDs yet. Нет цифровых идентификаторов.
|
||||
Configure New Digital ID Настроить новый цифровой идентификатор
|
||||
Remove "{name}" from this list? The file itself is not deleted. Убрать «{name}» из этого списка? Сам файл не удаляется.
|
||||
Continue Продолжить
|
||||
Configure a Digital ID for Signing Настроить цифровой идентификатор для подписи
|
||||
Use a Digital ID from a file Использовать цифровой идентификатор из файла
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -425,6 +425,7 @@
|
||||
Compress document structure (object streams) Stisni strukturo dokumenta (tokovi objektov)
|
||||
Compression Stiskanje
|
||||
Configure New Digital ID Nastavi novo digitalno identiteto
|
||||
Remove "{name}" from this list? The file itself is not deleted. Odstranim »{name}« s tega seznama? Sama datoteka ne bo izbrisana.
|
||||
Configure a Digital ID for Signing Nastavite digitalno identiteto za podpisovanje
|
||||
Confirm Password Potrdite geslo
|
||||
Conformance level: Raven skladnosti:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -828,6 +828,7 @@ comment menu Edit సవరించు
|
||||
, Expires: , గడువు:
|
||||
No digital IDs yet. ఇంకా డిజిటల్ ఐడీలు ఏవీ లేవు.
|
||||
Configure New Digital ID కొత్త డిజిటల్ ఐడీని కాన్ఫిగర్ చేయి
|
||||
Remove "{name}" from this list? The file itself is not deleted. ఈ జాబితా నుండి "{name}"ని తీసివేయాలా? ఫైల్ తొలగించబడదు.
|
||||
Continue కొనసాగించు
|
||||
Configure a Digital ID for Signing సంతకం కోసం డిజిటల్ ఐడీని కాన్ఫిగర్ చేయి
|
||||
Use a Digital ID from a file ఫైల్లోని డిజిటల్ ఐడీని ఉపయోగించు
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 13 and column 16.
|
@@ -810,6 +810,7 @@
|
||||
, Expires: , Son kullanma tarihi:
|
||||
No digital IDs yet. Henüz dijital kimlik yok.
|
||||
Configure New Digital ID Yeni Dijital Kimlik Yapılandır
|
||||
Remove "{name}" from this list? The file itself is not deleted. "{name}" bu listeden kaldırılsın mı? Dosyanın kendisi silinmez.
|
||||
Continue Devam Et
|
||||
Configure a Digital ID for Signing İmzalama için Dijital Kimlik Yapılandır
|
||||
Use a Digital ID from a file Dosyadan Dijital Kimlik Kullan
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 813 and column 9.
|
@@ -853,6 +853,7 @@
|
||||
, Expires: , Дійсний до:
|
||||
No digital IDs yet. Ще немає цифрових посвідчень.
|
||||
Configure New Digital ID Налаштувати нове цифрове посвідчення
|
||||
Remove "{name}" from this list? The file itself is not deleted. Прибрати «{name}» з цього списку? Сам файл не видаляється.
|
||||
Continue Продовжити
|
||||
Configure a Digital ID for Signing Налаштувати цифрове посвідчення для підписування
|
||||
Use a Digital ID from a file Використати цифрове посвідчення з файлу
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -537,6 +537,7 @@
|
||||
, Expires: ,有效期至:
|
||||
No digital IDs yet. 尚无数字 ID。
|
||||
Configure New Digital ID 配置新数字 ID
|
||||
Remove "{name}" from this list? The file itself is not deleted. 从此列表中移除“{name}”?文件本身不会被删除。
|
||||
Continue 继续
|
||||
Configure a Digital ID for Signing 配置用于签名的数字 ID
|
||||
Use a Digital ID from a file 使用文件中的数字 ID
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -489,6 +489,7 @@
|
||||
, Expires: ,有效期至:
|
||||
No digital IDs yet. 尚無數位 ID。
|
||||
Configure New Digital ID 配置新數位 ID
|
||||
Remove "{name}" from this list? The file itself is not deleted. 從此清單中移除「{name}」?檔案本身不會被刪除。
|
||||
Continue 繼續
|
||||
Configure a Digital ID for Signing 設定簽署用的數位 ID
|
||||
Use a Digital ID from a file 使用檔案中的數位 ID
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -111,6 +111,8 @@ pub struct SignDraft {
|
||||
pub image: Option<SignatureImage>,
|
||||
pub new_id: NewIdDraft,
|
||||
pub error: Option<String>,
|
||||
/// Sign with a Digital ID ▸ Remove was clicked for this list entry: asking to confirm.
|
||||
pub confirm_remove: Option<usize>,
|
||||
}
|
||||
|
||||
impl SignDraft {
|
||||
@@ -132,6 +134,7 @@ impl SignDraft {
|
||||
image: None,
|
||||
new_id: NewIdDraft::default(),
|
||||
error: None,
|
||||
confirm_remove: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,6 +328,28 @@ impl PdfCraftApp {
|
||||
self.digital_ids.len() - 1
|
||||
}
|
||||
|
||||
/// Take the digital ID file at `index` off the list (issue #1396). The file itself stays on
|
||||
/// disk. Keychain and Windows store IDs belong to the OS and are listed again on every
|
||||
/// signing, so they can't be removed here. The open dialog's selection follows the list.
|
||||
pub fn remove_digital_id(&mut self, index: usize) -> bool {
|
||||
if self.digital_ids.get(index).is_none_or(|e| e.path.starts_with("keychain:") || e.path.starts_with("windows:")) {
|
||||
return false;
|
||||
}
|
||||
self.digital_ids.remove(index);
|
||||
if let Some(d) = self.sign_draft.as_mut() {
|
||||
d.confirm_remove = None;
|
||||
d.selected = match d.selected {
|
||||
Some(s) if s > index => Some(s - 1),
|
||||
Some(s) if s == index => self.digital_ids.iter().position(|e| e.unusable.is_none()),
|
||||
s => s,
|
||||
};
|
||||
if self.digital_ids.is_empty() {
|
||||
d.step = SignStep::Configure;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Configure New Digital ID ▸ Create: a self-signed ID saved as a .p12 next to the app data
|
||||
/// (or in `export_dir_override`). Returns its list index.
|
||||
fn create_digital_id(&mut self) -> Result<usize, String> {
|
||||
@@ -620,6 +645,7 @@ fn choose(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens) -> bool {
|
||||
}
|
||||
if resp.clicked() {
|
||||
d.selected = Some(i);
|
||||
d.confirm_remove = None;
|
||||
}
|
||||
if resp.double_clicked() {
|
||||
d.step = SignStep::SignAs;
|
||||
@@ -630,11 +656,29 @@ fn choose(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens) -> bool {
|
||||
}
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
// Remove takes a digital ID file off the list after asking (#1396); OS key store IDs stay.
|
||||
let mut remove = None;
|
||||
if let Some(e) = d.confirm_remove.and_then(|i| ids.get(i)) {
|
||||
ui.label(crate::i18n::fmt(tl!("Remove \"{name}\" from this list? The file itself is not deleted."), &[("name", &e.name)]));
|
||||
ui.horizontal(|ui| {
|
||||
if widgets::pill_button(ui, tl!("Remove"), true).clicked() {
|
||||
remove = d.confirm_remove;
|
||||
}
|
||||
if widgets::pill_button(ui, tl!("Cancel"), false).clicked() {
|
||||
d.confirm_remove = None;
|
||||
}
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
}
|
||||
let removable = d.selected.filter(|&i| ids.get(i).is_some_and(|e| !e.path.starts_with("keychain:") && !e.path.starts_with("windows:")));
|
||||
ui.horizontal(|ui| {
|
||||
if widgets::pill_button(ui, tl!("Configure New Digital ID"), false).clicked() {
|
||||
d.step = SignStep::Configure;
|
||||
d.error = None;
|
||||
}
|
||||
if d.confirm_remove.is_none() && ui.add_enabled_ui(removable.is_some(), |ui| widgets::pill_button(ui, tl!("Remove"), false)).inner.clicked() {
|
||||
d.confirm_remove = removable;
|
||||
}
|
||||
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
||||
if ui.add_enabled_ui(d.selected.is_some(), |ui| widgets::pill_button(ui, tl!("Continue"), true)).inner.clicked() {
|
||||
d.step = SignStep::SignAs;
|
||||
@@ -645,6 +689,9 @@ fn choose(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens) -> bool {
|
||||
}
|
||||
});
|
||||
});
|
||||
if let Some(i) = remove {
|
||||
app.remove_digital_id(i);
|
||||
}
|
||||
close
|
||||
}
|
||||
|
||||
@@ -1373,4 +1420,40 @@ mod tests {
|
||||
assert_eq!(mode & 0o077, 0, "the private key is not readable by others: {mode:o}");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
fn listed(path: &str, name: &str) -> DigitalIdEntry {
|
||||
DigitalIdEntry { path: path.into(), name: name.into(), issuer: String::new(), email: String::new(), expires: String::new(), unusable: None }
|
||||
}
|
||||
|
||||
/// Issue #1396: an imported ID can be taken off the list (its file stays), the dialog's
|
||||
/// selection follows, an OS key store ID or a stale index is refused, and the removal is saved.
|
||||
#[test]
|
||||
fn a_digital_id_file_is_removed_from_the_list_and_stays_removed() {
|
||||
let dir = scratch();
|
||||
let file = dir.join("old.p12");
|
||||
std::fs::write(&file, b"not opened").unwrap();
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.digital_ids = vec![listed("windows:abc", "Store"), listed(&file.to_string_lossy(), "Old"), listed("/ids/new.p12", "New")];
|
||||
let mut draft = SignDraft::new(0, None, None, None, &app.digital_ids);
|
||||
draft.selected = Some(2);
|
||||
draft.confirm_remove = Some(1);
|
||||
app.sign_draft = Some(draft);
|
||||
|
||||
assert!(!app.remove_digital_id(0), "OS key store IDs stay");
|
||||
assert!(!app.remove_digital_id(9), "an index past the list is refused");
|
||||
assert!(app.remove_digital_id(1));
|
||||
assert_eq!(app.digital_ids.iter().map(|e| e.name.as_str()).collect::<Vec<_>>(), ["Store", "New"]);
|
||||
assert!(file.exists(), "the file itself is not deleted");
|
||||
let d = app.sign_draft.as_ref().unwrap();
|
||||
assert_eq!((d.selected, d.confirm_remove, d.step), (Some(1), None, SignStep::Choose), "still New, no pending question");
|
||||
|
||||
// Removing the selected ID selects the first usable one; removing the last file ID
|
||||
// leaves only the store ID, which isn't saved.
|
||||
assert!(app.remove_digital_id(1));
|
||||
assert_eq!(app.sign_draft.as_ref().unwrap().selected, Some(0));
|
||||
let mut fresh = PdfCraftApp::new();
|
||||
fresh.restore(&app.persist());
|
||||
assert!(fresh.digital_ids.is_empty(), "the removal survives a restart: {:?}", fresh.digital_ids);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
@@ -444,3 +444,48 @@ fn an_unusable_id_is_shown_with_its_reason_and_cannot_be_chosen() {
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.state().sign_draft.as_ref().unwrap().selected, Some(1));
|
||||
}
|
||||
|
||||
/// Issue #1396: an imported digital ID can be removed from Sign with a Digital ID, after a
|
||||
/// confirmation, and its file stays where it was.
|
||||
#[test]
|
||||
fn an_imported_digital_id_can_be_removed() {
|
||||
let dir = dir().join("remove");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let p12 = dir.join("signer.p12");
|
||||
std::fs::copy(concat!(env!("CARGO_MANIFEST_DIR"), "/../sign/tests/data/ec-p256.p12"), &p12).unwrap();
|
||||
let mut h = harness(dir.clone());
|
||||
assert!(h.state_mut().execute("sign.certify_invisible"));
|
||||
h.run_steps(2);
|
||||
{
|
||||
let d = h.state_mut().sign_draft.as_mut().unwrap();
|
||||
d.new_id.create = false;
|
||||
d.new_id.file = p12.to_string_lossy().into_owned();
|
||||
d.new_id.file_password = "test".into();
|
||||
}
|
||||
h.run_steps(1);
|
||||
h.get_by_label("Continue").click();
|
||||
h.run_steps(4);
|
||||
assert_eq!(h.state().digital_ids.len(), 1);
|
||||
assert_eq!(h.state().sign_draft.as_ref().map(|d| d.step), Some(SignStep::Choose));
|
||||
|
||||
// Remove asks first, and Cancel keeps the ID. The dialog changes size with the question;
|
||||
// egui centres it from the previous frame's size, so let it settle before each click.
|
||||
h.get_by_label("Remove").click();
|
||||
h.run_steps(4);
|
||||
h.get_by_label("Remove \"Test Signer EC\" from this list? The file itself is not deleted.");
|
||||
// The question's Cancel comes before the dialog's own.
|
||||
h.get_all_by_label("Cancel").next().unwrap().click();
|
||||
h.run_steps(4);
|
||||
assert!(h.query_by_label_contains("from this list?").is_none());
|
||||
assert_eq!(h.state().digital_ids.len(), 1);
|
||||
|
||||
h.get_by_label("Remove").click();
|
||||
h.run_steps(4);
|
||||
h.get_by_label("Remove").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().digital_ids.is_empty());
|
||||
assert!(p12.exists(), "the file itself is not deleted");
|
||||
// With no IDs left the dialog offers to configure one.
|
||||
assert_eq!(h.state().sign_draft.as_ref().map(|d| d.step), Some(SignStep::Configure));
|
||||
h.get_by_label("Configure a Digital ID for Signing");
|
||||
}
|
||||
Reference in new issue
Block a user