diff --git a/CMakeLists.txt b/CMakeLists.txt index e990cd5..c372338 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(alg-app-store VERSION 0.2.28 LANGUAGES CXX) +project(alg-app-store VERSION 0.3.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -34,6 +34,7 @@ set(SOURCES # Core src/core/alpm_wrapper.cpp src/core/aur_helper.cpp + src/core/auth_manager.cpp src/core/package_manager.cpp # GUI @@ -55,6 +56,7 @@ set(HEADERS # Core src/core/alpm_wrapper.h src/core/aur_helper.h + src/core/auth_manager.h src/core/package_manager.h # GUI @@ -87,6 +89,11 @@ target_link_libraries(${PROJECT_NAME} PRIVATE # Link directories link_directories(${ALPM_LIBRARY_DIRS}) +# Add version definition +target_compile_definitions(${PROJECT_NAME} PRIVATE + APP_VERSION="${PROJECT_VERSION}" +) + # Compiler flags target_compile_options(${PROJECT_NAME} PRIVATE -Wall diff --git a/TODO.md b/TODO.md index 6998488..bbd7544 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,7 @@ - [] Add detailed mirrorlist tab to set mirrorlist - [x] Add version information - [] Implement an AUR helper in core to remove dependence on paru and yay -- [] Ask password only once on startup - startup_auth +- [x] Ask password only once on startup - startup_auth - [] Improve settings page - settings_tab - [] Move all styles to single stylesheet - style_and_theme - [] Clean up UI; make UI look more modern (check gnome's styling options) - style_and_theme diff --git a/src/core/auth_manager.cpp b/src/core/auth_manager.cpp new file mode 100644 index 0000000..a04665e --- /dev/null +++ b/src/core/auth_manager.cpp @@ -0,0 +1,102 @@ +#include "auth_manager.h" +#include "../utils/logger.h" +#include +#include +#include + +AuthManager& AuthManager::instance() { + static AuthManager instance; + return instance; +} + +AuthManager::AuthManager() + : QObject(nullptr) { +} + +AuthManager::~AuthManager() { + // Zero out the password in memory + m_password.fill('\0'); + m_password.clear(); +} + +bool AuthManager::authenticate(QWidget* parent) { + if (m_authenticated) { + return true; + } + + const int maxAttempts = 3; + + for (int attempt = 0; attempt < maxAttempts; ++attempt) { + bool ok = false; + QString prompt = "Enter your password to continue:"; + if (attempt > 0) { + prompt = QString("Incorrect password. Attempt %1 of %2.\nEnter your password:") + .arg(attempt + 1) + .arg(maxAttempts); + } + + QString password = QInputDialog::getText( + parent, + "Authentication Required", + prompt, + QLineEdit::Password, + QString(), + &ok + ); + + if (!ok) { + // User cancelled + Logger::info("Authentication cancelled by user"); + return false; + } + + QByteArray passwordBytes = password.toUtf8(); + + if (validatePassword(passwordBytes)) { + m_password = passwordBytes; + m_authenticated = true; + Logger::info("Authentication successful"); + return true; + } + + Logger::warning(QString("Authentication failed (attempt %1/%2)") + .arg(attempt + 1) + .arg(maxAttempts)); + } + + QMessageBox::critical(parent, "Authentication Failed", + "Maximum authentication attempts exceeded.\n" + "The application will now exit."); + + return false; +} + +bool AuthManager::isAuthenticated() const { + return m_authenticated; +} + +void AuthManager::writePasswordToProcess(QProcess* process) { + if (!process || !m_authenticated) { + return; + } + + process->write(m_password + "\n"); + process->closeWriteChannel(); +} + +bool AuthManager::validatePassword(const QByteArray& password) { + QProcess process; + process.start("sudo", QStringList() << "-S" << "-p" << "" << "true"); + + if (!process.waitForStarted(3000)) { + Logger::error("Failed to start sudo validation process"); + return false; + } + + process.write(password + "\n"); + process.closeWriteChannel(); + + process.waitForFinished(10000); + + return process.exitCode() == 0; +} diff --git a/src/core/auth_manager.h b/src/core/auth_manager.h new file mode 100644 index 0000000..f6fd981 --- /dev/null +++ b/src/core/auth_manager.h @@ -0,0 +1,62 @@ +#ifndef AUTH_MANAGER_H +#define AUTH_MANAGER_H + +#include +#include + +class QProcess; +class QWidget; + +/** + * @brief Singleton class for managing sudo authentication. + * + * Prompts for the user's password once at startup and reuses it + * for all subsequent privileged operations via sudo -S. + * + * Memory Management: + * - m_password: Zeroed out in destructor for security + */ +class AuthManager : public QObject { + Q_OBJECT + +public: + static AuthManager& instance(); + + ~AuthManager() override; + + // Disable copy and move + AuthManager(const AuthManager&) = delete; + AuthManager& operator=(const AuthManager&) = delete; + AuthManager(AuthManager&&) = delete; + AuthManager& operator=(AuthManager&&) = delete; + + /** + * @brief Show password dialog and validate credentials. + * @param parent Parent widget for the dialog + * @return true if authentication succeeded + */ + bool authenticate(QWidget* parent = nullptr); + + /** + * @brief Check if user has been authenticated this session. + */ + bool isAuthenticated() const; + + /** + * @brief Write the stored password to a QProcess's stdin. + * + * Call this after QProcess::start() for any process that uses + * sudo -S to read the password from stdin. + */ + void writePasswordToProcess(QProcess* process); + +private: + AuthManager(); + + bool validatePassword(const QByteArray& password); + + QByteArray m_password; + bool m_authenticated = false; +}; + +#endif // AUTH_MANAGER_H diff --git a/src/core/package_manager.cpp b/src/core/package_manager.cpp index 5b50364..e2e07c0 100644 --- a/src/core/package_manager.cpp +++ b/src/core/package_manager.cpp @@ -1,4 +1,5 @@ #include "package_manager.h" +#include "auth_manager.h" #include "../utils/logger.h" #include #include @@ -40,7 +41,7 @@ void PackageManager::detectHelper() { return; } - // Check for paru - deprecate because paru doesn't allow running with pkexec + // Check for paru - deprecated because paru doesn't allow running as root // QString paruPath = QStandardPaths::findExecutable("paru"); // if (!paruPath.isEmpty()) { // m_helper = Helper::Paru; @@ -72,17 +73,14 @@ void PackageManager::installPackage(const QString& packageName, const QString& r bool isAUR = repoLower == "aur"; QString helper = getHelperName(); - QString command; if (isAUR && (m_helper == Helper::Yay)) { - // AUR packages - use pkexec to get userpassword before hand + // AUR packages need sudo for yay // Paru has a problem here, so default to yay - command = QString("pkexec %1 -S %2 --noconfirm").arg(helper, packageName); + executeCommand("sudo", QStringList() << "-S" << helper << "-S" << packageName << "--noconfirm", true); } else { // Official repos and chaotic-aur need root access and use pacman - command = QString("pkexec pacman -S %1 --noconfirm").arg(packageName); + executeCommand("sudo", QStringList() << "-S" << "pacman" << "-S" << packageName << "--noconfirm", true); } - - executeCommand("sh", QStringList() << "-c" << command); } void PackageManager::uninstallPackage(const QString& packageName, const QString& repository) { @@ -92,9 +90,7 @@ void PackageManager::uninstallPackage(const QString& packageName, const QString& emit operationStarted(QString("Uninstalling %1...").arg(packageName)); // Uninstall always needs root (even for AUR packages, they're in the system db once installed) - QString command = QString("pkexec pacman -Rdd %1 --noconfirm").arg(packageName); - - executeCommand("sh", QStringList() << "-c" << command); + executeCommand("sudo", QStringList() << "-S" << "pacman" << "-Rdd" << packageName << "--noconfirm", true); } void PackageManager::updatePackage(const QString& packageName, const QString& repository) { @@ -108,16 +104,13 @@ void PackageManager::updatePackage(const QString& packageName, const QString& re bool isAUR = repoLower == "aur"; QString helper = getHelperName(); - QString command; if (isAUR && (m_helper == Helper::Yay)) { - // AUR packages - run helper as regular user (no pkexec) - command = QString("%1 -S %2 --noconfirm").arg(helper, packageName); + // AUR packages - run helper as regular user (no sudo) + executeCommand(helper, QStringList() << "-S" << packageName << "--noconfirm"); } else { // Official repos and chaotic-aur need root access and use pacman - command = QString("pkexec pacman -S %1 --noconfirm").arg(packageName); + executeCommand("sudo", QStringList() << "-S" << "pacman" << "-S" << packageName << "--noconfirm", true); } - - executeCommand("sh", QStringList() << "-c" << command); } void PackageManager::updateAllPackages() { @@ -126,35 +119,38 @@ void PackageManager::updateAllPackages() { Logger::info("Updating all packages"); emit operationStarted("Updating all packages..."); - QString command = QString("pkexec %1 -Syu --noconfirm") - .arg(getHelperName()); - - executeCommand("sh", QStringList() << "-c" << command); + executeCommand("sudo", QStringList() << "-S" << getHelperName() << "-Syu" << "--noconfirm", true); } -void PackageManager::executeCommand(const QString& command, const QStringList& args) { +void PackageManager::executeCommand(const QString& command, const QStringList& args, bool needsAuth) { if (m_process->state() != QProcess::NotRunning) { Logger::warning("Another operation is already running"); emit operationError("Another operation is already in progress"); return; } - + // Merge stdout and stderr so we capture all output m_process->setProcessChannelMode(QProcess::MergedChannels); - + Logger::debug(QString("Executing: %1 %2").arg(command, args.join(" "))); - + // Emit the actual command being executed to the UI for visibility QString fullCommand = command + " " + args.join(" "); emit operationOutput(QString(">> Executing: %1\n").arg(fullCommand)); - + m_process->start(command, args); - + // Check if process started successfully if (!m_process->waitForStarted(3000)) { QString error = QString("Failed to start process: %1").arg(m_process->errorString()); Logger::error(error); emit operationError(error); + return; + } + + // Write stored password to sudo's stdin if this is an elevated operation + if (needsAuth) { + AuthManager::instance().writePasswordToProcess(m_process.get()); } } @@ -191,29 +187,35 @@ void PackageManager::cancelRunningOperation() { if (m_process && m_process->state() != QProcess::NotRunning) { Logger::warning("Cancelling running operation..."); emit operationOutput("\n>>> Operation cancelled by user <<<\n"); - - // When using pkexec, we need to kill the actual pacman/yay/paru process - // not just the pkexec wrapper. Use pkill to terminate all package manager processes. + + // When using sudo, we need to kill the actual pacman/yay/paru process + // not just the sudo wrapper. Use pkill to terminate all package manager processes. QProcess killProcess; - killProcess.start("pkexec", QStringList() << "bash" << "-c" + killProcess.start("sudo", QStringList() << "-S" << "bash" << "-c" << "pkill -TERM pacman; pkill -TERM yay; pkill -TERM paru"); + if (killProcess.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&killProcess); + } killProcess.waitForFinished(2000); - + // Also terminate the QProcess wrapper m_process->terminate(); - + // Wait up to 3 seconds for graceful termination if (!m_process->waitForFinished(3000)) { // Force kill if still running Logger::warning("Process did not terminate gracefully, forcing kill..."); - killProcess.start("pkexec", QStringList() << "bash" << "-c" + killProcess.start("sudo", QStringList() << "-S" << "bash" << "-c" << "pkill -KILL pacman; pkill -KILL yay; pkill -KILL paru"); + if (killProcess.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&killProcess); + } killProcess.waitForFinished(2000); - + m_process->kill(); m_process->waitForFinished(1000); } - + emit operationCompleted(false, "Operation cancelled by user"); Logger::info("Operation cancelled successfully"); } else { diff --git a/src/core/package_manager.h b/src/core/package_manager.h index 0e86a9b..570b40b 100644 --- a/src/core/package_manager.h +++ b/src/core/package_manager.h @@ -54,7 +54,7 @@ class PackageManager : public QObject { PackageManager(); void detectHelper(); - void executeCommand(const QString& command, const QStringList& args); + void executeCommand(const QString& command, const QStringList& args, bool needsAuth = false); Helper m_helper = Helper::Pacman; std::unique_ptr m_process; diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index dd71d18..e6a8fe8 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -6,6 +6,7 @@ #include "settings_widget.h" #include "../utils/logger.h" #include "../core/alpm_wrapper.h" +#include "../core/auth_manager.h" #include #include #include @@ -19,10 +20,21 @@ MainWindow::MainWindow(QWidget* parent) // Initialize ALPM before creating widgets that might need it if (!AlpmWrapper::instance().initialize()) { - QMessageBox::critical(this, "Error", + QMessageBox::critical(this, "Error", "Failed to initialize package manager. Please check your system configuration."); Logger::error("Failed to initialize ALPM in MainWindow"); } + + // Authenticate once at startup for all privileged operations + if (!AuthManager::instance().authenticate(this)) { + Logger::error("Authentication failed or cancelled"); + QMessageBox::critical(this, "Authentication Required", + "This application requires administrator privileges to manage packages.\n" + "The application will now exit."); + // Schedule exit after event loop starts + QMetaObject::invokeMethod(qApp, &QApplication::quit, Qt::QueuedConnection); + return; + } setupUi(); loadStyleSheet(); @@ -117,9 +129,9 @@ void MainWindow::createMenuBar() { QMessageBox::about(this, "About ALG App Store", "ALG App Store (Beta)\n\n" "A modern package manager for Arch Linux\n" - "Version: 0.2.28\n" + "Version: " APP_VERSION "\n" "Built with Qt6 and C++17\n\n" - "© 2025 Arka Linux GUI"); + "© 2024-2026 Arka Linux GUI"); }); helpMenu->addAction(aboutAction); } diff --git a/src/gui/settings_widget.cpp b/src/gui/settings_widget.cpp index 6d31e71..535038b 100644 --- a/src/gui/settings_widget.cpp +++ b/src/gui/settings_widget.cpp @@ -1,6 +1,7 @@ #include "settings_widget.h" #include "../utils/logger.h" #include "../core/alpm_wrapper.h" +#include "../core/auth_manager.h" #include "../core/package_manager.h" #include #include @@ -455,31 +456,34 @@ bool SettingsWidget::enableMultilibInPacmanConf() { } file.close(); - // Write back to file using pkexec for elevated privileges + // Write modified config to a temp file, then copy with elevated privileges QString tempFile = "/tmp/pacman.conf.tmp"; QFile temp(tempFile); if (!temp.open(QIODevice::WriteOnly | QIODevice::Text)) { Logger::error("Failed to create temporary file"); return false; } - + QTextStream out(&temp); for (const QString& line : lines) { out << line << "\n"; } temp.close(); - - // Use pkexec to copy the file with elevated privileges + + // Use sudo to copy the file with elevated privileges QProcess process; - process.start("pkexec", QStringList() << "cp" << tempFile << "/etc/pacman.conf"); + process.start("sudo", QStringList() << "-S" << "cp" << tempFile << "/etc/pacman.conf"); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(30000); // 30 second timeout - + if (process.exitCode() != 0) { Logger::error("Failed to update pacman.conf with elevated privileges"); QFile::remove(tempFile); return false; } - + QFile::remove(tempFile); Logger::info("Successfully enabled multilib repository"); return true; @@ -522,31 +526,34 @@ bool SettingsWidget::disableMultilibInPacmanConf() { } file.close(); - // Write back to file using pkexec for elevated privileges + // Write back to file using sudo for elevated privileges QString tempFile = "/tmp/pacman.conf.tmp"; QFile temp(tempFile); if (!temp.open(QIODevice::WriteOnly | QIODevice::Text)) { Logger::error("Failed to create temporary file"); return false; } - + QTextStream out(&temp); for (const QString& line : lines) { out << line << "\n"; } temp.close(); - - // Use pkexec to copy the file with elevated privileges + + // Use sudo to copy the file with elevated privileges QProcess process; - process.start("pkexec", QStringList() << "cp" << tempFile << "/etc/pacman.conf"); + process.start("sudo", QStringList() << "-S" << "cp" << tempFile << "/etc/pacman.conf"); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(30000); // 30 second timeout - + if (process.exitCode() != 0) { Logger::error("Failed to update pacman.conf with elevated privileges"); QFile::remove(tempFile); return false; } - + QFile::remove(tempFile); Logger::info("Successfully disabled multilib repository"); return true; @@ -606,31 +613,34 @@ bool SettingsWidget::enableChaoticAurInPacmanConf() { lines.append("Include = /etc/pacman.d/chaotic-mirrorlist"); } - // Write back to file using pkexec for elevated privileges + // Write back to file using sudo for elevated privileges QString tempFile = "/tmp/pacman.conf.tmp"; QFile temp(tempFile); if (!temp.open(QIODevice::WriteOnly | QIODevice::Text)) { Logger::error("Failed to create temporary file"); return false; } - + QTextStream out(&temp); for (const QString& line : lines) { out << line << "\n"; } temp.close(); - - // Use pkexec to copy the file with elevated privileges + + // Use sudo to copy the file with elevated privileges QProcess process; - process.start("pkexec", QStringList() << "cp" << tempFile << "/etc/pacman.conf"); + process.start("sudo", QStringList() << "-S" << "cp" << tempFile << "/etc/pacman.conf"); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(30000); // 30 second timeout - + if (process.exitCode() != 0) { Logger::error("Failed to update pacman.conf with elevated privileges"); QFile::remove(tempFile); return false; } - + QFile::remove(tempFile); Logger::info("Successfully enabled chaotic-aur repository"); return true; @@ -678,31 +688,34 @@ bool SettingsWidget::disableChaoticAurInPacmanConf() { } file.close(); - // Write back to file using pkexec for elevated privileges + // Write back to file using sudo for elevated privileges QString tempFile = "/tmp/pacman.conf.tmp"; QFile temp(tempFile); if (!temp.open(QIODevice::WriteOnly | QIODevice::Text)) { Logger::error("Failed to create temporary file"); return false; } - + QTextStream out(&temp); for (const QString& line : lines) { out << line << "\n"; } temp.close(); - - // Use pkexec to copy the file with elevated privileges + + // Use sudo to copy the file with elevated privileges QProcess process; - process.start("pkexec", QStringList() << "cp" << tempFile << "/etc/pacman.conf"); + process.start("sudo", QStringList() << "-S" << "cp" << tempFile << "/etc/pacman.conf"); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(30000); // 30 second timeout - + if (process.exitCode() != 0) { Logger::error("Failed to update pacman.conf with elevated privileges"); QFile::remove(tempFile); return false; } - + QFile::remove(tempFile); Logger::info("Successfully disabled chaotic-aur repository"); return true; @@ -727,13 +740,11 @@ void SettingsWidget::onApplyClicked() { // Show confirmation dialog QString message; if (currentMultilibState) { - message = "This will enable the multilib repository by modifying /etc/pacman.conf.\n" - "You will be prompted for administrator privileges.\n\n" - "After enabling, you should run 'sudo pacman -Sy' to sync the databases.\n\n" + message = "This will enable the multilib repository by modifying /etc/pacman.conf.\n\n" + "After enabling, you should sync the databases.\n\n" "Do you want to continue?"; } else { - message = "This will disable the multilib repository by modifying /etc/pacman.conf.\n" - "You will be prompted for administrator privileges.\n\n" + message = "This will disable the multilib repository by modifying /etc/pacman.conf.\n\n" "Do you want to continue?"; } @@ -768,14 +779,12 @@ void SettingsWidget::onApplyClicked() { // Show confirmation dialog QString message; if (currentChaoticAurState) { - message = "This will enable the chaotic-aur repository by modifying /etc/pacman.conf.\n" - "You will be prompted for administrator privileges.\n\n" + message = "This will enable the chaotic-aur repository by modifying /etc/pacman.conf.\n\n" "Note: Make sure chaotic-keyring and chaotic-mirrorlist are installed first.\n\n" - "After enabling, you should run 'sudo pacman -Sy' to sync the databases.\n\n" + "After enabling, you should sync the databases.\n\n" "Do you want to continue?"; } else { - message = "This will disable the chaotic-aur repository by modifying /etc/pacman.conf.\n" - "You will be prompted for administrator privileges.\n\n" + message = "This will disable the chaotic-aur repository by modifying /etc/pacman.conf.\n\n" "Do you want to continue?"; } @@ -817,13 +826,16 @@ void SettingsWidget::onApplyClicked() { // Suggest database sync auto reply = QMessageBox::question(this, "Sync Package Database", "Would you like to sync the package database now?\n" - "(This will run 'pkexec pacman -Sy')", + "(This will run 'pacman -Sy')", QMessageBox::Yes | QMessageBox::No); - + if (reply == QMessageBox::Yes) { QProcess process; m_statusLabel->setText("Syncing package databases..."); - process.start("pkexec", QStringList() << "pacman" << "-Sy"); + process.start("sudo", QStringList() << "-S" << "pacman" << "-Sy"); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(60000); // 60 second timeout if (process.exitCode() == 0) { @@ -833,7 +845,7 @@ void SettingsWidget::onApplyClicked() { // Refresh ALPM databases to pick up the new repository AlpmWrapper::instance().refreshDatabases(); } else { - m_statusLabel->setText("Failed to sync package databases. Please run 'sudo pacman -Sy' manually."); + m_statusLabel->setText("Failed to sync package databases. Please run 'pacman -Sy' manually as root."); m_statusLabel->setStyleSheet("QLabel { color: #aa0000; padding: 10px; }"); } } else { @@ -893,9 +905,12 @@ void SettingsWidget::onRemoveLockClicked() { int ret = msgBox.exec(); if (ret == QMessageBox::Yes && confirmCheckbox->isChecked()) { - // Use pkexec to remove the lock file with elevated privileges + // Use sudo to remove the lock file with elevated privileges QProcess process; - process.start("pkexec", QStringList() << "rm" << "-f" << lockFilePath); + process.start("sudo", QStringList() << "-S" << "rm" << "-f" << lockFilePath); + if (process.waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(&process); + } process.waitForFinished(30000); // 30 second timeout if (process.exitCode() == 0) { @@ -933,7 +948,7 @@ void SettingsWidget::onSetupChaoticClicked() { "1. Download chaotic-keyring and chaotic-mirrorlist packages\n" "2. Install them using pacman\n" "3. Add the repository to /etc/pacman.conf\n\n" - "This requires internet connection and administrator privileges."); + "This requires an internet connection."); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); @@ -998,8 +1013,7 @@ void SettingsWidget::onSetupChaoticClicked() { QString errorDetails = "Possible reasons:\n" "• No internet connection\n" "• Download failed\n" - "• Installation cancelled\n" - "• User denied authentication\n\n"; + "• Installation cancelled\n\n"; if (!output.isEmpty() && output.length() < 500) { errorDetails += "Error output:\n" + output; @@ -1010,7 +1024,10 @@ void SettingsWidget::onSetupChaoticClicked() { } }); - process->start("pkexec", QStringList() << "bash" << "-c" << script); + process->start("sudo", QStringList() << "-S" << "bash" << "-c" << script); + if (process->waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(process); + } } void SettingsWidget::onRemoveChaoticClicked() { @@ -1068,8 +1085,11 @@ void SettingsWidget::onRemoveChaoticClicked() { } }); - process->start("pkexec", QStringList() << "pacman" << "-Rns" << "--noconfirm" + process->start("sudo", QStringList() << "-S" << "pacman" << "-Rns" << "--noconfirm" << "chaotic-keyring" << "chaotic-mirrorlist"); + if (process->waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(process); + } } void SettingsWidget::onSyncReposClicked() { @@ -1094,13 +1114,13 @@ void SettingsWidget::onSyncReposClicked() { m_statusLabel->show(); m_syncReposButton->setEnabled(false); - // Run pacman -Sy with pkexec + // Run pacman -Sy with sudo QProcess* process = new QProcess(this); connect(process, QOverload::of(&QProcess::finished), this, [this, process](int exitCode, QProcess::ExitStatus exitStatus) { process->deleteLater(); m_syncReposButton->setEnabled(true); - + if (exitCode == 0 && exitStatus == QProcess::NormalExit) { m_statusLabel->setText("Repositories synchronized successfully!"); m_statusLabel->setStyleSheet("QLabel { color: #00aa00; padding: 10px; font-weight: bold; }"); @@ -1125,7 +1145,10 @@ void SettingsWidget::onSyncReposClicked() { } }); - process->start("pkexec", QStringList() << "pacman" << "-Sy"); + process->start("sudo", QStringList() << "-S" << "pacman" << "-Sy"); + if (process->waitForStarted(3000)) { + AuthManager::instance().writePasswordToProcess(process); + } } void SettingsWidget::onCancelProcessClicked() {