Compare commits

...

16 Commits

Author SHA1 Message Date
Kevin Yue
ef43d10a70 fix: add missing build dependency 2023-01-02 20:27:52 +08:00
Kevin Yue
bd73466e48 ci: fix CI 2023-01-02 20:10:35 +08:00
Kevin Yue
cc2c0ae34e ci: fix CI 2023-01-02 19:56:45 +08:00
Kevin Yue
9207f7a798 Merge branch 'master' into develop 2023-01-02 19:47:58 +08:00
Kevin Yue
2069b7fd8e feat: expose os-version to settings 2023-01-01 17:18:50 +08:00
Nils Goroll
f552ef6204
Add two missing dependencies for building on debian (#198) 2022-12-08 17:41:23 +08:00
Kevin Yue
2761f7521a ci: assert no library missing 2022-10-30 21:48:46 +08:00
Kevin Yue
c3939a774b fix: update qtkeychain 2022-10-30 21:35:36 +08:00
Kevin Yue
49e5242bf2 ci: run gpclient after build 2022-10-30 21:28:26 +08:00
Kevin Yue
3181d37b20 fix: add qtkeychain 2022-10-30 21:21:47 +08:00
Kevin Yue
6d788a5e91 chore: update CMake file 2022-10-30 21:15:17 +08:00
VJatla
74c7549444
Added install instructions for MX Linux. (#190) 2022-10-30 19:07:27 +08:00
Carlo Ramponi
c52ccb87f1
Credentials autocompleting (secure version) (#179) 2022-10-12 10:25:49 +08:00
gmarco
fab25848e1
Read all saved Gateways (for selecting in Systray) (#181) 2022-10-07 12:37:51 +08:00
simonleary-umass-edu
75a24c89cd
copy install script for debian (#180)
Co-authored-by: simon <simon.leary42@gmail.com>
2022-08-31 16:28:11 +08:00
Joe
15a73b7dba
add es and pt support to shange status when connected to vpn (#162) 2022-06-20 10:28:02 +08:00
22 changed files with 184 additions and 16 deletions

View File

@ -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' }}

View File

@ -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
View File

@ -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

1
3rdparty/qtkeychain vendored Submodule

@ -0,0 +1 @@
Subproject commit f197cdb935b0cfd9881fdc6860874cb8379d1238

View File

@ -64,6 +64,17 @@ add_3rdparty(
-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
) )
add_3rdparty(
qtkeychain
GIT_REPOSITORY https://github.com/frankosterfeld/qtkeychain.git
GIT_TAG master
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE}
-DCMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}
-DCMAKE_PREFIX_PATH=$ENV{CMAKE_PREFIX_PATH}
)
ExternalProject_Get_Property(SingleApplication-${PROJECT_NAME} SOURCE_DIR BINARY_DIR) ExternalProject_Get_Property(SingleApplication-${PROJECT_NAME} SOURCE_DIR BINARY_DIR)
set(SingleApplication_INCLUDE_DIR ${SOURCE_DIR}) set(SingleApplication_INCLUDE_DIR ${SOURCE_DIR})
set(SingleApplication_LIBRARY ${BINARY_DIR}/libSingleApplication.a) set(SingleApplication_LIBRARY ${BINARY_DIR}/libSingleApplication.a)
@ -71,7 +82,16 @@ 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}) ExternalProject_Get_Property(qtkeychain-${PROJECT_NAME} SOURCE_DIR BINARY_DIR)
set(qtkeychain_INCLUDE_DIR "${SOURCE_DIR}")
set(qtkeychain_BINARY_DIR "${BINARY_DIR}")
set(qtkeychain_LIBRARY ${BINARY_DIR}/libqt5keychain.so)
add_dependencies(gpclient
SingleApplication-${PROJECT_NAME}
plog-${PROJECT_NAME}
qtkeychain-${PROJECT_NAME}
)
target_include_directories(gpclient PRIVATE target_include_directories(gpclient PRIVATE
${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}
@ -79,10 +99,13 @@ 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_DIR}
${qtkeychain_BINARY_DIR}
) )
target_link_libraries(gpclient target_link_libraries(gpclient
${SingleApplication_LIBRARY} ${SingleApplication_LIBRARY}
${qtkeychain_LIBRARY}
Qt5::Widgets Qt5::Widgets
Qt5::Network Qt5::Network
Qt5::WebSockets Qt5::WebSockets

View File

@ -61,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()
@ -438,8 +440,14 @@ 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)
@ -467,6 +475,7 @@ void GPClient::setCurrentGateway(const GPGateway gateway)
LOGI << "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();
} }

View File

@ -9,9 +9,12 @@
#include <plog/Log.h> #include <plog/Log.h>
#include <QWebEngineProfile> #include <QWebEngineProfile>
#include <QWebEngineCookieStore> #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)
@ -115,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);
@ -132,3 +141,38 @@ void gpclient::helper::settings::clear()
QWebEngineProfile::defaultProfile()->cookieStore()->deleteAllCookies(); 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;
}

View File

@ -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);
} }
} }
} }

View File

@ -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", "");

View File

@ -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();
}

View File

@ -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;
}; };

View File

@ -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 &quot;clientos&quot;:</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>

View File

@ -2,6 +2,9 @@
#include "standardloginwindow.h" #include "standardloginwindow.h"
#include "ui_standardloginwindow.h" #include "ui_standardloginwindow.h"
#include "gphelper.h"
using namespace gpclient::helper;
StandardLoginWindow::StandardLoginWindow(const QString &portalAddress, const QString &labelUsername, StandardLoginWindow::StandardLoginWindow(const QString &portalAddress, const QString &labelUsername,
const QString &labelPassword, const QString &authMessage) : const QString &labelPassword, const QString &authMessage) :
@ -13,11 +16,24 @@ StandardLoginWindow::StandardLoginWindow(const QString &portalAddress, const QSt
ui->password->setPlaceholderText(labelPassword); ui->password->setPlaceholderText(labelPassword);
ui->authMessage->setText(authMessage); ui->authMessage->setText(authMessage);
autocomplete();
setWindowTitle("GlobalProtect Login"); setWindowTitle("GlobalProtect Login");
setFixedSize(width(), height()); setFixedSize(width(), height());
setModal(true); 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) { void StandardLoginWindow::setProcessing(bool isProcessing) {
ui->username->setReadOnly(isProcessing); ui->username->setReadOnly(isProcessing);
ui->password->setReadOnly(isProcessing); ui->password->setReadOnly(isProcessing);
@ -32,6 +48,9 @@ void StandardLoginWindow::on_loginButton_clicked() {
return; return;
} }
settings::secureSave("username", username);
settings::secureSave("password", password);
emit performLogin(username, password); emit performLogin(username, password);
} }

View File

@ -28,6 +28,7 @@ private:
Ui::StandardLoginWindow *ui; Ui::StandardLoginWindow *ui;
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void autocomplete();
}; };
#endif // STANDARDLOGINWINDOW_H #endif // STANDARDLOGINWINDOW_H

View File

@ -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();
} }

View File

@ -97,6 +97,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 +146,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:

2
debian/control vendored
View File

@ -2,7 +2,7 @@ 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), debhelper (>=11~), qtbase5-dev, qttools5-dev, libqt5websockets5-dev (>=5.9), qtwebengine5-dev (>=5.9)
Standards-Version: 4.1.4 Standards-Version: 4.1.4
Homepage: https://github.com/yuezk/GlobalProtect-openconnect Homepage: https://github.com/yuezk/GlobalProtect-openconnect

14
scripts/install-debian.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash -e
sudo apt-get update
sudo apt-get install -y \
build-essential \
qtbase5-dev \
libqt5websockets5-dev \
qtwebengine5-dev \
qttools5-dev \
libsecret-1-dev \
openconnect \
libqt5keychain1
./scripts/install.sh

View File

@ -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 \
openconnect openconnect \
qtkeychain
./scripts/install.sh ./scripts/install.sh

View File

@ -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 \
openconnect openconnect \
qtkeychain-qt5
./scripts/install.sh ./scripts/install.sh

View File

@ -6,6 +6,8 @@ sudo apt-get install -y \
qtbase5-dev \ qtbase5-dev \
libqt5websockets5-dev \ libqt5websockets5-dev \
qtwebengine5-dev \ qtwebengine5-dev \
openconnect qttools5-dev \
openconnect \
libqt5keychain1
./scripts/install.sh ./scripts/install.sh

View File

@ -6,7 +6,9 @@ sudo apt-get install -y \
qtbase5-dev \ qtbase5-dev \
libqt5websockets5-dev \ libqt5websockets5-dev \
qtwebengine5-dev \ qtwebengine5-dev \
libqt5keychain1 \
cmake \ cmake \
qttools5-dev \
debhelper debhelper
mkdir -p build mkdir -p build