From c52ccb87f156b7c04daafe683beb574dd553ff0b Mon Sep 17 00:00:00 2001 From: Carlo Ramponi Date: Wed, 12 Oct 2022 04:25:49 +0200 Subject: [PATCH] Credentials autocompleting (secure version) (#179) --- .gitmodules | 3 +++ 3rdparty/qtkeychain | 1 + GPClient/CMakeLists.txt | 21 +++++++++++++++++- GPClient/gphelper.cpp | 38 ++++++++++++++++++++++++++++++++ GPClient/gphelper.h | 3 +++ GPClient/standardloginwindow.cpp | 19 ++++++++++++++++ GPClient/standardloginwindow.h | 1 + scripts/install-ubuntu.sh | 1 + 8 files changed, 86 insertions(+), 1 deletion(-) create mode 160000 3rdparty/qtkeychain diff --git a/.gitmodules b/.gitmodules index 45a9506..706e889 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "plog"] path = 3rdparty/plog url = https://github.com/SergiusTheBest/plog.git +[submodule "3rdparty/qtkeychain"] + path = 3rdparty/qtkeychain + url = git@github.com:frankosterfeld/qtkeychain.git diff --git a/3rdparty/qtkeychain b/3rdparty/qtkeychain new file mode 160000 index 0000000..f197cdb --- /dev/null +++ b/3rdparty/qtkeychain @@ -0,0 +1 @@ +Subproject commit f197cdb935b0cfd9881fdc6860874cb8379d1238 diff --git a/GPClient/CMakeLists.txt b/GPClient/CMakeLists.txt index 578e1fd..0c94cd2 100644 --- a/GPClient/CMakeLists.txt +++ b/GPClient/CMakeLists.txt @@ -64,6 +64,17 @@ add_3rdparty( -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ) +add_3rdparty( + qtkeychain + GIT_REPOSITORY https://github.com/frankosterfeld/qtkeychain.git + GIT_TAG master + CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} + -DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH} + -DCMAKE_PREFIX_PATH=$ENV{CMAKE_PREFIX_PATH} +) + ExternalProject_Get_Property(SingleApplication-${PROJECT_NAME} SOURCE_DIR BINARY_DIR) set(SingleApplication_INCLUDE_DIR ${SOURCE_DIR}) set(SingleApplication_LIBRARY ${BINARY_DIR}/libSingleApplication.a) @@ -71,7 +82,12 @@ set(SingleApplication_LIBRARY ${BINARY_DIR}/libSingleApplication.a) ExternalProject_Get_Property(plog-${PROJECT_NAME} SOURCE_DIR) set(plog_INCLUDE_DIR "${SOURCE_DIR}/include") -add_dependencies(gpclient SingleApplication-${PROJECT_NAME} plog-${PROJECT_NAME}) +ExternalProject_Get_Property(qtkeychain-${PROJECT_NAME} SOURCE_DIR BINARY_DIR) +set(qtkeychain_INCLUDE_DIR "${SOURCE_DIR}") +set(qtkeychain_BINARY_DIR "${BINARY_DIR}") +set(qtkeychain_LIBRARY ${BINARY_DIR}/libqt5keychain.so) + +add_dependencies(gpclient SingleApplication-${PROJECT_NAME} plog-${PROJECT_NAME} qtkeychain-${PROJECT_NAME}) target_include_directories(gpclient PRIVATE ${CMAKE_BINARY_DIR} @@ -79,10 +95,13 @@ target_include_directories(gpclient PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${SingleApplication_INCLUDE_DIR} ${plog_INCLUDE_DIR} + ${qtkeychain_INCLUDE_DIR} + ${qtkeychain_BINARY_DIR} ) target_link_libraries(gpclient ${SingleApplication_LIBRARY} + ${qtkeychain_LIBRARY} Qt5::Widgets Qt5::Network Qt5::WebSockets diff --git a/GPClient/gphelper.cpp b/GPClient/gphelper.cpp index a556966..f38d2a8 100644 --- a/GPClient/gphelper.cpp +++ b/GPClient/gphelper.cpp @@ -9,9 +9,12 @@ #include #include #include +#include #include "gphelper.h" +using namespace QKeychain; + QNetworkAccessManager* gpclient::helper::networkManager = new QNetworkAccessManager; QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params) @@ -138,3 +141,38 @@ void gpclient::helper::settings::clear() QWebEngineProfile::defaultProfile()->cookieStore()->deleteAllCookies(); } + + +bool gpclient::helper::settings::secureSave(const QString &key, const QString &value) { + WritePasswordJob job( QLatin1String("gpclient") ); + job.setAutoDelete( false ); + job.setKey( key ); + job.setTextData( value ); + QEventLoop loop; + job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) ); + job.start(); + loop.exec(); + if ( job.error() ) { + return false; + } + + return true; +} + +bool gpclient::helper::settings::secureGet(const QString &key, QString &value) { + ReadPasswordJob job( QLatin1String("gpclient") ); + job.setAutoDelete( false ); + job.setKey( key ); + QEventLoop loop; + job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) ); + job.start(); + loop.exec(); + + const QString pw = job.textData(); + if ( job.error() ) { + return false; + } + + value = pw; + return true; +} \ No newline at end of file diff --git a/GPClient/gphelper.h b/GPClient/gphelper.h index a8a14b8..634f82e 100644 --- a/GPClient/gphelper.h +++ b/GPClient/gphelper.h @@ -37,6 +37,9 @@ namespace gpclient { QStringList get_all(const QString &key, const QVariant &defaultValue = QVariant()); void save(const QString &key, const QVariant &value); void clear(); + + bool secureSave(const QString &key, const QString &value); + bool secureGet(const QString &key, QString &value); } } } diff --git a/GPClient/standardloginwindow.cpp b/GPClient/standardloginwindow.cpp index bdd9aa4..7964d1c 100644 --- a/GPClient/standardloginwindow.cpp +++ b/GPClient/standardloginwindow.cpp @@ -2,6 +2,9 @@ #include "standardloginwindow.h" #include "ui_standardloginwindow.h" +#include "gphelper.h" + +using namespace gpclient::helper; StandardLoginWindow::StandardLoginWindow(const QString &portalAddress, const QString &labelUsername, const QString &labelPassword, const QString &authMessage) : @@ -13,11 +16,24 @@ StandardLoginWindow::StandardLoginWindow(const QString &portalAddress, const QSt ui->password->setPlaceholderText(labelPassword); ui->authMessage->setText(authMessage); + autocomplete(); + setWindowTitle("GlobalProtect Login"); setFixedSize(width(), height()); setModal(true); } +void StandardLoginWindow::autocomplete() { + QString username, password; + settings::secureGet("username", username); + settings::secureGet("password", password); + + if (!username.isEmpty() && !password.isEmpty()) { + ui->username->setText(username); + ui->password->setText(password); + } +} + void StandardLoginWindow::setProcessing(bool isProcessing) { ui->username->setReadOnly(isProcessing); ui->password->setReadOnly(isProcessing); @@ -32,6 +48,9 @@ void StandardLoginWindow::on_loginButton_clicked() { return; } + settings::secureSave("username", username); + settings::secureSave("password", password); + emit performLogin(username, password); } diff --git a/GPClient/standardloginwindow.h b/GPClient/standardloginwindow.h index 92f5f5d..894e7e3 100644 --- a/GPClient/standardloginwindow.h +++ b/GPClient/standardloginwindow.h @@ -28,6 +28,7 @@ private: Ui::StandardLoginWindow *ui; void closeEvent(QCloseEvent *event); + void autocomplete(); }; #endif // STANDARDLOGINWINDOW_H diff --git a/scripts/install-ubuntu.sh b/scripts/install-ubuntu.sh index c4ebe68..91c755f 100755 --- a/scripts/install-ubuntu.sh +++ b/scripts/install-ubuntu.sh @@ -6,6 +6,7 @@ sudo apt-get install -y \ qtbase5-dev \ libqt5websockets5-dev \ qtwebengine5-dev \ + qttools5-dev \ openconnect ./scripts/install.sh