diff --git a/CMakeLists.txt b/CMakeLists.txt index c036cc6..ba788f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(SOURCE_FILES extrasettingwindow/extrasettingwindow.cpp settingwindow/settingwindow.cpp loginwindow/loginwindow.cpp + sudowindow/sudowindow.cpp ssologinwebview/ssologinwebview.cpp authinfowindow/authinfowindow.cpp graphcaptchawindow/graphcaptchawindow.cpp diff --git a/mainwindow.h b/mainwindow.h index ab5572d..42f8487 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -10,6 +10,7 @@ #include #include "loginwindow/loginwindow.h" +#include "sudowindow/sudowindow.h" #include "ssologinwebview/ssologinwebview.h" #include "zjuconnectcontroller/zjuconnectcontroller.h" #include "settingwindow/settingwindow.h" @@ -98,6 +99,7 @@ private: QPointer settingWindow; QPointer loginWindow; + QPointer sudoWindow; QPointer ssoLoginWebView; QPointer graphCaptchaWindow; diff --git a/sudowindow/sudowindow.cpp b/sudowindow/sudowindow.cpp new file mode 100644 index 0000000..5267fe5 --- /dev/null +++ b/sudowindow/sudowindow.cpp @@ -0,0 +1,44 @@ +#include "sudowindow.h" + +#include +#include + +SudoWindow::SudoWindow(QWidget *parent) + : QDialog(parent), + ui(new Ui::SudoWindow) +{ + ui->setupUi(this); + + setWindowModality(Qt::WindowModal); + setAttribute(Qt::WA_DeleteOnClose); + + connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, + [&]() + { + emit sudo(ui->passwordLineEdit->text(), ui->savePasswordCheckBox->isChecked()); + emit accept(); + } + ); + + connect(ui->passwordVisibleCheckBox, &QCheckBox::checkStateChanged, + [&](Qt::CheckState state) + { + ui->passwordLineEdit->setEchoMode(state == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password); + } + ); +} + +SudoWindow::~SudoWindow() +{ + delete ui; +} + +void SudoWindow::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) + ui->buttonBox->button(QDialogButtonBox::Ok)->click(); + else if (event->key() == Qt::Key_Escape) + reject(); + else + QDialog::keyPressEvent(event); +} diff --git a/sudowindow/sudowindow.h b/sudowindow/sudowindow.h new file mode 100644 index 0000000..435134b --- /dev/null +++ b/sudowindow/sudowindow.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "ui_sudowindow.h" + +class SudoWindow : public QDialog +{ + Q_OBJECT + +public: + SudoWindow(QWidget *parent = nullptr); + + ~SudoWindow() override; + + void keyPressEvent(QKeyEvent *event) override; + +signals: + void sudo(const QString& password, bool save); + +private: + Ui::SudoWindow *ui; +}; diff --git a/sudowindow/sudowindow.ui b/sudowindow/sudowindow.ui new file mode 100644 index 0000000..802ab3b --- /dev/null +++ b/sudowindow/sudowindow.ui @@ -0,0 +1,101 @@ + + + SudoWindow + + + + 0 + 0 + 385 + 164 + + + + Sudo + + + + + + 需要 root 权限 + + + + + + 显示密码 + + + + + + + 本次会话内保存 + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + QLineEdit::EchoMode::Password + + + + + + + 请输入 sudo 密码: + + + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + passwordLineEdit + + + + + buttonBox + rejected() + SudoWindow + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/utils/utils.cpp b/utils/utils.cpp index 86fe517..2b0dccb 100644 --- a/utils/utils.cpp +++ b/utils/utils.cpp @@ -229,23 +229,6 @@ bool Utils::isRunningAsAdmin() #endif } -bool Utils::promptForSudoPassword(QString &password, QWidget *parent) -{ - bool ok = false; - QString text = QInputDialog::getText(parent, - "需要 Root 权限", - "请输入 sudo 密码:", - QLineEdit::Password, - "", - &ok); - if (!ok) - { - return false; - } - password = text; - return true; -} - bool Utils::relaunchAsAdmin() { QString program = QCoreApplication::applicationFilePath(); diff --git a/utils/utils.h b/utils/utils.h index 9c0e568..fdd3df0 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -44,8 +44,6 @@ namespace Utils bool relaunchAsAdmin(); - bool promptForSudoPassword(QString &password, QWidget *parent = nullptr); - void clearClientData(const QString &profileId); QString getClientDataPath(const QString &profileId); diff --git a/zjuconnectcontroller/zjuconnectcontroller.cpp b/zjuconnectcontroller/zjuconnectcontroller.cpp index a833020..0c7725f 100644 --- a/zjuconnectcontroller/zjuconnectcontroller.cpp +++ b/zjuconnectcontroller/zjuconnectcontroller.cpp @@ -35,7 +35,11 @@ ZjuConnectController::ZjuConnectController(QWidget* parent) : QObject(parent) logStream->flush(); } - if (output.contains("Graph check code saved to ")) + if (output.contains("SUDO_ASK_PASS")) + { + emit askSudoPass(); + } + else if (output.contains("Graph check code saved to ")) { emit graphCaptcha(graphFile); } @@ -432,34 +436,18 @@ void ZjuConnectController::start( #if defined(Q_OS_UNIX) QString sudoPassword; - bool useSudo = false; if (tunMode && !Utils::isRunningAsAdmin()) { - if (!Utils::promptForSudoPassword(sudoPassword, qobject_cast(parent()))) - { - emit outputRead(timeString + " 已取消 sudo 密码输入"); - } - else - { - QStringList sudoArgs; - sudoArgs << "-S"; - sudoArgs << programToStart; - sudoArgs << finalArgs; - programToStart = "sudo"; - finalArgs = sudoArgs; - useSudo = true; - emit outputRead(timeString + " 使用 sudo 提升权限启动核心"); - } + QStringList sudoArgs; + sudoArgs << "-p" << "SUDO_ASK_PASS"; + sudoArgs << "-S"; + sudoArgs << programToStart << finalArgs; + programToStart = "sudo"; + finalArgs = sudoArgs; + enteredSudoPassword = false; } #endif - zjuConnectProcess->start(programToStart, finalArgs); -#if defined(Q_OS_UNIX) - if (useSudo) - { - zjuConnectProcess->write((sudoPassword + "\n").toUtf8()); - } -#endif zjuConnectProcess->waitForStarted(); if (zjuConnectProcess->state() == QProcess::NotRunning) { diff --git a/zjuconnectcontroller/zjuconnectcontroller.h b/zjuconnectcontroller/zjuconnectcontroller.h index 21fc098..6e4bb7c 100644 --- a/zjuconnectcontroller/zjuconnectcontroller.h +++ b/zjuconnectcontroller/zjuconnectcontroller.h @@ -88,6 +88,8 @@ signals: void casAuth(); + void askSudoPass(); + void finished(); void write(const QByteArray &data); @@ -102,6 +104,11 @@ private: QFile *logFile = nullptr; QTextStream *logStream = nullptr; bool stopRequested = false; + +public: + bool savedSudoPassword; + bool enteredSudoPassword; + QString sudoPassword; }; #endif //ZJUCONNECTCONTROLLER_H diff --git a/zjuconnectmode.cpp b/zjuconnectmode.cpp index 227b713..d8c4ca7 100644 --- a/zjuconnectmode.cpp +++ b/zjuconnectmode.cpp @@ -4,6 +4,7 @@ #include "mainwindow.h" #include "ui_mainwindow.h" +#include "sudowindow/sudowindow.h" #include "loginwindow/loginwindow.h" #include "utils/utils.h" #include "zjuconnectcontroller/zjuconnectcontroller.h" @@ -36,6 +37,45 @@ void MainWindow::initZjuConnect() } }); + connect(zjuConnectController, &ZjuConnectController::askSudoPass, this, + [&]() + { + if (zjuConnectController->savedSudoPassword) + { + if (zjuConnectController->enteredSudoPassword) + { + addLog("sudo 密码可能有误,不使用记住的密码"); + zjuConnectController->savedSudoPassword = false; + zjuConnectController->sudoPassword.clear(); + } + else + { + zjuConnectController->enteredSudoPassword = true; + emit WriteToProcess(zjuConnectController->sudoPassword.toUtf8() + "\n"); + return; + } + } + sudoWindow = new SudoWindow(this); + connect(sudoWindow, &SudoWindow::sudo, this, [&](const QString &password, bool save) + { + if (password.isEmpty()) + { + zjuConnectController->stop(); + } + else + { + if (save) + { + zjuConnectController->savedSudoPassword = true; + zjuConnectController->sudoPassword = password; + } + zjuConnectController->enteredSudoPassword = true; + emit WriteToProcess(password.toUtf8() + "\n"); + } + }); + sudoWindow->show(); + }); + connect(zjuConnectController, &ZjuConnectController::graphCaptcha, this, [&](const QString &graphFile) { addLog("需要图形验证码");