|  | 
|  | 1 | +#include "agentimpl.hpp" | 
|  | 2 | +#include <algorithm> | 
|  | 3 | +#include <utility> | 
|  | 4 | + | 
|  | 5 | +#include <qlist.h> | 
|  | 6 | +#include <qloggingcategory.h> | 
|  | 7 | +#include <qobject.h> | 
|  | 8 | +#include <qtmetamacros.h> | 
|  | 9 | + | 
|  | 10 | +#include "../../core/generation.hpp" | 
|  | 11 | +#include "../../core/logcat.hpp" | 
|  | 12 | +#include "gobjectref.hpp" | 
|  | 13 | +#include "listener.hpp" | 
|  | 14 | +#include "qml.hpp" | 
|  | 15 | + | 
|  | 16 | +namespace { | 
|  | 17 | +QS_LOGGING_CATEGORY(logPolkit, "quickshell.service.polkit"); | 
|  | 18 | +} | 
|  | 19 | + | 
|  | 20 | +namespace qs::service::polkit { | 
|  | 21 | +PolkitAgentImpl* PolkitAgentImpl::instance = nullptr; | 
|  | 22 | + | 
|  | 23 | +PolkitAgentImpl::PolkitAgentImpl(PolkitAgent* agent) | 
|  | 24 | +    : QObject(nullptr) | 
|  | 25 | +    , listener(qs_polkit_agent_new(this), G_OBJECT_NO_REF) | 
|  | 26 | +    , qmlAgent(agent) | 
|  | 27 | +    , path(this->qmlAgent->path()) { | 
|  | 28 | +	auto utf8Path = this->path.toUtf8(); | 
|  | 29 | +	qs_polkit_agent_register(this->listener.get(), utf8Path.constData()); | 
|  | 30 | +} | 
|  | 31 | + | 
|  | 32 | +PolkitAgentImpl::~PolkitAgentImpl() { this->cancelAllRequests("PolkitAgent is being destroyed"); } | 
|  | 33 | + | 
|  | 34 | +void PolkitAgentImpl::cancelAllRequests(const QString& reason) { | 
|  | 35 | +	for (; !this->queuedRequests.empty(); this->queuedRequests.pop_back()) { | 
|  | 36 | +		AuthRequest* req = this->queuedRequests.back(); | 
|  | 37 | +		qCDebug(logPolkit) << "destroying queued authentication request for action" << req->actionId; | 
|  | 38 | +		req->cancel(reason); | 
|  | 39 | +		delete req; | 
|  | 40 | +	} | 
|  | 41 | + | 
|  | 42 | +	auto* flow = this->bActiveFlow.value(); | 
|  | 43 | +	if (flow) { | 
|  | 44 | +		flow->cancelAuthenticationRequest(); | 
|  | 45 | +		flow->deleteLater(); | 
|  | 46 | +	} | 
|  | 47 | + | 
|  | 48 | +	if (this->bIsRegistered.value()) qs_polkit_agent_unregister(this->listener.get()); | 
|  | 49 | +} | 
|  | 50 | + | 
|  | 51 | +PolkitAgentImpl* PolkitAgentImpl::tryGetOrCreate(PolkitAgent* agent) { | 
|  | 52 | +	if (instance == nullptr) instance = new PolkitAgentImpl(agent); | 
|  | 53 | +	if (instance->qmlAgent == agent) return instance; | 
|  | 54 | +	return nullptr; | 
|  | 55 | +} | 
|  | 56 | + | 
|  | 57 | +PolkitAgentImpl* PolkitAgentImpl::tryGet(const PolkitAgent* agent) { | 
|  | 58 | +	if (instance == nullptr) return nullptr; | 
|  | 59 | +	if (instance->qmlAgent == agent) return instance; | 
|  | 60 | +	return nullptr; | 
|  | 61 | +} | 
|  | 62 | + | 
|  | 63 | +PolkitAgentImpl* PolkitAgentImpl::tryTakeover(PolkitAgent* agent) { | 
|  | 64 | +	if (instance == nullptr) return nullptr; | 
|  | 65 | + | 
|  | 66 | +	auto* prevGen = EngineGeneration::findObjectGeneration(instance->qmlAgent); | 
|  | 67 | +	auto* myGen = EngineGeneration::findObjectGeneration(agent); | 
|  | 68 | +	if (prevGen == myGen) return nullptr; | 
|  | 69 | + | 
|  | 70 | +	qCDebug(logPolkit) << "taking over listener from previous generation"; | 
|  | 71 | +	instance->qmlAgent = agent; | 
|  | 72 | + | 
|  | 73 | +	return instance; | 
|  | 74 | +} | 
|  | 75 | + | 
|  | 76 | +void PolkitAgentImpl::onEndOfQmlAgent(PolkitAgent* agent) { | 
|  | 77 | +	if (instance != nullptr && instance->qmlAgent == agent) { | 
|  | 78 | +		delete instance; | 
|  | 79 | +		instance = nullptr; | 
|  | 80 | +	} | 
|  | 81 | +} | 
|  | 82 | + | 
|  | 83 | +QBindable<AuthFlow*> PolkitAgentImpl::activeFlow() { return &this->bActiveFlow; } | 
|  | 84 | +QBindable<bool> PolkitAgentImpl::isRegistered() { return &this->bIsRegistered; } | 
|  | 85 | + | 
|  | 86 | +const QString& PolkitAgentImpl::getPath() const { return this->path; } | 
|  | 87 | + | 
|  | 88 | +void PolkitAgentImpl::setPath(const QString& path) { | 
|  | 89 | +	if (this->path == path) return; | 
|  | 90 | + | 
|  | 91 | +	this->path = path; | 
|  | 92 | +	auto utf8Path = path.toUtf8(); | 
|  | 93 | + | 
|  | 94 | +	this->cancelAllRequests("PolkitAgent path changed"); | 
|  | 95 | +	qs_polkit_agent_unregister(this->listener.get()); | 
|  | 96 | +	this->bIsRegistered = false; | 
|  | 97 | + | 
|  | 98 | +	qs_polkit_agent_register(this->listener.get(), utf8Path.constData()); | 
|  | 99 | +} | 
|  | 100 | + | 
|  | 101 | +void PolkitAgentImpl::registerComplete(bool success) { | 
|  | 102 | +	if (success) this->bIsRegistered = true; | 
|  | 103 | +	else qCWarning(logPolkit) << "failed to register listener on path" << this->qmlAgent->path(); | 
|  | 104 | +} | 
|  | 105 | + | 
|  | 106 | +void PolkitAgentImpl::initiateAuthentication(AuthRequest* request) { | 
|  | 107 | +	qCDebug(logPolkit) << "incoming authentication request for action" << request->actionId; | 
|  | 108 | + | 
|  | 109 | +	this->queuedRequests.emplace_back(request); | 
|  | 110 | + | 
|  | 111 | +	if (this->queuedRequests.size() == 1) { | 
|  | 112 | +		this->activateAuthenticationRequest(); | 
|  | 113 | +	} | 
|  | 114 | +} | 
|  | 115 | + | 
|  | 116 | +void PolkitAgentImpl::cancelAuthentication(AuthRequest* request) { | 
|  | 117 | +	qCDebug(logPolkit) << "cancelling authentication request from agent"; | 
|  | 118 | + | 
|  | 119 | +	auto* flow = this->bActiveFlow.value(); | 
|  | 120 | +	if (flow && flow->authRequest() == request) { | 
|  | 121 | +		flow->cancelFromAgent(); | 
|  | 122 | +	} else if (auto it = std::ranges::find(this->queuedRequests, request); | 
|  | 123 | +	           it != this->queuedRequests.end()) | 
|  | 124 | +	{ | 
|  | 125 | +		qCDebug(logPolkit) << "removing queued authentication request for action" << (*it)->actionId; | 
|  | 126 | +		(*it)->cancel("Authentication request was cancelled"); | 
|  | 127 | +		delete (*it); | 
|  | 128 | +		this->queuedRequests.erase(it); | 
|  | 129 | +	} else { | 
|  | 130 | +		qCWarning(logPolkit) << "the cancelled request was not found in the queue."; | 
|  | 131 | +	} | 
|  | 132 | +} | 
|  | 133 | + | 
|  | 134 | +void PolkitAgentImpl::activateAuthenticationRequest() { | 
|  | 135 | +	if (this->queuedRequests.empty()) return; | 
|  | 136 | + | 
|  | 137 | +	AuthRequest* req = this->queuedRequests.front(); | 
|  | 138 | +	this->queuedRequests.pop_front(); | 
|  | 139 | +	qCDebug(logPolkit) << "activating authentication request for action" << req->actionId | 
|  | 140 | +	                   << ", cookie: " << req->cookie; | 
|  | 141 | + | 
|  | 142 | +	QList<Identity*> identities; | 
|  | 143 | +	for (auto& identity: req->identities) { | 
|  | 144 | +		auto* obj = Identity::fromPolkitIdentity(identity); | 
|  | 145 | +		if (obj) identities.append(obj); | 
|  | 146 | +	} | 
|  | 147 | +	if (identities.isEmpty()) { | 
|  | 148 | +		qCWarning(logPolkit | 
|  | 149 | +		) << "no supported identities available for authentication request, cancelling."; | 
|  | 150 | +		req->cancel("Error requesting authentication: no supported identities available."); | 
|  | 151 | +		delete req; | 
|  | 152 | +		return; | 
|  | 153 | +	} | 
|  | 154 | + | 
|  | 155 | +	this->bActiveFlow = new AuthFlow(req, std::move(identities)); | 
|  | 156 | + | 
|  | 157 | +	QObject::connect( | 
|  | 158 | +	    this->bActiveFlow.value(), | 
|  | 159 | +	    &AuthFlow::isCompletedChanged, | 
|  | 160 | +	    this, | 
|  | 161 | +	    &PolkitAgentImpl::finishAuthenticationRequest | 
|  | 162 | +	); | 
|  | 163 | + | 
|  | 164 | +	emit this->qmlAgent->isActiveChanged(); | 
|  | 165 | +	emit this->qmlAgent->flowChanged(); | 
|  | 166 | +	emit this->qmlAgent->authenticationRequestStarted(); | 
|  | 167 | +} | 
|  | 168 | + | 
|  | 169 | +void PolkitAgentImpl::finishAuthenticationRequest() { | 
|  | 170 | +	if (!this->bActiveFlow.value()) return; | 
|  | 171 | + | 
|  | 172 | +	qCDebug(logPolkit) << "finishing authentication request for action" | 
|  | 173 | +	                   << this->bActiveFlow.value()->actionId(); | 
|  | 174 | + | 
|  | 175 | +	this->bActiveFlow.value()->deleteLater(); | 
|  | 176 | + | 
|  | 177 | +	if (!this->queuedRequests.empty()) { | 
|  | 178 | +		this->activateAuthenticationRequest(); | 
|  | 179 | +	} else { | 
|  | 180 | +		this->bActiveFlow = nullptr; | 
|  | 181 | +	} | 
|  | 182 | +} | 
|  | 183 | +} // namespace qs::service::polkit | 
0 commit comments