diff --git a/autotests/TestBackend.h b/autotests/TestBackend.h --- a/autotests/TestBackend.h +++ b/autotests/TestBackend.h @@ -39,7 +39,7 @@ Action::AuthStatus authorizeAction(const QString &) override; Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) override; bool actionExists(const QString &action) override; public Q_SLOTS: diff --git a/autotests/TestBackend.cpp b/autotests/TestBackend.cpp --- a/autotests/TestBackend.cpp +++ b/autotests/TestBackend.cpp @@ -73,8 +73,10 @@ return QByteArray("a random caller Id"); } -bool TestBackend::isCallerAuthorized(const QString &action, QByteArray callerId) +bool TestBackend::isCallerAuthorized(const QString &action, QByteArray callerId, const QVariantMap &details) { + Q_UNUSED(details); + if (action == QLatin1String("doomed.to.fail")) { return false; } else if (action == QLatin1String("requires.auth")) { diff --git a/src/AuthBackend.h b/src/AuthBackend.h --- a/src/AuthBackend.h +++ b/src/AuthBackend.h @@ -28,6 +28,8 @@ namespace KAuth { +typedef Action::DetailsMap DetailsMap; + class AuthBackend : public QObject { Q_OBJECT @@ -57,8 +59,9 @@ virtual Action::AuthStatus actionStatus(const QString &action) = 0; virtual QByteArray callerID() const = 0; virtual ExtraCallerIDVerificationMethod extraCallerIDVerificationMethod() const; - virtual bool isCallerAuthorized(const QString &action, QByteArray callerID) = 0; + virtual bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) = 0; virtual bool actionExists(const QString &action); + virtual QVariantMap getBackendDetails(const DetailsMap &details); Capabilities capabilities() const; diff --git a/src/AuthBackend.cpp b/src/AuthBackend.cpp --- a/src/AuthBackend.cpp +++ b/src/AuthBackend.cpp @@ -71,5 +71,11 @@ Q_UNUSED(parent) } +QVariantMap AuthBackend::getBackendDetails(const DetailsMap &details) +{ + Q_UNUSED(details); + return QVariantMap(); +} + } //namespace KAuth diff --git a/src/HelperProxy.h b/src/HelperProxy.h --- a/src/HelperProxy.h +++ b/src/HelperProxy.h @@ -31,6 +31,8 @@ namespace KAuth { +typedef Action::DetailsMap DetailsMap; + class HelperProxy : public QObject { Q_OBJECT @@ -40,7 +42,8 @@ // Application-side methods virtual void executeAction(const QString &action, const QString &helperID, - const QVariantMap &arguments, int timeout) = 0; + const DetailsMap &details, const QVariantMap &arguments, + int timeout) = 0; virtual void stopAction(const QString &action, const QString &helperID) = 0; // Helper-side methods diff --git a/src/backends/dbus/DBusHelperProxy.h b/src/backends/dbus/DBusHelperProxy.h --- a/src/backends/dbus/DBusHelperProxy.h +++ b/src/backends/dbus/DBusHelperProxy.h @@ -59,7 +59,8 @@ ~DBusHelperProxy() override; virtual void executeAction(const QString &action, const QString &helperID, - const QVariantMap &arguments, int timeout = -1) override; + const DetailsMap &details, const QVariantMap &arguments, + int timeout = -1) override; void stopAction(const QString &action, const QString &helperID) override; bool initHelper(const QString &name) override; @@ -71,16 +72,16 @@ public Q_SLOTS: void stopAction(const QString &action); - QByteArray performAction(const QString &action, const QByteArray &callerID, QByteArray arguments); + QByteArray performAction(const QString &action, const QByteArray &callerID, const QVariantMap &details, QByteArray arguments); Q_SIGNALS: void remoteSignal(int type, const QString &action, const QByteArray &blob); // This signal is sent from the helper to the app private Q_SLOTS: void remoteSignalReceived(int type, const QString &action, QByteArray blob); private: - bool isCallerAuthorized(const QString &action, const QByteArray &callerID); + bool isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details); }; } // namespace Auth diff --git a/src/backends/dbus/DBusHelperProxy.cpp b/src/backends/dbus/DBusHelperProxy.cpp --- a/src/backends/dbus/DBusHelperProxy.cpp +++ b/src/backends/dbus/DBusHelperProxy.cpp @@ -68,7 +68,7 @@ m_busConnection.asyncCall(message); } -void DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout) +void DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout) { QByteArray blob; { @@ -102,7 +102,7 @@ message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.kf5auth"), QLatin1String("performAction")); QList args; - args << action << BackendsManager::authBackend()->callerID() << blob; + args << action << BackendsManager::authBackend()->callerID() << BackendsManager::authBackend()->getBackendDetails(details) << blob; message.setArguments(args); m_actionsInProgress.push_back(action); @@ -198,7 +198,7 @@ return m_stopRequest; } -bool DBusHelperProxy::isCallerAuthorized(const QString &action, const QByteArray &callerID) +bool DBusHelperProxy::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { // Check the caller is really who it says it is switch (BackendsManager::authBackend()->extraCallerIDVerificationMethod()) { @@ -218,10 +218,10 @@ break; } - return BackendsManager::authBackend()->isCallerAuthorized(action, callerID); + return BackendsManager::authBackend()->isCallerAuthorized(action, callerID, details); } -QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments) +QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, const QVariantMap &details, QByteArray arguments) { if (!responder) { return ActionReply::NoResponderReply().serialized(); @@ -252,7 +252,7 @@ QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value(); timer->stop(); - if (isCallerAuthorized(action, callerID)) { + if (isCallerAuthorized(action, callerID, details)) { QString slotname = action; if (slotname.startsWith(m_name + QLatin1Char('.'))) { slotname = slotname.right(slotname.length() - m_name.length() - 1); diff --git a/src/backends/dbus/org.kde.kf5auth.xml b/src/backends/dbus/org.kde.kf5auth.xml --- a/src/backends/dbus/org.kde.kf5auth.xml +++ b/src/backends/dbus/org.kde.kf5auth.xml @@ -4,8 +4,10 @@ + + diff --git a/src/backends/fake/FakeBackend.h b/src/backends/fake/FakeBackend.h --- a/src/backends/fake/FakeBackend.h +++ b/src/backends/fake/FakeBackend.h @@ -39,7 +39,7 @@ Action::AuthStatus authorizeAction(const QString &) override; Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) override; }; } // namespace Auth diff --git a/src/backends/fake/FakeBackend.cpp b/src/backends/fake/FakeBackend.cpp --- a/src/backends/fake/FakeBackend.cpp +++ b/src/backends/fake/FakeBackend.cpp @@ -50,10 +50,11 @@ return QByteArray(); } -bool FakeBackend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool FakeBackend::isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) { Q_UNUSED(action) Q_UNUSED(callerID) + Q_UNUSED(details) return false; } diff --git a/src/backends/fakehelper/FakeHelperProxy.h b/src/backends/fakehelper/FakeHelperProxy.h --- a/src/backends/fakehelper/FakeHelperProxy.h +++ b/src/backends/fakehelper/FakeHelperProxy.h @@ -41,7 +41,7 @@ void setHelperResponder(QObject *o) override; bool initHelper(const QString &name) override; void stopAction(const QString &action, const QString &helperID) override; - void executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout = -1) override; + void executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout = -1) override; }; } diff --git a/src/backends/fakehelper/FakeHelperProxy.cpp b/src/backends/fakehelper/FakeHelperProxy.cpp --- a/src/backends/fakehelper/FakeHelperProxy.cpp +++ b/src/backends/fakehelper/FakeHelperProxy.cpp @@ -71,9 +71,10 @@ Q_UNUSED(helperID) } -void FakeHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments, int timeout) +void FakeHelperProxy::executeAction(const QString &action, const QString &helperID, const DetailsMap &details, const QVariantMap &arguments, int timeout) { Q_UNUSED(helperID) + Q_UNUSED(details) Q_UNUSED(arguments) Q_UNUSED(timeout) emit actionPerformed(action, KAuth::ActionReply::NoSuchActionReply()); diff --git a/src/backends/mac/AuthServicesBackend.h b/src/backends/mac/AuthServicesBackend.h --- a/src/backends/mac/AuthServicesBackend.h +++ b/src/backends/mac/AuthServicesBackend.h @@ -39,7 +39,7 @@ virtual Action::AuthStatus authorizeAction(const QString &); virtual Action::AuthStatus actionStatus(const QString &); virtual QByteArray callerID() const; - virtual bool isCallerAuthorized(const QString &action, QByteArray callerID); + virtual bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details); virtual bool actionExists(const QString &action); }; diff --git a/src/backends/mac/AuthServicesBackend.cpp b/src/backends/mac/AuthServicesBackend.cpp --- a/src/backends/mac/AuthServicesBackend.cpp +++ b/src/backends/mac/AuthServicesBackend.cpp @@ -165,8 +165,10 @@ return id; } -bool AuthServicesBackend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool AuthServicesBackend::isCallerAuthorized(const QString &action, const QByteArray &callerID, const QVariantMap &details) { + Q_UNUSED(details); + AuthorizationExternalForm ext; memcpy(&ext, callerID.data(), sizeof(ext)); diff --git a/src/backends/policykit/PolicyKitBackend.h b/src/backends/policykit/PolicyKitBackend.h --- a/src/backends/policykit/PolicyKitBackend.h +++ b/src/backends/policykit/PolicyKitBackend.h @@ -41,7 +41,7 @@ virtual Action::AuthStatus actionStatus(const QString &); virtual QByteArray callerID() const; ExtraCallerIDVerificationMethod extraCallerIDVerificationMethod() const override; - virtual bool isCallerAuthorized(const QString &action, QByteArray callerID); + virtual bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details); private Q_SLOTS: void checkForResultChanged(); diff --git a/src/backends/policykit/PolicyKitBackend.cpp b/src/backends/policykit/PolicyKitBackend.cpp --- a/src/backends/policykit/PolicyKitBackend.cpp +++ b/src/backends/policykit/PolicyKitBackend.cpp @@ -83,8 +83,10 @@ return VerifyAgainstDBusServicePid; } -bool PolicyKitBackend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool PolicyKitBackend::isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) { + Q_UNUSED(details); + QDataStream s(&callerID, QIODevice::ReadOnly); qint64 pid; diff --git a/src/backends/polkit-1/Polkit1Backend.h b/src/backends/polkit-1/Polkit1Backend.h --- a/src/backends/polkit-1/Polkit1Backend.h +++ b/src/backends/polkit-1/Polkit1Backend.h @@ -50,8 +50,9 @@ Action::AuthStatus actionStatus(const QString &) override; QByteArray callerID() const override; ExtraCallerIDVerificationMethod extraCallerIDVerificationMethod() const override; - bool isCallerAuthorized(const QString &action, QByteArray callerID) override; + bool isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) override; bool actionExists(const QString &action) override; + QVariantMap getBackendDetails(const DetailsMap &details) override; private Q_SLOTS: void checkForResultChanged(); diff --git a/src/backends/polkit-1/Polkit1Backend.cpp b/src/backends/polkit-1/Polkit1Backend.cpp --- a/src/backends/polkit-1/Polkit1Backend.cpp +++ b/src/backends/polkit-1/Polkit1Backend.cpp @@ -174,15 +174,18 @@ return VerifyAgainstDBusServiceName; } -bool Polkit1Backend::isCallerAuthorized(const QString &action, QByteArray callerID) +bool Polkit1Backend::isCallerAuthorized(const QString &action, QByteArray callerID, const QVariantMap &details) { PolkitQt1::SystemBusNameSubject subject(QString::fromUtf8(callerID)); PolkitQt1::Authority *authority = PolkitQt1::Authority::instance(); - + QMap polkit1Details; + for (auto it = details.cbegin(); it != details.cend(); ++it) { + polkit1Details.insert(it.key(), it.value().toString()); + } PolkitResultEventLoop e; connect(authority, SIGNAL(checkAuthorizationFinished(PolkitQt1::Authority::Result)), &e, SLOT(requestQuit(PolkitQt1::Authority::Result))); - authority->checkAuthorization(action, subject, PolkitQt1::Authority::AllowUserInteraction); + authority->checkAuthorizationWithDetails(action, subject, PolkitQt1::Authority::AllowUserInteraction, polkit1Details); e.exec(); if (authority->hasError()) { @@ -238,5 +241,22 @@ return m_knownActions.contains(action); } +QVariantMap Polkit1Backend::getBackendDetails(const DetailsMap &details) +{ + QVariantMap backendDetails; + for (auto it = details.cbegin(); it != details.cend(); ++it) { + switch (it.key()) { + case Action::DetailMessage: + backendDetails.insert(QStringLiteral("polkit.message"), it.value()); + break; + case Action::DetailOther: + default: + backendDetails.insert(QStringLiteral("other_details"), it.value()); + break; + } + } + return backendDetails; +} + } // namespace Auth diff --git a/src/kauthaction.h b/src/kauthaction.h --- a/src/kauthaction.h +++ b/src/kauthaction.h @@ -102,6 +102,17 @@ }; Q_ENUM(ExecutionMode) + /** + * The backend specific details. + */ + enum AuthDetail { + DetailOther = 0, + DetailMessage, ///< The message to show in authentication dialog. + }; + Q_ENUM(AuthDetail) + + typedef QMap DetailsMap; + /** * @brief Default constructor * @@ -126,8 +137,21 @@ * @param details The details of the action * * @see setDetails + * @deprecated since 5.62 + */ +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED 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.62 */ - Action(const QString &name, const QString &details); + Action(const QString &name, const DetailsMap &details); /// Virtual destructor ~Action(); @@ -207,18 +231,50 @@ * 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.62, use setDetails() with DetailsMap. + */ +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED 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.62 + */ + void setDetails(const DetailsMap &details); + + /** + * @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.62, use details() with DetailsMap. */ - void setDetails(const QString &details); +#ifndef KAUTHCORE_NO_DEPRECATED + KAUTHCORE_DEPRECATED 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.62 */ - QString details() const; + DetailsMap detailsV2() const; /** * @brief Returns if the object represents a valid action diff --git a/src/kauthaction.cpp b/src/kauthaction.cpp --- a/src/kauthaction.cpp +++ b/src/kauthaction.cpp @@ -38,17 +38,17 @@ ActionData(const ActionData &other) : QSharedData(other) , name(other.name) - , details(other.details) , helperId(other.helperId) + , details(other.details) , args(other.args) , valid(other.valid) , parent(other.parent) , timeout(other.timeout) {} ~ActionData() {} QString name; - QString details; QString helperId; + Action::DetailsMap details; QVariantMap args; bool valid; QWidget *parent = nullptr; @@ -73,7 +73,14 @@ BackendsManager::authBackend()->setupAction(d->name); } +#ifndef KAUTHCORE_NO_DEPRECATED Action::Action(const QString &name, const QString &details) + : Action(name, DetailsMap{{DetailOther, details}}) +{ +} +#endif + +Action::Action(const QString &name, const DetailsMap &details) : d(new ActionData()) { setName(name); @@ -139,12 +146,25 @@ d->timeout = timeout; } +#ifndef KAUTHCORE_NO_DEPRECATED QString Action::details() const { - return d->details; + return d->details.value(DetailOther).toString(); } void Action::setDetails(const QString &details) +{ + d->details.clear(); + d->details.insert(DetailOther, details); +} +#endif + +Action::DetailsMap Action::detailsV2() const +{ + return d->details; +} + +void Action::setDetails(const DetailsMap &details) { d->details = details; } diff --git a/src/kauthexecutejob.cpp b/src/kauthexecutejob.cpp --- a/src/kauthexecutejob.cpp +++ b/src/kauthexecutejob.cpp @@ -125,7 +125,7 @@ if (s == Action::AuthorizedStatus) { if (action.hasHelper()) { - BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); + BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); } else { // Done actionPerformedSlot(action.name(), ActionReply::SuccessReply()); @@ -160,7 +160,7 @@ actionPerformedSlot(action.name(), r); return; } - BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); + BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout()); } else { // There's something totally wrong here ActionReply r(ActionReply::BackendError);