initial commit
This commit is contained in:
parent
2e810ff125
commit
2c97f97336
|
@ -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
|
|
@ -30,3 +30,9 @@
|
||||||
*.exe
|
*.exe
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
.cache/
|
||||||
|
build/
|
||||||
|
|
||||||
|
compile_commands.json
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "subprojects/sdbus-cpp"]
|
||||||
|
path = subprojects/sdbus-cpp
|
||||||
|
url = https://github.com/Kistler-Group/sdbus-cpp/
|
|
@ -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}
|
||||||
|
)
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
};
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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 New Issue