Add a scripting mode to GPClient (#110)

This commit is contained in:
Karolin Varner 2021-12-20 11:46:16 +01:00 committed by GitHub
parent dd81ed9519
commit 9d6ec84c14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 190 additions and 27 deletions

2
3rdparty/plog vendored

@ -1 +1 @@
Subproject commit f4c22b03d5d3aa753cca8e716636ac4eb29b0917 Subproject commit 914e799d2b08d790f5d04d1c46928586b3a41250

View File

@ -33,6 +33,8 @@ add_executable(gpclient
gpclient.ui gpclient.ui
normalloginwindow.ui normalloginwindow.ui
settingsdialog.ui settingsdialog.ui
vpn_dbus.cpp
vpn_json.cpp
resources.qrc resources.qrc
${gpclient_GENERATED_SOURCES} ${gpclient_GENERATED_SOURCES}
) )
@ -52,7 +54,7 @@ add_3rdparty(
add_3rdparty( add_3rdparty(
plog plog
GIT_REPOSITORY https://github.com/SergiusTheBest/plog.git GIT_REPOSITORY https://github.com/SergiusTheBest/plog.git
GIT_TAG 1.1.5 GIT_TAG master
CMAKE_ARGS CMAKE_ARGS
-DPLOG_BUILD_SAMPLES=OFF -DPLOG_BUILD_SAMPLES=OFF
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}

View File

@ -11,9 +11,10 @@
using namespace gpclient::helper; using namespace gpclient::helper;
GPClient::GPClient(QWidget *parent) GPClient::GPClient(QWidget *parent, IVpn *vpn)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::GPClient) , ui(new Ui::GPClient)
, vpn(vpn)
, settingsDialog(new SettingsDialog(this)) , settingsDialog(new SettingsDialog(this))
{ {
ui->setupUi(this); ui->setupUi(this);
@ -25,14 +26,14 @@ GPClient::GPClient(QWidget *parent)
setupSettings(); setupSettings();
// Restore portal from the previous settings // Restore portal from the previous settings
ui->portalInput->setText(settings::get("portal", "").toString()); this->portal(settings::get("portal", "").toString());
// DBus service setup // DBus service setup
vpn = new com::yuezk::qt::GPService("com.yuezk.qt.GPService", "/", QDBusConnection::systemBus(), this); QObject *ov = dynamic_cast<QObject*>(vpn);
connect(vpn, &com::yuezk::qt::GPService::connected, this, &GPClient::onVPNConnected); connect(ov, SIGNAL(connected()), this, SLOT(onVPNConnected()));
connect(vpn, &com::yuezk::qt::GPService::disconnected, this, &GPClient::onVPNDisconnected); connect(ov, SIGNAL(disconnected()), this, SLOT(onVPNDisconnected()));
connect(vpn, &com::yuezk::qt::GPService::error, this, &GPClient::onVPNError); connect(ov, SIGNAL(error(const &QString)), this, SLOT(onVPNError(const QString&)));
connect(vpn, &com::yuezk::qt::GPService::logAvailable, this, &GPClient::onVPNLogAvailable); connect(ov, SIGNAL(logAvailable(const &QString)), this, SLOT(onVPNLogAvailable(const QString&)));
// Initiallize the context menu of system tray. // Initiallize the context menu of system tray.
initSystemTrayIcon(); initSystemTrayIcon();
@ -373,7 +374,11 @@ void GPClient::onGatewaySuccess(const QString &authCookie)
PLOGI << "Gateway login succeeded, got the cookie " << authCookie; PLOGI << "Gateway login succeeded, got the cookie " << authCookie;
isQuickConnect = false; isQuickConnect = false;
vpn->connect(currentGateway().address(), portalConfig.username(), authCookie, settings::get("extraArgs", "").toString()); QList<QString> gatewayAddresses;
for (GPGateway &gw : allGateways()) {
gatewayAddresses.push_back(gw.address());
}
vpn->connect(currentGateway().address(), gatewayAddresses, portalConfig.username(), authCookie, settings::get("extraArgs", "").toString());
ui->statusLabel->setText("Connecting..."); ui->statusLabel->setText("Connecting...");
updateConnectionStatus(VpnStatus::pending); updateConnectionStatus(VpnStatus::pending);
} }
@ -410,6 +415,11 @@ QString GPClient::portal() const
return input; return input;
} }
void GPClient::portal(QString p)
{
ui->portalInput->setText(p);
}
bool GPClient::connected() const bool GPClient::connected() const
{ {
const QString statusText = ui->statusLabel->text(); const QString statusText = ui->statusLabel->text();

View File

@ -6,9 +6,9 @@
#include <QtWidgets/QMenu> #include <QtWidgets/QMenu>
#include <QtWidgets/QPushButton> #include <QtWidgets/QPushButton>
#include "gpserviceinterface.h"
#include "portalconfigresponse.h" #include "portalconfigresponse.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include "vpn.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class GPClient; } namespace Ui { class GPClient; }
@ -19,12 +19,20 @@ class GPClient : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
GPClient(QWidget *parent = nullptr); GPClient(QWidget *parent, IVpn *vpn);
~GPClient(); ~GPClient();
void activate(); void activate();
void quit(); void quit();
QString portal() const;
void portal(QString);
GPGateway currentGateway() const;
void setCurrentGateway(const GPGateway gateway);
void doConnect();
private slots: private slots:
void onSettingsButtonClicked(); void onSettingsButtonClicked();
void onSettingsAccepted(); void onSettingsAccepted();
@ -58,7 +66,7 @@ private:
}; };
Ui::GPClient *ui; Ui::GPClient *ui;
com::yuezk::qt::GPService *vpn; IVpn *vpn;
QSystemTrayIcon *systemTrayIcon; QSystemTrayIcon *systemTrayIcon;
QMenu *contextMenu; QMenu *contextMenu;
@ -83,20 +91,15 @@ private:
void populateGatewayMenu(); void populateGatewayMenu();
void updateConnectionStatus(const VpnStatus &status); void updateConnectionStatus(const VpnStatus &status);
void doConnect();
void portalLogin(); void portalLogin();
void tryGatewayLogin(); void tryGatewayLogin();
void gatewayLogin(); void gatewayLogin();
QString portal() const;
bool connected() const; bool connected() const;
QList<GPGateway> allGateways() const; QList<GPGateway> allGateways() const;
void setAllGateways(QList<GPGateway> gateways); void setAllGateways(QList<GPGateway> gateways);
GPGateway currentGateway() const;
void setCurrentGateway(const GPGateway gateway);
void clearSettings(); void clearSettings();
}; };
#endif // GPCLIENT_H #endif // GPCLIENT_H

View File

@ -3,24 +3,22 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <plog/Log.h> #include <plog/Log.h>
#include <plog/Init.h>
#include <plog/Appenders/ColorConsoleAppender.h> #include <plog/Appenders/ColorConsoleAppender.h>
#include <plog/Formatters/TxtFormatter.h>
#include "singleapplication.h" #include "singleapplication.h"
#include "gpclient.h" #include "gpclient.h"
#include "vpn_dbus.h"
#include "vpn_json.h"
#include "enhancedwebview.h" #include "enhancedwebview.h"
#include "sigwatch.h" #include "sigwatch.h"
#include "version.h" #include "version.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const QDir path = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/GlobalProtect-openconnect"; plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender(plog::streamStdErr);
const QString logFile = path.path() + "/gpclient.log"; plog::init(plog::debug, &consoleAppender);
if (!path.exists()) {
path.mkpath(".");
}
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
plog::init(plog::debug, logFile.toUtf8()).addAppender(&consoleAppender);
PLOGI << "GlobalProtect started, version: " << VERSION; PLOGI << "GlobalProtect started, version: " << VERSION;
@ -33,9 +31,35 @@ int main(int argc, char *argv[])
SingleApplication app(argc, argv); SingleApplication app(argc, argv);
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
GPClient w; QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("server", "The URL of the VPN server. Optional.");
parser.addPositionalArgument("gateway", "The URL of the specific VPN gateway. Optional.");
parser.addOptions({
{"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."},
});
parser.process(app);
const QStringList positional = parser.positionalArguments();
IVpn *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 VpnDbus(nullptr)); // Contact GPService daemon via dbus
GPClient w(nullptr, vpn);
w.show(); w.show();
if (positional.size() > 0) {
w.portal(positional.at(0));
}
if (positional.size() > 1) {
GPGateway gw;
gw.setName(positional.at(1));
gw.setAddress(positional.at(1));
w.setCurrentGateway(gw);
}
QObject::connect(&app, &SingleApplication::instanceStarted, &w, &GPClient::activate); QObject::connect(&app, &SingleApplication::instanceStarted, &w, &GPClient::activate);
UnixSignalWatcher sigwatch; UnixSignalWatcher sigwatch;
@ -45,5 +69,12 @@ 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("now")) {
w.doConnect();
}
if (parser.isSet("json")) {
QObject::connect(static_cast<VpnJson*>(vpn), &VpnJson::connected, &w, &GPClient::quit);
}
return app.exec(); return app.exec();
} }

24
GPClient/vpn.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef VPN_H
#define VPN_H
#include <QtCore/QObject>
#include <QtCore/QString>
class IVpn
{
public:
virtual ~IVpn() = default;
virtual void connect(const QString &preferredServer, const QList<QString> &servers, const QString &username, const QString &passwd, const QString &extraArgs) = 0;
virtual void disconnect() = 0;
virtual int status() = 0;
// signals: // SIGNALS
// virtual void connected();
// virtual void disconnected();
// virtual void error(const QString &errorMessage);
// virtual void logAvailable(const QString &log);
};
Q_DECLARE_INTERFACE(IVpn, "IVpn") // define this out of namespace scope
#endif

13
GPClient/vpn_dbus.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "vpn_dbus.h"
void VpnDbus::connect(const QString &preferredServer, const QList<QString> &servers, const QString &username, const QString &passwd, const QString &extraArgs) {
inner->connect(preferredServer, username, passwd, extraArgs);
}
void VpnDbus::disconnect() {
inner->disconnect();
}
int VpnDbus::status() {
return inner->status();
}

33
GPClient/vpn_dbus.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef VPN_DBUS_H
#define VPN_DBUS_H
#include "vpn.h"
#include "gpserviceinterface.h"
class VpnDbus : public QObject, public IVpn
{
Q_OBJECT
Q_INTERFACES(IVpn)
private:
com::yuezk::qt::GPService *inner;
public:
VpnDbus(QObject *parent) : QObject(parent) {
inner = new com::yuezk::qt::GPService("com.yuezk.qt.GPService", "/", QDBusConnection::systemBus(), this);
QObject::connect(inner, &com::yuezk::qt::GPService::connected, this, &VpnDbus::connected);
QObject::connect(inner, &com::yuezk::qt::GPService::disconnected, this, &VpnDbus::disconnected);
QObject::connect(inner, &com::yuezk::qt::GPService::error, this, &VpnDbus::error);
QObject::connect(inner, &com::yuezk::qt::GPService::logAvailable, this, &VpnDbus::logAvailable);
}
void connect(const QString &preferredServer, const QList<QString> &servers, const QString &username, const QString &passwd, const QString &extraArgs);
void disconnect();
int status();
signals: // SIGNALS
void connected();
void disconnected();
void error(const QString &errorMessage);
void logAvailable(const QString &log);
};
#endif

24
GPClient/vpn_json.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "vpn_json.h"
#include <QTextStream>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
void VpnJson::connect(const QString &preferredServer, const QList<QString> &servers, const QString &username, const QString &passwd, const QString &extraArgs) {
QJsonArray sl;
for (const QString &srv : servers) {
sl.push_back(QJsonValue(srv));
}
QJsonObject j;
j["server"] = preferredServer;
j["availableServers"] = sl;
j["cookie"] = passwd;
QTextStream(stdout) << QJsonDocument(j).toJson(QJsonDocument::Compact) << "\n";
emit connected();
}
void VpnJson::disconnect() { /* nop */ }
int VpnJson::status() {
return 4; // disconnected
}

23
GPClient/vpn_json.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef VPN_JSON_H
#define VPN_JSON_H
#include "vpn.h"
class VpnJson : public QObject, public IVpn
{
Q_OBJECT
Q_INTERFACES(IVpn)
public:
VpnJson(QObject *parent) : QObject(parent) {}
void connect(const QString &preferredServer, const QList<QString> &servers, const QString &username, const QString &passwd, const QString &extraArgs);
void disconnect();
int status();
signals: // SIGNALS
void connected();
void disconnected();
void error(const QString &errorMessage);
void logAvailable(const QString &log);
};
#endif