diff --git a/CMakeLists.txt b/CMakeLists.txt index 0533ebd8a..ab1744673 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option(WITH_DNF5 "Build dnf5 command-line package manager" ON) option(WITH_DNF5_PLUGINS "Build plugins for dnf5 command-line package manager" ON) option(WITH_PLUGIN_ACTIONS "Build a dnf5 actions plugin" ON) option(WITH_PLUGIN_APPSTREAM "Build with plugin to install repo's Appstream metadata" ON) +option(WITH_PLUGIN_EXPIRED_PGP_KEYS "Build a libdnf5 expired pgp keys plugin" ON) option(WITH_PLUGIN_RHSM "Build a libdnf5 rhsm (Red Hat Subscription Manager) plugin" OFF) option(WITH_PYTHON_PLUGINS_LOADER "Build a special dnf5 plugin that loads Python plugins. Requires WITH_PYTHON3=ON." ON) diff --git a/dnf5.spec b/dnf5.spec index 62019eb5a..b506726d4 100644 --- a/dnf5.spec +++ b/dnf5.spec @@ -78,6 +78,7 @@ Provides: dnf5-command(versionlock) %bcond_without dnf5_plugins %bcond_without plugin_actions %bcond_without plugin_appstream +%bcond_without plugin_expired_pgp_keys %bcond_without plugin_rhsm %bcond_without python_plugins_loader @@ -624,6 +625,23 @@ Libdnf5 plugin that installs repository's Appstream data, for repositories which %endif +# ========== libdnf5-plugin-expired-pgp-keys ========== + +%if %{with plugin_expired_pgp_keys} +%package -n libdnf5-plugin-expired-pgp-keys +Summary: Libdnf5 plugin for detecting and removing expired PGP keys +License: LGPL-2.1-or-later +Requires: libdnf5%{?_isa} = %{version}-%{release} + +%description -n libdnf5-plugin-expired-pgp-keys +Libdnf5 plugin for detecting and removing expired PGP keys. + +%files -n libdnf5-plugin-expired-pgp-keys -f libdnf5-plugin-expired-pgp-keys.lang +%{_libdir}/libdnf5/plugins/expired-pgp-keys.* +%config %{_sysconfdir}/dnf/libdnf5-plugins/expired-pgp-keys.conf +%{_mandir}/man8/libdnf5-expired-pgp-keys.8.* +%endif + # ========== libdnf5-plugin-plugin_rhsm ========== %if %{with plugin_rhsm} @@ -825,6 +843,7 @@ automatically and regularly from systemd timers, cron jobs or similar. -DWITH_DNF5=%{?with_dnf5:ON}%{!?with_dnf5:OFF} \ -DWITH_PLUGIN_ACTIONS=%{?with_plugin_actions:ON}%{!?with_plugin_actions:OFF} \ -DWITH_PLUGIN_APPSTREAM=%{?with_plugin_appstream:ON}%{!?with_plugin_appstream:OFF} \ + -DWITH_PLUGIN_EXPIRED_PGP_KEYS=%{?with_plugin_expired_pgp_keys:ON}%{!?with_plugin_expired_pgp_keys:OFF} \ -DWITH_PLUGIN_RHSM=%{?with_plugin_rhsm:ON}%{!?with_plugin_rhsm:OFF} \ -DWITH_PYTHON_PLUGINS_LOADER=%{?with_python_plugins_loader:ON}%{!?with_python_plugins_loader:OFF} \ \ @@ -915,6 +934,7 @@ popd %find_lang libdnf5 %find_lang libdnf5-cli %find_lang libdnf5-plugin-actions +%find_lang libdnf5-plugin-expired-pgp-keys %find_lang libdnf5-plugin-rhsm %ldconfig_scriptlets diff --git a/dnf5/context.cpp b/dnf5/context.cpp index 6fd620e71..18519c150 100644 --- a/dnf5/context.cpp +++ b/dnf5/context.cpp @@ -59,7 +59,7 @@ namespace dnf5 { namespace { // The `KeyImportRepoCB` class implements callback only for importing repository key. -class KeyImportRepoCB : public libdnf5::repo::RepoCallbacks { +class KeyImportRepoCB : public libdnf5::repo::RepoCallbacks2 { public: explicit KeyImportRepoCB(libdnf5::ConfigMain & config) : config(&config) {} @@ -87,6 +87,35 @@ class KeyImportRepoCB : public libdnf5::repo::RepoCallbacks { std::cerr << _("The key was successfully imported.") << std::endl; } + bool repokey_remove(const libdnf5::rpm::KeyInfo & key_info) override { + if (config->get_assumeno_option().get_value()) { + return false; + } + + std::cerr << libdnf5::utils::sformat( + _("The following PGP key (0x{}) has expired on {}:"), + key_info.get_short_key_id(), + libdnf5::utils::string::format_epoch(key_info.get_timestamp())) + << std::endl; + for (auto & user_id : key_info.get_user_ids()) { + std::cerr << libdnf5::utils::sformat(_(" UserID : \"{}\"\n"), user_id); + } + std::cerr << libdnf5::utils::sformat(_(" From : {}\n"), key_info.get_url()); + + std::cerr << std::endl << _("As a result, installing packages signed with this key will fail.") << std::endl; + std::cerr << _("It is recommended to remove the expired key to allow importing") << std::endl; + std::cerr << _("an updated key. This might leave already installed packages unverifiable.") << std::endl + << std::endl; + + std::cerr << _("The system will now proceed with removing the key.") << std::endl; + + return libdnf5::cli::utils::userconfirm::userconfirm(*config); + } + + void repokey_removed([[maybe_unused]] const libdnf5::rpm::KeyInfo & key_info) override { + std::cerr << _("The key was successfully removed.") << std::endl; + } + private: libdnf5::ConfigMain * config; }; diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 6cb59ad16..26b2fc2cd 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -41,6 +41,10 @@ if(WITH_MAN) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/libdnf5-actions.8 DESTINATION share/man/man8) endif() + if(WITH_PLUGIN_EXPIRED_PGP_KEYS) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/libdnf5-expired-pgp-keys.8 DESTINATION share/man/man8) + endif() + if(WITH_DNF5DAEMON_CLIENT) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5daemon-client.8 DESTINATION share/man/man8) endif() diff --git a/doc/conf.py.in b/doc/conf.py.in index fff2d7869..4e8bfd381 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -151,6 +151,7 @@ man_pages = [ ('dnf5_plugins/repoclosure.8', 'dnf5-repoclosure', 'Repoclosure Command', AUTHORS, 8), ('dnf5_plugins/reposync.8', 'dnf5-reposync', 'Reposync Command', AUTHORS, 8), ('libdnf5_plugins/actions.8', 'libdnf5-actions', 'Actions Plugin', AUTHORS, 8), + ('libdnf5_plugins/expired-pgp-keys.8', 'libdnf5-expired-pgp-keys', 'Expired PGP Keys Plugin', AUTHORS, 8), ('misc/aliases.7', 'dnf5-aliases', 'Aliases for command line arguments', AUTHORS, 7), ('misc/caching.7', 'dnf5-caching', 'Caching', AUTHORS, 7), ('misc/comps.7', 'dnf5-comps', 'Comps Groups And Environments', AUTHORS, 7), diff --git a/doc/dnf5.8.rst b/doc/dnf5.8.rst index c380a27bc..7b7890a7f 100644 --- a/doc/dnf5.8.rst +++ b/doc/dnf5.8.rst @@ -452,6 +452,7 @@ Application Plugins: Library Plugins: | :manpage:`libdnf5-actions(8)`, :ref:`Actions plugin ` + | :manpage:`libdnf5-expired-pgp-keys(8)`, :ref:`Expired PGP keys plugin ` Configuration: | :manpage:`dnf5-conf(5)`, :ref:`DNF5 Configuration Reference ` diff --git a/doc/libdnf5_plugins/expired-pgp-keys.8.rst b/doc/libdnf5_plugins/expired-pgp-keys.8.rst new file mode 100644 index 000000000..4788e62df --- /dev/null +++ b/doc/libdnf5_plugins/expired-pgp-keys.8.rst @@ -0,0 +1,40 @@ +.. + Copyright Contributors to the libdnf project. + + This file is part of libdnf: https://github.com/rpm-software-management/libdnf/ + + Libdnf is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Libdnf is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdnf. If not, see . + +.. _expired-pgp-keys_plugin_ref-label: + +######################## + Expired PGP Keys Plugin +######################## + +Description +=========== + +The plugin checks for installed but expired PGP keys before executing the transaction. +For each expired key, the user is prompted with information about the specific key +and can confirm its removal, allowing for the import of an updated key later. +When the ``assumeyes`` option is configured, expired keys are removed automatically. + +Configuration +============= + +The plugin configuration is in ``/etc/dnf/libdnf5-plugins/expired-pgp-keys.conf``. All configuration +options are in the ``[main]`` section. + +``enabled`` + Whether the plugin is enabled. Default value is ``True``. diff --git a/doc/libdnf5_plugins/index.rst b/doc/libdnf5_plugins/index.rst index 9e02d158f..264f39a25 100644 --- a/doc/libdnf5_plugins/index.rst +++ b/doc/libdnf5_plugins/index.rst @@ -9,5 +9,6 @@ LIBDNF5 Plugins :maxdepth: 1 actions.8 + expired-pgp-keys.8 .. diff --git a/include/libdnf5/repo/repo_callbacks.hpp b/include/libdnf5/repo/repo_callbacks.hpp index e5b7d08bf..ff328db7d 100644 --- a/include/libdnf5/repo/repo_callbacks.hpp +++ b/include/libdnf5/repo/repo_callbacks.hpp @@ -53,6 +53,18 @@ class LIBDNF_API RepoCallbacks { virtual void repokey_imported(const libdnf5::rpm::KeyInfo & key_info); }; +/// @brief Extended repository callbacks with additional methods for support of key removal. +class LIBDNF_API RepoCallbacks2 : public RepoCallbacks { +public: + /// OpenPGP key remove callback. Allows to confirm or deny the removal. + /// @param key_info The key that is about to be removed + /// @return `true` to remove the key, `false` to not remove + virtual bool repokey_remove(const libdnf5::rpm::KeyInfo & key_info); + /// Called on successful repo key removal. + /// @param key_info The key that was successfully removed + virtual void repokey_removed(const libdnf5::rpm::KeyInfo & key_info); +}; + } // namespace libdnf5::repo #endif // LIBDNF5_REPO_REPO_CALLBACKS_HPP diff --git a/libdnf5-plugins/CMakeLists.txt b/libdnf5-plugins/CMakeLists.txt index e8c99de03..c8100a8c6 100644 --- a/libdnf5-plugins/CMakeLists.txt +++ b/libdnf5-plugins/CMakeLists.txt @@ -3,5 +3,6 @@ set(CMAKE_C_VISIBILITY_PRESET hidden) add_subdirectory("actions") add_subdirectory("appstream") +add_subdirectory("expired-pgp-keys") add_subdirectory("python_plugins_loader") add_subdirectory("rhsm") diff --git a/libdnf5-plugins/expired-pgp-keys/CMakeLists.txt b/libdnf5-plugins/expired-pgp-keys/CMakeLists.txt new file mode 100644 index 000000000..24602d28a --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/CMakeLists.txt @@ -0,0 +1,24 @@ +if(NOT WITH_PLUGIN_EXPIRED_PGP_KEYS) + return() +endif() + +# set gettext domain for translations +set(GETTEXT_DOMAIN libdnf5-plugin-expired-pgp-keys) +add_definitions(-DGETTEXT_DOMAIN=\"${GETTEXT_DOMAIN}\") + +add_library(expired-pgp-keys MODULE expired-pgp-keys.cpp) + +# disable the 'lib' prefix in order to create expired-pgp-keys.so +set_target_properties(expired-pgp-keys PROPERTIES PREFIX "") + +target_link_libraries(expired-pgp-keys PRIVATE common_obj) +target_link_libraries(expired-pgp-keys PRIVATE libdnf5 libdnf5-cli) + +pkg_check_modules(RPM REQUIRED rpm) +target_link_libraries(expired-pgp-keys PRIVATE ${RPM_LIBRARIES}) + +install(TARGETS expired-pgp-keys LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/libdnf5/plugins/") + +install(FILES "expired-pgp-keys.conf" DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}/dnf/libdnf5-plugins") + +add_subdirectory(po) diff --git a/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.conf b/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.conf new file mode 100644 index 000000000..e261d9239 --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.conf @@ -0,0 +1,3 @@ +[main] +name = expired-pgp-keys +enabled = 1 diff --git a/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.cpp b/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.cpp new file mode 100644 index 000000000..75b8c81a4 --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/expired-pgp-keys.cpp @@ -0,0 +1,236 @@ +/* +Copyright Contributors to the libdnf project. + +This file is part of libdnf: https://github.com/rpm-software-management/libdnf/ + +Libdnf is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 of the License, or +(at your option) any later version. + +Libdnf is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with libdnf. If not, see . +*/ + +#include "utils/string.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace libdnf5; + +namespace { + +constexpr const char * PLUGIN_NAME = "expired-pgp-keys"; +constexpr plugin::Version PLUGIN_VERSION{1, 0, 0}; + +constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr}; +constexpr const char * attrs_value[]{"Jan Kolarik", "jkolarik@redhat.com", "Expired PGP Keys Plugin."}; + +/// @brief Find expired PGP keys and suggest their removal. +/// This is a workaround to solve https://github.com/rpm-software-management/dnf5/issues/1192. +class ExpiredPgpKeys final : public plugin::IPlugin3 { +public: + ExpiredPgpKeys(libdnf5::plugin::IPluginData & data, libdnf5::ConfigParser &) : IPlugin3(data) {} + virtual ~ExpiredPgpKeys() = default; + + PluginAPIVersion get_api_version() const noexcept override { return PLUGIN_API_VERSION; } + + const char * get_name() const noexcept override { return PLUGIN_NAME; } + + plugin::Version get_version() const noexcept override { return PLUGIN_VERSION; } + + const char * const * get_attributes() const noexcept override { return attrs; } + + const char * get_attribute(const char * attribute) const noexcept override { + for (size_t i = 0; attrs[i]; ++i) { + if (std::strcmp(attribute, attrs[i]) == 0) { + return attrs_value[i]; + } + } + return nullptr; + } + + void resolved(const libdnf5::base::Transaction & transaction) override { process_expired_pgp_keys(transaction); } + +private: + void process_expired_pgp_keys(const libdnf5::base::Transaction & transaction) const; +}; + +/// Check that GPG is installed to enable querying expired keys later. +static bool is_gpg_installed() { + auto ts = rpmtsCreate(); + rpmdbMatchIterator mi; + mi = rpmtsInitIterator(ts, RPMDBI_PROVIDENAME, "gpg", 0); + bool found = rpmdbNextIterator(mi) != NULL; + rpmdbFreeIterator(mi); + rpmtsFree(ts); + return found; +} + +/// Check if the transaction contains any inbound actions. +/// This determines if new software is to be installed, which might require downloading a new PGP signing key. +static bool any_inbound_action(const libdnf5::base::Transaction & transaction) { + for (const auto & package : transaction.get_transaction_packages()) { + if (transaction_item_action_is_inbound(package.get_action())) { + return true; + } + } + return false; +} + +/// Retrieve the PGP key expiration timestamp, or return -1 if the expiration is not available. +static int64_t get_key_expire_timestamp(std::string raw_key) { + // open gpg process to retrieve information about the key + std::unique_ptr pipe( + popen(libdnf5::utils::sformat("echo \"{}\" | gpg --show-keys --with-colon", raw_key).c_str(), "r"), pclose); + if (!pipe) { + return -1; + } + + // read key information from the gpg process + char buffer[1024]; + std::string output; + while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) { + output += buffer; + } + + // check expired time is a numeric value + auto expired_date_string = libdnf5::utils::string::split(libdnf5::utils::string::split(output, "\n")[0], ":")[6]; + if (expired_date_string.empty() || expired_date_string.find_first_not_of("0123456789") != std::string::npos) { + return -1; + } + + return static_cast(std::stoull(expired_date_string)); +} + +/// Remove the system package corresponding to the PGP key from the given RPM header. +static bool remove_pgp_key(const libdnf5::rpm::KeyInfo & key) { + bool retval{false}; + auto ts = rpmtsCreate(); + Header h; + rpmdbMatchIterator mi; + mi = rpmtsInitIterator(ts, RPMDBI_NAME, "gpg-pubkey", 0); + auto key_id = key.get_short_key_id(); + while ((h = rpmdbNextIterator(mi)) != nullptr) { + if (headerGetAsString(h, RPMTAG_VERSION) == libdnf5::utils::string::tolower(key_id)) { + rpmtsAddEraseElement(ts, h, -1); + retval = rpmtsRun(ts, nullptr, RPMPROB_FILTER_NONE) == 0; + break; + } + } + rpmtsFree(ts); + rpmdbFreeIterator(mi); + return retval; +} + +void ExpiredPgpKeys::process_expired_pgp_keys(const libdnf5::base::Transaction & transaction) const { + auto & logger = *get_base().get_logger(); + const auto & config = get_base().get_config(); + + if (!config.get_gpgcheck_option().get_value()) { + return; + } + + if (!is_gpg_installed()) { + logger.error("Expired PGP Keys Plugin: GPG is not installed on the system. Aborting..."); + return; + } + + if (!any_inbound_action(transaction)) { + return; + } + + auto current_date = std::chrono::system_clock::now(); + auto current_timestamp = std::chrono::duration_cast(current_date.time_since_epoch()).count(); + + libdnf5::rpm::RpmSignature rpm_signature(get_base()); + libdnf5::repo::RepoQuery enabled_repos(get_base()); + enabled_repos.filter_enabled(true); + enabled_repos.filter_type(libdnf5::repo::Repo::Type::AVAILABLE); + + for (auto const & repo : enabled_repos) { + auto key_urls = repo->get_config().get_gpgkey_option().get_value(); + if (key_urls.empty()) { + continue; + } + + auto callbacks = dynamic_cast(repo->get_callbacks().get()); + + for (auto const & key_url : key_urls) { + for (auto & key_info : rpm_signature.parse_key_file(key_url)) { + if (rpm_signature.key_present(key_info)) { + auto user_ids = key_info.get_user_ids(); + auto key_timestamp = get_key_expire_timestamp(key_info.get_raw_key()); + if (key_timestamp > 0 && key_timestamp < current_timestamp) { + libdnf5::rpm::KeyInfo expired_key_info( + key_info.get_url(), + key_info.get_path(), + key_info.get_key_id(), + user_ids, + key_info.get_fingerprint(), + key_timestamp, + key_info.get_raw_key()); + if (callbacks && !callbacks->repokey_remove(expired_key_info)) { + continue; + } + logger.debug( + "Expired PGP Keys Plugin: Removing the 0x{} key (user id: \"{}\").", + key_info.get_short_key_id(), + !user_ids.empty() ? user_ids.front() : ""); + auto removed = remove_pgp_key(key_info); + if (!removed) { + logger.error( + "Expired PGP Keys Plugin: Failed to remove the 0x{} key.", key_info.get_short_key_id()); + } else if (callbacks) { + callbacks->repokey_removed(expired_key_info); + } + } + } + } + } + } +} + +} // namespace + +PluginAPIVersion libdnf_plugin_get_api_version(void) { + return PLUGIN_API_VERSION; +} + +const char * libdnf_plugin_get_name(void) { + return PLUGIN_NAME; +} + +plugin::Version libdnf_plugin_get_version(void) { + return PLUGIN_VERSION; +} + +plugin::IPlugin * libdnf_plugin_new_instance( + [[maybe_unused]] LibraryVersion library_version, + libdnf5::plugin::IPluginData & data, + libdnf5::ConfigParser & parser) try { + return new ExpiredPgpKeys(data, parser); +} catch (...) { + return nullptr; +} + +void libdnf_plugin_delete_instance(plugin::IPlugin * plugin_object) { + delete plugin_object; +} diff --git a/libdnf5-plugins/expired-pgp-keys/po/CMakeLists.txt b/libdnf5-plugins/expired-pgp-keys/po/CMakeLists.txt new file mode 100644 index 000000000..cb10bc8bd --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/po/CMakeLists.txt @@ -0,0 +1,5 @@ +if(NOT WITH_TRANSLATIONS) + return() +endif() + +include(Translations) diff --git a/libdnf5-plugins/expired-pgp-keys/po/cs.po b/libdnf5-plugins/expired-pgp-keys/po/cs.po new file mode 100644 index 000000000..d9c5fc149 --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/po/cs.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Bot , 2024. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-25 06:01+0000\n" +"PO-Revision-Date: 2024-07-25 06:01+0000\n" +"Last-Translator: Bot \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#: expired-pgp-keys.cpp:182 +#, c++-format +msgid "The following PGP key has expired on {}:" +msgstr "Následující PGP klíč vypršel dne {}:" + +#: expired-pgp-keys.cpp:186 +msgid "For more information about the key:" +msgstr "Pro více informací o klíči:" + +#: expired-pgp-keys.cpp:189 +msgid "As a result, installing packages signed with this key will fail." +msgstr "V důsledku toho se instalace balíčků podepsaných tímto klíčem nezdaří." + +#: expired-pgp-keys.cpp:190 +msgid "It is recommended to remove the expired key to allow importing" +msgstr "Doporučuje se odstranit vypršelý klíč, aby bylo možné importovat" + +#: expired-pgp-keys.cpp:191 +msgid "" +"an updated key. This might leave already installed packages unverifiable." +msgstr "" +"aktualizovaný klíč. To může zanechat již nainstalované balíčky neověřitelné." + +#: expired-pgp-keys.cpp:194 +msgid "The system will now proceed with removing the key." +msgstr "Systém nyní přistoupí k odstranění klíče." + +#: expired-pgp-keys.cpp:199 +msgid "Key successfully removed." +msgstr "Klíč byl úspěšně odstraněn." + +#: expired-pgp-keys.cpp:201 +msgid "Failed to remove the key." +msgstr "Nepodařilo se odstranit klíč." diff --git a/libdnf5-plugins/expired-pgp-keys/po/libdnf5-plugin-expired-pgp-keys.pot b/libdnf5-plugins/expired-pgp-keys/po/libdnf5-plugin-expired-pgp-keys.pot new file mode 100644 index 000000000..678d946ac --- /dev/null +++ b/libdnf5-plugins/expired-pgp-keys/po/libdnf5-plugin-expired-pgp-keys.pot @@ -0,0 +1,52 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-25 06:01+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: expired-pgp-keys.cpp:182 +#, c++-format +msgid "The following PGP key has expired on {}:" +msgstr "" + +#: expired-pgp-keys.cpp:186 +msgid "For more information about the key:" +msgstr "" + +#: expired-pgp-keys.cpp:189 +msgid "As a result, installing packages signed with this key will fail." +msgstr "" + +#: expired-pgp-keys.cpp:190 +msgid "It is recommended to remove the expired key to allow importing" +msgstr "" + +#: expired-pgp-keys.cpp:191 +msgid "" +"an updated key. This might leave already installed packages unverifiable." +msgstr "" + +#: expired-pgp-keys.cpp:194 +msgid "The system will now proceed with removing the key." +msgstr "" + +#: expired-pgp-keys.cpp:199 +msgid "Key successfully removed." +msgstr "" + +#: expired-pgp-keys.cpp:201 +msgid "Failed to remove the key." +msgstr "" diff --git a/libdnf5/repo/repo_callbacks.cpp b/libdnf5/repo/repo_callbacks.cpp index 614f3d63e..ee393bb57 100644 --- a/libdnf5/repo/repo_callbacks.cpp +++ b/libdnf5/repo/repo_callbacks.cpp @@ -31,4 +31,10 @@ bool RepoCallbacks::repokey_import(const libdnf5::rpm::KeyInfo &) { void RepoCallbacks::repokey_imported(const libdnf5::rpm::KeyInfo &) {} +bool RepoCallbacks2::repokey_remove(const libdnf5::rpm::KeyInfo &) { + return true; +} + +void RepoCallbacks2::repokey_removed(const libdnf5::rpm::KeyInfo &) {} + } // namespace libdnf5::repo diff --git a/libdnf5/rpm/rpm_signature.cpp b/libdnf5/rpm/rpm_signature.cpp index 7e59f6df4..270615cbf 100644 --- a/libdnf5/rpm/rpm_signature.cpp +++ b/libdnf5/rpm/rpm_signature.cpp @@ -73,7 +73,7 @@ static bool rpmdb_lookup(const RpmTransactionPtr & ts_ptr, const KeyInfo & key) mi = rpmtsInitIterator(ts_ptr.get(), RPMDBI_NAME, "gpg-pubkey", 0); auto key_id = key.get_short_key_id(); while ((h = rpmdbNextIterator(mi)) != nullptr) { - if (headerGetAsString(h, RPMTAG_VERSION) == key_id) { + if (headerGetAsString(h, RPMTAG_VERSION) == utils::string::tolower(key_id)) { retval = true; break; }