mirror of
https://github.com/hyprwm/hyprpolkitagent.git
synced 2024-12-25 08:09:50 +01:00
initial commit
This commit is contained in:
parent
2e810ff125
commit
2c97f97336
15 changed files with 788 additions and 0 deletions
65
.clang-format
Normal file
65
.clang-format
Normal file
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ColumnLimit: 180
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
|
||||
BraceWrapping:
|
||||
AfterEnum: false
|
||||
|
||||
AlignConsecutiveDeclarations: AcrossEmptyLines
|
||||
|
||||
NamespaceIndentation: All
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -30,3 +30,9 @@
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
.vscode/
|
||||
.cache/
|
||||
build/
|
||||
|
||||
compile_commands.json
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "subprojects/sdbus-cpp"]
|
||||
path = subprojects/sdbus-cpp
|
||||
url = https://github.com/Kistler-Group/sdbus-cpp/
|
58
CMakeLists.txt
Normal file
58
CMakeLists.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Get version
|
||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
|
||||
string(STRIP ${VER_RAW} VER)
|
||||
|
||||
project(hpa VERSION ${VER} LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
hyprutils
|
||||
polkit-agent-1
|
||||
polkit-qt6-1)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
qt_add_executable(hyprpolkitagent
|
||||
src/main.cpp
|
||||
src/core/Agent.cpp
|
||||
src/core/Agent.hpp
|
||||
src/core/PolkitListener.hpp
|
||||
src/core/PolkitListener.cpp
|
||||
src/QMLIntegration.cpp
|
||||
src/QMLIntegration.hpp
|
||||
src/SigDaemon.hpp
|
||||
src/SigDaemon.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(hyprpolkitagent
|
||||
URI hpa
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
qml/main.qml
|
||||
SOURCES
|
||||
src/QMLIntegration.cpp
|
||||
src/QMLIntegration.hpp
|
||||
src/SigDaemon.hpp
|
||||
src/SigDaemon.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(hyprpolkitagent
|
||||
PRIVATE Qt6::Widgets Qt6::Quick Qt6::Gui Qt6::QuickControls2 PkgConfig::deps
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS hyprpolkitagent
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
0.1.0
|
141
qml/main.qml
Normal file
141
qml/main.qml
Normal file
|
@ -0,0 +1,141 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
|
||||
property var windowWidth: 550
|
||||
property var windowHeight: 240
|
||||
|
||||
maximumWidth: windowWidth
|
||||
maximumHeight: windowHeight
|
||||
minimumWidth: windowWidth
|
||||
minimumHeight: windowHeight
|
||||
visible: true
|
||||
|
||||
FontMetrics {
|
||||
id: fontMetrics
|
||||
}
|
||||
|
||||
SystemPalette {
|
||||
id: system
|
||||
|
||||
colorGroup: SystemPalette.Active
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
Keys.onEscapePressed: (e) => {
|
||||
hpa.setResult("fail");
|
||||
}
|
||||
Keys.onReturnPressed: (e) => {
|
||||
hpa.setResult("auth:" + passwordField.text);
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
|
||||
Text {
|
||||
color: Qt.darker(system.windowText, 0.8)
|
||||
font.bold: true
|
||||
font.pointSize: Math.round(fontMetrics.height * 1.05)
|
||||
text: "Authenticating for " + hpa.getUser()
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
HSeparator {
|
||||
Layout.topMargin: fontMetrics.height / 2
|
||||
Layout.bottomMargin: fontMetrics.height / 2
|
||||
}
|
||||
|
||||
Text {
|
||||
color: system.windowText
|
||||
text: hpa.getMessage()
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
|
||||
Layout.topMargin: fontMetrics.height / 2
|
||||
placeholderText: "Password"
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
hoverEnabled: true
|
||||
persistentSelection: true
|
||||
echoMode: TextInput.Password
|
||||
focus: true
|
||||
|
||||
Connections {
|
||||
target: hpa
|
||||
onFocusField: () => {
|
||||
passwordField.focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
id: errorLabel
|
||||
|
||||
color: "red"
|
||||
font.italic: true
|
||||
Layout.topMargin: fontMetrics.height
|
||||
text: ""
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Connections {
|
||||
target: hpa
|
||||
onSetErrorString: (e) => {
|
||||
errorLabel.text = e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
HSeparator {
|
||||
Layout.topMargin: fontMetrics.height / 2
|
||||
Layout.bottomMargin: fontMetrics.height / 2
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: fontMetrics.height / 2
|
||||
|
||||
Button {
|
||||
text: "Cancel"
|
||||
onClicked: (e) => {
|
||||
hpa.setResult("fail");
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Authenticate"
|
||||
onClicked: (e) => {
|
||||
hpa.setResult("auth:" + passwordField.text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
component Separator: Rectangle {
|
||||
color: Qt.darker(window.palette.text, 1.5)
|
||||
}
|
||||
|
||||
component HSeparator: Separator {
|
||||
implicitHeight: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: fontMetrics.height * 8
|
||||
Layout.rightMargin: fontMetrics.height * 8
|
||||
}
|
||||
|
||||
}
|
29
src/QMLIntegration.cpp
Normal file
29
src/QMLIntegration.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "QMLIntegration.hpp"
|
||||
|
||||
#include "core/Agent.hpp"
|
||||
#include "core/PolkitListener.hpp"
|
||||
|
||||
void CQMLIntegration::onExit() {
|
||||
g_pAgent->submitResultThreadSafe(result.toStdString());
|
||||
}
|
||||
|
||||
void CQMLIntegration::setResult(QString str) {
|
||||
result = str;
|
||||
g_pAgent->submitResultThreadSafe(result.toStdString());
|
||||
}
|
||||
|
||||
QString CQMLIntegration::getMessage() {
|
||||
return g_pAgent->listener.session.inProgress ? g_pAgent->listener.session.message : "An application is requesting authentication.";
|
||||
}
|
||||
|
||||
QString CQMLIntegration::getUser() {
|
||||
return g_pAgent->listener.session.inProgress ? g_pAgent->listener.session.selectedUser.toString() : "an unknown user";
|
||||
}
|
||||
|
||||
void CQMLIntegration::setError(QString str) {
|
||||
emit setErrorString(str);
|
||||
}
|
||||
|
||||
void CQMLIntegration::focus() {
|
||||
emit focusField();
|
||||
}
|
36
src/QMLIntegration.hpp
Normal file
36
src/QMLIntegration.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QPixmap>
|
||||
#include <QIcon>
|
||||
|
||||
class CQMLIntegration : public QObject {
|
||||
Q_OBJECT;
|
||||
Q_PROPERTY(QString errorText MEMBER errorText);
|
||||
|
||||
public:
|
||||
explicit CQMLIntegration(QObject* parent = nullptr) : QObject(parent) {
|
||||
;
|
||||
}
|
||||
virtual ~CQMLIntegration() {
|
||||
;
|
||||
}
|
||||
|
||||
void setError(QString str);
|
||||
void focus();
|
||||
|
||||
QString result = "fail", errorText = "";
|
||||
|
||||
Q_INVOKABLE QString getMessage();
|
||||
Q_INVOKABLE QString getUser();
|
||||
|
||||
Q_INVOKABLE void setResult(QString str);
|
||||
|
||||
public slots:
|
||||
void onExit();
|
||||
|
||||
signals:
|
||||
void setErrorString(QString err);
|
||||
void focusField();
|
||||
};
|
81
src/SigDaemon.cpp
Normal file
81
src/SigDaemon.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include "SigDaemon.hpp"
|
||||
#include "core/Agent.hpp"
|
||||
|
||||
#include <print>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
static int sighupFd[2];
|
||||
static int sigtermFd[2];
|
||||
static int sigintFd[2];
|
||||
|
||||
//
|
||||
void CSigDaemon::onSignal(int signo) {
|
||||
char a = 1;
|
||||
if (signo == SIGHUP)
|
||||
::write(sighupFd[0], &a, sizeof(a));
|
||||
else if (signo == SIGINT)
|
||||
::write(sigintFd[0], &a, sizeof(a));
|
||||
else if (signo == SIGTERM)
|
||||
::write(sigtermFd[0], &a, sizeof(a));
|
||||
}
|
||||
|
||||
CSigDaemon::CSigDaemon(QObject* parent) : QObject(parent) {
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
|
||||
qFatal("Couldn't create HUP socketpair");
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
|
||||
qFatal("Couldn't create TERM socketpair");
|
||||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
|
||||
qFatal("Couldn't create INT socketpair");
|
||||
snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
|
||||
connect(snHup, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigHup()));
|
||||
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
|
||||
connect(snTerm, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigTerm()));
|
||||
snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
|
||||
connect(snInt, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigInt()));
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = onSignal;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(SIGHUP, &sa, 0))
|
||||
std::print(stderr, "sigaction for hup failed\n");
|
||||
|
||||
if (sigaction(SIGTERM, &sa, 0))
|
||||
std::print(stderr, "sigaction for term failed\n");
|
||||
|
||||
if (sigaction(SIGINT, &sa, 0))
|
||||
std::print(stderr, "sigaction for int failed\n");
|
||||
}
|
||||
|
||||
void CSigDaemon::handleSigHup() {
|
||||
std::print("> signal received: SIGHUP\n");
|
||||
snHup->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sighupFd[1], &tmp, sizeof(tmp));
|
||||
g_pAgent->resetAuthState();
|
||||
snHup->setEnabled(true);
|
||||
}
|
||||
|
||||
void CSigDaemon::handleSigInt() {
|
||||
std::print("> signal received: SIGINT\n");
|
||||
snInt->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sigintFd[1], &tmp, sizeof(tmp));
|
||||
g_pAgent->resetAuthState();
|
||||
snInt->setEnabled(true);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void CSigDaemon::handleSigTerm() {
|
||||
std::print("> signal received: SIGTERM\n");
|
||||
snTerm->setEnabled(false);
|
||||
char tmp;
|
||||
::read(sigtermFd[1], &tmp, sizeof(tmp));
|
||||
g_pAgent->resetAuthState();
|
||||
snTerm->setEnabled(true);
|
||||
}
|
23
src/SigDaemon.hpp
Normal file
23
src/SigDaemon.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
class CSigDaemon : public QObject {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
CSigDaemon(QObject* parent = nullptr);
|
||||
|
||||
static void onSignal(int signo);
|
||||
|
||||
public slots:
|
||||
void handleSigHup();
|
||||
void handleSigTerm();
|
||||
void handleSigInt();
|
||||
|
||||
private:
|
||||
QSocketNotifier* snHup = nullptr;
|
||||
QSocketNotifier* snTerm = nullptr;
|
||||
QSocketNotifier* snInt = nullptr;
|
||||
};
|
96
src/core/Agent.cpp
Normal file
96
src/core/Agent.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE 1
|
||||
|
||||
#include <polkitagent/polkitagent.h>
|
||||
#include <print>
|
||||
|
||||
#include "Agent.hpp"
|
||||
#include "../QMLIntegration.hpp"
|
||||
#include "../SigDaemon.hpp"
|
||||
|
||||
CAgent::CAgent() {
|
||||
;
|
||||
}
|
||||
|
||||
CAgent::~CAgent() {
|
||||
;
|
||||
}
|
||||
|
||||
bool CAgent::start() {
|
||||
sessionSubject = makeShared<PolkitQt1::UnixSessionSubject>(getpid());
|
||||
|
||||
listener.registerListener(*sessionSubject, "/org/hyprland/PolicyKit1/AuthenticationAgent");
|
||||
|
||||
int argc = 1;
|
||||
char* argv = (char*)"hyprpolkitagent";
|
||||
QApplication app(argc, &argv);
|
||||
|
||||
sigDaemon = makeShared<CSigDaemon>();
|
||||
|
||||
app.setApplicationName("Hyprland Polkit Agent");
|
||||
QGuiApplication::setQuitOnLastWindowClosed(false);
|
||||
|
||||
app.exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAgent::resetAuthState() {
|
||||
if (authState.authing) {
|
||||
authState.authing = false;
|
||||
authState.qmlEngine.reset();
|
||||
authState.qmlIntegration.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CAgent::initAuthPrompt() {
|
||||
resetAuthState();
|
||||
|
||||
if (!listener.session.inProgress) {
|
||||
std::print(stderr, "INTERNAL ERROR: Spawning qml prompt but session isn't in progress\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::print("Spawning qml prompt\n");
|
||||
|
||||
authState.qmlEngine.reset();
|
||||
authState.authing = true;
|
||||
|
||||
authState.qmlIntegration = makeShared<CQMLIntegration>();
|
||||
|
||||
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE"))
|
||||
QQuickStyle::setStyle("org.kde.desktop");
|
||||
|
||||
authState.qmlEngine = makeShared<QQmlApplicationEngine>();
|
||||
authState.qmlEngine->rootContext()->setContextProperty("hpa", authState.qmlIntegration.get());
|
||||
authState.qmlEngine->load(QUrl{u"qrc:/qt/qml/hpa/qml/main.qml"_qs});
|
||||
|
||||
authState.qmlIntegration->focusField();
|
||||
}
|
||||
|
||||
bool CAgent::resultReady() {
|
||||
std::lock_guard<std::mutex> lg(lastAuthResult.resultMutex);
|
||||
|
||||
return !lastAuthResult.used;
|
||||
}
|
||||
|
||||
void CAgent::submitResultThreadSafe(const std::string& result) {
|
||||
std::lock_guard<std::mutex> lg(lastAuthResult.resultMutex);
|
||||
lastAuthResult.used = false;
|
||||
lastAuthResult.result = result;
|
||||
|
||||
const bool PASS = result.starts_with("auth:");
|
||||
|
||||
std::print("Got result from qml: {}\n", PASS ? "auth:**PASSWORD**" : result);
|
||||
|
||||
if (PASS)
|
||||
listener.submitPassword(result.substr(result.find(":") + 1).c_str());
|
||||
else
|
||||
listener.cancelPending();
|
||||
}
|
||||
|
||||
void CAgent::setAuthError(const QString& err) {
|
||||
if (!authState.qmlIntegration)
|
||||
return;
|
||||
|
||||
authState.qmlIntegration->setErrorString(err);
|
||||
}
|
53
src/core/Agent.hpp
Normal file
53
src/core/Agent.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQuickStyle>
|
||||
#include <QScreen>
|
||||
|
||||
#include "PolkitListener.hpp"
|
||||
#include <polkitqt1-subject.h>
|
||||
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
using namespace Hyprutils::Memory;
|
||||
#define SP CSharedPointer
|
||||
#define WP CWeakPointer
|
||||
|
||||
class CQMLIntegration;
|
||||
class CSigDaemon;
|
||||
|
||||
class CAgent {
|
||||
public:
|
||||
CAgent();
|
||||
~CAgent();
|
||||
|
||||
void submitResultThreadSafe(const std::string& result);
|
||||
void resetAuthState();
|
||||
bool start();
|
||||
void initAuthPrompt();
|
||||
void setAuthError(const QString& err);
|
||||
|
||||
private:
|
||||
struct {
|
||||
bool authing = false;
|
||||
SP<QQmlApplicationEngine> qmlEngine;
|
||||
SP<CQMLIntegration> qmlIntegration;
|
||||
} authState;
|
||||
|
||||
struct {
|
||||
std::mutex resultMutex;
|
||||
std::string result;
|
||||
bool used = true;
|
||||
} lastAuthResult;
|
||||
|
||||
CPolkitListener listener;
|
||||
SP<CSigDaemon> sigDaemon;
|
||||
SP<PolkitQt1::UnixSessionSubject> sessionSubject;
|
||||
|
||||
bool resultReady();
|
||||
|
||||
friend class CQMLIntegration;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CAgent> g_pAgent;
|
142
src/core/PolkitListener.cpp
Normal file
142
src/core/PolkitListener.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include <QDebug>
|
||||
#include <QInputDialog>
|
||||
|
||||
#include "PolkitListener.hpp"
|
||||
#include "Agent.hpp"
|
||||
#include <polkitqt1-agent-session.h>
|
||||
|
||||
#include <print>
|
||||
|
||||
using namespace PolkitQt1::Agent;
|
||||
|
||||
CPolkitListener::CPolkitListener(QObject* parent) : Listener(parent) {
|
||||
;
|
||||
}
|
||||
|
||||
void CPolkitListener::initiateAuthentication(const QString& actionId, const QString& message, const QString& iconName, const PolkitQt1::Details& details, const QString& cookie,
|
||||
const PolkitQt1::Identity::List& identities, AsyncResult* result) {
|
||||
|
||||
std::print("> New authentication session\n");
|
||||
|
||||
if (session.inProgress) {
|
||||
result->setError("Authentication in progress");
|
||||
result->setCompleted();
|
||||
std::print("> REJECTING: Another session present\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (identities.isEmpty()) {
|
||||
result->setError("No identities, this is a problem with your system configuration.");
|
||||
result->setCompleted();
|
||||
std::print("> REJECTING: No idents\n");
|
||||
return;
|
||||
}
|
||||
|
||||
session.selectedUser = identities.at(0);
|
||||
session.cookie = cookie;
|
||||
session.result = result;
|
||||
session.actionId = actionId;
|
||||
session.message = message;
|
||||
session.iconName = iconName;
|
||||
session.gainedAuth = false;
|
||||
session.cancelled = false;
|
||||
session.inProgress = true;
|
||||
|
||||
g_pAgent->initAuthPrompt();
|
||||
|
||||
reattempt();
|
||||
}
|
||||
|
||||
void CPolkitListener::reattempt() {
|
||||
session.cancelled = false;
|
||||
|
||||
session.session = new Session(session.selectedUser, session.cookie, session.result);
|
||||
connect(session.session, SIGNAL(request(QString, bool)), this, SLOT(request(QString, bool)));
|
||||
connect(session.session, SIGNAL(completed(bool)), this, SLOT(completed(bool)));
|
||||
connect(session.session, SIGNAL(showError(QString)), this, SLOT(showError(QString)));
|
||||
connect(session.session, SIGNAL(showInfo(QString)), this, SLOT(showInfo(QString)));
|
||||
|
||||
session.session->initiate();
|
||||
}
|
||||
|
||||
bool CPolkitListener::initiateAuthenticationFinish() {
|
||||
std::print("> initiateAuthenticationFinish()\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPolkitListener::cancelAuthentication() {
|
||||
std::print("> cancelAuthentication()\n");
|
||||
|
||||
session.cancelled = true;
|
||||
|
||||
finishAuth();
|
||||
}
|
||||
|
||||
void CPolkitListener::request(const QString& request, bool echo) {
|
||||
std::print("> PKS request: {} echo: {}\n", request.toStdString(), echo);
|
||||
}
|
||||
|
||||
void CPolkitListener::completed(bool gainedAuthorization) {
|
||||
std::print("> PKS completed: {}\n", gainedAuthorization ? "Auth successful" : "Auth unsuccessful");
|
||||
|
||||
session.gainedAuth = gainedAuthorization;
|
||||
|
||||
if (!gainedAuthorization)
|
||||
g_pAgent->setAuthError("Authentication failed");
|
||||
|
||||
finishAuth();
|
||||
}
|
||||
|
||||
void CPolkitListener::showError(const QString& text) {
|
||||
std::print("> PKS showError: {}\n", text.toStdString());
|
||||
|
||||
g_pAgent->setAuthError(text);
|
||||
}
|
||||
|
||||
void CPolkitListener::showInfo(const QString& text) {
|
||||
std::print("> PKS showInfo: {}\n", text.toStdString());
|
||||
}
|
||||
|
||||
void CPolkitListener::finishAuth() {
|
||||
if (!session.inProgress) {
|
||||
std::print("> finishAuth: ODD. !session.inProgress\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session.gainedAuth && !session.cancelled) {
|
||||
std::print("> finishAuth: Did not gain auth. Reattempting.\n");
|
||||
session.session->deleteLater();
|
||||
reattempt();
|
||||
return;
|
||||
}
|
||||
|
||||
std::print("> finishAuth: Gained auth, cleaning up.\n");
|
||||
|
||||
session.inProgress = false;
|
||||
|
||||
if (session.session) {
|
||||
session.session->result()->setCompleted();
|
||||
session.session->deleteLater();
|
||||
} else
|
||||
session.result->setCompleted();
|
||||
|
||||
g_pAgent->resetAuthState();
|
||||
}
|
||||
|
||||
void CPolkitListener::submitPassword(const QString& pass) {
|
||||
if (!session.session)
|
||||
return;
|
||||
|
||||
session.session->setResponse(pass);
|
||||
}
|
||||
|
||||
void CPolkitListener::cancelPending() {
|
||||
if (!session.session)
|
||||
return;
|
||||
|
||||
session.session->cancel();
|
||||
|
||||
session.cancelled = true;
|
||||
|
||||
finishAuth();
|
||||
}
|
47
src/core/PolkitListener.hpp
Normal file
47
src/core/PolkitListener.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <polkitqt1-agent-listener.h>
|
||||
#include <polkitqt1-identity.h>
|
||||
#include <polkitqt1-details.h>
|
||||
#include <polkitqt1-agent-session.h>
|
||||
|
||||
class CPolkitListener : public PolkitQt1::Agent::Listener {
|
||||
Q_OBJECT;
|
||||
Q_DISABLE_COPY(CPolkitListener);
|
||||
|
||||
public:
|
||||
CPolkitListener(QObject* parent = nullptr);
|
||||
~CPolkitListener() override {};
|
||||
|
||||
void submitPassword(const QString& pass);
|
||||
void cancelPending();
|
||||
|
||||
public Q_SLOTS:
|
||||
void initiateAuthentication(const QString& actionId, const QString& message, const QString& iconName, const PolkitQt1::Details& details, const QString& cookie,
|
||||
const PolkitQt1::Identity::List& identities, PolkitQt1::Agent::AsyncResult* result) override;
|
||||
bool initiateAuthenticationFinish() override;
|
||||
void cancelAuthentication() override;
|
||||
|
||||
void request(const QString& request, bool echo);
|
||||
void completed(bool gainedAuthorization);
|
||||
void showError(const QString& text);
|
||||
void showInfo(const QString& text);
|
||||
|
||||
private:
|
||||
struct {
|
||||
bool inProgress = false, cancelled = false, gainedAuth = false;
|
||||
QString cookie, message, iconName, actionId;
|
||||
PolkitQt1::Agent::AsyncResult* result = nullptr;
|
||||
PolkitQt1::Identity selectedUser;
|
||||
PolkitQt1::Agent::Session* session = nullptr;
|
||||
} session;
|
||||
|
||||
void reattempt();
|
||||
void finishAuth();
|
||||
|
||||
friend class CAgent;
|
||||
friend class CQMLIntegration;
|
||||
};
|
7
src/main.cpp
Normal file
7
src/main.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "core/Agent.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
g_pAgent = std::make_unique<CAgent>();
|
||||
|
||||
return g_pAgent->start() == false ? 1 : 0;
|
||||
}
|
Loading…
Reference in a new issue