Compare commits

...

59 Commits

Author SHA1 Message Date
Kevin Yue
64e6487e7e release 1.3.2 2021-09-02 21:11:47 +08:00
Kevin Yue
e8b2c1606f Add default value to client os (#86)
* add default value for clientos

* update CI

* update icon format

* change the icon format
2021-09-02 21:08:56 +08:00
Kevin Yue
84f1480653 release 1.3.1 2021-08-31 20:54:04 +08:00
Kevin Yue
3175855122 add rpm packaging (#83) 2021-08-31 20:52:08 +08:00
Kevin Yue
fa8b5c1528 Update CI scripts 2021-08-29 20:06:13 +08:00
Kevin Yue
7b9942c7e6 Update README.md 2021-08-26 00:42:25 +08:00
Kevin Yue
011a1a0dec Update README.md 2021-08-26 00:39:13 +08:00
Kevin Yue
4a53033023 [ci] use action-automatic-releases 2021-08-23 08:53:41 +08:00
Kevin Yue
9c6ea1c4b5 [ci] replace artifacts 2021-08-23 08:32:12 +08:00
Kevin Yue
3369ad4c1d [ci] update release action 2021-08-23 08:13:01 +08:00
Kevin Yue
25c9f2291a Update pre-release.yml 2021-08-23 01:35:12 +08:00
Kevin Yue
bba3bc7e4f [ci] improve action script 2021-08-23 01:04:17 +08:00
Kevin Yue
b12b692090 [ci] update action script 2021-08-23 00:30:01 +08:00
Kevin Yue
1300a0cc43 [ci] install qt 2021-08-22 23:56:05 +08:00
Kevin Yue
165080b476 [ci] build debian package 2021-08-22 23:46:20 +08:00
Kevin Yue
d6af8a1598 [ci] Update the changlog 2021-08-22 22:41:47 +08:00
Kevin Yue
eef92b1d31 Update action script 2021-08-22 21:07:52 +08:00
Kevin Yue
946ead24a4 Bump the changelog 2021-08-22 20:05:59 +08:00
Kevin Yue
39e57c8598 Add version suffix 2021-08-22 19:30:34 +08:00
Kevin Yue
4e2e423c27 Update the branch 2021-08-22 18:39:31 +08:00
Kevin Yue
732a62f1ee Add pre-release action 2021-08-22 18:34:56 +08:00
Kevin Yue
9f9444a72b Display error when OpenConnect was not found (#81) 2021-08-21 19:32:13 +08:00
Kevin Yue
6352e1fb2b Make the clientos configurable and improve Reset Settings (#80)
* Set the gateway

* Make clientos configurable

* Update readme.md

* Update README.md
2021-08-21 18:44:16 +08:00
Kevin Yue
42cae3ff26 Port the splitCommand method (#79) 2021-08-19 19:10:05 +08:00
Kevin Yue
53c8572cf6 Update main.yml 2021-08-19 18:42:26 +08:00
Kevin Yue
3f6467321f Update main.yml 2021-08-19 18:33:01 +08:00
Kevin Yue
563ec48c8c Update main.yml 2021-08-19 18:26:05 +08:00
Kevin Yue
3787ae164c Update main.yml 2021-08-19 18:24:30 +08:00
Kevin Yue
04a24c34e8 Update future plan 2021-08-18 16:16:52 +08:00
Kevin Yue
fe68248b1f Add future plan 2021-08-18 16:03:08 +08:00
Kevin Yue
47013033ec Release 1.3.0 2021-08-15 20:44:18 +08:00
Kevin Yue
05fb9a26bd Update links 2021-08-15 20:40:13 +08:00
Kevin Yue
96962f957c Add links (#77) 2021-08-15 17:36:51 +08:00
Kevin Yue
b4f9cfae67 Support custom parameters (#76)
* Add the setting icon

* Add support for custom parameters

* Ignore auto generated files

* Update README.md
2021-08-15 12:47:02 +08:00
Jan Vlug
c8942984a8 Added missing dependency for Fedora 34 (#75)
* Added missing dependency for Fedora 34.

* Removed architecture specification.

* Whitespace.
2021-08-08 19:17:15 +08:00
Darío Cutillas
3907827d0e Add pre-requisites for Fedora (#73) 2021-08-03 22:25:09 +08:00
Kevin Yue
f089996cdc Release 1.2.9 2021-08-03 22:20:36 +08:00
Tom Almeida
260b557238 Properly handle gateway responses that return Javascript errors (#74)
This was previously causing a segmentation fault, as the gateway
response would not be valid XML to be parsed.

Closes: #38, #71
2021-08-03 22:17:50 +08:00
Robert M Flight
3495dbfe18 Remove qt5 default (#68)
* removing qt5-default

as of ubuntu 21.04 it doesn't exist anymore

* update readme

based on ubuntu 21, and actually installing the deb for ubuntu

* missed the other package
2021-07-04 18:31:28 +08:00
Matt McHenry
cdf193024c README.md: add section for NixOS (#65) 2021-06-18 21:35:28 +08:00
Kevin Yue
76de070d78 Update publish.yml 2021-05-07 13:42:33 +08:00
Kevin Yue
420ae27888 Update publish.yml 2021-05-07 13:34:22 +08:00
Tobias Sarnowski
6a347746cc Mark for inclusion in aarch64 archlinux repository (#58)
This version of the software was tested on current Manjaro as of this
commit date on a Pinebook Pro with the official aarch64 KDE image.
2021-05-06 15:19:07 +08:00
Kevin Yue
624babb380 Update publish.yml 2021-04-25 21:24:08 +08:00
Kevin Yue
511b20fdcd Update publish.yml 2021-04-25 10:36:44 +08:00
Kevin Yue
abe33c7407 Update publish.yml 2021-04-25 10:29:03 +08:00
Kevin Yue
99a82c8641 Update publish.yml 2021-04-24 23:08:10 +08:00
Kevin Yue
e5d0acad3c Update publish.yml 2021-04-24 22:44:24 +08:00
Kevin Yue
38a1eded19 Release 1.2.8 2021-04-24 22:21:29 +08:00
Kevin Yue
3e23e7eaae Update publish action 2021-04-24 22:20:33 +08:00
Kevin Yue
cf46848e63 Merge branch 'add-github-actions' 2021-04-24 22:15:42 +08:00
Kevin Yue
2e826201d2 Create publish.yml 2021-04-24 22:13:48 +08:00
Kevin Yue
adba408dc3 Add PKGBUILD.template 2021-04-24 21:13:33 +08:00
Kevin Yue
5d613369ee Create main.yml 2021-04-24 19:02:07 +08:00
hakasapl
ebd3de6f63 added startupwmclass to desktop file (#51) 2021-04-15 16:15:13 +08:00
Michaël Arnauts
266ab65892 Update README.md (#45)
Add qttools5-dev as required package for Ubuntu.
2021-03-03 14:31:23 +08:00
Kevin Yue
ccaf93ec31 Release 1.2.7 2020-12-29 21:32:04 +08:00
Mike Gelfand
e08d7d7c4d Don't quit the app when closing the main window (#40)
Fixes: #15
2020-12-24 10:40:35 +08:00
Raphael Sant'Anna
c14a6ad1d2 Fix parsing of Gateways and Priority Rules (#35)
* Fix gateways and priority rules parsing

* Removing comment with dead code

Co-authored-by: Raphael Sant'Anna <raphael.santanna@exame.com>
2020-11-01 09:55:27 +08:00
36 changed files with 804 additions and 62 deletions

30
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: 5.12.11
modules: 'qtwebengine qtwebsockets'
# Checkout repository and submodules
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Build
run: |
qmake CONFIG+=release
make

60
.github/workflows/pre-release.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: Pre Release
on:
workflow_dispatch:
jobs:
pre-release:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
env:
DEBFULLNAME: "Kevin Yue"
DEBEMAIL: "yuezk001@gmail.com"
steps:
# Checkout repository and submodules
- uses: actions/checkout@v2
with:
submodules: recursive
fetch-depth: 0
- name: Init variables
id: vars
run: |
TAG=$(git tag --sort=-v:refname --list "v[0-9]*" | head -n 1 | cut -c 2-)
echo ::set-output name=VERSION::"${TAG}+SNAPSHOT$(date -u +"%Y%m%d%H%M%S")"
echo ::set-output name=TAG::${TAG}
- name: Update debian/changelog
run: |
sudo apt install devscripts
git log --format="%s" v${{ steps.vars.outputs.TAG }}.. | xargs -L1 dch -v ${{ steps.vars.outputs.VERSION }}-1ppa1
- name: "Archive all"
run: |
python -m pip install --upgrade pip
pip install git-archive-all
git-archive-all \
--force-submodules \
--prefix=globalprotect-openconnect-${{ steps.vars.outputs.VERSION }}/ \
./globalprotect-openconnect-${{ steps.vars.outputs.VERSION }}.full.tar.gz
- name: "Debian Packaging"
run: |
sudo apt update
sudo apt install qtbase5-dev libqt5websockets5-dev qtwebengine5-dev qttools5-dev debhelper
mkdir build-debian && cd build-debian
cp ../*.tar.gz globalprotect-openconnect_${{ steps.vars.outputs.VERSION }}.orig.tar.gz
tar xf *.tar.gz
cd globalprotect-openconnect-${{ steps.vars.outputs.VERSION }}
fakeroot dpkg-buildpackage -uc -us -sa
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
title: "globalprotect-openconnect_${{ steps.vars.outputs.VERSION }}"
files: |
*.tar.gz
build-debian/*.deb

61
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Publish
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: 5.12.11
modules: 'qtwebengine qtwebsockets'
# Checkout repository and submodules
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Build
run: |
qmake CONFIG+=release
make
aur-publish:
needs:
- build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Get latest version
id: get-version
run: |
echo ::set-output name=VERSION::$(git tag --sort=-v:refname --list "v[0-9]*" | head -n 1 | cut -c 2-)
- name: Get the sha256sum
id: get-sha256sum
run: |
echo ::set-output name=SHA::$(curl -L https://github.com/yuezk/GlobalProtect-openconnect/archive/refs/tags/v${{ steps.get-version.outputs.VERSION }}.tar.gz | sha256sum | cut -f1 -d" ")
- name: Generate PKGBUILD
run: |
sed "s/{PKG_VERSION}/${{ steps.get-version.outputs.VERSION }}/g;s/{SOURCE_SHA}/${{ steps.get-sha256sum.outputs.SHA }}/g" PKGBUILD.template > PKGBUILD
- name: Publish AUR package
uses: KSXGitHub/github-actions-deploy-aur@v2.2.4
with:
pkgname: globalprotect-openconnect
pkgbuild: ./PKGBUILD
commit_username: ${{ secrets.AUR_USERNAME }}
commit_email: ${{ secrets.AUR_EMAIL }}
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: 'Release v${{ steps.get-version.outputs.VERSION }}'
force_push: true

7
.gitignore vendored
View File

@@ -2,10 +2,17 @@
gpclient
gpservice
*.rpm
*.gz
.DS_Store
build-debian
# Auto generated DBus files
*_adaptor.cpp
*_adaptor.h
gpservice_interface.*
# C++ objects and libs
*.slo
*.lo

View File

@@ -26,6 +26,7 @@ SOURCES += \
cdpcommandmanager.cpp \
enhancedwebview.cpp \
gatewayauthenticator.cpp \
gatewayauthenticatorparams.cpp \
gpgateway.cpp \
gphelper.cpp \
loginparams.cpp \
@@ -35,13 +36,15 @@ SOURCES += \
portalconfigresponse.cpp \
preloginresponse.cpp \
samlloginwindow.cpp \
gpclient.cpp
gpclient.cpp \
settingsdialog.cpp
HEADERS += \
cdpcommand.h \
cdpcommandmanager.h \
enhancedwebview.h \
gatewayauthenticator.h \
gatewayauthenticatorparams.h \
gpgateway.h \
gphelper.h \
loginparams.h \
@@ -50,11 +53,13 @@ HEADERS += \
portalconfigresponse.h \
preloginresponse.h \
samlloginwindow.h \
gpclient.h
gpclient.h \
settingsdialog.h
FORMS += \
gpclient.ui \
normalloginwindow.ui
normalloginwindow.ui \
settingsdialog.ui
DBUS_INTERFACES += ../GPService/gpservice.xml

View File

@@ -8,3 +8,4 @@ Exec=/usr/bin/gpclient
Icon=com.yuezk.qt.GPClient
Categories=Network;VPN;Utility;Qt;
Keywords=GlobalProtect;Openconnect;SAML;connection;VPN;
StartupWMClass=gpclient

View File

@@ -8,12 +8,16 @@
using namespace gpclient::helper;
GatewayAuthenticator::GatewayAuthenticator(const QString& gateway, const PortalConfigResponse& portalConfig)
GatewayAuthenticator::GatewayAuthenticator(const QString& gateway, const GatewayAuthenticatorParams& params)
: QObject()
, preloginUrl("https://" + gateway + "/ssl-vpn/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100&clientos=Linux")
, gateway(gateway)
, params(params)
, preloginUrl("https://" + gateway + "/ssl-vpn/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100")
, loginUrl("https://" + gateway + "/ssl-vpn/login.esp")
, portalConfig(portalConfig)
{
if (!params.clientos().isEmpty()) {
preloginUrl = preloginUrl + "&clientos=" + params.clientos();
}
}
GatewayAuthenticator::~GatewayAuthenticator()
@@ -25,12 +29,16 @@ void GatewayAuthenticator::authenticate()
{
PLOGI << "Start gateway authentication...";
LoginParams params;
params.setUser(portalConfig.username());
params.setPassword(portalConfig.password());
params.setUserAuthCookie(portalConfig.userAuthCookie());
LoginParams loginParams;
loginParams.setUser(params.username());
loginParams.setPassword(params.password());
loginParams.setUserAuthCookie(params.userAuthCookie());
login(params);
if (!params.clientos().isEmpty()) {
loginParams.setClientos(params.clientos());
}
login(loginParams);
}
void GatewayAuthenticator::login(const LoginParams &params)
@@ -44,8 +52,9 @@ void GatewayAuthenticator::login(const LoginParams &params)
void GatewayAuthenticator::onLoginFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
QByteArray response;
if (reply->error()) {
if (reply->error() || (response = reply->readAll()).contains("Authentication failure")) {
PLOGE << QString("Failed to login the gateway at %1, %2").arg(loginUrl).arg(reply->errorString());
if (normalLoginWindow) {
@@ -61,7 +70,7 @@ void GatewayAuthenticator::onLoginFinished()
normalLoginWindow->close();
}
const QUrlQuery params = gpclient::helper::parseGatewayResponse(reply->readAll());
const QUrlQuery params = gpclient::helper::parseGatewayResponse(response);
emit success(params.toString());
}

View File

@@ -1,16 +1,16 @@
#ifndef GATEWAYAUTHENTICATOR_H
#define GATEWAYAUTHENTICATOR_H
#include "portalconfigresponse.h"
#include "normalloginwindow.h"
#include "loginparams.h"
#include "gatewayauthenticatorparams.h"
#include <QObject>
class GatewayAuthenticator : public QObject
{
Q_OBJECT
public:
explicit GatewayAuthenticator(const QString& gateway, const PortalConfigResponse& portalConfig);
explicit GatewayAuthenticator(const QString& gateway, const GatewayAuthenticatorParams& params);
~GatewayAuthenticator();
void authenticate();
@@ -30,11 +30,10 @@ private slots:
private:
QString gateway;
const GatewayAuthenticatorParams& params;
QString preloginUrl;
QString loginUrl;
const PortalConfigResponse& portalConfig;
NormalLoginWindow *normalLoginWindow{ nullptr };
void login(const LoginParams& params);

View File

@@ -0,0 +1,57 @@
#include "gatewayauthenticatorparams.h"
GatewayAuthenticatorParams::GatewayAuthenticatorParams()
{
}
GatewayAuthenticatorParams GatewayAuthenticatorParams::fromPortalConfigResponse(const PortalConfigResponse &portalConfig)
{
GatewayAuthenticatorParams params;
params.setUsername(portalConfig.username());
params.setPassword(portalConfig.password());
params.setUserAuthCookie(portalConfig.userAuthCookie());
return params;
}
const QString &GatewayAuthenticatorParams::username() const
{
return m_username;
}
void GatewayAuthenticatorParams::setUsername(const QString &newUsername)
{
m_username = newUsername;
}
const QString &GatewayAuthenticatorParams::password() const
{
return m_password;
}
void GatewayAuthenticatorParams::setPassword(const QString &newPassword)
{
m_password = newPassword;
}
const QString &GatewayAuthenticatorParams::userAuthCookie() const
{
return m_userAuthCookie;
}
void GatewayAuthenticatorParams::setUserAuthCookie(const QString &newUserAuthCookie)
{
m_userAuthCookie = newUserAuthCookie;
}
const QString &GatewayAuthenticatorParams::clientos() const
{
return m_clientos;
}
void GatewayAuthenticatorParams::setClientos(const QString &newClientos)
{
m_clientos = newClientos;
}

View File

@@ -0,0 +1,33 @@
#ifndef GATEWAYAUTHENTICATORPARAMS_H
#define GATEWAYAUTHENTICATORPARAMS_H
#include <QString>
#include "portalconfigresponse.h"
class GatewayAuthenticatorParams
{
public:
GatewayAuthenticatorParams();
static GatewayAuthenticatorParams fromPortalConfigResponse(const PortalConfigResponse &portalConfig);
const QString &username() const;
void setUsername(const QString &newUsername);
const QString &password() const;
void setPassword(const QString &newPassword);
const QString &userAuthCookie() const;
void setUserAuthCookie(const QString &newUserAuthCookie);
const QString &clientos() const;
void setClientos(const QString &newClientos);
private:
QString m_username;
QString m_password;
QString m_userAuthCookie;
QString m_clientos;
};
#endif // GATEWAYAUTHENTICATORPARAMS_H

View File

@@ -3,6 +3,8 @@
#include "ui_gpclient.h"
#include "portalauthenticator.h"
#include "gatewayauthenticator.h"
#include "settingsdialog.h"
#include "gatewayauthenticatorparams.h"
#include <plog/Log.h>
#include <QIcon>
@@ -12,12 +14,16 @@ using namespace gpclient::helper;
GPClient::GPClient(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::GPClient)
, settingsDialog(new SettingsDialog(this))
{
ui->setupUi(this);
setWindowTitle("GlobalProtect");
setFixedSize(width(), height());
gpclient::helper::moveCenter(this);
setupSettings();
// Restore portal from the previous settings
ui->portalInput->setText(settings::get("portal", "").toString());
@@ -25,6 +31,7 @@ GPClient::GPClient(QWidget *parent)
vpn = new com::yuezk::qt::GPService("com.yuezk.qt.GPService", "/", QDBusConnection::systemBus(), this);
connect(vpn, &com::yuezk::qt::GPService::connected, this, &GPClient::onVPNConnected);
connect(vpn, &com::yuezk::qt::GPService::disconnected, this, &GPClient::onVPNDisconnected);
connect(vpn, &com::yuezk::qt::GPService::error, this, &GPClient::onVPNError);
connect(vpn, &com::yuezk::qt::GPService::logAvailable, this, &GPClient::onVPNLogAvailable);
// Initiallize the context menu of system tray.
@@ -36,6 +43,39 @@ GPClient::~GPClient()
{
delete ui;
delete vpn;
delete settingsDialog;
delete settingsButton;
}
void GPClient::setupSettings()
{
settingsButton = new QPushButton(this);
settingsButton->setIcon(QIcon(":/images/settings_icon.png"));
settingsButton->setFixedSize(QSize(28, 28));
QRect rect = this->geometry();
settingsButton->setGeometry(
rect.width() - settingsButton->width() - 15,
15,
settingsButton->geometry().width(),
settingsButton->geometry().height()
);
connect(settingsButton, &QPushButton::clicked, this, &GPClient::onSettingsButtonClicked);
connect(settingsDialog, &QDialog::accepted, this, &GPClient::onSettingsAccepted);
}
void GPClient::onSettingsButtonClicked()
{
settingsDialog->setExtraArgs(settings::get("extraArgs", "").toString());
settingsDialog->setClientos(settings::get("clientos", "Linux").toString());
settingsDialog->show();
}
void GPClient::onSettingsAccepted()
{
settings::save("extraArgs", settingsDialog->extraArgs());
settings::save("clientos", settingsDialog->clientos());
}
void GPClient::on_connectButton_clicked()
@@ -69,7 +109,7 @@ void GPClient::initSystemTrayIcon()
connect(systemTrayIcon, &QSystemTrayIcon::activated, this, &GPClient::onSystemTrayActivated);
connect(gatewaySwitchMenu, &QMenu::triggered, this, &GPClient::onGatewayChanged);
openAction = contextMenu->addAction(QIcon::fromTheme("window-new"), "Open", this, &GPClient::activiate);
openAction = contextMenu->addAction(QIcon::fromTheme("window-new"), "Open", this, &GPClient::activate);
connectAction = contextMenu->addAction(QIcon::fromTheme("preferences-system-network"), "Connect", this, &GPClient::doConnect);
contextMenu->addMenu(gatewaySwitchMenu);
contextMenu->addSeparator();
@@ -167,7 +207,7 @@ void GPClient::onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason)
switch (reason) {
case QSystemTrayIcon::Trigger:
case QSystemTrayIcon::DoubleClick:
this->activiate();
this->activate();
break;
default:
break;
@@ -209,7 +249,7 @@ void GPClient::doConnect()
// Display the main window if portal is empty
if (portal.isEmpty()) {
activiate();
activate();
return;
}
@@ -238,7 +278,7 @@ void GPClient::doConnect()
// Login to the portal interface to get the portal config and preferred gateway
void GPClient::portalLogin()
{
PortalAuthenticator *portalAuth = new PortalAuthenticator(portal());
PortalAuthenticator *portalAuth = new PortalAuthenticator(portal(), settings::get("clientos", "Linux").toString());
connect(portalAuth, &PortalAuthenticator::success, this, &GPClient::onPortalSuccess);
// Prelogin failed on the portal interface, try to treat the portal as a gateway interface
@@ -315,7 +355,10 @@ void GPClient::gatewayLogin()
{
PLOGI << "Performing gateway login...";
GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), portalConfig);
GatewayAuthenticatorParams params = GatewayAuthenticatorParams::fromPortalConfigResponse(portalConfig);
params.setClientos(settings::get("clientos", "Linux").toString());
GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), params);
connect(gatewayAuth, &GatewayAuthenticator::success, this, &GPClient::onGatewaySuccess);
connect(gatewayAuth, &GatewayAuthenticator::fail, this, &GPClient::onGatewayFail);
@@ -330,7 +373,7 @@ void GPClient::onGatewaySuccess(const QString &authCookie)
PLOGI << "Gateway login succeeded, got the cookie " << authCookie;
isQuickConnect = false;
vpn->connect(currentGateway().address(), portalConfig.username(), authCookie);
vpn->connect(currentGateway().address(), portalConfig.username(), authCookie, settings::get("extraArgs", "").toString());
ui->statusLabel->setText("Connecting...");
updateConnectionStatus(VpnStatus::pending);
}
@@ -351,7 +394,7 @@ void GPClient::onGatewayFail(const QString &msg)
updateConnectionStatus(VpnStatus::disconnected);
}
void GPClient::activiate()
void GPClient::activate()
{
activateWindow();
showNormal();
@@ -435,6 +478,12 @@ void GPClient::onVPNDisconnected()
}
}
void GPClient::onVPNError(QString errorMessage)
{
updateConnectionStatus(VpnStatus::disconnected);
openMessageBox("Failed to connect", errorMessage);
}
void GPClient::onVPNLogAvailable(QString log)
{
PLOGI << log;

View File

@@ -3,10 +3,12 @@
#include "gpservice_interface.h"
#include "portalconfigresponse.h"
#include "settingsdialog.h"
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class GPClient; }
@@ -20,9 +22,12 @@ public:
GPClient(QWidget *parent = nullptr);
~GPClient();
void activiate();
void activate();
private slots:
void onSettingsButtonClicked();
void onSettingsAccepted();
void on_connectButton_clicked();
void on_portalInput_returnPressed();
void on_portalInput_editingFinished();
@@ -40,6 +45,7 @@ private slots:
void onVPNConnected();
void onVPNDisconnected();
void onVPNError(QString errorMessage);
void onVPNLogAvailable(QString log);
private:
@@ -62,10 +68,15 @@ private:
QAction *clearAction;
QAction *quitAction;
SettingsDialog *settingsDialog;
QPushButton *settingsButton;
bool isQuickConnect { false };
bool isSwitchingGateway { false };
PortalConfigResponse portalConfig;
void setupSettings();
void initSystemTrayIcon();
void initVpnStatus();
void populateGatewayMenu();

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>260</width>
<height>338</height>
<height>362</height>
</rect>
</property>
<property name="windowTitle">
@@ -36,7 +36,7 @@
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,0">
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,0,0">
<property name="leftMargin">
<number>15</number>
</property>
@@ -123,6 +123,16 @@
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;https://bit.ly/3g5DHqy&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4c6b8a;&quot;&gt;Report a bug&lt;/span&gt;&lt;/a&gt; / &lt;a href=&quot;https://bit.ly/3jQYfEi&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4c6b8a;&quot;&gt;Buy me a coffee&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@@ -116,7 +116,13 @@ void gpclient::helper::settings::save(const QString &key, const QVariant &value)
_settings->setValue(key, value);
}
void gpclient::helper::settings::clear()
{
_settings->clear();
QStringList keys = _settings->allKeys();
for (const auto &key : qAsConst(keys)) {
if (!reservedKeys.contains(key)) {
_settings->remove(key);
}
}
}

View File

@@ -31,6 +31,7 @@ namespace gpclient {
namespace settings {
extern QSettings *_settings;
static const QStringList reservedKeys {"extraArgs", "clientos"};
QVariant get(const QString &key, const QVariant &defaultValue = QVariant());
void save(const QString &key, const QVariant &value);

View File

@@ -15,7 +15,6 @@ LoginParams::LoginParams()
params.addQueryItem("direct", "yes");
params.addQueryItem("clientVer", "4100");
params.addQueryItem("os-version", QUrl::toPercentEncoding(QSysInfo::prettyProductName()));
params.addQueryItem("clientos", "Linux");
params.addQueryItem("portal-userauthcookie", "");
params.addQueryItem("portal-prelogonuserauthcookie", "");
params.addQueryItem("prelogin-cookie", "");
@@ -56,6 +55,11 @@ void LoginParams::setPreloginCookie(const QString cookie)
updateQueryItem("prelogin-cookie", cookie);
}
void LoginParams::setClientos(const QString clientos)
{
updateQueryItem("clientos", clientos);
}
QByteArray LoginParams::toUtf8() const
{
return params.toString().toUtf8();

View File

@@ -15,6 +15,7 @@ public:
void setUserAuthCookie(const QString cookie);
void setPrelogonAuthCookie(const QString cookie);
void setPreloginCookie(const QString cookie);
void setClientos(const QString clientos);
QByteArray toUtf8() const;

View File

@@ -6,7 +6,7 @@
#include <plog/Log.h>
#include <plog/Appenders/ColorConsoleAppender.h>
static const QString version = "v1.2.5";
static const QString version = "v1.3.2";
int main(int argc, char *argv[])
{
@@ -28,10 +28,12 @@ int main(int argc, char *argv[])
}
SingleApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false);
GPClient w;
w.show();
QObject::connect(&app, &SingleApplication::instanceStarted, &w, &GPClient::activiate);
QObject::connect(&app, &SingleApplication::instanceStarted, &w, &GPClient::activate);
return app.exec();
}

View File

@@ -12,11 +12,14 @@
using namespace gpclient::helper;
PortalAuthenticator::PortalAuthenticator(const QString& portal) : QObject()
PortalAuthenticator::PortalAuthenticator(const QString& portal, const QString& clientos) : QObject()
, portal(portal)
, preloginUrl("https://" + portal + "/global-protect/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100&clientos=Linux")
, preloginUrl("https://" + portal + "/global-protect/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100")
, configUrl("https://" + portal + "/global-protect/getconfig.esp")
{
if (!clientos.isEmpty()) {
preloginUrl = preloginUrl + "&clientos=" + clientos;
}
}
PortalAuthenticator::~PortalAuthenticator()

View File

@@ -12,7 +12,7 @@ class PortalAuthenticator : public QObject
{
Q_OBJECT
public:
explicit PortalAuthenticator(const QString& portal);
explicit PortalAuthenticator(const QString& portal, const QString& clientos);
~PortalAuthenticator();
void authenticate();

View File

@@ -46,17 +46,17 @@ PortalConfigResponse PortalConfigResponse::parse(const QByteArray xml)
const QByteArray PortalConfigResponse::rawResponse() const
{
return _rawResponse;
return m_rawResponse;
}
QString PortalConfigResponse::username() const
const QString &PortalConfigResponse::username() const
{
return _username;
return m_username;
}
QString PortalConfigResponse::password() const
{
return _password;
return m_password;
}
QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader)
@@ -65,6 +65,14 @@ QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader
QList<GPGateway> gateways;
while (xmlReader.name() != "external"){
xmlReader.readNext();
}
while (xmlReader.name() != "list"){
xmlReader.readNext();
}
while (xmlReader.name() != xmlGateways || !xmlReader.isEndElement()) {
xmlReader.readNext();
// Parse the gateways -> external -> list -> entry
@@ -89,13 +97,15 @@ QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xm
QMap<QString, int> priorityRules;
while (xmlReader.name() != "priority-rule" || !xmlReader.isEndElement()) {
while ((xmlReader.name() != "priority-rule" || !xmlReader.isEndElement()) && !xmlReader.hasError()) {
xmlReader.readNext();
if (xmlReader.name() == "entry" && xmlReader.isStartElement()) {
QString ruleName = xmlReader.attributes().value("name").toString();
// Read the priority tag
xmlReader.readNextStartElement();
while (xmlReader.name() != "priority"){
xmlReader.readNext();
}
int ruleValue = xmlReader.readElementText().toUInt();
priorityRules.insert(ruleName, ruleValue);
}
@@ -124,45 +134,45 @@ QString PortalConfigResponse::parseGatewayName(QXmlStreamReader &xmlReader)
QString PortalConfigResponse::userAuthCookie() const
{
return _userAuthCookie;
return m_userAuthCookie;
}
QString PortalConfigResponse::prelogonUserAuthCookie() const
{
return _prelogonAuthCookie;
return m_prelogonAuthCookie;
}
QList<GPGateway> PortalConfigResponse::allGateways() const
{
return _gateways;
return m_gateways;
}
void PortalConfigResponse::setAllGateways(QList<GPGateway> gateways)
{
_gateways = gateways;
m_gateways = gateways;
}
void PortalConfigResponse::setRawResponse(const QByteArray response)
{
_rawResponse = response;
m_rawResponse = response;
}
void PortalConfigResponse::setUsername(const QString username)
{
_username = username;
m_username = username;
}
void PortalConfigResponse::setPassword(const QString password)
{
_password = password;
m_password = password;
}
void PortalConfigResponse::setUserAuthCookie(const QString cookie)
{
_userAuthCookie = cookie;
m_userAuthCookie = cookie;
}
void PortalConfigResponse::setPrelogonUserAuthCookie(const QString cookie)
{
_prelogonAuthCookie = cookie;
m_prelogonAuthCookie = cookie;
}

View File

@@ -16,7 +16,7 @@ public:
static PortalConfigResponse parse(const QByteArray xml);
const QByteArray rawResponse() const;
QString username() const;
const QString &username() const;
QString password() const;
QString userAuthCookie() const;
QString prelogonUserAuthCookie() const;
@@ -31,13 +31,13 @@ private:
static QString xmlPrelogonUserAuthCookie;
static QString xmlGateways;
QByteArray _rawResponse;
QString _username;
QString _password;
QString _userAuthCookie;
QString _prelogonAuthCookie;
QByteArray m_rawResponse;
QString m_username;
QString m_password;
QString m_userAuthCookie;
QString m_prelogonAuthCookie;
QList<GPGateway> _gateways;
QList<GPGateway> m_gateways;
void setRawResponse(const QByteArray response);
void setUserAuthCookie(const QString cookie);

View File

@@ -6,5 +6,6 @@
<file>not_connected.png</file>
<file>radio_unselected.png</file>
<file>radio_selected.png</file>
<file>settings_icon.png</file>
</qresource>
</RCC>

BIN
GPClient/settings_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,34 @@
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
SettingsDialog::SettingsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
}
SettingsDialog::~SettingsDialog()
{
delete ui;
}
void SettingsDialog::setExtraArgs(QString extraArgs)
{
ui->extraArgsInput->setPlainText(extraArgs);
}
QString SettingsDialog::extraArgs()
{
return ui->extraArgsInput->toPlainText().trimmed();
}
void SettingsDialog::setClientos(QString clientos)
{
ui->clientosInput->setText(clientos);
}
QString SettingsDialog::clientos()
{
return ui->clientosInput->text();
}

28
GPClient/settingsdialog.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include <QDialog>
namespace Ui {
class SettingsDialog;
}
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit SettingsDialog(QWidget *parent = nullptr);
~SettingsDialog();
void setExtraArgs(QString extraArgs);
QString extraArgs();
void setClientos(QString clientos);
QString clientos();
private:
Ui::SettingsDialog *ui;
};
#endif // SETTINGSDIALOG_H

104
GPClient/settingsdialog.ui Normal file
View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>488</width>
<height>177</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<property name="windowIcon">
<iconset resource="resources.qrc">
<normaloff>:/images/connected.png</normaloff>:/images/connected.png</iconset>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Custom Parameters:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPlainTextEdit" name="extraArgsInput">
<property name="placeholderText">
<string extracomment="Tokens with spaces can be surrounded by double quotes">e.g. --name=value --script=&quot;vpn-slice xxx&quot;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Value of &quot;clientos&quot;:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="clientosInput">
<property name="placeholderText">
<string>e.g., Windows</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -39,6 +39,47 @@ QString GPService::findBinary()
return nullptr;
}
/* Port from https://github.com/qt/qtbase/blob/11d1dcc6e263c5059f34b44d531c9ccdf7c0b1d6/src/corelib/io/qprocess.cpp#L2115 */
QStringList GPService::splitCommand(QStringView command)
{
QStringList args;
QString tmp;
int quoteCount = 0;
bool inQuote = false;
// handle quoting. tokens can be surrounded by double quotes
// "hello world". three consecutive double quotes represent
// the quote character itself.
for (int i = 0; i < command.size(); ++i) {
if (command.at(i) == QLatin1Char('"')) {
++quoteCount;
if (quoteCount == 3) {
// third consecutive quote
quoteCount = 0;
tmp += command.at(i);
}
continue;
}
if (quoteCount) {
if (quoteCount == 1)
inQuote = !inQuote;
quoteCount = 0;
}
if (!inQuote && command.at(i).isSpace()) {
if (!tmp.isEmpty()) {
args += tmp;
tmp.clear();
}
} else {
tmp += command.at(i);
}
}
if (!tmp.isEmpty())
args += tmp;
return args;
}
void GPService::quit()
{
if (openconnect->state() == QProcess::NotRunning) {
@@ -49,7 +90,7 @@ void GPService::quit()
}
}
void GPService::connect(QString server, QString username, QString passwd)
void GPService::connect(QString server, QString username, QString passwd, QString extraArgs)
{
if (vpnStatus != GPService::VpnNotConnected) {
log("VPN status is: " + QVariant::fromValue(vpnStatus).toString());
@@ -58,17 +99,21 @@ void GPService::connect(QString server, QString username, QString passwd)
QString bin = findBinary();
if (bin == nullptr) {
log("Could not found openconnect binary, make sure openconnect is installed, exiting.");
log("Could not find openconnect binary, make sure openconnect is installed, exiting.");
emit error("The OpenConect CLI was not found, make sure it has been installed!");
return;
}
QStringList args;
args << QCoreApplication::arguments().mid(1)
<< "--protocol=gp"
<< splitCommand(extraArgs)
<< "-u" << username
<< "-C" << passwd
<< server;
log("Start process with arugments: " + args.join(" "));
openconnect->start(bin, args);
}

View File

@@ -31,10 +31,11 @@ public:
signals:
void connected();
void disconnected();
void error(QString errorMessage);
void logAvailable(QString log);
public slots:
void connect(QString server, QString username, QString passwd);
void connect(QString server, QString username, QString passwd, QString extraArgs);
void disconnect();
int status();
void quit();
@@ -53,6 +54,7 @@ private:
void log(QString msg);
static QString findBinary();
static QStringList splitCommand(QStringView command);
};
#endif // GLOBALPROTECTSERVICE_H

View File

@@ -8,10 +8,14 @@
<signal name="logAvailable">
<arg name="log" type="s" />
</signal>
<signal name="error">
<arg name="errorMessage" type="s" />
</signal>
<method name="connect">
<arg name="server" type="s" direction="in"/>
<arg name="username" type="s" direction="in"/>
<arg name="passwd" type="s" direction="in"/>
<arg name="extraArgs" type="s" direction="in"/>
</method>
<method name="disconnect">
</method>

39
PKGBUILD.template Normal file
View File

@@ -0,0 +1,39 @@
# Maintainer: Keinv Yue <yuezk001@gmail.com>
pkgname=globalprotect-openconnect
_gitname=GlobalProtect-openconnect
pkgver={PKG_VERSION}
pkgrel=1
pkgdesc="A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Qt5, supports SAML auth mode."
arch=(x86_64 aarch64)
url="https://github.com/yuezk/${_gitname}"
license=('GPL3')
depends=('openconnect>=8.0.0' qt5-base qt5-webengine qt5-websockets)
makedepends=()
source=(
"${_gitname}-${pkgver}.tar.gz::${url}/archive/v${pkgver}.tar.gz"
"https://github.com/itay-grudev/SingleApplication/archive/v3.0.19.tar.gz"
"https://github.com/SergiusTheBest/plog/archive/1.1.5.tar.gz"
)
sha256sums=(
'{SOURCE_SHA}'
'9405fd259288b2a862e91e5135bccee936f0438e1b32c13603277132309d15e0'
'6c80b4701183d2415bec927e1f5ca9b1761b3b5c65d3e09fb29c743e016d5609'
);
prepare() {
mv "$srcdir/SingleApplication-3.0.19" -T "$srcdir/${_gitname}-${pkgver}/singleapplication"
mv "$srcdir/plog-1.1.5" -T "$srcdir/${_gitname}-${pkgver}/plog"
}
build() {
cd "$srcdir/${_gitname}-${pkgver}"
qmake CONFIG+=release "${srcdir}/${_gitname}-${pkgver}/GlobalProtect-openconnect.pro"
make
}
package() {
cd "$srcdir/${_gitname}-${pkgver}"
make INSTALL_ROOT="$pkgdir/" install
}

View File

@@ -12,6 +12,32 @@ A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Q
- Supports automatically selecting the preferred gateway from the multiple gateways.
- Supports switching gateway from the system tray menu manually.
## Future plan
- [ ] Improve the release process
- [ ] Process bugs and feature requests
- [ ] Support for bypassing the `gpclient` parameters
- [ ] Support the CLI mode
## Passing the Custom Parameters to `OpenConnect` CLI
Custom parameters can be appended to the `OpenConnect` CLI with the following settings.
> Tokens with spaces can be surrounded by double quotes; three consecutive double quotes represent the quote character itself.
<p align="center">
<img src="https://user-images.githubusercontent.com/3297602/130319209-744be02b-d657-4f49-a76d-d2c81b5c46d5.png" />
<p>
## Display the system tray icon on Gnome 40
Install the [AppIndicator and KStatusNotifierItem Support](https://extensions.gnome.org/extension/615/appindicator-support/) extension and you will see the system try icon (Restart the system after the installation).
<p align="center">
<img src="https://user-images.githubusercontent.com/3297602/130831022-b93492fd-46dd-4a8e-94a4-13b5747120b7.png" />
<p>
## Prerequisites
- Openconnect v8.x
@@ -20,12 +46,27 @@ A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Q
### Ubuntu
1. Install openconnect v8.x
```sh
sudo apt install openconnect
openconnect --version
```
For Ubuntu 18.04 you might need to [build the latest openconnect from source code](https://gist.github.com/yuezk/ab9a4b87a9fa0182bdb2df41fab5f613).
2. Install the Qt dependencies
For Ubuntu 20, this should work.
```sh
sudo apt install qt5-default libqt5websockets5-dev qtwebengine5-dev
sudo apt install qtbase5-dev libqt5websockets5-dev qtwebengine5-dev qttools5-dev debhelper
```
For Ubuntu 21, you need to install the base pieces separately as QT5 is the default.
```sh
sudo apt install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5websockets5-dev qtwebengine5-dev qttools5-dev debhelper
```
### OpenSUSE
Install the Qt dependencies
@@ -33,6 +74,13 @@ Install the Qt dependencies
sudo zypper install libqt5-qtbase-devel libqt5-qtwebsockets-devel libqt5-qtwebengine-devel
```
### Fedora
Install the Qt dependencies:
```sh
sudo dnf install qt5-qtbase-devel qt5-qtwebengine-devel qt5-qtwebsockets-devel
```
## Install
### Install from AUR (Arch/Manjaro)
@@ -76,15 +124,28 @@ Relatively manual process for now:
git-archive-all --force-submodules --prefix=globalprotect-openconnect-1.3.0/ ../globalprotect-openconnect_1.3.0.orig.tar.gz
```
* Finally extract the source tree and build the debian package.
* Finally extract the source tree, build the debian package, and install it.
```
cd ..
tar -xzvf globalprotect-openconnect_1.3.0.orig.tar.gz
cd globalprotect-openconnect-1.3.0
fakeroot dpkg-buildpackage -uc -us -sa 2>&1 | tee ../build.log
sudo dpkg -i globalprotect-openconnect_1.3.0-1ppa1_amd64.deb
```
### NixOS
In `configuration.nix`:
```
services.globalprotect = {
enable = true;
# if you need a Host Integrity Protection report
csdWrapper = "${pkgs.openconnect}/libexec/openconnect/hipreport.sh";
};
environment.systemPackages = [ globalprotect-openconnect ];
```
## [License](./LICENSE)

2
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: globalprotect-openconnect
Section: net
Priority: optional
Maintainer: Kevin Yue <k3vinyue@gmail.com>
Build-Depends: debhelper (>=11~), qt5-default (>=5.9), qttools5-dev (>=5.9), libqt5websockets5-dev (>=5.9), qtwebengine5-dev (>=5.9)
Build-Depends: debhelper (>=11~), qtbase5-dev, qttools5-dev (>=5.9), libqt5websockets5-dev (>=5.9), qtwebengine5-dev (>=5.9)
Standards-Version: 4.1.4
Homepage: https://github.com/yuezk/GlobalProtect-openconnect

5
packaging/rpm/README.md Normal file
View File

@@ -0,0 +1,5 @@
## Command
```sh
docker run --rm -it -v ${PWD}:/rpm --workdir=/rpm --entrypoint ./entrypoint.sh centos:8
```

21
packaging/rpm/entrypoint.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash -e
# Install the build tools
dnf install -y epel-release
rpm --import http://download.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8
dnf install -y make rpm-build rpm-devel rpmlint rpmdevtools
# Install the build dependencies
dnf install -y qt5-qtbase-devel qt5-qtwebengine-devel qt5-qtwebsockets-devel
# Prepare the RPM build environment
rpmdev-setuptree
cp *.spec $HOME/rpmbuild/SPECS/
cp *.tar.gz $HOME/rpmbuild/SOURCES/
# Build
rpmbuild -ba $HOME/rpmbuild/SPECS/globalprotect-openconnect.spec
# Copy the package to the current directory
cp $HOME/rpmbuild/RPMS/x86_64/globalprotect-openconnect-*.rpm .
cp $HOME/rpmbuild/SRPMS/globalprotect-openconnect-*.src.rpm .

View File

@@ -0,0 +1,39 @@
Name: globalprotect-openconnect
Version: 1.3.0+SNAPSHOT20210829120923
Release: 1
Summary: A GlobalProtect VPN client
License: GPLv3
URL: https://github.com/yuezk/GlobalProtect-openconnect
Source0: %{url}/releases/download/latest/globalprotect-openconnect_%{version}.full.tar.gz
BuildRequires: qt5-qtbase-devel qt5-qtwebengine-devel qt5-qtwebsockets-devel
Requires: qt5-qtbase >= 5.12 qt5-qtwebengine >= 5.12 qt5-qtwebsockets >= 5.12 openconnect >= 8.0
%global debug_package %{nil}
%description
A GlobalProtect VPN client (GUI) for Linux based on OpenConnect and built with Qt5, supports SAML auth mode.
%prep
%autosetup
%build
qmake-qt5 CONFIG+=release
%make_build
%install
INSTALL_ROOT=${RPM_BUILD_ROOT} %make_install
%files
/etc/systemd/system/gpservice.service
/usr/bin/gpclient
/usr/bin/gpservice
/usr/share/applications/com.yuezk.qt.gpclient.desktop
/usr/share/dbus-1/system-services/com.yuezk.qt.GPService.service
/usr/share/dbus-1/system.d/com.yuezk.qt.GPService.conf
/usr/share/pixmaps/com.yuezk.qt.GPClient.svg