mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	Compare commits
	
		
			60 Commits
		
	
	
		
			v1.4.5
			...
			4d4605439a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 4d4605439a | ||
|  | edc13ed14d | ||
|  | dd737bc8c5 | ||
|  | 939f2bd94a | ||
|  | abffa21268 | ||
|  | 99342372d2 | ||
|  | cd8d794655 | ||
|  | 705b03c0bb | ||
|  | 7bef2ccc68 | ||
|  | bffc5d733b | ||
|  | 8ca2610550 | ||
|  | acf184134a | ||
|  | 4a3f74f1c3 | ||
|  | b39983a0f8 | ||
|  | d6fa32d95d | ||
|  | 7c299f6e68 | ||
|  | 25e8ccd07e | ||
|  | 092123b075 | ||
|  | feb2956cc1 | ||
|  | d356839859 | ||
|  | 2ff39fd14e | ||
|  | c3d300c807 | ||
|  | ef43d10a70 | ||
|  | bd73466e48 | ||
|  | cc2c0ae34e | ||
|  | 9207f7a798 | ||
|  | 2069b7fd8e | ||
|  | f552ef6204 | ||
|  | 2761f7521a | ||
|  | c3939a774b | ||
|  | 49e5242bf2 | ||
|  | 3181d37b20 | ||
|  | 6d788a5e91 | ||
|  | 74c7549444 | ||
|  | c52ccb87f1 | ||
|  | fab25848e1 | ||
|  | 75a24c89cd | ||
|  | 15a73b7dba | ||
|  | 0adeaf9c28 | ||
|  | fe64b2cd19 | ||
|  | 5788474d7e | ||
|  | 3559834762 | ||
|  | f9926b4026 | ||
|  | cb457c4b09 | ||
|  | 5ebfe9b0f4 | ||
|  | 35266dd8bf | ||
|  | bf03d375e0 | ||
|  | 6cf909e34f | ||
|  | 343a6d03c1 | ||
|  | fab8e7591e | ||
|  | 5a485197b7 | ||
|  | 7bc02a4208 | ||
|  | 3067e6e911 | ||
|  | 5db77e8404 | ||
|  | 5714063457 | ||
|  | 41f88ed2e0 | ||
|  | 4fada9bd14 | ||
|  | b57fb993ca | ||
|  | f6d06ed978 | ||
|  | cc67de3a2b | 
							
								
								
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -31,6 +31,8 @@ jobs: | |||||||
|       - name: Build |       - name: Build | ||||||
|         run: | |         run: | | ||||||
|           ./scripts/install-ubuntu.sh |           ./scripts/install-ubuntu.sh | ||||||
|  |           # assert no library missing | ||||||
|  |           test $(ldd $(which gpclient) | grep 'not found' | wc -l) -eq 0 | ||||||
|  |  | ||||||
|   snapshot-archive-all: |   snapshot-archive-all: | ||||||
|     if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/develop' }} |     if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/develop' }} | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,7 +17,7 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         os: [ubuntu-18.04, ubuntu-20.04] |         os: [ubuntu-18.04, ubuntu-20.04] | ||||||
|      |  | ||||||
|     runs-on: ${{ matrix.os }} |     runs-on: ${{ matrix.os }} | ||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
| @@ -28,4 +28,6 @@ jobs: | |||||||
|  |  | ||||||
|       - name: Build |       - name: Build | ||||||
|         run: | |         run: | | ||||||
|           ./scripts/install-ubuntu.sh |           ./scripts/install-ubuntu.sh | ||||||
|  |           # assert no library missing | ||||||
|  |           test $(ldd $(which gpclient) | grep 'not found' | wc -l) -eq 0 | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -5,3 +5,6 @@ | |||||||
| [submodule "plog"] | [submodule "plog"] | ||||||
| 	path = 3rdparty/plog | 	path = 3rdparty/plog | ||||||
| 	url = https://github.com/SergiusTheBest/plog.git | 	url = https://github.com/SergiusTheBest/plog.git | ||||||
|  | [submodule "3rdparty/qtkeychain"] | ||||||
|  | 	path = 3rdparty/qtkeychain | ||||||
|  | 	url = git@github.com:frankosterfeld/qtkeychain.git | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								3rdparty/inih/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								3rdparty/inih/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,6 @@ | |||||||
| cmake_minimum_required(VERSION 3.10.0) | cmake_minimum_required(VERSION 3.10.0) | ||||||
|  |  | ||||||
|  | set(CMAKE_CXX_STANDARD 17) | ||||||
| project(inih) | project(inih) | ||||||
|  |  | ||||||
| add_library(inih STATIC | add_library(inih STATIC | ||||||
| @@ -8,4 +9,4 @@ add_library(inih STATIC | |||||||
|     cpp/INIReader.h |     cpp/INIReader.h | ||||||
|     cpp/INIReader.cpp |     cpp/INIReader.cpp | ||||||
| ) | ) | ||||||
| target_include_directories(inih PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/cpp") | target_include_directories(inih PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/cpp") | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								3rdparty/qt-unix-signals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								3rdparty/qt-unix-signals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1.0) | |||||||
|  |  | ||||||
| project(QtSignals LANGUAGES CXX) | project(QtSignals LANGUAGES CXX) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 11) | set(CMAKE_CXX_STANDARD 17) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
| # Instruct CMake to run moc automatically when needed. | # Instruct CMake to run moc automatically when needed. | ||||||
| set(CMAKE_AUTOMOC ON) | set(CMAKE_AUTOMOC ON) | ||||||
| @@ -11,4 +11,4 @@ find_package(Qt5 REQUIRED COMPONENTS Core) | |||||||
|  |  | ||||||
| add_library(QtSignals STATIC sigwatch.cpp) | add_library(QtSignals STATIC sigwatch.cpp) | ||||||
| target_include_directories(QtSignals INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) | target_include_directories(QtSignals INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) | ||||||
| target_link_libraries(QtSignals Qt5::Core) | target_link_libraries(QtSignals Qt5::Core) | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								3rdparty/qtkeychain
									
									
									
									
										vendored
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								3rdparty/qtkeychain
									
									
									
									
										vendored
									
									
										Submodule
									
								
							 Submodule 3rdparty/qtkeychain added at f197cdb935
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| cmake_minimum_required(VERSION 3.10.0) | cmake_minimum_required(VERSION 3.10.0) | ||||||
|  |  | ||||||
| set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") | ||||||
| set(CMAKE_CXX_STANDARD 11) | set(CMAKE_CXX_STANDARD 17) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
|  |  | ||||||
| set(CMAKE_AUTOMOC ON) | set(CMAKE_AUTOMOC ON) | ||||||
| @@ -30,6 +30,8 @@ find_package(Qt5 REQUIRED COMPONENTS | |||||||
|     DBus |     DBus | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | find_package(Qt5Keychain REQUIRED) | ||||||
|  |  | ||||||
| add_subdirectory(3rdparty/qt-unix-signals) | add_subdirectory(3rdparty/qt-unix-signals) | ||||||
| add_subdirectory(3rdparty/inih) | add_subdirectory(3rdparty/inih) | ||||||
| add_subdirectory(GPService) | add_subdirectory(GPService) | ||||||
|   | |||||||
| @@ -17,13 +17,14 @@ add_executable(gpclient | |||||||
|     cdpcommand.cpp |     cdpcommand.cpp | ||||||
|     cdpcommandmanager.cpp |     cdpcommandmanager.cpp | ||||||
|     enhancedwebview.cpp |     enhancedwebview.cpp | ||||||
|  |     enhancedwebpage.cpp | ||||||
|     gatewayauthenticator.cpp |     gatewayauthenticator.cpp | ||||||
|     gatewayauthenticatorparams.cpp |     gatewayauthenticatorparams.cpp | ||||||
|     gpgateway.cpp |     gpgateway.cpp | ||||||
|     gphelper.cpp |     gphelper.cpp | ||||||
|     loginparams.cpp |     loginparams.cpp | ||||||
|     main.cpp |     main.cpp | ||||||
|     normalloginwindow.cpp |     standardloginwindow.cpp | ||||||
|     portalauthenticator.cpp |     portalauthenticator.cpp | ||||||
|     portalconfigresponse.cpp |     portalconfigresponse.cpp | ||||||
|     preloginresponse.cpp |     preloginresponse.cpp | ||||||
| @@ -31,7 +32,7 @@ add_executable(gpclient | |||||||
|     gpclient.cpp |     gpclient.cpp | ||||||
|     settingsdialog.cpp |     settingsdialog.cpp | ||||||
|     gpclient.ui |     gpclient.ui | ||||||
|     normalloginwindow.ui |     standardloginwindow.ui | ||||||
|     settingsdialog.ui |     settingsdialog.ui | ||||||
|     challengedialog.h |     challengedialog.h | ||||||
|     challengedialog.cpp |     challengedialog.cpp | ||||||
| @@ -71,7 +72,10 @@ set(SingleApplication_LIBRARY ${BINARY_DIR}/libSingleApplication.a) | |||||||
| ExternalProject_Get_Property(plog-${PROJECT_NAME} SOURCE_DIR) | ExternalProject_Get_Property(plog-${PROJECT_NAME} SOURCE_DIR) | ||||||
| set(plog_INCLUDE_DIR "${SOURCE_DIR}/include") | set(plog_INCLUDE_DIR "${SOURCE_DIR}/include") | ||||||
|  |  | ||||||
| add_dependencies(gpclient SingleApplication-${PROJECT_NAME} plog-${PROJECT_NAME}) | add_dependencies(gpclient | ||||||
|  |     SingleApplication-${PROJECT_NAME} | ||||||
|  |     plog-${PROJECT_NAME} | ||||||
|  | ) | ||||||
|  |  | ||||||
| target_include_directories(gpclient PRIVATE | target_include_directories(gpclient PRIVATE | ||||||
|     ${CMAKE_BINARY_DIR} |     ${CMAKE_BINARY_DIR} | ||||||
| @@ -79,6 +83,7 @@ target_include_directories(gpclient PRIVATE | |||||||
|     ${CMAKE_CURRENT_BINARY_DIR} |     ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|     ${SingleApplication_INCLUDE_DIR} |     ${SingleApplication_INCLUDE_DIR} | ||||||
|     ${plog_INCLUDE_DIR} |     ${plog_INCLUDE_DIR} | ||||||
|  |     ${QTKEYCHAIN_INCLUDE_DIRS}/qt5keychain | ||||||
| ) | ) | ||||||
|  |  | ||||||
| target_link_libraries(gpclient | target_link_libraries(gpclient | ||||||
| @@ -90,6 +95,8 @@ target_link_libraries(gpclient | |||||||
|     Qt5::WebEngineWidgets |     Qt5::WebEngineWidgets | ||||||
|     Qt5::DBus |     Qt5::DBus | ||||||
|     QtSignals |     QtSignals | ||||||
|  |     ${QTKEYCHAIN_LIBRARIES} | ||||||
|  |     inih | ||||||
| ) | ) | ||||||
|  |  | ||||||
| if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0 AND CMAKE_BUILD_TYPE STREQUAL Release) | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0 AND CMAKE_BUILD_TYPE STREQUAL Release) | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ void CDPCommandManager::initialize(QString endpoint) | |||||||
|         reply, &QNetworkReply::finished, |         reply, &QNetworkReply::finished, | ||||||
|         [reply, this]() { |         [reply, this]() { | ||||||
|             if (reply->error()) { |             if (reply->error()) { | ||||||
|                 PLOGE << "CDP request error"; |                 LOGE << "CDP request error"; | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -78,10 +78,10 @@ void CDPCommandManager::onTextMessageReceived(QString message) | |||||||
|  |  | ||||||
| void CDPCommandManager::onSocketDisconnected() | void CDPCommandManager::onSocketDisconnected() | ||||||
| { | { | ||||||
|     PLOGI << "WebSocket disconnected"; |     LOGI << "WebSocket disconnected"; | ||||||
| } | } | ||||||
|  |  | ||||||
| void CDPCommandManager::onSocketError(QAbstractSocket::SocketError error) | void CDPCommandManager::onSocketError(QAbstractSocket::SocketError error) | ||||||
| { | { | ||||||
|     PLOGE << "WebSocket error" << error; |     LOGE << "WebSocket error" << error; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								GPClient/enhancedwebpage.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								GPClient/enhancedwebpage.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | #include "enhancedwebpage.h" | ||||||
|  | #include <QWebEngineCertificateError> | ||||||
|  | #include <plog/Log.h> | ||||||
|  |  | ||||||
|  | bool EnhancedWebPage::certificateError(const QWebEngineCertificateError &certificateError) { | ||||||
|  |     LOGI << "An error occurred during certificate verification for " << certificateError.url().toString() << "; " << certificateError.errorDescription(); | ||||||
|  |     return certificateError.isOverridable(); | ||||||
|  | }; | ||||||
							
								
								
									
										12
									
								
								GPClient/enhancedwebpage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								GPClient/enhancedwebpage.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #ifndef ENHANCEDWEBPAGE_H | ||||||
|  | #define ENHANCEDWEBPAGE_H | ||||||
|  |  | ||||||
|  | #include <QtWebEngineWidgets/qwebenginepage.h> | ||||||
|  |  | ||||||
|  | class EnhancedWebPage : public QWebEnginePage | ||||||
|  | { | ||||||
|  | protected: | ||||||
|  |     bool certificateError(const QWebEngineCertificateError &certificateError) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // !ECHANCEDWEBPAG | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| #include <QtCore/QProcessEnvironment> | #include <QtCore/QProcessEnvironment> | ||||||
| #include <QtWebEngineWidgets/QWebEngineView> | #include <QtWebEngineWidgets/QWebEngineView> | ||||||
|  |  | ||||||
|  | #include "enhancedwebpage.h" | ||||||
| #include "enhancedwebview.h" | #include "enhancedwebview.h" | ||||||
| #include "cdpcommandmanager.h" | #include "cdpcommandmanager.h" | ||||||
|  |  | ||||||
| @@ -8,18 +9,14 @@ EnhancedWebView::EnhancedWebView(QWidget *parent) | |||||||
|     : QWebEngineView(parent) |     : QWebEngineView(parent) | ||||||
|     , cdp(new CDPCommandManager) |     , cdp(new CDPCommandManager) | ||||||
| { | { | ||||||
|     QObject::connect(cdp, &CDPCommandManager::ready, this, &EnhancedWebView::onCDPReady); |    QObject::connect(cdp, &CDPCommandManager::ready, this, &EnhancedWebView::onCDPReady); | ||||||
|     QObject::connect(cdp, &CDPCommandManager::eventReceived, this, &EnhancedWebView::onEventReceived); |    QObject::connect(cdp, &CDPCommandManager::eventReceived, this, &EnhancedWebView::onEventReceived); | ||||||
| } |  | ||||||
|  |  | ||||||
| EnhancedWebView::~EnhancedWebView() |  | ||||||
| { |  | ||||||
|     delete cdp; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void EnhancedWebView::initialize() | void EnhancedWebView::initialize() | ||||||
| { | { | ||||||
|     QString port = QProcessEnvironment::systemEnvironment().value(ENV_CDP_PORT); |     setPage(new EnhancedWebPage()); | ||||||
|  |     auto port = QProcessEnvironment::systemEnvironment().value(ENV_CDP_PORT); | ||||||
|     cdp->initialize("http://127.0.0.1:" + port + "/json"); |     cdp->initialize("http://127.0.0.1:" + port + "/json"); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ class EnhancedWebView : public QWebEngineView | |||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| public: | public: | ||||||
|     explicit EnhancedWebView(QWidget *parent = nullptr); |     explicit EnhancedWebView(QWidget *parent = nullptr); | ||||||
|     ~EnhancedWebView(); |  | ||||||
|  |  | ||||||
|     void initialize(); |     void initialize(); | ||||||
|  |  | ||||||
| @@ -24,7 +23,7 @@ private slots: | |||||||
|     void onEventReceived(QString eventName, QJsonObject params); |     void onEventReceived(QString eventName, QJsonObject params); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     CDPCommandManager *cdp; |     CDPCommandManager *cdp { nullptr }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif // ENHANCEDWEBVIEW_H | #endif // ENHANCEDWEBVIEW_H | ||||||
|   | |||||||
| @@ -23,14 +23,9 @@ GatewayAuthenticator::GatewayAuthenticator(const QString& gateway, GatewayAuthen | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| GatewayAuthenticator::~GatewayAuthenticator() |  | ||||||
| { |  | ||||||
|     delete normalLoginWindow; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void GatewayAuthenticator::authenticate() | void GatewayAuthenticator::authenticate() | ||||||
| { | { | ||||||
|     PLOGI << "Start gateway authentication..."; |     LOGI << "Start gateway authentication..."; | ||||||
|  |  | ||||||
|     LoginParams loginParams { params.clientos() }; |     LoginParams loginParams { params.clientos() }; | ||||||
|     loginParams.setUser(params.username()); |     loginParams.setUser(params.username()); | ||||||
| @@ -43,9 +38,9 @@ void GatewayAuthenticator::authenticate() | |||||||
|  |  | ||||||
| void GatewayAuthenticator::login(const LoginParams &loginParams) | void GatewayAuthenticator::login(const LoginParams &loginParams) | ||||||
| { | { | ||||||
|     PLOGI << "Trying to login the gateway at " << loginUrl << " with " << loginParams.toUtf8(); |     LOGI << QString("Trying to login the gateway at %1, with %2").arg(loginUrl).arg(QString(loginParams.toUtf8())); | ||||||
|  |  | ||||||
|     QNetworkReply *reply = createRequest(loginUrl, loginParams.toUtf8()); |     auto *reply = createRequest(loginUrl, loginParams.toUtf8()); | ||||||
|     connect(reply, &QNetworkReply::finished, this, &GatewayAuthenticator::onLoginFinished); |     connect(reply, &QNetworkReply::finished, this, &GatewayAuthenticator::onLoginFinished); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -55,10 +50,10 @@ void GatewayAuthenticator::onLoginFinished() | |||||||
|     QByteArray response = reply->readAll(); |     QByteArray response = reply->readAll(); | ||||||
|  |  | ||||||
|     if (reply->error() || response.contains("Authentication failure")) { |     if (reply->error() || response.contains("Authentication failure")) { | ||||||
|         PLOGE << QString("Failed to login the gateway at %1, %2").arg(loginUrl, reply->errorString()); |         LOGE << QString("Failed to login the gateway at %1, %2").arg(loginUrl, reply->errorString()); | ||||||
|  |  | ||||||
|         if (normalLoginWindow) { |         if (standardLoginWindow) { | ||||||
|             normalLoginWindow->setProcessing(false); |             standardLoginWindow->setProcessing(false); | ||||||
|             openMessageBox("Gateway login failed.", "Please check your credentials and try again."); |             openMessageBox("Gateway login failed.", "Please check your credentials and try again."); | ||||||
|         } else { |         } else { | ||||||
|             doAuth(); |             doAuth(); | ||||||
| @@ -68,48 +63,48 @@ void GatewayAuthenticator::onLoginFinished() | |||||||
|  |  | ||||||
|     // 2FA |     // 2FA | ||||||
|     if (response.contains("Challenge")) { |     if (response.contains("Challenge")) { | ||||||
|         PLOGI << "The server need input the challenge..."; |         LOGI << "The server need input the challenge..."; | ||||||
|         showChallenge(response); |         showChallenge(response); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (normalLoginWindow) { |     if (standardLoginWindow) { | ||||||
|         normalLoginWindow->close(); |         standardLoginWindow->close(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const QUrlQuery params = gpclient::helper::parseGatewayResponse(response); |     const auto params = gpclient::helper::parseGatewayResponse(response); | ||||||
|     emit success(params.toString()); |     emit success(params.toString()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GatewayAuthenticator::doAuth() | void GatewayAuthenticator::doAuth() | ||||||
| { | { | ||||||
|     PLOGI << "Perform the gateway prelogin at " << preloginUrl; |     LOGI << "Perform the gateway prelogin at " << preloginUrl; | ||||||
|  |  | ||||||
|     QNetworkReply *reply = createRequest(preloginUrl); |     auto *reply = createRequest(preloginUrl); | ||||||
|     connect(reply, &QNetworkReply::finished, this, &GatewayAuthenticator::onPreloginFinished); |     connect(reply, &QNetworkReply::finished, this, &GatewayAuthenticator::onPreloginFinished); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GatewayAuthenticator::onPreloginFinished() | void GatewayAuthenticator::onPreloginFinished() | ||||||
| { | { | ||||||
|     QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); |     auto *reply = qobject_cast<QNetworkReply*>(sender()); | ||||||
|  |  | ||||||
|     if (reply->error()) { |     if (reply->error()) { | ||||||
|         PLOGE << QString("Failed to prelogin the gateway at %1, %2").arg(preloginUrl, reply->errorString()); |         LOGE << QString("Failed to prelogin the gateway at %1, %2").arg(preloginUrl, reply->errorString()); | ||||||
|  |  | ||||||
|         emit fail("Error occurred on the gateway prelogin interface."); |         emit fail("Error occurred on the gateway prelogin interface."); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PLOGI << "Gateway prelogin succeeded."; |     LOGI << "Gateway prelogin succeeded."; | ||||||
|  |  | ||||||
|     PreloginResponse response = PreloginResponse::parse(reply->readAll()); |     auto response = PreloginResponse::parse(reply->readAll()); | ||||||
|  |  | ||||||
|     if (response.hasSamlAuthFields()) { |     if (response.hasSamlAuthFields()) { | ||||||
|         samlAuth(response.samlMethod(), response.samlRequest(), reply->url().toString()); |         samlAuth(response.samlMethod(), response.samlRequest(), reply->url().toString()); | ||||||
|     } else if (response.hasNormalAuthFields()) { |     } else if (response.hasNormalAuthFields()) { | ||||||
|         normalAuth(response.labelUsername(), response.labelPassword(), response.authMessage()); |         normalAuth(response.labelUsername(), response.labelPassword(), response.authMessage()); | ||||||
|     } else { |     } else { | ||||||
|         PLOGE << QString("Unknown prelogin response for %1, got %2").arg(preloginUrl, QString::fromUtf8(response.rawResponse())); |         LOGE << QString("Unknown prelogin response for %1, got %2").arg(preloginUrl, QString::fromUtf8(response.rawResponse())); | ||||||
|         emit fail("Unknown response for gateway prelogin interface."); |         emit fail("Unknown response for gateway prelogin interface."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -118,30 +113,26 @@ void GatewayAuthenticator::onPreloginFinished() | |||||||
|  |  | ||||||
| void GatewayAuthenticator::normalAuth(QString labelUsername, QString labelPassword, QString authMessage) | void GatewayAuthenticator::normalAuth(QString labelUsername, QString labelPassword, QString authMessage) | ||||||
| { | { | ||||||
|     PLOGI << QString("Trying to perform the normal login with %1 / %2 credentials").arg(labelUsername, labelPassword); |     LOGI << QString("Trying to perform the normal login with %1 / %2 credentials").arg(labelUsername, labelPassword); | ||||||
|  |  | ||||||
|     normalLoginWindow = new NormalLoginWindow; |     standardLoginWindow = new StandardLoginWindow {gateway, labelUsername, labelPassword, authMessage}; | ||||||
|     normalLoginWindow->setPortalAddress(gateway); |  | ||||||
|     normalLoginWindow->setAuthMessage(authMessage); |  | ||||||
|     normalLoginWindow->setUsernameLabel(labelUsername); |  | ||||||
|     normalLoginWindow->setPasswordLabel(labelPassword); |  | ||||||
|  |  | ||||||
|     // Do login |     // Do login | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::performLogin, this, &GatewayAuthenticator::onPerformNormalLogin); |     connect(standardLoginWindow, &StandardLoginWindow::performLogin, this, &GatewayAuthenticator::onPerformStandardLogin); | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::rejected, this, &GatewayAuthenticator::onLoginWindowRejected); |     connect(standardLoginWindow, &StandardLoginWindow::rejected, this, &GatewayAuthenticator::onLoginWindowRejected); | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::finished, this, &GatewayAuthenticator::onLoginWindowFinished); |     connect(standardLoginWindow, &StandardLoginWindow::finished, this, &GatewayAuthenticator::onLoginWindowFinished); | ||||||
|  |  | ||||||
|     normalLoginWindow->show(); |     standardLoginWindow->show(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GatewayAuthenticator::onPerformNormalLogin(const QString &username, const QString &password) | void GatewayAuthenticator::onPerformStandardLogin(const QString &username, const QString &password) | ||||||
| { | { | ||||||
|     PLOGI << "Start to perform normal login..."; |     LOGI << "Start to perform normal login..."; | ||||||
|  |  | ||||||
|     normalLoginWindow->setProcessing(true); |     standardLoginWindow->setProcessing(true); | ||||||
|     params.setUsername(username); |     params.setUsername(username); | ||||||
|     params.setPassword(password); |     params.setPassword(password); | ||||||
|      |  | ||||||
|     authenticate(); |     authenticate(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -152,22 +143,22 @@ void GatewayAuthenticator::onLoginWindowRejected() | |||||||
|  |  | ||||||
| void GatewayAuthenticator::onLoginWindowFinished() | void GatewayAuthenticator::onLoginWindowFinished() | ||||||
| { | { | ||||||
|     delete normalLoginWindow; |     delete standardLoginWindow; | ||||||
|     normalLoginWindow = nullptr; |     standardLoginWindow = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| void GatewayAuthenticator::samlAuth(QString samlMethod, QString samlRequest, QString preloginUrl) | void GatewayAuthenticator::samlAuth(QString samlMethod, QString samlRequest, QString preloginUrl) | ||||||
| { | { | ||||||
|     PLOGI << "Trying to perform SAML login with saml-method " << samlMethod; |     LOGI << "Trying to perform SAML login with saml-method " << samlMethod; | ||||||
|  |  | ||||||
|     SAMLLoginWindow *loginWindow = new SAMLLoginWindow; |     auto *loginWindow = new SAMLLoginWindow(gateway); | ||||||
|  |  | ||||||
|     connect(loginWindow, &SAMLLoginWindow::success, [this, loginWindow](const QMap<QString, QString> &samlResult) { |     connect(loginWindow, &SAMLLoginWindow::success, [this, loginWindow](const QMap<QString, QString> &samlResult) { | ||||||
|         this->onSAMLLoginSuccess(samlResult); |         this->onSAMLLoginSuccess(samlResult); | ||||||
|         loginWindow->deleteLater(); |         loginWindow->deleteLater(); | ||||||
|     }); |     }); | ||||||
|     connect(loginWindow, &SAMLLoginWindow::fail, [this, loginWindow](const QString &error) { |     connect(loginWindow, &SAMLLoginWindow::fail, [this, loginWindow](const QString &code, const QString &error) { | ||||||
|         this->onSAMLLoginFail(error); |         this->onSAMLLoginFail(code, error); | ||||||
|         loginWindow->deleteLater(); |         loginWindow->deleteLater(); | ||||||
|     }); |     }); | ||||||
|     connect(loginWindow, &SAMLLoginWindow::rejected, [this, loginWindow]() { |     connect(loginWindow, &SAMLLoginWindow::rejected, [this, loginWindow]() { | ||||||
| @@ -181,9 +172,9 @@ void GatewayAuthenticator::samlAuth(QString samlMethod, QString samlRequest, QSt | |||||||
| void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult) | void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult) | ||||||
| { | { | ||||||
|     if (samlResult.contains("preloginCookie")) { |     if (samlResult.contains("preloginCookie")) { | ||||||
|         PLOGI << "SAML login succeeded, got the prelogin-cookie " << samlResult.value("preloginCookie"); |         LOGI << "SAML login succeeded, got the prelogin-cookie " << samlResult.value("preloginCookie"); | ||||||
|     } else { |     } else { | ||||||
|         PLOGI << "SAML login succeeded, got the portal-userauthcookie " << samlResult.value("userAuthCookie"); |         LOGI << "SAML login succeeded, got the portal-userauthcookie " << samlResult.value("userAuthCookie"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LoginParams loginParams { params.clientos() }; |     LoginParams loginParams { params.clientos() }; | ||||||
| @@ -194,7 +185,7 @@ void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &saml | |||||||
|     login(loginParams); |     login(loginParams); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GatewayAuthenticator::onSAMLLoginFail(const QString msg) | void GatewayAuthenticator::onSAMLLoginFail(const QString &code, const QString &msg) | ||||||
| { | { | ||||||
|     emit fail(msg); |     emit fail(msg); | ||||||
| } | } | ||||||
| @@ -215,13 +206,13 @@ void GatewayAuthenticator::showChallenge(const QString &responseText) | |||||||
|  |  | ||||||
|     connect(challengeDialog, &ChallengeDialog::accepted, this, [this] { |     connect(challengeDialog, &ChallengeDialog::accepted, this, [this] { | ||||||
|         params.setPassword(challengeDialog->getChallenge()); |         params.setPassword(challengeDialog->getChallenge()); | ||||||
|         PLOGI << "Challenge submitted, try to re-authenticate..."; |         LOGI << "Challenge submitted, try to re-authenticate..."; | ||||||
|         authenticate(); |         authenticate(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     connect(challengeDialog, &ChallengeDialog::rejected, this, [this] { |     connect(challengeDialog, &ChallengeDialog::rejected, this, [this] { | ||||||
|         if (normalLoginWindow) { |         if (standardLoginWindow) { | ||||||
|             normalLoginWindow->close(); |             standardLoginWindow->close(); | ||||||
|         } |         } | ||||||
|         emit fail(); |         emit fail(); | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
|  |  | ||||||
| #include <QtCore/QObject> | #include <QtCore/QObject> | ||||||
|  |  | ||||||
| #include "normalloginwindow.h" | #include "standardloginwindow.h" | ||||||
| #include "challengedialog.h" | #include "challengedialog.h" | ||||||
| #include "loginparams.h" | #include "loginparams.h" | ||||||
| #include "gatewayauthenticatorparams.h" | #include "gatewayauthenticatorparams.h" | ||||||
| @@ -12,23 +12,22 @@ class GatewayAuthenticator : public QObject | |||||||
| { | { | ||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| public: | public: | ||||||
|     explicit GatewayAuthenticator(const QString& gateway, GatewayAuthenticatorParams params); |     explicit GatewayAuthenticator(const QString &gateway, GatewayAuthenticatorParams params); | ||||||
|     ~GatewayAuthenticator(); |  | ||||||
|  |  | ||||||
|     void authenticate(); |     void authenticate(); | ||||||
|  |  | ||||||
| signals: | signals: | ||||||
|     void success(const QString& authCookie); |     void success(const QString &authCookie); | ||||||
|     void fail(const QString& msg = ""); |     void fail(const QString &msg = ""); | ||||||
|  |  | ||||||
| private slots: | private slots: | ||||||
|     void onLoginFinished(); |     void onLoginFinished(); | ||||||
|     void onPreloginFinished(); |     void onPreloginFinished(); | ||||||
|     void onPerformNormalLogin(const QString &username, const QString &password); |     void onPerformStandardLogin(const QString &username, const QString &password); | ||||||
|     void onLoginWindowRejected(); |     void onLoginWindowRejected(); | ||||||
|     void onLoginWindowFinished(); |     void onLoginWindowFinished(); | ||||||
|     void onSAMLLoginSuccess(const QMap<QString, QString> &samlResult); |     void onSAMLLoginSuccess(const QMap<QString, QString> &samlResult); | ||||||
|     void onSAMLLoginFail(const QString msg); |     void onSAMLLoginFail(const QString &code, const QString &msg); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     QString gateway; |     QString gateway; | ||||||
| @@ -36,8 +35,8 @@ private: | |||||||
|     QString preloginUrl; |     QString preloginUrl; | ||||||
|     QString loginUrl; |     QString loginUrl; | ||||||
|  |  | ||||||
|     NormalLoginWindow *normalLoginWindow{ nullptr }; |     StandardLoginWindow *standardLoginWindow { nullptr }; | ||||||
|     ChallengeDialog *challengeDialog{ nullptr }; |     ChallengeDialog *challengeDialog { nullptr }; | ||||||
|  |  | ||||||
|     void login(const LoginParams& loginParams); |     void login(const LoginParams& loginParams); | ||||||
|     void doAuth(); |     void doAuth(); | ||||||
|   | |||||||
| @@ -64,4 +64,3 @@ void GatewayAuthenticatorParams::setInputStr(const QString &inputStr) | |||||||
| { | { | ||||||
|     m_inputStr = inputStr; |     m_inputStr = inputStr; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,14 +40,6 @@ GPClient::GPClient(QWidget *parent, IVpn *vpn) | |||||||
|     initVpnStatus(); |     initVpnStatus(); | ||||||
| } | } | ||||||
|  |  | ||||||
| GPClient::~GPClient() |  | ||||||
| { |  | ||||||
|     delete ui; |  | ||||||
|     delete vpn; |  | ||||||
|     delete settingsDialog; |  | ||||||
|     delete settingsButton; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void GPClient::setupSettings() | void GPClient::setupSettings() | ||||||
| { | { | ||||||
|     settingsButton = new QPushButton(this); |     settingsButton = new QPushButton(this); | ||||||
| @@ -69,12 +61,14 @@ void GPClient::setupSettings() | |||||||
| void GPClient::onSettingsButtonClicked() | void GPClient::onSettingsButtonClicked() | ||||||
| { | { | ||||||
|     settingsDialog->setClientos(settings::get("clientos", "Linux").toString()); |     settingsDialog->setClientos(settings::get("clientos", "Linux").toString()); | ||||||
|  |     settingsDialog->setOsVersion(settings::get("os-version", QSysInfo::prettyProductName()).toString()); | ||||||
|     settingsDialog->show(); |     settingsDialog->show(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPClient::onSettingsAccepted() | void GPClient::onSettingsAccepted() | ||||||
| { | { | ||||||
|     settings::save("clientos", settingsDialog->clientos()); |     settings::save("clientos", settingsDialog->clientos()); | ||||||
|  |     settings::save("os-version", settingsDialog->osVersion()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPClient::on_connectButton_clicked() | void GPClient::on_connectButton_clicked() | ||||||
| @@ -112,7 +106,7 @@ void GPClient::initSystemTrayIcon() | |||||||
|     connectAction = contextMenu->addAction(QIcon::fromTheme("preferences-system-network"), "Connect", this, &GPClient::doConnect); |     connectAction = contextMenu->addAction(QIcon::fromTheme("preferences-system-network"), "Connect", this, &GPClient::doConnect); | ||||||
|     contextMenu->addMenu(gatewaySwitchMenu); |     contextMenu->addMenu(gatewaySwitchMenu); | ||||||
|     contextMenu->addSeparator(); |     contextMenu->addSeparator(); | ||||||
|     clearAction = contextMenu->addAction(QIcon::fromTheme("edit-clear"), "Reset Settings", this, &GPClient::clearSettings); |     clearAction = contextMenu->addAction(QIcon::fromTheme("edit-clear"), "Reset", this, &GPClient::reset); | ||||||
|     quitAction = contextMenu->addAction(QIcon::fromTheme("application-exit"), "Quit", this, &GPClient::quit); |     quitAction = contextMenu->addAction(QIcon::fromTheme("application-exit"), "Quit", this, &GPClient::quit); | ||||||
|  |  | ||||||
|     systemTrayIcon->show(); |     systemTrayIcon->show(); | ||||||
| @@ -136,7 +130,7 @@ void GPClient::initVpnStatus() { | |||||||
|  |  | ||||||
| void GPClient::populateGatewayMenu() | void GPClient::populateGatewayMenu() | ||||||
| { | { | ||||||
|     PLOGI << "Populating the Switch Gateway menu..."; |     LOGI << "Populating the Switch Gateway menu..."; | ||||||
|  |  | ||||||
|     const QList<GPGateway> gateways = allGateways(); |     const QList<GPGateway> gateways = allGateways(); | ||||||
|     gatewaySwitchMenu->clear(); |     gatewaySwitchMenu->clear(); | ||||||
| @@ -153,7 +147,7 @@ void GPClient::populateGatewayMenu() | |||||||
|         if (g.name() == currentGatewayName) { |         if (g.name() == currentGatewayName) { | ||||||
|             iconImage = ":/images/radio_selected.png"; |             iconImage = ":/images/radio_selected.png"; | ||||||
|         } |         } | ||||||
|         gatewaySwitchMenu->addAction(QIcon(iconImage), g.name())->setData(i); |         gatewaySwitchMenu->addAction(QIcon(iconImage), QString("%1 (%2)").arg(g.name(), g.address()))->setData(i); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -221,7 +215,7 @@ void GPClient::onGatewayChanged(QAction *action) | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const GPGateway g = allGateways().at(index); |     const auto g = allGateways().at(index); | ||||||
|  |  | ||||||
|     // If the selected gateway is the same as the current gateway |     // If the selected gateway is the same as the current gateway | ||||||
|     if (g.name() == currentGateway().name()) { |     if (g.name() == currentGateway().name()) { | ||||||
| @@ -241,10 +235,10 @@ void GPClient::onGatewayChanged(QAction *action) | |||||||
|  |  | ||||||
| void GPClient::doConnect() | void GPClient::doConnect() | ||||||
| { | { | ||||||
|     PLOGI << "Start connecting..."; |     LOGI << "Start connecting..."; | ||||||
|  |  | ||||||
|     const QString btnText = ui->connectButton->text(); |     const auto btnText = ui->connectButton->text(); | ||||||
|     const QString portal = this->portal(); |     const auto portal = this->portal(); | ||||||
|  |  | ||||||
|     // Display the main window if portal is empty |     // Display the main window if portal is empty | ||||||
|     if (portal.isEmpty()) { |     if (portal.isEmpty()) { | ||||||
| @@ -257,16 +251,16 @@ void GPClient::doConnect() | |||||||
|  |  | ||||||
|         // Login to the previously saved gateway |         // Login to the previously saved gateway | ||||||
|         if (!currentGateway().name().isEmpty()) { |         if (!currentGateway().name().isEmpty()) { | ||||||
|             PLOGI << "Start gateway login using the previously saved gateway..."; |             LOGI << "Start gateway login using the previously saved gateway..."; | ||||||
|             isQuickConnect = true; |             isQuickConnect = true; | ||||||
|             gatewayLogin(); |             gatewayLogin(); | ||||||
|         } else { |         } else { | ||||||
|             // Perform the portal login |             // Perform the portal login | ||||||
|             PLOGI << "Start portal login..."; |             LOGI << "Start portal login..."; | ||||||
|             portalLogin(); |             portalLogin(); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         PLOGI << "Start disconnecting the VPN..."; |         LOGI << "Start disconnecting the VPN..."; | ||||||
|  |  | ||||||
|         ui->statusLabel->setText("Disconnecting..."); |         ui->statusLabel->setText("Disconnecting..."); | ||||||
|         updateConnectionStatus(VpnStatus::pending); |         updateConnectionStatus(VpnStatus::pending); | ||||||
| @@ -277,7 +271,7 @@ void GPClient::doConnect() | |||||||
| // Login to the portal interface to get the portal config and preferred gateway | // Login to the portal interface to get the portal config and preferred gateway | ||||||
| void GPClient::portalLogin() | void GPClient::portalLogin() | ||||||
| { | { | ||||||
|     PortalAuthenticator *portalAuth = new PortalAuthenticator(portal(), settings::get("clientos", "Linux").toString()); |     auto *portalAuth = new PortalAuthenticator(portal(), settings::get("clientos", "Linux").toString()); | ||||||
|  |  | ||||||
|     connect(portalAuth, &PortalAuthenticator::success, [this, portalAuth](const PortalConfigResponse response, const QString region) { |     connect(portalAuth, &PortalAuthenticator::success, [this, portalAuth](const PortalConfigResponse response, const QString region) { | ||||||
|         this->onPortalSuccess(response, region); |         this->onPortalSuccess(response, region); | ||||||
| @@ -305,11 +299,11 @@ void GPClient::portalLogin() | |||||||
|  |  | ||||||
| void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const QString region) | void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const QString region) | ||||||
| { | { | ||||||
|     PLOGI << "Portal authentication succeeded."; |     LOGI << "Portal authentication succeeded."; | ||||||
|  |  | ||||||
|     // No gateway found in protal configuration |     // No gateway found in portal configuration | ||||||
|     if (portalConfig.allGateways().size() == 0) { |     if (portalConfig.allGateways().size() == 0) { | ||||||
|         PLOGI << "No gateway found in portal configuration, treat the portal address as a gateway."; |         LOGI << "No gateway found in portal configuration, treat the portal address as a gateway."; | ||||||
|         tryGatewayLogin(); |         tryGatewayLogin(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -324,13 +318,13 @@ void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const QS | |||||||
|  |  | ||||||
| void GPClient::onPortalPreloginFail(const QString msg) | void GPClient::onPortalPreloginFail(const QString msg) | ||||||
| { | { | ||||||
|     PLOGI << "Portal prelogin failed: " << msg; |     LOGI << "Portal prelogin failed, treat the portal address as a gateway." << msg; | ||||||
|     tryGatewayLogin(); |     tryGatewayLogin(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPClient::onPortalConfigFail(const QString msg) | void GPClient::onPortalConfigFail(const QString msg) | ||||||
| { | { | ||||||
|     PLOGI << "Failed to get the portal configuration, " << msg << " Treat the portal address as gateway."; |     LOGI << "Failed to get the portal configuration, " << msg << " Treat the portal address as gateway."; | ||||||
|     tryGatewayLogin(); |     tryGatewayLogin(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -345,7 +339,7 @@ void GPClient::onPortalFail(const QString &msg) | |||||||
|  |  | ||||||
| void GPClient::tryGatewayLogin() | void GPClient::tryGatewayLogin() | ||||||
| { | { | ||||||
|     PLOGI << "Try to preform login on the the gateway interface..."; |     LOGI << "Try to perform login on the the gateway interface..."; | ||||||
|  |  | ||||||
|     // Treat the portal input as the gateway address |     // Treat the portal input as the gateway address | ||||||
|     GPGateway g; |     GPGateway g; | ||||||
| @@ -364,12 +358,13 @@ void GPClient::tryGatewayLogin() | |||||||
| // Login to the gateway | // Login to the gateway | ||||||
| void GPClient::gatewayLogin() | void GPClient::gatewayLogin() | ||||||
| { | { | ||||||
|     PLOGI << "Performing gateway login..."; |     LOGI << "Performing gateway login..."; | ||||||
|  |  | ||||||
|     GatewayAuthenticatorParams params = GatewayAuthenticatorParams::fromPortalConfigResponse(portalConfig); |     GatewayAuthenticatorParams params = GatewayAuthenticatorParams::fromPortalConfigResponse(portalConfig); | ||||||
|     params.setClientos(settings::get("clientos", "Linux").toString()); |     params.setClientos(settings::get("clientos", "Linux").toString()); | ||||||
|  |  | ||||||
|     GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), params); |     GatewayAuthenticator *gatewayAuth; | ||||||
|  |     gatewayAuth = new GatewayAuthenticator(currentGateway().address(), params); | ||||||
|  |  | ||||||
|     connect(gatewayAuth, &GatewayAuthenticator::success, [this, gatewayAuth](const QString &authToken) { |     connect(gatewayAuth, &GatewayAuthenticator::success, [this, gatewayAuth](const QString &authToken) { | ||||||
|         this->onGatewaySuccess(authToken); |         this->onGatewaySuccess(authToken); | ||||||
| @@ -387,7 +382,7 @@ void GPClient::gatewayLogin() | |||||||
|  |  | ||||||
| void GPClient::onGatewaySuccess(const QString &authCookie) | void GPClient::onGatewaySuccess(const QString &authCookie) | ||||||
| { | { | ||||||
|     PLOGI << "Gateway login succeeded, got the cookie " << authCookie; |     LOGI << "Gateway login succeeded, got the cookie " << authCookie; | ||||||
|  |  | ||||||
|     isQuickConnect = false; |     isQuickConnect = false; | ||||||
|     QList<QString> gatewayAddresses; |     QList<QString> gatewayAddresses; | ||||||
| @@ -404,6 +399,7 @@ void GPClient::onGatewayFail(const QString &msg) | |||||||
|     // If the quick connect on gateway failed, perform the portal login |     // If the quick connect on gateway failed, perform the portal login | ||||||
|     if (isQuickConnect && !msg.isEmpty()) { |     if (isQuickConnect && !msg.isEmpty()) { | ||||||
|         isQuickConnect = false; |         isQuickConnect = false; | ||||||
|  |         LOGI << "Quick connection failed, trying to portal login..."; | ||||||
|         portalLogin(); |         portalLogin(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -444,13 +440,19 @@ bool GPClient::connected() const | |||||||
|  |  | ||||||
| QList<GPGateway> GPClient::allGateways() const | QList<GPGateway> GPClient::allGateways() const | ||||||
| { | { | ||||||
|     const QString gatewaysJson = settings::get(portal() + "_gateways").toString(); |  | ||||||
|     return GPGateway::fromJson(gatewaysJson); |     QList<GPGateway> gateways; | ||||||
|  |  | ||||||
|  |     for (auto g :settings::get_all("_gateways$") ){ | ||||||
|  |  | ||||||
|  |     	gateways.append(GPGateway::fromJson(settings::get(g).toString())); | ||||||
|  |     } | ||||||
|  |     return gateways; | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPClient::setAllGateways(QList<GPGateway> gateways) | void GPClient::setAllGateways(QList<GPGateway> gateways) | ||||||
| { | { | ||||||
|     PLOGI << "Updating all the gateways..."; |     LOGI << "Updating all the gateways..."; | ||||||
|  |  | ||||||
|     settings::save(portal() + "_gateways", GPGateway::serialize(gateways)); |     settings::save(portal() + "_gateways", GPGateway::serialize(gateways)); | ||||||
|     populateGatewayMenu(); |     populateGatewayMenu(); | ||||||
| @@ -470,13 +472,14 @@ GPGateway GPClient::currentGateway() const | |||||||
|  |  | ||||||
| void GPClient::setCurrentGateway(const GPGateway gateway) | void GPClient::setCurrentGateway(const GPGateway gateway) | ||||||
| { | { | ||||||
|     PLOGI << "Updating the current gateway to " << gateway.name(); |     LOGI << "Updating the current gateway to " << gateway.name(); | ||||||
|  |  | ||||||
|     settings::save(portal() + "_selectedGateway", gateway.name()); |     settings::save(portal() + "_selectedGateway", gateway.name()); | ||||||
|  |     ui->portalInput->setText(gateway.address()); | ||||||
|     populateGatewayMenu(); |     populateGatewayMenu(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GPClient::clearSettings() | void GPClient::reset() | ||||||
| { | { | ||||||
|     settings::clear(); |     settings::clear(); | ||||||
|     populateGatewayMenu(); |     populateGatewayMenu(); | ||||||
| @@ -512,5 +515,5 @@ void GPClient::onVPNError(QString errorMessage) | |||||||
|  |  | ||||||
| void GPClient::onVPNLogAvailable(QString log) | void GPClient::onVPNLogAvailable(QString log) | ||||||
| { | { | ||||||
|     PLOGI << log; |     LOGI << log; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ class GPClient : public QMainWindow | |||||||
|  |  | ||||||
| public: | public: | ||||||
|     GPClient(QWidget *parent, IVpn *vpn); |     GPClient(QWidget *parent, IVpn *vpn); | ||||||
|     ~GPClient(); |  | ||||||
|  |  | ||||||
|     void activate(); |     void activate(); | ||||||
|     void quit(); |     void quit(); | ||||||
| @@ -33,6 +32,7 @@ public: | |||||||
|     void setCurrentGateway(const GPGateway gateway); |     void setCurrentGateway(const GPGateway gateway); | ||||||
|  |  | ||||||
|     void doConnect(); |     void doConnect(); | ||||||
|  |     void reset(); | ||||||
|  |  | ||||||
| private slots: | private slots: | ||||||
|     void onSettingsButtonClicked(); |     void onSettingsButtonClicked(); | ||||||
| @@ -81,8 +81,6 @@ private: | |||||||
|     SettingsDialog *settingsDialog; |     SettingsDialog *settingsDialog; | ||||||
|     QPushButton *settingsButton; |     QPushButton *settingsButton; | ||||||
|  |  | ||||||
|     GatewayAuthenticator *gatewayAuthenticator; |  | ||||||
|  |  | ||||||
|     bool isQuickConnect { false }; |     bool isQuickConnect { false }; | ||||||
|     bool isSwitchingGateway { false }; |     bool isSwitchingGateway { false }; | ||||||
|     PortalConfigResponse portalConfig; |     PortalConfigResponse portalConfig; | ||||||
| @@ -102,7 +100,5 @@ private: | |||||||
|  |  | ||||||
|     QList<GPGateway> allGateways() const; |     QList<GPGateway> allGateways() const; | ||||||
|     void setAllGateways(QList<GPGateway> gateways); |     void setAllGateways(QList<GPGateway> gateways); | ||||||
|  |  | ||||||
|     void clearSettings(); |  | ||||||
| }; | }; | ||||||
| #endif // GPCLIENT_H | #endif // GPCLIENT_H | ||||||
|   | |||||||
| @@ -7,9 +7,14 @@ | |||||||
| #include <QtNetwork/QSslConfiguration> | #include <QtNetwork/QSslConfiguration> | ||||||
| #include <QtNetwork/QSslSocket> | #include <QtNetwork/QSslSocket> | ||||||
| #include <plog/Log.h> | #include <plog/Log.h> | ||||||
|  | #include <QWebEngineProfile> | ||||||
|  | #include <QWebEngineCookieStore> | ||||||
|  | #include <keychain.h> | ||||||
|  |  | ||||||
| #include "gphelper.h" | #include "gphelper.h" | ||||||
|  |  | ||||||
|  | using namespace QKeychain; | ||||||
|  |  | ||||||
| QNetworkAccessManager* gpclient::helper::networkManager = new QNetworkAccessManager; | QNetworkAccessManager* gpclient::helper::networkManager = new QNetworkAccessManager; | ||||||
|  |  | ||||||
| QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params) | QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params) | ||||||
| @@ -33,13 +38,13 @@ QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params) | |||||||
|  |  | ||||||
| GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName) | GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName) | ||||||
| { | { | ||||||
|     PLOGI << gateways.size() << " gateway(s) avaiable, filter the gateways with rule: " << ruleName; |     LOGI << gateways.size() << " gateway(s) available, filter the gateways with rule: " << ruleName; | ||||||
|  |  | ||||||
|     GPGateway gateway = gateways.first(); |     GPGateway gateway = gateways.first(); | ||||||
|  |  | ||||||
|     for (GPGateway g : gateways) { |     for (GPGateway g : gateways) { | ||||||
|         if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) { |         if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) { | ||||||
|             PLOGI << "Find a preferred gateway: " << g.name(); |             LOGI << "Find a preferred gateway: " << g.name(); | ||||||
|             gateway = g; |             gateway = g; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -49,8 +54,8 @@ GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, co | |||||||
|  |  | ||||||
| QUrlQuery gpclient::helper::parseGatewayResponse(const QByteArray &xml) | QUrlQuery gpclient::helper::parseGatewayResponse(const QByteArray &xml) | ||||||
| { | { | ||||||
|     PLOGI << "Start parsing the gateway response..."; |     LOGI << "Start parsing the gateway response..."; | ||||||
|     PLOGI << "The gateway response is: " << xml; |     LOGI << "The gateway response is: " << xml; | ||||||
|  |  | ||||||
|     QXmlStreamReader xmlReader{xml}; |     QXmlStreamReader xmlReader{xml}; | ||||||
|     QList<QString> args; |     QList<QString> args; | ||||||
| @@ -113,6 +118,12 @@ QVariant gpclient::helper::settings::get(const QString &key, const QVariant &def | |||||||
|     return _settings->value(key, defaultValue); |     return _settings->value(key, defaultValue); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | QStringList gpclient::helper::settings::get_all(const QString &key, const QVariant &defaultValue) | ||||||
|  | { | ||||||
|  | 	QRegularExpression re(key); | ||||||
|  | 	return 	_settings->allKeys().filter(re); | ||||||
|  | } | ||||||
|  |  | ||||||
| void gpclient::helper::settings::save(const QString &key, const QVariant &value) | void gpclient::helper::settings::save(const QString &key, const QVariant &value) | ||||||
| { | { | ||||||
|     _settings->setValue(key, value); |     _settings->setValue(key, value); | ||||||
| @@ -127,4 +138,41 @@ void gpclient::helper::settings::clear() | |||||||
|             _settings->remove(key); |             _settings->remove(key); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,8 +34,12 @@ namespace gpclient { | |||||||
|             static const QStringList reservedKeys {"extraArgs", "clientos"}; |             static const QStringList reservedKeys {"extraArgs", "clientos"}; | ||||||
|  |  | ||||||
|             QVariant get(const QString &key, const QVariant &defaultValue = QVariant()); |             QVariant get(const QString &key, const QVariant &defaultValue = QVariant()); | ||||||
|  |             QStringList get_all(const QString &key, const QVariant &defaultValue = QVariant()); | ||||||
|             void save(const QString &key, const QVariant &value); |             void save(const QString &key, const QVariant &value); | ||||||
|             void clear(); |             void clear(); | ||||||
|  |  | ||||||
|  |             bool secureSave(const QString &key, const QString &value); | ||||||
|  |             bool secureGet(const QString &key, QString &value); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,9 @@ | |||||||
| #include <QtCore/QUrlQuery> | #include <QtCore/QUrlQuery> | ||||||
|  |  | ||||||
| #include "loginparams.h" | #include "loginparams.h" | ||||||
|  | #include "gphelper.h" | ||||||
|  |  | ||||||
|  | using namespace gpclient::helper; | ||||||
|  |  | ||||||
| LoginParams::LoginParams(const QString clientos) | LoginParams::LoginParams(const QString clientos) | ||||||
| { | { | ||||||
| @@ -14,13 +17,18 @@ LoginParams::LoginParams(const QString clientos) | |||||||
|     params.addQueryItem("ok", "Login"); |     params.addQueryItem("ok", "Login"); | ||||||
|     params.addQueryItem("direct", "yes"); |     params.addQueryItem("direct", "yes"); | ||||||
|     params.addQueryItem("clientVer", "4100"); |     params.addQueryItem("clientVer", "4100"); | ||||||
|     params.addQueryItem("os-version", QUrl::toPercentEncoding(QSysInfo::prettyProductName())); |  | ||||||
|  |  | ||||||
|     // add the clientos parameter if not empty |     // add the clientos parameter if not empty | ||||||
|     if (!clientos.isEmpty()) { |     if (!clientos.isEmpty()) { | ||||||
|         params.addQueryItem("clientos", clientos); |         params.addQueryItem("clientos", clientos); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     auto osVersion = settings::get("os-version", "").toString(); | ||||||
|  |     if (osVersion.isEmpty()) { | ||||||
|  |         osVersion = QSysInfo::prettyProductName(); | ||||||
|  |     } | ||||||
|  |     params.addQueryItem("os-version", QUrl::toPercentEncoding(osVersion)); | ||||||
|  |  | ||||||
|     params.addQueryItem("portal-userauthcookie", ""); |     params.addQueryItem("portal-userauthcookie", ""); | ||||||
|     params.addQueryItem("portal-prelogonuserauthcookie", ""); |     params.addQueryItem("portal-prelogonuserauthcookie", ""); | ||||||
|     params.addQueryItem("prelogin-cookie", ""); |     params.addQueryItem("prelogin-cookie", ""); | ||||||
|   | |||||||
| @@ -21,10 +21,10 @@ int main(int argc, char *argv[]) | |||||||
|     plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender(plog::streamStdErr); |     plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender(plog::streamStdErr); | ||||||
|     plog::init(plog::debug, &consoleAppender); |     plog::init(plog::debug, &consoleAppender); | ||||||
|  |  | ||||||
|     PLOGI << "GlobalProtect started, version: " << VERSION; |     LOGI << "GlobalProtect started, version: " << VERSION; | ||||||
|  |  | ||||||
|     QString port = QString::fromLocal8Bit(qgetenv(ENV_CDP_PORT)); |     auto port = QString::fromLocal8Bit(qgetenv(ENV_CDP_PORT)); | ||||||
|     QString hidpiSupport = QString::fromLocal8Bit(qgetenv(QT_AUTO_SCREEN_SCALE_FACTOR)); |     auto hidpiSupport = QString::fromLocal8Bit(qgetenv(QT_AUTO_SCREEN_SCALE_FACTOR)); | ||||||
|  |  | ||||||
|     if (port.isEmpty()) { |     if (port.isEmpty()) { | ||||||
|         qputenv(ENV_CDP_PORT, "12315"); |         qputenv(ENV_CDP_PORT, "12315"); | ||||||
| @@ -46,16 +46,16 @@ int main(int argc, char *argv[]) | |||||||
|       {"json", "Write the result of the handshake with the GlobalConnect server to stdout as JSON and terminate. Useful for scripting."}, |       {"json", "Write the result of the handshake with the GlobalConnect server to stdout as JSON and terminate. Useful for scripting."}, | ||||||
|       {"now", "Do not show the dialog with the connect button; connect immediately instead."}, |       {"now", "Do not show the dialog with the connect button; connect immediately instead."}, | ||||||
|       {"start-minimized", "Launch the client minimized."}, |       {"start-minimized", "Launch the client minimized."}, | ||||||
|  |       {"reset", "Reset the client's settings."}, | ||||||
|     }); |     }); | ||||||
|     parser.process(app); |     parser.process(app); | ||||||
|  |  | ||||||
|     const QStringList positional = parser.positionalArguments(); |     const auto positional = parser.positionalArguments(); | ||||||
|  |  | ||||||
|     IVpn *vpn = parser.isSet("json") // yes it leaks, but this is cleared on exit anyway |     auto *vpn = parser.isSet("json") // yes it leaks, but this is cleared on exit anyway | ||||||
|       ? static_cast<IVpn*>(new VpnJson(nullptr)) // Print to stdout and exit |       ? static_cast<IVpn*>(new VpnJson(nullptr)) // Print to stdout and exit | ||||||
|       : static_cast<IVpn*>(new VpnDbus(nullptr)); // Contact GPService daemon via dbus |       : static_cast<IVpn*>(new VpnDbus(nullptr)); // Contact GPService daemon via dbus | ||||||
|     GPClient w(nullptr, vpn); |     GPClient w(nullptr, vpn); | ||||||
|     parser.isSet("start-minimized") ? w.showMinimized() : w.show(); |  | ||||||
|  |  | ||||||
|     if (positional.size() > 0) { |     if (positional.size() > 0) { | ||||||
|       w.portal(positional.at(0)); |       w.portal(positional.at(0)); | ||||||
| @@ -76,11 +76,20 @@ int main(int argc, char *argv[]) | |||||||
|     sigwatch.watchForSignal(SIGHUP); |     sigwatch.watchForSignal(SIGHUP); | ||||||
|     QObject::connect(&sigwatch, &UnixSignalWatcher::unixSignal, &w, &GPClient::quit); |     QObject::connect(&sigwatch, &UnixSignalWatcher::unixSignal, &w, &GPClient::quit); | ||||||
|  |  | ||||||
|  |     if (parser.isSet("json")) { | ||||||
|  |         QObject::connect(static_cast<VpnJson*>(vpn), &VpnJson::connected, &w, &GPClient::quit); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (parser.isSet("reset")) { | ||||||
|  |         w.reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (parser.isSet("now")) { |     if (parser.isSet("now")) { | ||||||
|       w.doConnect(); |       w.doConnect(); | ||||||
|     } |     } else if (parser.isSet("start-minimized")) { | ||||||
|     if (parser.isSet("json")) { |       w.showMinimized(); | ||||||
|       QObject::connect(static_cast<VpnJson*>(vpn), &VpnJson::connected, &w, &GPClient::quit); |     } else { | ||||||
|  |       w.show(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return app.exec(); |     return app.exec(); | ||||||
|   | |||||||
| @@ -1,64 +0,0 @@ | |||||||
| #include <QtGui/QCloseEvent> |  | ||||||
|  |  | ||||||
| #include "normalloginwindow.h" |  | ||||||
| #include "ui_normalloginwindow.h" |  | ||||||
|  |  | ||||||
| NormalLoginWindow::NormalLoginWindow(QWidget *parent) : |  | ||||||
|     QDialog(parent), |  | ||||||
|     ui(new Ui::NormalLoginWindow) |  | ||||||
| { |  | ||||||
|     ui->setupUi(this); |  | ||||||
|     setWindowTitle("GlobalProtect Login"); |  | ||||||
|     setFixedSize(width(), height()); |  | ||||||
|     setModal(true); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| NormalLoginWindow::~NormalLoginWindow() |  | ||||||
| { |  | ||||||
|     delete ui; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::setAuthMessage(QString message) |  | ||||||
| { |  | ||||||
|     ui->authMessage->setText(message); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::setUsernameLabel(QString label) |  | ||||||
| { |  | ||||||
|     ui->username->setPlaceholderText(label); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::setPasswordLabel(QString label) |  | ||||||
| { |  | ||||||
|     ui->password->setPlaceholderText(label); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::setPortalAddress(QString portal) |  | ||||||
| { |  | ||||||
|     ui->portalAddress->setText(portal); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::setProcessing(bool isProcessing) |  | ||||||
| { |  | ||||||
|     ui->username->setReadOnly(isProcessing); |  | ||||||
|     ui->password->setReadOnly(isProcessing); |  | ||||||
|     ui->loginButton->setDisabled(isProcessing); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::on_loginButton_clicked() |  | ||||||
| { |  | ||||||
|     const QString username = ui->username->text().trimmed(); |  | ||||||
|     const QString password = ui->password->text().trimmed(); |  | ||||||
|  |  | ||||||
|     if (username.isEmpty() || password.isEmpty()) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     emit performLogin(username, password); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void NormalLoginWindow::closeEvent(QCloseEvent *event) |  | ||||||
| { |  | ||||||
|     event->accept(); |  | ||||||
|     reject(); |  | ||||||
| } |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| #ifndef PORTALAUTHWINDOW_H |  | ||||||
| #define PORTALAUTHWINDOW_H |  | ||||||
|  |  | ||||||
| #include <QtWidgets/QDialog> |  | ||||||
|  |  | ||||||
| namespace Ui { |  | ||||||
| class NormalLoginWindow; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class NormalLoginWindow : public QDialog |  | ||||||
| { |  | ||||||
|     Q_OBJECT |  | ||||||
|  |  | ||||||
| public: |  | ||||||
|     explicit NormalLoginWindow(QWidget *parent = nullptr); |  | ||||||
|     ~NormalLoginWindow(); |  | ||||||
|  |  | ||||||
|     void setAuthMessage(QString); |  | ||||||
|     void setUsernameLabel(QString); |  | ||||||
|     void setPasswordLabel(QString); |  | ||||||
|     void setPortalAddress(QString); |  | ||||||
|  |  | ||||||
|     void setProcessing(bool isProcessing); |  | ||||||
|  |  | ||||||
| private slots: |  | ||||||
|     void on_loginButton_clicked(); |  | ||||||
|  |  | ||||||
| signals: |  | ||||||
|     void performLogin(QString username, QString password); |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     Ui::NormalLoginWindow *ui; |  | ||||||
|  |  | ||||||
|     void closeEvent(QCloseEvent *event); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #endif // PORTALAUTHWINDOW_H |  | ||||||
| @@ -3,7 +3,7 @@ | |||||||
|  |  | ||||||
| #include "portalauthenticator.h" | #include "portalauthenticator.h" | ||||||
| #include "gphelper.h" | #include "gphelper.h" | ||||||
| #include "normalloginwindow.h" | #include "standardloginwindow.h" | ||||||
| #include "samlloginwindow.h" | #include "samlloginwindow.h" | ||||||
| #include "loginparams.h" | #include "loginparams.h" | ||||||
| #include "preloginresponse.h" | #include "preloginresponse.h" | ||||||
| @@ -25,12 +25,14 @@ PortalAuthenticator::PortalAuthenticator(const QString& portal, const QString& c | |||||||
|  |  | ||||||
| PortalAuthenticator::~PortalAuthenticator() | PortalAuthenticator::~PortalAuthenticator() | ||||||
| { | { | ||||||
|     delete normalLoginWindow; |     delete standardLoginWindow; | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalAuthenticator::authenticate() | void PortalAuthenticator::authenticate() | ||||||
| { | { | ||||||
|     PLOGI << "Preform portal prelogin at " << preloginUrl; |     attempts++; | ||||||
|  |  | ||||||
|  |     LOGI << QString("(%1/%2) attempts").arg(attempts).arg(MAX_ATTEMPTS) << ", perform portal prelogin at " << preloginUrl; | ||||||
|  |  | ||||||
|     QNetworkReply *reply = createRequest(preloginUrl); |     QNetworkReply *reply = createRequest(preloginUrl); | ||||||
|     connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onPreloginFinished); |     connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onPreloginFinished); | ||||||
| @@ -38,20 +40,20 @@ void PortalAuthenticator::authenticate() | |||||||
|  |  | ||||||
| void PortalAuthenticator::onPreloginFinished() | void PortalAuthenticator::onPreloginFinished() | ||||||
| { | { | ||||||
|     QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); |     auto *reply = qobject_cast<QNetworkReply*>(sender()); | ||||||
|  |  | ||||||
|     if (reply->error()) { |     if (reply->error()) { | ||||||
|         PLOGE << QString("Error occurred while accessing %1, %2").arg(preloginUrl, reply->errorString()); |         LOGE << QString("Error occurred while accessing %1, %2").arg(preloginUrl, reply->errorString()); | ||||||
|         emit preloginFailed("Error occurred on the portal prelogin interface."); |         emit preloginFailed("Error occurred on the portal prelogin interface."); | ||||||
|         delete reply; |         delete reply; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PLOGI << "Portal prelogin succeeded."; |     LOGI << "Portal prelogin succeeded."; | ||||||
|  |  | ||||||
|     preloginResponse = PreloginResponse::parse(reply->readAll()); |     preloginResponse = PreloginResponse::parse(reply->readAll()); | ||||||
|  |  | ||||||
|     PLOGI << "Finished parsing the prelogin response. The region field is: " << preloginResponse.region(); |     LOGI << "Finished parsing the prelogin response. The region field is: " << preloginResponse.region(); | ||||||
|  |  | ||||||
|     if (preloginResponse.hasSamlAuthFields()) { |     if (preloginResponse.hasSamlAuthFields()) { | ||||||
|         // Do SAML authentication |         // Do SAML authentication | ||||||
| @@ -60,7 +62,7 @@ void PortalAuthenticator::onPreloginFinished() | |||||||
|         // Do normal username/password authentication |         // Do normal username/password authentication | ||||||
|         tryAutoLogin(); |         tryAutoLogin(); | ||||||
|     } else { |     } else { | ||||||
|         PLOGE << QString("Unknown prelogin response for %1 got %2").arg(preloginUrl).arg(QString::fromUtf8(preloginResponse.rawResponse())); |         LOGE << QString("Unknown prelogin response for %1 got %2").arg(preloginUrl).arg(QString::fromUtf8(preloginResponse.rawResponse())); | ||||||
|         emit preloginFailed("Unknown response for portal prelogin interface."); |         emit preloginFailed("Unknown response for portal prelogin interface."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -73,7 +75,7 @@ void PortalAuthenticator::tryAutoLogin() | |||||||
|     const QString password = settings::get("password").toString(); |     const QString password = settings::get("password").toString(); | ||||||
|  |  | ||||||
|     if (!username.isEmpty() && !password.isEmpty()) { |     if (!username.isEmpty() && !password.isEmpty()) { | ||||||
|         PLOGI << "Trying auto login using the saved credentials"; |         LOGI << "Trying auto login using the saved credentials"; | ||||||
|         isAutoLogin = true; |         isAutoLogin = true; | ||||||
|         fetchConfig(settings::get("username").toString(), settings::get("password").toString()); |         fetchConfig(settings::get("username").toString(), settings::get("password").toString()); | ||||||
|     } else { |     } else { | ||||||
| @@ -83,25 +85,21 @@ void PortalAuthenticator::tryAutoLogin() | |||||||
|  |  | ||||||
| void PortalAuthenticator::normalAuth() | void PortalAuthenticator::normalAuth() | ||||||
| { | { | ||||||
|     PLOGI << "Trying to launch the normal login window..."; |     LOGI << "Trying to launch the normal login window..."; | ||||||
|  |  | ||||||
|     normalLoginWindow = new NormalLoginWindow; |     standardLoginWindow = new StandardLoginWindow {portal, preloginResponse.labelUsername(), preloginResponse.labelPassword(), preloginResponse.authMessage() }; | ||||||
|     normalLoginWindow->setPortalAddress(portal); |  | ||||||
|     normalLoginWindow->setAuthMessage(preloginResponse.authMessage()); |  | ||||||
|     normalLoginWindow->setUsernameLabel(preloginResponse.labelUsername()); |  | ||||||
|     normalLoginWindow->setPasswordLabel(preloginResponse.labelPassword()); |  | ||||||
|  |  | ||||||
|     // Do login |     // Do login | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::performLogin, this, &PortalAuthenticator::onPerformNormalLogin); |     connect(standardLoginWindow, &StandardLoginWindow::performLogin, this, &PortalAuthenticator::onPerformNormalLogin); | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::rejected, this, &PortalAuthenticator::onLoginWindowRejected); |     connect(standardLoginWindow, &StandardLoginWindow::rejected, this, &PortalAuthenticator::onLoginWindowRejected); | ||||||
|     connect(normalLoginWindow, &NormalLoginWindow::finished, this, &PortalAuthenticator::onLoginWindowFinished); |     connect(standardLoginWindow, &StandardLoginWindow::finished, this, &PortalAuthenticator::onLoginWindowFinished); | ||||||
|  |  | ||||||
|     normalLoginWindow->show(); |     standardLoginWindow->show(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalAuthenticator::onPerformNormalLogin(const QString &username, const QString &password) | void PortalAuthenticator::onPerformNormalLogin(const QString &username, const QString &password) | ||||||
| { | { | ||||||
|     normalLoginWindow->setProcessing(true); |     standardLoginWindow->setProcessing(true); | ||||||
|     fetchConfig(username, password); |     fetchConfig(username, password); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -112,19 +110,28 @@ void PortalAuthenticator::onLoginWindowRejected() | |||||||
|  |  | ||||||
| void PortalAuthenticator::onLoginWindowFinished() | void PortalAuthenticator::onLoginWindowFinished() | ||||||
| { | { | ||||||
|     delete normalLoginWindow; |     delete standardLoginWindow; | ||||||
|     normalLoginWindow = nullptr; |     standardLoginWindow = nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalAuthenticator::samlAuth() | void PortalAuthenticator::samlAuth() | ||||||
| { | { | ||||||
|     PLOGI << "Trying to perform SAML login with saml-method " << preloginResponse.samlMethod(); |     LOGI << "Trying to perform SAML login with saml-method " << preloginResponse.samlMethod(); | ||||||
|  |  | ||||||
|     SAMLLoginWindow *loginWindow = new SAMLLoginWindow; |     auto *loginWindow = new SAMLLoginWindow(this->portal); | ||||||
|  |  | ||||||
|     connect(loginWindow, &SAMLLoginWindow::success, this, &PortalAuthenticator::onSAMLLoginSuccess); |     connect(loginWindow, &SAMLLoginWindow::success, [this, loginWindow](const QMap<QString, QString> samlResult) { | ||||||
|     connect(loginWindow, &SAMLLoginWindow::fail, this, &PortalAuthenticator::onSAMLLoginFail); |         this->onSAMLLoginSuccess(samlResult); | ||||||
|     connect(loginWindow, &SAMLLoginWindow::rejected, this, &PortalAuthenticator::onLoginWindowRejected); |         loginWindow->deleteLater(); | ||||||
|  |     }); | ||||||
|  |     connect(loginWindow, &SAMLLoginWindow::fail, [this, loginWindow](const QString &code, const QString msg) { | ||||||
|  |         this->onSAMLLoginFail(code, msg); | ||||||
|  |         loginWindow->deleteLater(); | ||||||
|  |     }); | ||||||
|  |     connect(loginWindow, &SAMLLoginWindow::rejected, [this, loginWindow]() { | ||||||
|  |         this->onLoginWindowRejected(); | ||||||
|  |         loginWindow->deleteLater(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     loginWindow->login(preloginResponse.samlMethod(), preloginResponse.samlRequest(), preloginUrl); |     loginWindow->login(preloginResponse.samlMethod(), preloginResponse.samlRequest(), preloginUrl); | ||||||
| } | } | ||||||
| @@ -132,17 +139,22 @@ void PortalAuthenticator::samlAuth() | |||||||
| void PortalAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> samlResult) | void PortalAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> samlResult) | ||||||
| { | { | ||||||
|     if (samlResult.contains("preloginCookie")) { |     if (samlResult.contains("preloginCookie")) { | ||||||
|         PLOGI << "SAML login succeeded, got the prelogin-cookie " << samlResult.value("preloginCookie"); |         LOGI << "SAML login succeeded, got the prelogin-cookie"; | ||||||
|     } else { |     } else { | ||||||
|         PLOGI << "SAML login succeeded, got the portal-userauthcookie " << samlResult.value("userAuthCookie"); |         LOGI << "SAML login succeeded, got the portal-userauthcookie"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie"), samlResult.value("userAuthCookie")); |     fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie"), samlResult.value("userAuthCookie")); | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalAuthenticator::onSAMLLoginFail(const QString msg) | void PortalAuthenticator::onSAMLLoginFail(const QString &code, const QString &msg) | ||||||
| { | { | ||||||
|     emitFail(msg); |     if (code == "ERR002" && attempts < MAX_ATTEMPTS) { | ||||||
|  |         LOGI << "Failed to authenticate, trying to re-authenticate..."; | ||||||
|  |         authenticate(); | ||||||
|  |     } else { | ||||||
|  |         emitFail(msg); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie, QString userAuthCookie) | void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie, QString userAuthCookie) | ||||||
| @@ -158,9 +170,9 @@ void PortalAuthenticator::fetchConfig(QString username, QString password, QStrin | |||||||
|     this->username = username; |     this->username = username; | ||||||
|     this->password = password; |     this->password = password; | ||||||
|  |  | ||||||
|     PLOGI << "Fetching the portal config from " << configUrl << " for user: " << username; |     LOGI << "Fetching the portal config from " << configUrl; | ||||||
|  |  | ||||||
|     QNetworkReply *reply = createRequest(configUrl, loginParams.toUtf8()); |     auto *reply = createRequest(configUrl, loginParams.toUtf8()); | ||||||
|     connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onFetchConfigFinished); |     connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onFetchConfigFinished); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -169,11 +181,11 @@ void PortalAuthenticator::onFetchConfigFinished() | |||||||
|     QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); |     QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); | ||||||
|  |  | ||||||
|     if (reply->error()) { |     if (reply->error()) { | ||||||
|         PLOGE << QString("Failed to fetch the portal config from %1, %2").arg(configUrl).arg(reply->errorString()); |         LOGE << QString("Failed to fetch the portal config from %1, %2").arg(configUrl).arg(reply->errorString()); | ||||||
|  |  | ||||||
|         // Login failed, enable the fields of the normal login window |         // Login failed, enable the fields of the normal login window | ||||||
|         if (normalLoginWindow) { |         if (standardLoginWindow) { | ||||||
|             normalLoginWindow->setProcessing(false); |             standardLoginWindow->setProcessing(false); | ||||||
|             openMessageBox("Portal login failed.", "Please check your credentials and try again."); |             openMessageBox("Portal login failed.", "Please check your credentials and try again."); | ||||||
|         } else if (isAutoLogin) { |         } else if (isAutoLogin) { | ||||||
|             isAutoLogin = false; |             isAutoLogin = false; | ||||||
| @@ -184,7 +196,7 @@ void PortalAuthenticator::onFetchConfigFinished() | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PLOGI << "Fetch the portal config succeeded."; |     LOGI << "Fetch the portal config succeeded."; | ||||||
|     PortalConfigResponse response = PortalConfigResponse::parse(reply->readAll()); |     PortalConfigResponse response = PortalConfigResponse::parse(reply->readAll()); | ||||||
|  |  | ||||||
|     // Add the username & password to the response object |     // Add the username & password to the response object | ||||||
| @@ -192,10 +204,10 @@ void PortalAuthenticator::onFetchConfigFinished() | |||||||
|     response.setPassword(password); |     response.setPassword(password); | ||||||
|  |  | ||||||
|     // Close the login window |     // Close the login window | ||||||
|     if (normalLoginWindow) { |     if (standardLoginWindow) { | ||||||
|         PLOGI << "Closing the NormalLoginWindow..."; |         LOGI << "Closing the StandardLoginWindow..."; | ||||||
|  |  | ||||||
|         normalLoginWindow->close(); |         standardLoginWindow->close(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     emit success(response, preloginResponse.region()); |     emit success(response, preloginResponse.region()); | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include <QtCore/QObject> | #include <QtCore/QObject> | ||||||
|  |  | ||||||
| #include "portalconfigresponse.h" | #include "portalconfigresponse.h" | ||||||
| #include "normalloginwindow.h" | #include "standardloginwindow.h" | ||||||
| #include "samlloginwindow.h" | #include "samlloginwindow.h" | ||||||
| #include "preloginresponse.h" | #include "preloginresponse.h" | ||||||
|  |  | ||||||
| @@ -30,10 +30,12 @@ private slots: | |||||||
|     void onLoginWindowRejected(); |     void onLoginWindowRejected(); | ||||||
|     void onLoginWindowFinished(); |     void onLoginWindowFinished(); | ||||||
|     void onSAMLLoginSuccess(const QMap<QString, QString> samlResult); |     void onSAMLLoginSuccess(const QMap<QString, QString> samlResult); | ||||||
|     void onSAMLLoginFail(const QString msg); |     void onSAMLLoginFail(const QString &code, const QString &msg); | ||||||
|     void onFetchConfigFinished(); |     void onFetchConfigFinished(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     static const auto MAX_ATTEMPTS{ 5 }; | ||||||
|  |  | ||||||
|     QString portal; |     QString portal; | ||||||
|     QString clientos; |     QString clientos; | ||||||
|     QString preloginUrl; |     QString preloginUrl; | ||||||
| @@ -41,11 +43,12 @@ private: | |||||||
|     QString username; |     QString username; | ||||||
|     QString password; |     QString password; | ||||||
|  |  | ||||||
|  |     int attempts{ 0 }; | ||||||
|     PreloginResponse preloginResponse; |     PreloginResponse preloginResponse; | ||||||
|  |  | ||||||
|     bool isAutoLogin { false }; |     bool isAutoLogin{ false }; | ||||||
|  |  | ||||||
|     NormalLoginWindow *normalLoginWindow{ nullptr }; |     StandardLoginWindow *standardLoginWindow { nullptr }; | ||||||
|  |  | ||||||
|     void tryAutoLogin(); |     void tryAutoLogin(); | ||||||
|     void normalAuth(); |     void normalAuth(); | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ PortalConfigResponse::~PortalConfigResponse() | |||||||
|  |  | ||||||
| PortalConfigResponse PortalConfigResponse::parse(const QByteArray xml) | PortalConfigResponse PortalConfigResponse::parse(const QByteArray xml) | ||||||
| { | { | ||||||
|     PLOGI << "Start parsing the portal configuration..."; |     LOGI << "Start parsing the portal configuration..."; | ||||||
|  |  | ||||||
|     QXmlStreamReader xmlReader(xml); |     QXmlStreamReader xmlReader(xml); | ||||||
|     PortalConfigResponse response; |     PortalConfigResponse response; | ||||||
| @@ -29,17 +29,17 @@ PortalConfigResponse PortalConfigResponse::parse(const QByteArray xml) | |||||||
|         QString name = xmlReader.name().toString(); |         QString name = xmlReader.name().toString(); | ||||||
|  |  | ||||||
|         if (name == xmlUserAuthCookie) { |         if (name == xmlUserAuthCookie) { | ||||||
|             PLOGI << "Start reading " << name; |             LOGI << "Start reading " << name; | ||||||
|             response.setUserAuthCookie(xmlReader.readElementText()); |             response.setUserAuthCookie(xmlReader.readElementText()); | ||||||
|         } else if (name == xmlPrelogonUserAuthCookie) { |         } else if (name == xmlPrelogonUserAuthCookie) { | ||||||
|             PLOGI << "Start reading " << name; |             LOGI << "Start reading " << name; | ||||||
|             response.setPrelogonUserAuthCookie(xmlReader.readElementText()); |             response.setPrelogonUserAuthCookie(xmlReader.readElementText()); | ||||||
|         } else if (name == xmlGateways) { |         } else if (name == xmlGateways) { | ||||||
|             response.setAllGateways(parseGateways(xmlReader)); |             response.setAllGateways(parseGateways(xmlReader)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PLOGI << "Finished parsing portal configuration."; |     LOGI << "Finished parsing portal configuration."; | ||||||
|  |  | ||||||
|     return response; |     return response; | ||||||
| } | } | ||||||
| @@ -61,7 +61,7 @@ QString PortalConfigResponse::password() const | |||||||
|  |  | ||||||
| QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader) | QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader) | ||||||
| { | { | ||||||
|     PLOGI << "Start parsing the gateways from portal configuration..."; |     LOGI << "Start parsing the gateways from portal configuration..."; | ||||||
|  |  | ||||||
|     QList<GPGateway> gateways; |     QList<GPGateway> gateways; | ||||||
|  |  | ||||||
| @@ -83,46 +83,51 @@ QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PLOGI << "Finished parsing the gateways."; |     LOGI << "Finished parsing the gateways."; | ||||||
|  |  | ||||||
|     return gateways; |     return gateways; | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalConfigResponse::parseGateway(QXmlStreamReader &reader, GPGateway &gateway) { | void PortalConfigResponse::parseGateway(QXmlStreamReader &reader, GPGateway &gateway) { | ||||||
|     PLOGI << "Start parsing gateway..."; |     LOGI << "Start parsing gateway..."; | ||||||
|  |  | ||||||
|     auto finished = false; |     auto finished = false; | ||||||
|     while (!finished) { |     while (!finished) { | ||||||
|         if (reader.name() == "entry") { |         if (reader.name() == "entry" && reader.isStartElement()) { | ||||||
|             auto address = reader.attributes().value("name").toString(); |             auto address = reader.attributes().value("name").toString(); | ||||||
|             gateway.setAddress(address); |             gateway.setAddress(address); | ||||||
|         } else if (reader.name() == "description") { // gateway name |         } else if (reader.name() == "description" && reader.isStartElement()) { // gateway name | ||||||
|             gateway.setName(reader.readElementText()); |             gateway.setName(reader.readElementText()); | ||||||
|         } else if (reader.name() == "priority-rule") { // priority rules |         } else if (reader.name() == "priority-rule" && reader.isStartElement()) { // priority rules | ||||||
|             parsePriorityRule(reader, gateway); |             parsePriorityRule(reader, gateway); | ||||||
|         } |         } | ||||||
|         finished = !reader.readNextStartElement(); |  | ||||||
|  |         auto result = reader.readNext(); | ||||||
|  |         finished = result == QXmlStreamReader::Invalid || (reader.name() == "entry" && reader.isEndElement()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void PortalConfigResponse::parsePriorityRule(QXmlStreamReader &reader, GPGateway &gateway) { | void PortalConfigResponse::parsePriorityRule(QXmlStreamReader &reader, GPGateway &gateway) { | ||||||
|     PLOGI << "Start parsing priority rule..."; |     LOGI << "Start parsing priority rule..."; | ||||||
|  |  | ||||||
|     QMap<QString, int> priorityRules; |     QMap<QString, int> priorityRules; | ||||||
|     auto finished = false; |     auto finished = false; | ||||||
|  |  | ||||||
|     while (!finished) { |     while (!finished) { | ||||||
|         // Parse the priority-rule -> entry |         // Parse the priority-rule -> entry | ||||||
|         if (reader.name() == "entry") { |         if (reader.name() == "entry" && reader.isStartElement()) { | ||||||
|             auto ruleName = reader.attributes().value("name").toString(); |             auto ruleName = reader.attributes().value("name").toString(); | ||||||
|             // move to the priority value |             // move to the priority value | ||||||
|             while (reader.name() != "priority") { |             while (reader.readNextStartElement()) { | ||||||
|                 reader.readNextStartElement(); |                 if (reader.name() == "priority") { | ||||||
|  |                     auto priority = reader.readElementText().toInt(); | ||||||
|  |                     priorityRules.insert(ruleName, priority); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             auto priority = reader.readElementText().toInt(); |  | ||||||
|             priorityRules.insert(ruleName, priority); |  | ||||||
|         } |         } | ||||||
|         finished = !reader.readNextStartElement(); |         auto result = reader.readNext(); | ||||||
|  |         finished = result == QXmlStreamReader::Invalid || (reader.name() == "priority-rule" && reader.isEndElement()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     gateway.setPriorityRules(priorityRules); |     gateway.setPriorityRules(priorityRules); | ||||||
| @@ -167,4 +172,3 @@ void PortalConfigResponse::setPrelogonUserAuthCookie(const QString cookie) | |||||||
| { | { | ||||||
|     m_prelogonAuthCookie = cookie; |     m_prelogonAuthCookie = cookie; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ PreloginResponse::PreloginResponse() | |||||||
|  |  | ||||||
| PreloginResponse PreloginResponse::parse(const QByteArray& xml) | PreloginResponse PreloginResponse::parse(const QByteArray& xml) | ||||||
| { | { | ||||||
|     PLOGI << "Start parsing the prelogin response..."; |     LOGI << "Start parsing the prelogin response..."; | ||||||
|  |  | ||||||
|     QXmlStreamReader xmlReader(xml); |     QXmlStreamReader xmlReader(xml); | ||||||
|     PreloginResponse response; |     PreloginResponse response; | ||||||
|   | |||||||
| @@ -1,11 +1,13 @@ | |||||||
| #include <QtWidgets/QVBoxLayout> | #include <QtWidgets/QVBoxLayout> | ||||||
| #include <QtWebEngineWidgets/QWebEngineProfile> | #include <QtWebEngineWidgets/QWebEngineProfile> | ||||||
| #include <QtWebEngineWidgets/QWebEngineView> | #include <QtWebEngineWidgets/QWebEngineView> | ||||||
|  | #include <QWebEngineCookieStore> | ||||||
| #include <plog/Log.h> | #include <plog/Log.h> | ||||||
|  |  | ||||||
|  | #include "INIReader.h" | ||||||
| #include "samlloginwindow.h" | #include "samlloginwindow.h" | ||||||
|  |  | ||||||
| SAMLLoginWindow::SAMLLoginWindow(QWidget *parent) | SAMLLoginWindow::SAMLLoginWindow(QString portal, QWidget *parent) | ||||||
|     : QDialog(parent) |     : QDialog(parent) | ||||||
|     , webView(new EnhancedWebView(this)) |     , webView(new EnhancedWebView(this)) | ||||||
| { | { | ||||||
| @@ -16,17 +18,23 @@ SAMLLoginWindow::SAMLLoginWindow(QWidget *parent) | |||||||
|     QVBoxLayout *verticalLayout = new QVBoxLayout(this); |     QVBoxLayout *verticalLayout = new QVBoxLayout(this); | ||||||
|     webView->setUrl(QUrl("about:blank")); |     webView->setUrl(QUrl("about:blank")); | ||||||
|     webView->setAttribute(Qt::WA_DeleteOnClose); |     webView->setAttribute(Qt::WA_DeleteOnClose); | ||||||
|     // webView->page()->profile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); |  | ||||||
|     verticalLayout->addWidget(webView); |     verticalLayout->addWidget(webView); | ||||||
|  |  | ||||||
|     webView->initialize(); |     webView->initialize(); | ||||||
|     connect(webView, &EnhancedWebView::responseReceived, this, &SAMLLoginWindow::onResponseReceived); |     connect(webView, &EnhancedWebView::responseReceived, this, &SAMLLoginWindow::onResponseReceived); | ||||||
|     connect(webView, &EnhancedWebView::loadFinished, this, &SAMLLoginWindow::onLoadFinished); |     connect(webView, &EnhancedWebView::loadFinished, this, &SAMLLoginWindow::onLoadFinished); | ||||||
| } |  | ||||||
|  |  | ||||||
| SAMLLoginWindow::~SAMLLoginWindow() |     // Portal | ||||||
| { |     this->portal = portal; | ||||||
|     delete webView; |  | ||||||
|  |     // Show the login window automatically when exceeds the MAX_WAIT_TIME | ||||||
|  |     QTimer::singleShot(MAX_WAIT_TIME, this, [this]() { | ||||||
|  |         if (failed) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         LOGI << "MAX_WAIT_TIME exceeded, display the login window."; | ||||||
|  |         this->show(); | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| void SAMLLoginWindow::closeEvent(QCloseEvent *event) | void SAMLLoginWindow::closeEvent(QCloseEvent *event) | ||||||
| @@ -35,47 +43,55 @@ void SAMLLoginWindow::closeEvent(QCloseEvent *event) | |||||||
|     reject(); |     reject(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void SAMLLoginWindow::login(const QString samlMethod, const QString samlRequest, const QString preloingUrl) | void SAMLLoginWindow::login(const QString samlMethod, const QString samlRequest, const QString preloginUrl) | ||||||
| { | { | ||||||
|  |     webView->page()->profile()->cookieStore()->deleteSessionCookies(); | ||||||
|  |  | ||||||
|     if (samlMethod == "POST") { |     if (samlMethod == "POST") { | ||||||
|         webView->setHtml(samlRequest, preloingUrl); |         webView->setHtml(samlRequest, preloginUrl); | ||||||
|     } else if (samlMethod == "REDIRECT") { |     } else if (samlMethod == "REDIRECT") { | ||||||
|  |         LOGI << "Redirect to " << samlRequest; | ||||||
|         webView->load(samlRequest); |         webView->load(samlRequest); | ||||||
|     } else { |     } else { | ||||||
|         PLOGE << "Unknown saml-auth-method expected POST or REDIRECT, got " << samlMethod; |         LOGE << "Unknown saml-auth-method expected POST or REDIRECT, got " << samlMethod; | ||||||
|         emit fail("Unknown saml-auth-method, got " + samlMethod); |         failed = true; | ||||||
|  |         emit fail("ERR001", "Unknown saml-auth-method, got " + samlMethod); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void SAMLLoginWindow::onResponseReceived(QJsonObject params) | void SAMLLoginWindow::onResponseReceived(QJsonObject params) | ||||||
| { | { | ||||||
|     QString type = params.value("type").toString(); |     const auto type = params.value("type").toString(); | ||||||
|     // Skip non-document response |     // Skip non-document response | ||||||
|     if (type != "Document") { |     if (type != "Document") { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     QJsonObject response = params.value("response").toObject(); |     auto response = params.value("response").toObject(); | ||||||
|     QJsonObject headers = response.value("headers").toObject(); |     auto headers = response.value("headers").toObject(); | ||||||
|  |  | ||||||
|     const QString username = headers.value("saml-username").toString(); |     LOGI << "Trying to receive authentication cookie from " << response.value("url").toString(); | ||||||
|     const QString preloginCookie = headers.value("prelogin-cookie").toString(); |  | ||||||
|     const QString userAuthCookie = headers.value("portal-userauthcookie").toString(); |  | ||||||
|  |  | ||||||
|     LOGI << "Response received from " << response.value("url").toString(); |     const auto username = headers.value("saml-username").toString(); | ||||||
|  |     const auto preloginCookie = headers.value("prelogin-cookie").toString(); | ||||||
|  |     const auto userAuthCookie = headers.value("portal-userauthcookie").toString(); | ||||||
|  |  | ||||||
|  |     this->checkSamlResult(username, preloginCookie, userAuthCookie); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SAMLLoginWindow::checkSamlResult(QString username, QString preloginCookie, QString userAuthCookie) | ||||||
|  | { | ||||||
|  |     LOGI << "Checking the authentication result..."; | ||||||
|  |  | ||||||
|     if (!username.isEmpty()) { |     if (!username.isEmpty()) { | ||||||
|         LOGI << "Got username from SAML response headers " << username; |  | ||||||
|         samlResult.insert("username", username); |         samlResult.insert("username", username); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!preloginCookie.isEmpty()) { |     if (!preloginCookie.isEmpty()) { | ||||||
|         LOGI << "Got prelogin-cookie from SAML response headers " << preloginCookie; |  | ||||||
|         samlResult.insert("preloginCookie", preloginCookie); |         samlResult.insert("preloginCookie", preloginCookie); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!userAuthCookie.isEmpty()) { |     if (!userAuthCookie.isEmpty()) { | ||||||
|         LOGI << "Got portal-userauthcookie from SAML response headers " << userAuthCookie; |  | ||||||
|         samlResult.insert("userAuthCookie", userAuthCookie); |         samlResult.insert("userAuthCookie", userAuthCookie); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -89,12 +105,61 @@ void SAMLLoginWindow::onResponseReceived(QJsonObject params) | |||||||
|  |  | ||||||
|         emit success(samlResult); |         emit success(samlResult); | ||||||
|         accept(); |         accept(); | ||||||
|     } else { |  | ||||||
|         this->show(); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void SAMLLoginWindow::onLoadFinished() | void SAMLLoginWindow::onLoadFinished() | ||||||
| { | { | ||||||
|      LOGI << "Load finished " << this->webView->page()->url().toString(); |      LOGI << "Load finished " << webView->page()->url().toString(); | ||||||
|  |      webView->page()->toHtml([this] (const QString &html) { this->handleHtml(html); }); | ||||||
|  |      QMap<QString, QString> credentials = this->loadCredentials(); | ||||||
|  |      webView->page()->runJavaScript("document.getElementById('username').value='" + credentials["username"] + "';"); | ||||||
|  |      webView->page()->runJavaScript("document.getElementById('password').value='" + credentials["password"] + "';"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void SAMLLoginWindow::handleHtml(const QString &html) | ||||||
|  | { | ||||||
|  |     // try to check the html body and extract from there | ||||||
|  |     const auto samlAuthStatus = parseTag("saml-auth-status", html); | ||||||
|  |  | ||||||
|  |     if (samlAuthStatus == "1") { | ||||||
|  |         const auto preloginCookie = parseTag("prelogin-cookie", html); | ||||||
|  |         const auto username = parseTag("saml-username", html); | ||||||
|  |         const auto userAuthCookie = parseTag("portal-userauthcookie", html); | ||||||
|  |  | ||||||
|  |         checkSamlResult(username, preloginCookie, userAuthCookie); | ||||||
|  |     } else if (samlAuthStatus == "-1") { | ||||||
|  |         LOGI << "SAML authentication failed..."; | ||||||
|  |         failed = true; | ||||||
|  |         emit fail("ERR002", "Authentication failed, please try again."); | ||||||
|  |     } else { | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString SAMLLoginWindow::parseTag(const QString &tag, const QString &html) { | ||||||
|  |     const QRegularExpression expression(QString("<%1>(.*)</%1>").arg(tag)); | ||||||
|  |     return expression.match(html).captured(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QMap<QString, QString> SAMLLoginWindow::loadCredentials() | ||||||
|  | { | ||||||
|  |     std::string home = getenv("HOME"); | ||||||
|  |     std::string iniFile = home + "/.gpclient-credentials"; | ||||||
|  |     INIReader reader(iniFile); | ||||||
|  |  | ||||||
|  |     QMap<QString, QString> credentials; | ||||||
|  |     if (reader.ParseError() < 0) { | ||||||
|  |         LOGE << "File '" << iniFile << "' not found."; | ||||||
|  |         return credentials; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (reader.HasSection(this->portal.toStdString())) { | ||||||
|  |         credentials.insert(QString("username"), QString::fromStdString(reader.Get(this->portal.toStdString(), "username", ""))); | ||||||
|  |         credentials.insert(QString("password"), QString::fromStdString(reader.Get(this->portal.toStdString(), "password", ""))); | ||||||
|  |     } else { | ||||||
|  |         LOGE << "No credentials found for '" << this->portal.toStdString() << "' in '" << iniFile << "'"; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return credentials; | ||||||
|  | } | ||||||
| @@ -12,24 +12,32 @@ class SAMLLoginWindow : public QDialog | |||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     explicit SAMLLoginWindow(QWidget *parent = nullptr); |     explicit SAMLLoginWindow(QString portal, QWidget *parent = nullptr); | ||||||
|     ~SAMLLoginWindow(); |  | ||||||
|  |  | ||||||
|     void login(const QString samlMethod, const QString samlRequest, const QString preloingUrl); |     void login(const QString samlMethod, const QString samlRequest, const QString preloginUrl); | ||||||
|  |     QMap<QString, QString> loadCredentials(); | ||||||
|  |  | ||||||
| signals: | signals: | ||||||
|     void success(QMap<QString, QString> samlResult); |     void success(QMap<QString, QString> samlResult); | ||||||
|     void fail(const QString msg); |     void fail(const QString code, const QString msg); | ||||||
|  |  | ||||||
| private slots: | private slots: | ||||||
|     void onResponseReceived(QJsonObject params); |     void onResponseReceived(QJsonObject params); | ||||||
|     void onLoadFinished(); |     void onLoadFinished(); | ||||||
|  |     void checkSamlResult(QString username, QString preloginCookie, QString userAuthCookie); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     EnhancedWebView *webView; |     static const auto MAX_WAIT_TIME { 10 * 1000 }; | ||||||
|  |  | ||||||
|  |     bool failed { false }; | ||||||
|  |     EnhancedWebView *webView { nullptr }; | ||||||
|     QMap<QString, QString> samlResult; |     QMap<QString, QString> samlResult; | ||||||
|  |     QString portal; | ||||||
|  |  | ||||||
|     void closeEvent(QCloseEvent *event); |     void closeEvent(QCloseEvent *event); | ||||||
|  |     void handleHtml(const QString &html); | ||||||
|  |  | ||||||
|  |     static QString parseTag(const QString &tag, const QString &html); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif // SAMLLOGINWINDOW_H | #endif // SAMLLOGINWINDOW_H | ||||||
|   | |||||||
| @@ -32,3 +32,11 @@ QString SettingsDialog::clientos() | |||||||
| { | { | ||||||
|     return ui->clientosInput->text(); |     return ui->clientosInput->text(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void SettingsDialog::setOsVersion(QString osVersion) { | ||||||
|  |     ui->osVersionInput->setText(osVersion); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString SettingsDialog::osVersion() { | ||||||
|  |     return ui->osVersionInput->text(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ public: | |||||||
|     void setClientos(QString clientos); |     void setClientos(QString clientos); | ||||||
|     QString clientos(); |     QString clientos(); | ||||||
|  |  | ||||||
|  |     void setOsVersion(QString osVersion); | ||||||
|  |     QString osVersion(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     Ui::SettingsDialog *ui; |     Ui::SettingsDialog *ui; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>488</width> |     <width>488</width> | ||||||
|     <height>177</height> |     <height>220</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="sizePolicy"> |   <property name="sizePolicy"> | ||||||
| @@ -44,7 +44,7 @@ | |||||||
|    <item row="1" column="0"> |    <item row="1" column="0"> | ||||||
|     <widget class="QLabel" name="label_2"> |     <widget class="QLabel" name="label_2"> | ||||||
|      <property name="text"> |      <property name="text"> | ||||||
|       <string>Value of "clientos":</string> |       <string>clientos:</string> | ||||||
|      </property> |      </property> | ||||||
|     </widget> |     </widget> | ||||||
|    </item> |    </item> | ||||||
| @@ -55,7 +55,7 @@ | |||||||
|      </property> |      </property> | ||||||
|     </widget> |     </widget> | ||||||
|    </item> |    </item> | ||||||
|    <item row="2" column="1"> |    <item row="3" column="1"> | ||||||
|     <widget class="QDialogButtonBox" name="buttonBox"> |     <widget class="QDialogButtonBox" name="buttonBox"> | ||||||
|      <property name="orientation"> |      <property name="orientation"> | ||||||
|       <enum>Qt::Horizontal</enum> |       <enum>Qt::Horizontal</enum> | ||||||
| @@ -65,6 +65,16 @@ | |||||||
|      </property> |      </property> | ||||||
|     </widget> |     </widget> | ||||||
|    </item> |    </item> | ||||||
|  |    <item row="2" column="1"> | ||||||
|  |     <widget class="QLineEdit" name="osVersionInput"/> | ||||||
|  |    </item> | ||||||
|  |    <item row="2" column="0"> | ||||||
|  |     <widget class="QLabel" name="label_3"> | ||||||
|  |      <property name="text"> | ||||||
|  |       <string>os-version:</string> | ||||||
|  |      </property> | ||||||
|  |     </widget> | ||||||
|  |    </item> | ||||||
|   </layout> |   </layout> | ||||||
|  </widget> |  </widget> | ||||||
|  <resources> |  <resources> | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								GPClient/standardloginwindow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								GPClient/standardloginwindow.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | #include <QtGui/QCloseEvent> | ||||||
|  |  | ||||||
|  | #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) : | ||||||
|  |         QDialog(nullptr), | ||||||
|  |         ui(new Ui::StandardLoginWindow) { | ||||||
|  |     ui->setupUi(this); | ||||||
|  |     ui->portalAddress->setText(portalAddress); | ||||||
|  |     ui->username->setPlaceholderText(labelUsername); | ||||||
|  |     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); | ||||||
|  |     ui->loginButton->setDisabled(isProcessing); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void StandardLoginWindow::on_loginButton_clicked() { | ||||||
|  |     const QString username = ui->username->text().trimmed(); | ||||||
|  |     const QString password = ui->password->text().trimmed(); | ||||||
|  |  | ||||||
|  |     if (username.isEmpty() || password.isEmpty()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     settings::secureSave("username", username); | ||||||
|  |     settings::secureSave("password", password); | ||||||
|  |  | ||||||
|  |     emit performLogin(username, password); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void StandardLoginWindow::closeEvent(QCloseEvent *event) { | ||||||
|  |     event->accept(); | ||||||
|  |     reject(); | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								GPClient/standardloginwindow.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								GPClient/standardloginwindow.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | #ifndef STANDARDLOGINWINDOW_H | ||||||
|  | #define STANDARDLOGINWINDOW_H | ||||||
|  |  | ||||||
|  | #include <QtWidgets/QDialog> | ||||||
|  |  | ||||||
|  | namespace Ui { | ||||||
|  |     class StandardLoginWindow; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class StandardLoginWindow : public QDialog { | ||||||
|  | Q_OBJECT | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     explicit StandardLoginWindow(const QString &portalAddress, const QString &labelUsername, | ||||||
|  |                                  const QString &labelPassword, const QString &authMessage); | ||||||
|  |  | ||||||
|  |     void setProcessing(bool isProcessing); | ||||||
|  |  | ||||||
|  | private slots: | ||||||
|  |  | ||||||
|  |     void on_loginButton_clicked(); | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  |  | ||||||
|  |     void performLogin(QString username, QString password); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     Ui::StandardLoginWindow *ui; | ||||||
|  |  | ||||||
|  |     void closeEvent(QCloseEvent *event); | ||||||
|  |     void autocomplete(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // STANDARDLOGINWINDOW_H | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <ui version="4.0"> | <ui version="4.0"> | ||||||
|  <class>NormalLoginWindow</class> |  <class>StandardLoginWindow</class> | ||||||
|  <widget class="QDialog" name="NormalLoginWindow"> |  <widget class="QDialog" name="StandardLoginWindow"> | ||||||
|   <property name="geometry"> |   <property name="geometry"> | ||||||
|    <rect> |    <rect> | ||||||
|     <x>0</x> |     <x>0</x> | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| #include "vpn_json.h" | #include "vpn_json.h" | ||||||
| #include <QTextStream>  | #include <QTextStream> | ||||||
| #include <QJsonDocument> | #include <QJsonDocument> | ||||||
| #include <QJsonObject> | #include <QJsonObject> | ||||||
| #include <QJsonArray> | #include <QJsonArray> | ||||||
|   | |||||||
| @@ -34,9 +34,9 @@ GPService::~GPService() | |||||||
|  |  | ||||||
| QString GPService::findBinary() | QString GPService::findBinary() | ||||||
| { | { | ||||||
|     for (int i = 0; i < binaryPaths->length(); i++) { |     for (auto& binaryPath : binaryPaths) { | ||||||
|         if (QFileInfo::exists(binaryPaths[i])) { |         if (QFileInfo::exists(binaryPath)) { | ||||||
|             return binaryPaths[i]; |             return binaryPath; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return nullptr; |     return nullptr; | ||||||
| @@ -136,7 +136,7 @@ void GPService::connect(QString server, QString username, QString passwd) | |||||||
|          << "--cookie-on-stdin" |          << "--cookie-on-stdin" | ||||||
|          << server; |          << server; | ||||||
|  |  | ||||||
|     log("Start process with arugments: " + args.join(", ")); |     log("Start process with arguments: " + args.join(", ")); | ||||||
|  |  | ||||||
|     openconnect->start(bin, args); |     openconnect->start(bin, args); | ||||||
|     openconnect->write((passwd + "\n").toUtf8()); |     openconnect->write((passwd + "\n").toUtf8()); | ||||||
| @@ -199,7 +199,9 @@ void GPService::onProcessStdout() | |||||||
|     QString output = openconnect->readAllStandardOutput(); |     QString output = openconnect->readAllStandardOutput(); | ||||||
|  |  | ||||||
|     log(output); |     log(output); | ||||||
|     if (output.indexOf("Connected as") >= 0 || output.indexOf("Configured as") >= 0) { |     if (output.indexOf("Connected as") >= 0 || | ||||||
|  |         output.indexOf("Configured as") >= 0 || | ||||||
|  |         output.indexOf("Configurado como") >= 0) { | ||||||
|         vpnStatus = GPService::VpnConnected; |         vpnStatus = GPService::VpnConnected; | ||||||
|         emit connected(); |         emit connected(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -4,14 +4,13 @@ | |||||||
| #include <QtCore/QObject> | #include <QtCore/QObject> | ||||||
| #include <QtCore/QProcess> | #include <QtCore/QProcess> | ||||||
|  |  | ||||||
| static const QString binaryPaths[] { | static QList<QString> binaryPaths = QList<QString>() << | ||||||
|     "/usr/local/bin/openconnect", |     "/usr/local/bin/openconnect" << | ||||||
|     "/usr/local/sbin/openconnect", |      "/usr/local/sbin/openconnect" << | ||||||
|     "/usr/bin/openconnect", |      "/usr/bin/openconnect" << | ||||||
|     "/usr/sbin/openconnect", |      "/usr/sbin/openconnect" << | ||||||
|     "/opt/bin/openconnect", |      "/opt/bin/openconnect" << | ||||||
|     "/opt/sbin/openconnect" |      "/opt/sbin/openconnect"; | ||||||
| }; |  | ||||||
|  |  | ||||||
| class GPService : public QObject | class GPService : public QObject | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @@ -23,7 +23,7 @@ A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Q | |||||||
| |OS|Stable version | Development version| | |OS|Stable version | Development version| | ||||||
| |---|--------------|--------------------| | |---|--------------|--------------------| | ||||||
| |Linux Mint, Ubuntu 18.04 or later|[ppa:yuezk/globalprotect-openconnect](https://launchpad.net/~yuezk/+archive/ubuntu/globalprotect-openconnect)|[ppa:yuezk/globalprotect-openconnect-snapshot](https://launchpad.net/~yuezk/+archive/ubuntu/globalprotect-openconnect-snapshot)| | |Linux Mint, Ubuntu 18.04 or later|[ppa:yuezk/globalprotect-openconnect](https://launchpad.net/~yuezk/+archive/ubuntu/globalprotect-openconnect)|[ppa:yuezk/globalprotect-openconnect-snapshot](https://launchpad.net/~yuezk/+archive/ubuntu/globalprotect-openconnect-snapshot)| | ||||||
| |Arch, Manjaro|[globalprotect-openconnect](https://archlinux.org/packages/community/x86_64/globalprotect-openconnect/)|[AUR: globalprotect-openconnect-git](https://aur.archlinux.org/packages/globalprotect-openconnect-git/)| | |Arch, Manjaro|[globalprotect-openconnect](https://archlinux.org/packages/extra/x86_64/globalprotect-openconnect/)|[AUR: globalprotect-openconnect-git](https://aur.archlinux.org/packages/globalprotect-openconnect-git/)| | ||||||
| |Fedora|[copr: yuezk/globalprotect-openconnect](https://copr.fedorainfracloud.org/coprs/yuezk/globalprotect-openconnect/)|[copr: yuezk/globalprotect-openconnect](https://copr.fedorainfracloud.org/coprs/yuezk/globalprotect-openconnect/)| | |Fedora|[copr: yuezk/globalprotect-openconnect](https://copr.fedorainfracloud.org/coprs/yuezk/globalprotect-openconnect/)|[copr: yuezk/globalprotect-openconnect](https://copr.fedorainfracloud.org/coprs/yuezk/globalprotect-openconnect/)| | ||||||
| |openSUSE, CentOS 8|[OBS: globalprotect-openconnect](https://build.opensuse.org/package/show/home:yuezk/globalprotect-openconnect)|[OBS: globalprotect-openconnect-snapshot](https://build.opensuse.org/package/show/home:yuezk/globalprotect-openconnect-snapshot)| | |openSUSE, CentOS 8|[OBS: globalprotect-openconnect](https://build.opensuse.org/package/show/home:yuezk/globalprotect-openconnect)|[OBS: globalprotect-openconnect-snapshot](https://build.opensuse.org/package/show/home:yuezk/globalprotect-openconnect-snapshot)| | ||||||
|  |  | ||||||
| @@ -77,8 +77,9 @@ sudo dnf install globalprotect-openconnect | |||||||
|  |  | ||||||
| - openSUSE Leap | - openSUSE Leap | ||||||
|  |  | ||||||
|   ```sh |   ```sh   | ||||||
|   sudo zypper ar https://download.opensuse.org/repositories/home:/yuezk/openSUSE_Leap_15.2/home:yuezk.repo |   sudo zypper ar https://download.opensuse.org/repositories/home:/yuezk/15.4/home:yuezk.repo | ||||||
|  |    | ||||||
|   sudo zypper ref |   sudo zypper ref | ||||||
|   sudo zypper install globalprotect-openconnect |   sudo zypper install globalprotect-openconnect | ||||||
|   ``` |   ``` | ||||||
| @@ -97,6 +98,14 @@ git clone https://github.com/yuezk/GlobalProtect-openconnect.git | |||||||
| cd GlobalProtect-openconnect | cd GlobalProtect-openconnect | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ### MX Linux | ||||||
|  | The following instructions are for **MX-21.2.1_x64 KDE**. | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | sudo apt install qttools5-dev libsecret-1-dev libqt5keychain1 | ||||||
|  | ./scripts/install-debian.sh | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ### Ubuntu/Mint | ### Ubuntu/Mint | ||||||
|  |  | ||||||
| > **⚠️ REQUIRED for Ubuntu 18.04 ⚠️** | > **⚠️ REQUIRED for Ubuntu 18.04 ⚠️** | ||||||
| @@ -138,6 +147,7 @@ Install the Qt5 dependencies and OpenConnect: | |||||||
| - QtWebSockets | - QtWebSockets | ||||||
| - QtDBus | - QtDBus | ||||||
| - openconnect v8.x | - openconnect v8.x | ||||||
|  | - qtkeychain | ||||||
|  |  | ||||||
| ...then build and install with: | ...then build and install with: | ||||||
|  |  | ||||||
| @@ -176,15 +186,6 @@ Install the [AppIndicator and KStatusNotifierItem Support](https://extensions.gn | |||||||
| <p> | <p> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Future plan |  | ||||||
|  |  | ||||||
| - [x] Improve the release process |  | ||||||
| - [ ] Process bugs and feature requests |  | ||||||
| - [ ] Support for bypassing the `gpclient` parameters |  | ||||||
| - [ ] Support the CLI mode |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Troubleshooting | ## Troubleshooting | ||||||
|  |  | ||||||
| Run `gpclient` in the Terminal and collect the logs. | Run `gpclient` in the Terminal and collect the logs. | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								cmakew
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								cmakew
									
									
									
									
									
								
							| @@ -36,7 +36,7 @@ fi | |||||||
| cmake_base="./.cmake" | cmake_base="./.cmake" | ||||||
| cmake_bin="${cmake_base}/cmake-$cmake_version/bin/cmake" | cmake_bin="${cmake_base}/cmake-$cmake_version/bin/cmake" | ||||||
|  |  | ||||||
| # download cmake if neccessary | # download cmake if necessary | ||||||
| if [ ! -f "$cmake_bin" ]; then | if [ ! -f "$cmake_bin" ]; then | ||||||
|     download_link="" |     download_link="" | ||||||
|  |  | ||||||
| @@ -99,4 +99,4 @@ if [ "$cygwin" = true ]; then | |||||||
| fi | fi | ||||||
|  |  | ||||||
| # run cmake | # run cmake | ||||||
| exec "$cmake_bin" "$@" | exec "$cmake_bin" "$@" | ||||||
|   | |||||||
							
								
								
									
										65
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,66 @@ | |||||||
|  | globalprotect-openconnect (1.4.9-1) unstable; urgency=medium | ||||||
|  |  | ||||||
|  |   * Updated VERSION, Bumped 1.4.8 –> 1.4.9 | ||||||
|  |   * fix: update cmake version | ||||||
|  |   * fix: correct the package name | ||||||
|  |   * fix: use the dev package | ||||||
|  |   * fix: use qtkeychain package | ||||||
|  |   * fix: add qt5-tools | ||||||
|  |   * fix: add libsecret-1-dev | ||||||
|  |   * fix: add pkg-config | ||||||
|  |   * fix: use cmake 3.16 | ||||||
|  |   * fix: add missing build dependency | ||||||
|  |   * ci: fix CI | ||||||
|  |   * Merge branch 'master' into develop | ||||||
|  |   * feat: expose os-version to settings | ||||||
|  |   * Add two missing dependencies for building on debian (#198) | ||||||
|  |   * ci: assert no library missing | ||||||
|  |   * fix: update qtkeychain | ||||||
|  |   * ci: run gpclient after build | ||||||
|  |   * fix: add qtkeychain | ||||||
|  |   * chore: update CMake file | ||||||
|  |   * Added install instructions for MX Linux. (#190) | ||||||
|  |   * Credentials autocompleting (secure version) (#179) | ||||||
|  |   * Read all saved Gateways (for selecting in Systray) (#181) | ||||||
|  |   * copy install script for debian (#180) | ||||||
|  |   * add es and pt support to shange status when connected to vpn (#162) | ||||||
|  |   * fix: improve the cli support | ||||||
|  |   * feat: add --reset option to gpclient | ||||||
|  |  | ||||||
|  |  -- Kevin Yue <k3vinyue@gmail.com>  Sun, 08 Jan 2023 20:58:32 +0800 | ||||||
|  |  | ||||||
|  | globalprotect-openconnect (1.4.8-1) unstable; urgency=medium | ||||||
|  |  | ||||||
|  |   * Updated VERSION, Bumped 1.4.7 –> 1.4.8 | ||||||
|  |   * fix: fix compile error | ||||||
|  |   * refactor: simplify the code | ||||||
|  |   * chore: use auto to declare variables | ||||||
|  |   * chore: use c++ 17 | ||||||
|  |   * fix: clear cookies when click the Reset button | ||||||
|  |   * fix: refine the authentication workflow | ||||||
|  |   * chore: PLOG -> LOG | ||||||
|  |  | ||||||
|  |  -- Kevin Yue <k3vinyue@gmail.com>  Sun, 12 Jun 2022 20:28:58 +0800 | ||||||
|  |  | ||||||
|  | globalprotect-openconnect (1.4.7-1) unstable; urgency=medium | ||||||
|  |  | ||||||
|  |   * Updated VERSION, Bumped 1.4.6 –> 1.4.7 | ||||||
|  |   * fix: release resources when properly | ||||||
|  |   * fix: add support for parsing tokens from HTML | ||||||
|  |   * handle html comment for saml result with okta 2fa (#156) | ||||||
|  |   * chore: use auto to declare variable | ||||||
|  |   * chore: simplify readme | ||||||
|  |  | ||||||
|  |  -- Kevin Yue <k3vinyue@gmail.com>  Tue, 07 Jun 2022 21:46:04 +0800 | ||||||
|  |  | ||||||
|  | globalprotect-openconnect (1.4.6-1) unstable; urgency=medium | ||||||
|  |  | ||||||
|  |   * Updated VERSION, Bumped 1.4.5 –> 1.4.6 | ||||||
|  |   * feat: display address in gateway menu item | ||||||
|  |   * fix: fix bug of parsing the portal response | ||||||
|  |  | ||||||
|  |  -- Kevin Yue <k3vinyue@gmail.com>  Wed, 01 Jun 2022 23:55:50 +0800 | ||||||
|  |  | ||||||
| globalprotect-openconnect (1.4.5-1) unstable; urgency=medium | globalprotect-openconnect (1.4.5-1) unstable; urgency=medium | ||||||
|  |  | ||||||
|   * Updated VERSION, Bumped 1.4.4 –> 1.4.5 |   * Updated VERSION, Bumped 1.4.4 –> 1.4.5 | ||||||
| @@ -7,7 +70,7 @@ globalprotect-openconnect (1.4.5-1) unstable; urgency=medium | |||||||
|   * packaging: fix postinst for debian |   * packaging: fix postinst for debian | ||||||
|   * packaging: add postinst for debian |   * packaging: add postinst for debian | ||||||
|   * test: test debian packaging |   * test: test debian packaging | ||||||
|   * ci: fix the foder path |   * ci: fix the folder path | ||||||
|   * chore: apt -> apt-get |   * chore: apt -> apt-get | ||||||
|   * ci: verify debian package |   * ci: verify debian package | ||||||
|   * Revert "Revert "fix: improve the dbus security"" |   * Revert "Revert "fix: improve the dbus security"" | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							| @@ -2,12 +2,12 @@ Source: globalprotect-openconnect | |||||||
| Section: net | Section: net | ||||||
| Priority: optional | Priority: optional | ||||||
| Maintainer: Kevin Yue <k3vinyue@gmail.com> | Maintainer: Kevin Yue <k3vinyue@gmail.com> | ||||||
| Build-Depends: cmake (>=3.10), debhelper (>=11~), qtbase5-dev, libqt5websockets5-dev (>=5.9), qtwebengine5-dev (>=5.9) | Build-Depends: cmake (>=3.10), pkg-config, debhelper (>=11~), qtbase5-dev, qttools5-dev, libqt5websockets5-dev (>=5.9), qtwebengine5-dev (>=5.9), qt5keychain-dev | ||||||
| Standards-Version: 4.1.4 | Standards-Version: 4.1.4 | ||||||
| Homepage: https://github.com/yuezk/GlobalProtect-openconnect | Homepage: https://github.com/yuezk/GlobalProtect-openconnect | ||||||
|  |  | ||||||
| Package: globalprotect-openconnect | Package: globalprotect-openconnect | ||||||
| Architecture: any | Architecture: any | ||||||
| Multi-Arch: foreign | Multi-Arch: foreign | ||||||
| Depends: ${misc:Depends}, ${shlibs:Depends}, openconnect (>=8.0), libqt5websockets5 (>=5.9), libqt5webengine5 (>=5.9) | Depends: ${misc:Depends}, ${shlibs:Depends}, openconnect (>=8.0), libqt5websockets5 (>=5.9), libqt5webengine5 (>=5.9), libqt5keychain1 | ||||||
| Description: A GlobalProtect VPN client (GUI) based on OpenConnect. | Description: A GlobalProtect VPN client (GUI) based on OpenConnect. | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| # Maintainer: Keinv Yue <yuezk001@gmail.com> | # Maintainer: Keinv Yue <yuezk001@gmail.com> | ||||||
|  |  | ||||||
| _pkgver="1.4.5" | _pkgver="1.4.9" | ||||||
| _commit="a489c5881bdc9d3565da0f2efac4963bec3f7069" | _commit="acf184134a2ff19e4a39528bd6a7fbbafa4cf017" | ||||||
| pkgname=globalprotect-openconnect-git | pkgname=globalprotect-openconnect-git | ||||||
| pkgver=${_pkgver} | pkgver=${_pkgver} | ||||||
| pkgrel=1 | pkgrel=1 | ||||||
| @@ -13,7 +13,7 @@ backup=( | |||||||
|     etc/gpservice/gp.conf |     etc/gpservice/gp.conf | ||||||
| ) | ) | ||||||
| install=gp.install | install=gp.install | ||||||
| depends=('openconnect>=8.0.0' qt5-base qt5-webengine qt5-websockets) | depends=('openconnect>=8.0.0' qt5-base qt5-webengine qt5-websockets qt5-tools qtkeychain-qt5) | ||||||
| makedepends=(git cmake) | makedepends=(git cmake) | ||||||
| conflicts=('globalprotect-openconnect') | conflicts=('globalprotect-openconnect') | ||||||
| provides=('globalprotect-openconnect' 'gpclient' 'gpservice') | provides=('globalprotect-openconnect' 'gpclient' 'gpservice') | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ backup=( | |||||||
|     etc/gpservice/gp.conf |     etc/gpservice/gp.conf | ||||||
| ) | ) | ||||||
| install=gp.install | install=gp.install | ||||||
| depends=('openconnect>=8.0.0' qt5-base qt5-webengine qt5-websockets) | depends=('openconnect>=8.0.0' qt5-base qt5-webengine qt5-websockets qt5-tools qtkeychain-qt5) | ||||||
| makedepends=(git cmake) | makedepends=(git cmake) | ||||||
| conflicts=('globalprotect-openconnect') | conflicts=('globalprotect-openconnect') | ||||||
| provides=('globalprotect-openconnect' 'gpclient' 'gpservice') | provides=('globalprotect-openconnect' 'gpclient' 'gpservice') | ||||||
|   | |||||||
| @@ -1,3 +1,66 @@ | |||||||
|  | ------------------------------------------------------------------- | ||||||
|  | Sun Jan  8 12:58:32 UTC 2023 - k3vinyue@gmail.com - 1.4.9 | ||||||
|  |  | ||||||
|  | - Update to 1.4.9 | ||||||
|  |   * Updated VERSION, Bumped 1.4.8 –> 1.4.9 | ||||||
|  |   * fix: update cmake version | ||||||
|  |   * fix: correct the package name | ||||||
|  |   * fix: use the dev package | ||||||
|  |   * fix: use qtkeychain package | ||||||
|  |   * fix: add qt5-tools | ||||||
|  |   * fix: add libsecret-1-dev | ||||||
|  |   * fix: add pkg-config | ||||||
|  |   * fix: use cmake 3.16 | ||||||
|  |   * fix: add missing build dependency | ||||||
|  |   * ci: fix CI | ||||||
|  |   * Merge branch 'master' into develop | ||||||
|  |   * feat: expose os-version to settings | ||||||
|  |   * Add two missing dependencies for building on debian (#198) | ||||||
|  |   * ci: assert no library missing | ||||||
|  |   * fix: update qtkeychain | ||||||
|  |   * ci: run gpclient after build | ||||||
|  |   * fix: add qtkeychain | ||||||
|  |   * chore: update CMake file | ||||||
|  |   * Added install instructions for MX Linux. (#190) | ||||||
|  |   * Credentials autocompleting (secure version) (#179) | ||||||
|  |   * Read all saved Gateways (for selecting in Systray) (#181) | ||||||
|  |   * copy install script for debian (#180) | ||||||
|  |   * add es and pt support to change status when connected to vpn (#162) | ||||||
|  |   * fix: improve the cli support | ||||||
|  |   * feat: add --reset option to gpclient | ||||||
|  |  | ||||||
|  | ------------------------------------------------------------------- | ||||||
|  | Sun Jun 12 12:28:58 UTC 2022 - k3vinyue@gmail.com - 1.4.8 | ||||||
|  |  | ||||||
|  | - Update to 1.4.8 | ||||||
|  |   * Updated VERSION, Bumped 1.4.7 –> 1.4.8 | ||||||
|  |   * fix: fix compile error | ||||||
|  |   * refactor: simplify the code | ||||||
|  |   * chore: use auto to declare variables | ||||||
|  |   * chore: use c++ 17 | ||||||
|  |   * fix: clear cookies when click the Reset button | ||||||
|  |   * fix: refine the authentication workflow | ||||||
|  |   * chore: PLOG -> LOG | ||||||
|  |  | ||||||
|  | ------------------------------------------------------------------- | ||||||
|  | Tue Jun  7 13:46:04 UTC 2022 - k3vinyue@gmail.com - 1.4.7 | ||||||
|  |  | ||||||
|  | - Update to 1.4.7 | ||||||
|  |   * Updated VERSION, Bumped 1.4.6 –> 1.4.7 | ||||||
|  |   * fix: release resources when properly | ||||||
|  |   * fix: add support for parsing tokens from HTML | ||||||
|  |   * handle html comment for saml result with okta 2fa (#156) | ||||||
|  |   * chore: use auto to declare variable | ||||||
|  |   * chore: simplify readme | ||||||
|  |  | ||||||
|  | ------------------------------------------------------------------- | ||||||
|  | Wed Jun  1 15:55:50 UTC 2022 - k3vinyue@gmail.com - 1.4.6 | ||||||
|  |  | ||||||
|  | - Update to 1.4.6 | ||||||
|  |   * Updated VERSION, Bumped 1.4.5 –> 1.4.6 | ||||||
|  |   * feat: display address in gateway menu item | ||||||
|  |   * fix: fix bug of parsing the portal response | ||||||
|  |  | ||||||
| ------------------------------------------------------------------- | ------------------------------------------------------------------- | ||||||
| Sun May 29 13:15:40 UTC 2022 - k3vinyue@gmail.com - 1.4.5 | Sun May 29 13:15:40 UTC 2022 - k3vinyue@gmail.com - 1.4.5 | ||||||
|  |  | ||||||
| @@ -9,7 +72,7 @@ Sun May 29 13:15:40 UTC 2022 - k3vinyue@gmail.com - 1.4.5 | |||||||
|   * packaging: fix postinst for debian |   * packaging: fix postinst for debian | ||||||
|   * packaging: add postinst for debian |   * packaging: add postinst for debian | ||||||
|   * test: test debian packaging |   * test: test debian packaging | ||||||
|   * ci: fix the foder path |   * ci: fix the folder path | ||||||
|   * chore: apt -> apt-get |   * chore: apt -> apt-get | ||||||
|   * ci: verify debian package |   * ci: verify debian package | ||||||
|   * Revert "Revert "fix: improve the dbus security"" |   * Revert "Revert "fix: improve the dbus security"" | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| Name:           globalprotect-openconnect | Name:           globalprotect-openconnect | ||||||
| Version:        1.4.5 | Version:        1.4.9 | ||||||
| Release:        1 | Release:        1 | ||||||
| Summary:        A GlobalProtect VPN client powered by OpenConnect | Summary:        A GlobalProtect VPN client powered by OpenConnect | ||||||
| Group:          Productivity/Networking/PPP | Group:          Productivity/Networking/PPP | ||||||
| @@ -8,7 +8,7 @@ BuildRoot:      %{_tmppath}/%{name}-%{version}-build | |||||||
| License:        GPL-3.0 | License:        GPL-3.0 | ||||||
| URL:            https://github.com/yuezk/GlobalProtect-openconnect | URL:            https://github.com/yuezk/GlobalProtect-openconnect | ||||||
| Source0:        %{name}.tar.gz | Source0:        %{name}.tar.gz | ||||||
| BuildRequires:  cmake cmake(Qt5) cmake(Qt5Gui) cmake(Qt5WebEngine) cmake(Qt5WebSockets) cmake(Qt5DBus) | BuildRequires:  cmake cmake(Qt5) cmake(Qt5Gui) cmake(Qt5WebEngine) cmake(Qt5WebSockets) cmake(Qt5DBus) cmake(Qt5Keychain) | ||||||
| BuildRequires:  systemd-rpm-macros | BuildRequires:  systemd-rpm-macros | ||||||
| Requires:       openconnect >= 8.0 | Requires:       openconnect >= 8.0 | ||||||
| Conflicts:      globalprotect-openconnect-snapshot | Conflicts:      globalprotect-openconnect-snapshot | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								scripts/install-debian.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								scripts/install-debian.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #!/bin/bash -e | ||||||
|  |  | ||||||
|  | sudo apt-get update | ||||||
|  | sudo apt-get install -y \ | ||||||
|  |     build-essential \ | ||||||
|  |     qtbase5-dev \ | ||||||
|  |     libqt5websockets5-dev \ | ||||||
|  |     qtwebengine5-dev \ | ||||||
|  |     qttools5-dev \ | ||||||
|  |     qt5keychain-dev \ | ||||||
|  |     openconnect \ | ||||||
|  |  | ||||||
|  | ./scripts/install.sh | ||||||
| @@ -4,6 +4,7 @@ sudo dnf install -y \ | |||||||
|     qt5-qtbase-devel \ |     qt5-qtbase-devel \ | ||||||
|     qt5-qtwebengine-devel \ |     qt5-qtwebengine-devel \ | ||||||
|     qt5-qtwebsockets-devel \ |     qt5-qtwebsockets-devel \ | ||||||
|  |     qtkeychain-qt5-devel \ | ||||||
|     openconnect |     openconnect | ||||||
|  |  | ||||||
| ./scripts/install.sh | ./scripts/install.sh | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ sudo zypper install -y \ | |||||||
|     libqt5-qtbase-devel \ |     libqt5-qtbase-devel \ | ||||||
|     libqt5-qtwebsockets-devel \ |     libqt5-qtwebsockets-devel \ | ||||||
|     libqt5-qtwebengine-devel \ |     libqt5-qtwebengine-devel \ | ||||||
|  |     qtkeychain-qt5-devel \ | ||||||
|     openconnect |     openconnect | ||||||
|  |  | ||||||
| ./scripts/install.sh | ./scripts/install.sh | ||||||
|   | |||||||
| @@ -6,6 +6,8 @@ sudo apt-get install -y \ | |||||||
|     qtbase5-dev \ |     qtbase5-dev \ | ||||||
|     libqt5websockets5-dev \ |     libqt5websockets5-dev \ | ||||||
|     qtwebengine5-dev \ |     qtwebengine5-dev \ | ||||||
|  |     qttools5-dev \ | ||||||
|  |     qt5keychain-dev \ | ||||||
|     openconnect |     openconnect | ||||||
|  |  | ||||||
| ./scripts/install.sh | ./scripts/install.sh | ||||||
|   | |||||||
| @@ -6,7 +6,9 @@ sudo apt-get install -y \ | |||||||
| 	qtbase5-dev \ | 	qtbase5-dev \ | ||||||
| 	libqt5websockets5-dev \ | 	libqt5websockets5-dev \ | ||||||
| 	qtwebengine5-dev \ | 	qtwebengine5-dev \ | ||||||
|  | 	qt5keychain-dev \ | ||||||
| 	cmake \ | 	cmake \ | ||||||
|  | 	qttools5-dev \ | ||||||
| 	debhelper | 	debhelper | ||||||
|  |  | ||||||
| mkdir -p build | mkdir -p build | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user