diff --git a/CMakeLists.txt b/CMakeLists.txt index e0c56f7..5268c32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,109 +1,111 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.71.0") # handled by release scripts set(KF5_DEP_VERSION "5.70.0") # handled by release scripts project(KAuth VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.70.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) set(REQUIRED_QT_VERSION 5.12.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED DBus) option(KAUTH_BUILD_CODEGENERATOR_ONLY "Only build the kauth-policy-gen code generator." OFF) if(NOT KAUTH_BUILD_CODEGENERATOR_ONLY) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Widgets) endif() include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -include(GenerateExportHeader) +include(ECMGenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(ECMQtDeclareLoggingCategory) include(ECMPoQmTools) include(ECMAddQch) +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") + option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KAUTH VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kauth_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AuthConfigVersion.cmake" SOVERSION 5) find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED) set(KAUTH_HELPER_INSTALL_DIR "${KDE_INSTALL_LIBEXECDIR}/kauth") if(IS_ABSOLUTE ${KAUTH_HELPER_INSTALL_DIR}) set(KAUTH_HELPER_INSTALL_ABSOLUTE_DIR ${KAUTH_HELPER_INSTALL_DIR}) else() set(KAUTH_HELPER_INSTALL_ABSOLUTE_DIR "${CMAKE_INSTALL_PREFIX}/${KAUTH_HELPER_INSTALL_DIR}") endif() if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x054600) add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if(TARGET Qt5::Widgets) if (BUILD_TESTING) add_subdirectory(autotests) endif() add_subdirectory(examples) endif() # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Auth") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Auth_QCH FILE KF5AuthQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5AuthQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5AuthConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5AuthConfig.cmake" PATH_VARS KDE_INSTALL_DATADIR_KF5 INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5AuthConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5AuthConfigVersion.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/KF5AuthMacros.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) if(TARGET KF5Auth) install(EXPORT KF5AuthTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5AuthTargets.cmake NAMESPACE KF5:: COMPONENT Devel) endif() if(NOT "${KAUTH_BACKEND_NAME}" STREQUAL "FAKE") install(EXPORT KF5AuthToolsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5AuthToolsTargets.cmake NAMESPACE KF5:: COMPONENT Devel) endif() install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kauth_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index f2e413d..9223699 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,73 +1,82 @@ find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG QUIET) if(NOT Qt5Test_FOUND) message(STATUS "Qt5Test not found, autotests will not be built.") return() endif() qt5_add_dbus_adaptor(kauth_dbus_adaptor_tests_SRCS ../src/backends/dbus/org.kde.kf5auth.xml ../src/backends/dbus/DBusHelperProxy.h KAuth::DBusHelperProxy) include(ECMAddTests) set(kauthdebug_SRCS) ecm_qt_declare_logging_category(kauthdebug_tests_SRCS HEADER kauthdebug.h IDENTIFIER KAUTH CATEGORY_NAME kf5.kauth) set(libkauth_tests_static_SRCS ../src/kauthaction.cpp ../src/kauthactionreply.cpp ../src/kauthexecutejob.cpp ../src/AuthBackend.cpp # Use our "special" backends manager BackendsManager.cpp ../src/HelperProxy.cpp ../src/kauthhelpersupport.cpp TestBackend.cpp ../src/backends/dbus/DBusHelperProxy.cpp ${kauth_dbus_adaptor_tests_SRCS} ${kauthdebug_tests_SRCS} ) add_library(kauth_tests_static STATIC ${libkauth_tests_static_SRCS}) # make sure all executables using this library have the define set to make sure it builds on MSVC target_compile_definitions(kauth_tests_static PUBLIC KAUTHCORE_STATIC_DEFINE=1 PUBLIC KAUTH_STATIC_DEFINE=1 ) +# have to manually duplicate logic of flags set by ecm_generate_expoirt_header on the library +ecm_export_header_format_version(${EXCLUDE_DEPRECATED_BEFORE_AND_AT} + CURRENT_VERSION ${KF5_VERSION} + HEXNUMBER_VAR kauthcore_tests_no_deprecated_before_and_at +) +target_compile_definitions(kauth_tests_static + PUBLIC "KAUTHCORE_DISABLE_DEPRECATED_BEFORE_AND_AT=${kauthcore_tests_no_deprecated_before_and_at}" + PUBLIC "KAUTHCORE_DEPRECATED_WARNINGS_SINCE=${kauthcore_tests_no_deprecated_before_and_at}" +) ecm_mark_as_test(kauth_tests_static) target_include_directories(kauth_tests_static PUBLIC $ ${CMAKE_CURRENT_SOURCE_DIR}/../src ) target_link_libraries(kauth_tests_static PUBLIC Qt5::DBus KF5::CoreAddons) ########### next target ############### set(SetupActionTest_SRCS SetupActionTest.cpp) ecm_add_test(${SetupActionTest_SRCS} TEST_NAME KAuthSetupActionTest LINK_LIBRARIES Qt5::Test kauth_tests_static ) ########### next target ############### set(HelperTest_SRCS HelperTest.cpp TestHelper.cpp) ecm_add_test(${HelperTest_SRCS} TEST_NAME KAuthHelperTest LINK_LIBRARIES Qt5::Test kauth_tests_static ) ########### test kauth-policy-gen ############### add_test(NAME KAuthPolicyGenTest COMMAND kauth-policy-gen ${CMAKE_SOURCE_DIR}/autotests/foo_actions.actions ${CMAKE_BINARY_DIR}/generated-foo.policy) add_test(KAuthPolicyGenTestCompare ${CMAKE_COMMAND} -E compare_files ${CMAKE_BINARY_DIR}/generated-foo.policy ${CMAKE_SOURCE_DIR}/autotests/foo.policy) diff --git a/autotests/SetupActionTest.cpp b/autotests/SetupActionTest.cpp index 07c3e92..5dd6530 100644 --- a/autotests/SetupActionTest.cpp +++ b/autotests/SetupActionTest.cpp @@ -1,152 +1,202 @@ /* * Copyright (C) 2012 Dario Freddi * * This program 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. * * This program 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 Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include #include #include #include #include "BackendsManager.h" class SetupActionTest : public QObject { Q_OBJECT public: SetupActionTest(QObject *parent = nullptr) : QObject(parent) { } private Q_SLOTS: void initTestCase(); void init() {} void testNonExistentAction(); +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) + void testBasicActionPropertiesDeprecated(); +#endif void testBasicActionProperties(); void testUserAuthorization(); void testAuthorizationFail(); void cleanup() {} void cleanupTestCase() {} Q_SIGNALS: void changeCapabilities(KAuth::AuthBackend::Capabilities capabilities); private: }; void SetupActionTest::initTestCase() { connect(this, SIGNAL(changeCapabilities(KAuth::AuthBackend::Capabilities)), KAuth::BackendsManager::authBackend(), SLOT(setNewCapabilities(KAuth::AuthBackend::Capabilities))); } void SetupActionTest::testNonExistentAction() { emit changeCapabilities(KAuth::AuthBackend::AuthorizeFromHelperCapability | KAuth::AuthBackend::CheckActionExistenceCapability); KAuth::Action action(QLatin1String("i.do.not.exist")); QVERIFY(!action.isValid()); action = KAuth::Action(QLatin1String("/safinvalid124%$&")); QVERIFY(action.isValid()); // Now with regexp check emit changeCapabilities(KAuth::AuthBackend::NoCapability); action = KAuth::Action(QLatin1String("/safinvalid124%$&")); QVERIFY(!action.isValid()); } -void SetupActionTest::testBasicActionProperties() +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) +void SetupActionTest::testBasicActionPropertiesDeprecated() { emit changeCapabilities(KAuth::AuthBackend::AuthorizeFromHelperCapability | KAuth::AuthBackend::CheckActionExistenceCapability); + KAuth::Action::DetailsMap detailsMap{{KAuth::Action::AuthDetail::DetailOther, QLatin1String("details")}}; KAuth::Action action(QLatin1String("always.authorized"), QLatin1String("details")); QVERIFY(action.isValid()); QCOMPARE(action.name(), QLatin1String("always.authorized")); QCOMPARE(action.details(), QLatin1String("details")); + QCOMPARE(action.detailsV2(), detailsMap); QVERIFY(!action.hasHelper()); QVERIFY(action.helperId().isEmpty()); QCOMPARE(action.status(), KAuth::Action::AuthorizedStatus); QVERIFY(action.arguments().isEmpty()); QVariantMap args; args.insert(QLatin1String("akey"), QVariant::fromValue(42)); action.setArguments(args); QCOMPARE(action.arguments(), args); action.setName(QLatin1String("i.do.not.exist")); QVERIFY(!action.isValid()); emit changeCapabilities(KAuth::AuthBackend::NoCapability); action = KAuth::Action(QLatin1String("i.do.not.exist"), QLatin1String("details")); QVERIFY(action.isValid()); QCOMPARE(action.name(), QLatin1String("i.do.not.exist")); QCOMPARE(action.details(), QLatin1String("details")); + QCOMPARE(action.detailsV2(), detailsMap); + QVERIFY(!action.hasHelper()); + QVERIFY(action.helperId().isEmpty()); + QCOMPARE(action.status(), KAuth::Action::InvalidStatus); +} +#endif + +void SetupActionTest::testBasicActionProperties() +{ + emit changeCapabilities(KAuth::AuthBackend::AuthorizeFromHelperCapability | KAuth::AuthBackend::CheckActionExistenceCapability); + KAuth::Action::DetailsMap detailsMap{{KAuth::Action::AuthDetail::DetailOther, QLatin1String("details")}}; + KAuth::Action action(QLatin1String("always.authorized"), detailsMap); + QVERIFY(action.isValid()); + + QCOMPARE(action.name(), QLatin1String("always.authorized")); +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) + QCOMPARE(action.details(), QLatin1String("details")); +#endif + QCOMPARE(action.detailsV2(), detailsMap); + QVERIFY(!action.hasHelper()); + QVERIFY(action.helperId().isEmpty()); + QCOMPARE(action.status(), KAuth::Action::AuthorizedStatus); + + QVERIFY(action.arguments().isEmpty()); + QVariantMap args; + args.insert(QLatin1String("akey"), QVariant::fromValue(42)); + action.setArguments(args); + QCOMPARE(action.arguments(), args); + + action.setName(QLatin1String("i.do.not.exist")); + QVERIFY(!action.isValid()); + + emit changeCapabilities(KAuth::AuthBackend::NoCapability); + + action = KAuth::Action(QLatin1String("i.do.not.exist"), detailsMap); + + QVERIFY(action.isValid()); + QCOMPARE(action.name(), QLatin1String("i.do.not.exist")); +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) + QCOMPARE(action.details(), QLatin1String("details")); +#endif + QCOMPARE(action.detailsV2(), detailsMap); QVERIFY(!action.hasHelper()); QVERIFY(action.helperId().isEmpty()); QCOMPARE(action.status(), KAuth::Action::InvalidStatus); } void SetupActionTest::testUserAuthorization() { emit changeCapabilities(KAuth::AuthBackend::CheckActionExistenceCapability); - KAuth::Action action(QLatin1String("requires.auth"), QLatin1String("details")); + KAuth::Action::DetailsMap detailsMap{{KAuth::Action::AuthDetail::DetailOther, QLatin1String("details")}}; + KAuth::Action action(QLatin1String("requires.auth"), detailsMap); QVERIFY(action.isValid()); QCOMPARE(action.status(), KAuth::Action::AuthRequiredStatus); KAuth::ExecuteJob *job = action.execute(); QVERIFY(!job->exec()); QCOMPARE(job->error(), (int)KAuth::ActionReply::BackendError); emit changeCapabilities(KAuth::AuthBackend::CheckActionExistenceCapability | KAuth::AuthBackend::AuthorizeFromClientCapability); QVERIFY(action.isValid()); QCOMPARE(action.status(), KAuth::Action::AuthRequiredStatus); job = action.execute(); QVERIFY(job->exec()); QVERIFY(!job->error()); QVERIFY(job->data().isEmpty()); } void SetupActionTest::testAuthorizationFail() { emit changeCapabilities(KAuth::AuthBackend::CheckActionExistenceCapability | KAuth::AuthBackend::AuthorizeFromClientCapability); - KAuth::Action action(QLatin1String("doomed.to.fail"), QLatin1String("details")); + KAuth::Action::DetailsMap detailsMap{{KAuth::Action::AuthDetail::DetailOther, QLatin1String("details")}}; + KAuth::Action action(QLatin1String("doomed.to.fail"), detailsMap); QVERIFY(action.isValid()); QCOMPARE(action.status(), KAuth::Action::DeniedStatus); KAuth::ExecuteJob *job = action.execute(); QVERIFY(!job->exec()); QCOMPARE(job->error(), (int)KAuth::ActionReply::AuthorizationDeniedError); QVERIFY(job->data().isEmpty()); } QTEST_MAIN(SetupActionTest) #include "SetupActionTest.moc" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 074c834..e094e40 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,199 +1,206 @@ # This file handles all the logic for compiling KAuth's backends include(ConfigureChecks.cmake) # Configure a small file to tell BackendsManager what to use configure_file(BackendsConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/BackendsConfig.h) ecm_create_qm_loader(KAuth_QM_LOADER kauth5_qt) set(kauthdebug_SRCS) ecm_qt_declare_logging_category(kauthdebug_SRCS HEADER kauthdebug.h IDENTIFIER KAUTH CATEGORY_NAME kf5.kauth DESCRIPTION "KAuth" EXPORT KAUTH ) if(TARGET Qt5::Widgets) # TODO KF6 Rename KAuth to KAuthWidgets # TODO KAuthCore should be installed also when no widgets available, in the header installation etc, so ignoring for now set(libkauth_core_SRCS kauthaction.cpp kauthactionreply.cpp kauthexecutejob.cpp AuthBackend.cpp BackendsManager.cpp HelperProxy.cpp kauthhelpersupport.cpp ${kauthdebug_SRCS} backends/fake/FakeBackend.cpp backends/fakehelper/FakeHelperProxy.cpp ${KAuth_QM_LOADER} ) add_library(KF5AuthCore ${libkauth_core_SRCS}) - generate_export_header(KF5AuthCore BASE_NAME KAuthCore) + ecm_generate_export_header(KF5AuthCore + BASE_NAME KAuthCore + GROUP_BASE_NAME KF + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.71 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} + ) add_library(KF5::AuthCore ALIAS KF5AuthCore) target_link_libraries(KF5AuthCore PUBLIC Qt5::Core KF5::CoreAddons) # for KJob target_link_libraries(KF5AuthCore PRIVATE Qt5::DBus) target_include_directories(KF5AuthCore INTERFACE "$") install(TARGETS KF5AuthCore EXPORT KF5AuthTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) set_target_properties(KF5AuthCore PROPERTIES VERSION ${KAUTH_VERSION_STRING} SOVERSION ${KAUTH_SOVERSION} EXPORT_NAME AuthCore) set(libkauth_SRCS ${kauthdebug_SRCS} kauthobjectdecorator.cpp ) add_library(KF5Auth ${libkauth_SRCS}) generate_export_header(KF5Auth BASE_NAME KAuth) add_library(KF5::Auth ALIAS KF5Auth) target_include_directories(KF5Auth INTERFACE "$") target_link_libraries(KF5Auth PUBLIC KF5AuthCore) target_link_libraries(KF5Auth PRIVATE Qt5::Widgets) set_target_properties(KF5Auth PROPERTIES VERSION ${KAUTH_VERSION_STRING} SOVERSION ${KAUTH_SOVERSION} EXPORT_NAME Auth ) ecm_generate_headers(KAuth_HEADERS HEADER_NAMES KAuth KAuthHelperSupport KAuthAction KAuthActionReply KAuthExecuteJob KAuthObjectDecorator REQUIRED_HEADERS KAuth_HEADERS ) install(TARGETS KF5Auth EXPORT KF5AuthTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kauth_export.h ${CMAKE_CURRENT_BINARY_DIR}/kauthcore_export.h ${KAuth_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KAuth COMPONENT Devel ) endif() find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) ecm_generate_python_binding( TARGET KF5::Auth PYTHONNAMESPACE PyKF5 MODULENAME KAuth RULES_FILE "${CMAKE_SOURCE_DIR}/cmake/rules_PyKF5.py" SIP_INCLUDES $ SIP_DEPENDS QtWidgets/QtWidgetsmod.sip PyKF5/KCoreAddons/KCoreAddonsmod.sip HEADERS kauth.h kauthhelpersupport.h kauthaction.h kauthactionreply.h kauthexecutejob.h kauthobjectdecorator.h ) endif() # KAuth policy generator executable # Compile only if fake backend has not been selected if (NOT "${KAUTH_BACKEND_NAME}" STREQUAL "FAKE") # KAUTH_POLICY_GEN_SRCS has been generated from ConfigureChecks.cmake add_executable(kauth-policy-gen ${KAUTH_POLICY_GEN_SRCS}) add_executable(KF5::kauth-policy-gen ALIAS kauth-policy-gen) if (APPLE) include(ECMMarkNonGuiExecutable) ecm_mark_nongui_executable(kauth-policy-gen) endif () # KAUTH_POLICY_GEN_LIBRARIES has been generated from ConfigureChecks.cmake target_link_libraries( kauth-policy-gen PRIVATE ${KAUTH_POLICY_GEN_LIBRARIES} ) install( TARGETS kauth-policy-gen EXPORT KF5AuthToolsTargets DESTINATION ${KAUTH_HELPER_INSTALL_DIR}) endif () # KAuth backend plugin if (NOT "${KAUTH_BACKEND_NAME}" STREQUAL "FAKE" AND TARGET Qt5::Widgets) set(KAUTH_BACKEND_SRCS ${KAUTH_BACKEND_SRCS}) # KAuth::AuthBackend is not exported add_library(kauth_backend_plugin MODULE ${KAUTH_BACKEND_SRCS} AuthBackend.cpp ${kauthdebug_SRCS}) target_link_libraries(kauth_backend_plugin PRIVATE ${KAUTH_BACKEND_LIBS}) set_target_properties(kauth_backend_plugin PROPERTIES PREFIX "") install(TARGETS kauth_backend_plugin LIBRARY DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_BACKEND_PLUGIN_DIR}" ARCHIVE DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_BACKEND_PLUGIN_DIR}" RUNTIME DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_BACKEND_PLUGIN_DIR}" ) endif () # KAuth helper plugin if (NOT "${KAUTH_HELPER_BACKEND_NAME}" STREQUAL "FAKE" AND TARGET Qt5::Widgets) # KAuth::HelperProxy is not exported add_library(kauth_helper_plugin MODULE ${KAUTH_HELPER_BACKEND_SRCS} HelperProxy.cpp ${kauthdebug_SRCS}) target_link_libraries(kauth_helper_plugin PRIVATE ${KAUTH_HELPER_BACKEND_LIBS}) set_target_properties(kauth_helper_plugin PROPERTIES PREFIX "") install(TARGETS kauth_helper_plugin LIBRARY DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_HELPER_PLUGIN_DIR}" ARCHIVE DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_HELPER_PLUGIN_DIR}" RUNTIME DESTINATION "${KDE_INSTALL_PLUGINDIR}/${KAUTH_HELPER_PLUGIN_DIR}" ) endif () ecm_qt_install_logging_categories( EXPORT KAUTH FILE kauth.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) if(BUILD_QCH) ecm_add_qch( KF5Auth_QCH NAME KAuth BASE_NAME KF5Auth VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KAuth_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS Qt5Core_QCH KF5CoreAddons_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS KAUTHCORE_EXPORT KAUTH_EXPORT KAUTH_DEPRECATED KAUTH_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() # TODO: Remove once we depend on polkit-qt1 > 0.99.0 # core/polkitqt1-actiondescription.h from polkit currently fails when built with -pedantic string(REPLACE "--pedantic-errors" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "-pedantic-errors" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "--pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KAuthCore LIB_NAME KF5AuthCore DEPS "core KCoreAddons" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KAuth) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) ecm_generate_pri_file(BASE_NAME KAuth LIB_NAME KF5Auth DEPS "KAuthCore" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KAuth) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/kauthaction.cpp b/src/kauthaction.cpp index 1d37851..ea65f84 100644 --- a/src/kauthaction.cpp +++ b/src/kauthaction.cpp @@ -1,232 +1,234 @@ /* * Copyright (C) 2009-2012 Dario Freddi * * This program 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. * * This program 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 Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "kauthaction.h" #include #include class QWidget; #include "kauthexecutejob.h" #include "BackendsManager.h" namespace KAuth { class ActionData : public QSharedData { public: ActionData() : parent(nullptr), timeout(-1) {} ActionData(const ActionData &other) : QSharedData(other) , name(other.name) , helperId(other.helperId) , details(other.details) , args(other.args) , parent(other.parent) , timeout(other.timeout) {} ~ActionData() {} QString name; QString helperId; Action::DetailsMap details; QVariantMap args; QWidget *parent = nullptr; int timeout; }; // Constructors Action::Action() : d(new ActionData()) { } Action::Action(const Action &action) : d(action.d) { } Action::Action(const QString &name) : d(new ActionData()) { setName(name); BackendsManager::authBackend()->setupAction(d->name); } -#ifndef KAUTHCORE_NO_DEPRECATED +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) Action::Action(const QString &name, const QString &details) : Action(name, DetailsMap{{AuthDetail::DetailOther, details}}) { } #endif Action::Action(const QString &name, const DetailsMap &details) : d(new ActionData()) { setName(name); setDetailsV2(details); BackendsManager::authBackend()->setupAction(d->name); } Action::~Action() { } // Operators Action &Action::operator=(const Action &action) { if (this == &action) { // Protect against self-assignment return *this; } d = action.d; return *this; } bool Action::operator==(const Action &action) const { return d->name == action.d->name; } bool Action::operator!=(const Action &action) const { return d->name != action.d->name; } // Accessors QString Action::name() const { return d->name; } void Action::setName(const QString &name) { d->name = name; } // Accessors int Action::timeout() const { return d->timeout; } void Action::setTimeout(int timeout) { d->timeout = timeout; } -#ifndef KAUTHCORE_NO_DEPRECATED +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) QString Action::details() const { return d->details.value(AuthDetail::DetailOther).toString(); } +#endif +#if KAUTHCORE_BUILD_DEPRECATED_SINCE(5, 71) void Action::setDetails(const QString &details) { d->details.clear(); d->details.insert(AuthDetail::DetailOther, details); } #endif Action::DetailsMap Action::detailsV2() const { return d->details; } void Action::setDetailsV2(const DetailsMap &details) { d->details = details; } bool Action::isValid() const { if (d->name.isEmpty()) { return false; } // Does the backend support checking for known actions? if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::CheckActionExistenceCapability) { // In this case, just ask the backend return BackendsManager::authBackend()->actionExists(name()); } else { // Otherwise, check through a regexp const QRegularExpression re(QRegularExpression::anchoredPattern(QStringLiteral("[0-z]+(\\.[0-z]+)*"))); return re.match(name()).hasMatch(); } } void Action::setArguments(const QVariantMap &arguments) { d->args = arguments; } void Action::addArgument(const QString &key, const QVariant &value) { d->args.insert(key, value); } QVariantMap Action::arguments() const { return d->args; } QString Action::helperId() const { return d->helperId; } // TODO: Check for helper id's syntax void Action::setHelperId(const QString &id) { d->helperId = id; } void Action::setParentWidget(QWidget *parent) { d->parent = parent; } QWidget *Action::parentWidget() const { return d->parent; } Action::AuthStatus Action::status() const { if (!isValid()) { return Action::InvalidStatus; } return BackendsManager::authBackend()->actionStatus(d->name); } ExecuteJob *Action::execute(ExecutionMode mode) { return new ExecuteJob(*this, mode, nullptr); } bool Action::hasHelper() const { return !d->helperId.isEmpty(); } } // namespace Auth diff --git a/src/kauthaction.h b/src/kauthaction.h index b3f0f37..ced39fc 100644 --- a/src/kauthaction.h +++ b/src/kauthaction.h @@ -1,443 +1,446 @@ /* * Copyright (C) 2009-2012 Dario Freddi * Copyright (C) 2008 Nicola Gigante * * This program 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. * * This program 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 Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef ACTION_H #define ACTION_H #include #include #include #include #include namespace KAuth { class ExecuteJob; class ActionData; /** * @brief Class to access, authorize and execute actions. * * This is the main class of the kauth API. It provides the interface to * manipulate actions. Every action is identified by its name. Every instance * of the Action class with the same name refers to the same action. * * Once you have an action object you can tell the helper to execute it * (asking the user to authenticate if needed) with the execute() method. * The simplest thing to do is to execute a single action synchronously * blocking for the reply by callin exec() on the job object returned by * execute(). * * For asynchronous calls, use KAuth::ExecuteJob::start() instead. * It sends the request * to the helper and returns immediately. Before doing so you should however * connect to at least the KJob::result(KJob *) signal to receive a slot call * once the action is done executing. * * To use the execute() method you have to set the default helper's ID using * the setHelperID() static method. Alternatively, you can specify the helperID using * the overloaded version of the methods that takes it as a parameter. * * Each action object contains a QVariantMap object that is passed directly to the * helper when the action is executed. You can access this map using the arguments() * method. You can insert into it any kind of custom data you need to pass to the helper. * * @code * void MyApp::runAction() * { * action = KAuth::Action("org.kde.myapp.action"); * KAuth::ExecuteJob *job = action.execute(); * connect(job, &KAuth::ExecuteJob::result, this, &MyApp::actionResult); * job->start(); * } * * void MyApp::actionResult(KJob *kjob) * { * auto job = qobject_cast(kjob); * qDebug() << job.error() << job.data(); * } * @endcode * * @since 4.4 */ class KAUTHCORE_EXPORT Action { Q_GADGET public: /** * The three values set by authorization methods */ enum AuthStatus { DeniedStatus, ///< The authorization has been denied by the authorization backend ErrorStatus, ///< An error occurred InvalidStatus, ///< An invalid action cannot be authorized AuthorizedStatus, ///< The authorization has been granted by the authorization backend AuthRequiredStatus, ///< The user could obtain the authorization after authentication UserCancelledStatus ///< The user pressed Cancel the authentication dialog. Currently used only on the mac }; Q_ENUM(AuthStatus) enum ExecutionMode { ExecuteMode, AuthorizeOnlyMode }; Q_ENUM(ExecutionMode) /** * The backend specific details. */ enum class AuthDetail { DetailOther = 0, DetailMessage, ///< The message to show in authentication dialog. }; Q_ENUM(AuthDetail) typedef QMap DetailsMap; /** * @brief Default constructor * * This constructor sets the name to the empty string. * Such an action is invalid and cannot be authorized nor executed, so * you need to call setName() before you can use the object. */ Action(); /** Copy constructor */ Action(const Action &action); /** * This creates a new action object with this name * @param name The name of the new action */ Action(const QString &name); +#if KAUTHCORE_ENABLE_DEPRECATED_SINCE(5, 71) /** * This creates a new action object with this name and details * @param name The name of the new action * @param details The details of the action * * @see setDetails - * @deprecated since 5.68 + * @deprecated since 5.68, use constructor with DetailsMap */ -#ifndef KAUTHCORE_NO_DEPRECATED - KAUTHCORE_DEPRECATED Action(const QString &name, const QString &details); + KAUTHCORE_DEPRECATED_VERSION_BELATED(5, 71, 5, 68, "Use constructor with DetailsMap") + Action(const QString &name, const QString &details); #endif /** * This creates a new action object with this name and details * @param name The name of the new action * @param details The details of the action * * @see setDetails * @since 5.68 */ Action(const QString &name, const DetailsMap &details); /// Virtual destructor ~Action(); /// Assignment operator Action &operator=(const Action &action); /** * @brief Comparison operator * * This comparison operator compares the names of two * actions and returns whether they are the same. It does not * care about the arguments stored in the actions. However, * if two actions are invalid they'll match as equal, even * if the invalid names are different. * * @returns true if the two actions are the same or both invalid */ bool operator==(const Action &action) const; /** * @brief Negated comparison operator * * Returns the negation of operator== * * @returns true if the two actions are different and not both invalid */ bool operator!=(const Action &action) const; /** * @brief Gets the action's name. * * This is the unique attribute that identifies * an action object. Two action objects with the same * name always refer to the same action. * * @return The action name */ QString name() const; /** * @brief Sets the action's name. * * It's not common to change the action name * after its creation. Usually you set the name * with the constructor (and you have to, because * there's no default constructor) */ void setName(const QString &name); /** * @brief Gets the action's timeout. * * The timeout of the action in milliseconds * -1 means the default D-Bus timeout (usually 25 seconds) * * @since 5.29 * * @return The action timeouts */ int timeout() const; /** * @brief Sets the action's timeout. * * The timeout of the action in milliseconds * -1 means the default D-Bus timeout (usually 25 seconds) * * @since 5.29 * */ void setTimeout(int timeout); +#if KAUTHCORE_ENABLE_DEPRECATED_SINCE(5, 71) /** * @brief Sets the action's details * * You can use this function to provide the user more details * (if the backend supports it) on the action being authorized in * the authorization dialog * - * @deprecated since 5.68, use setDetails() with DetailsMap. + * @deprecated since 5.68, use setDetailsV2() with DetailsMap. */ -#ifndef KAUTHCORE_NO_DEPRECATED - KAUTHCORE_DEPRECATED void setDetails(const QString &details); + KAUTHCORE_DEPRECATED_VERSION_BELATED(5, 71, 5, 68, "Use setDetailsV2() with DetailsMap") + void setDetails(const QString &details); #endif /** * @brief Sets the action's details * * You can use this function to provide the user more details * (if the backend supports it) on the action being authorized in * the authorization dialog * * @param details the details describing the action. For e.g, "DetailMessage" key can * be used to give a customized authentication message. * * @since 5.68 */ void setDetailsV2(const DetailsMap &details); +#if KAUTHCORE_ENABLE_DEPRECATED_SINCE(5, 71) /** * @brief Gets the action's details * * The details that will be shown in the authorization dialog, if the * backend supports it. * * @return The action's details * @deprecated since 5.68, use detailsV2() with DetailsMap. */ -#ifndef KAUTHCORE_NO_DEPRECATED - KAUTHCORE_DEPRECATED QString details() const; + KAUTHCORE_DEPRECATED_VERSION_BELATED(5, 71, 5, 68, "Use detailsV2() with DetailsMap") + QString details() const; #endif /** * @brief Gets the action's details * * The details that will be shown in the authorization dialog, if the * backend supports it. * * @return The action's details * @since 5.68 */ DetailsMap detailsV2() const; /** * @brief Returns if the object represents a valid action * * Action names have to respect a simple syntax. * They have to be all in lowercase characters, separated * by dots. Dots can't appear at the beginning and at the end of * the name. * * In other words, the action name has to match this perl-like * regular expression: * @verbatim * /^[a-z]+(\.[a-z]+)*$/ * @endverbatim * * This method returns false if the action name doesn't match the * valid syntax. * * If the backend supports it, this method also checks if the action is * valid and recognized by the backend itself. * @note This may spawn a nested event loop. * * Invalid actions cannot be authorized nor executed. * The empty string is not a valid action name, so the default * constructor returns an invalid action. */ bool isValid() const; /** * @brief Gets the default helper ID used for actions execution * * The helper ID is the string that uniquely identifies the helper in * the system. It is the string passed to the KAUTH_HELPER() macro * in the helper source. Because one could have different helpers, * you need to specify an helper ID for each execution, or set a default * ID by calling setHelperID(). This method returns the current default * value. * * @return The default helper ID. */ QString helperId() const; /** * @brief Sets the default helper ID used for actions execution * * This method sets the helper ID which contains the body of this action. * If the string is non-empty, the corresponding helper will be fired and * the action executed inside the helper. Otherwise, the action will be just * authorized. * * @note To unset a previously set helper, just pass an empty string * * @param id The default helper ID. * * @see hasHelper * @see helperId */ void setHelperId(const QString &id); /** * @brief Checks if the action has an helper * * This function can be used to check if an helper will be called upon the * execution of an action. Such an helper can be set through setHelperID. If * this function returns false, upon execution the action will be just authorized. * * @since 4.5 * * @return Whether the action has an helper or not * * @see setHelperID */ bool hasHelper() const; /** * @brief Sets the map object used to pass arguments to the helper. * * This method sets the variant map that the application * can use to pass arbitrary data to the helper when executing the action. * * Only non-gui variants are supported. * * @param arguments The new arguments map */ void setArguments(const QVariantMap &arguments); /** * @brief Returns map object used to pass arguments to the helper. * * This method returns the variant map that the application * can use to pass arbitrary data to the helper when executing the action. * * @return The arguments map that will be passed to the helper. */ QVariantMap arguments() const; /** * @brief Convenience method to add an argument. * * This method adds the pair @c key/value to the QVariantMap used to * send custom data to the helper. * * Use this method if you don't want to create a new QVariantMap only to * add a new entry. * * @param key The new entry's key * @param value The value of the new entry */ void addArgument(const QString &key, const QVariant &value); /** * @brief Gets information about the authorization status of an action * * This methods query the authorization backend to know if the user can try * to acquire the authorization for this action. If the result is Action::AuthRequired, * the user can try to acquire the authorization by authenticating. * * It should not be needed to call this method directly, because the execution methods * already take care of all the authorization stuff. * * @return @c Action::Denied if the user doesn't have the authorization to execute the action, * @c Action::Authorized if the action can be executed, * @c Action::AuthRequired if the user could acquire the authorization after authentication, * @c Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend */ AuthStatus status() const; /** * @brief Get the job object used to execute the action * * @return The KJob::ExecuteJob object to be used to run the action. */ ExecuteJob *execute(ExecutionMode mode = ExecuteMode); /** * @brief Sets a parent widget for the authentication dialog * * This function is used for explicitly setting a parent window for an eventual authentication dialog required when * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying * the dialog correctly. * * @note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not * call this function, as it is already done by the component itself. * * @since 4.6 * * @param parent A QWidget which will be used as the dialog's parent */ void setParentWidget(QWidget *parent); /** * @brief Returns the parent widget for the authentication dialog for this action * * @since 4.6 * * @returns A QWidget which will is being used as the dialog's parent */ QWidget *parentWidget() const; private: QSharedDataPointer d; }; } // namespace Auth #endif