clean up /platform/linux/ folder

This commit is contained in:
leetthewire 2022-05-11 22:05:00 +00:00
parent ac7de6213a
commit 271e948c1f
21 changed files with 0 additions and 1611 deletions

View file

@ -1,36 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "backendlogsobserver.h"
#include "leakdetector.h"
#include "logger.h"
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
namespace {
Logger logger({LOG_LINUX, LOG_CONTROLLER}, "BackendLogsObserver");
}
BackendLogsObserver::BackendLogsObserver(
QObject* parent, std::function<void(const QString&)>&& callback)
: QObject(parent), m_callback(std::move(callback)) {
MVPN_COUNT_CTOR(BackendLogsObserver);
}
BackendLogsObserver::~BackendLogsObserver() {
MVPN_COUNT_DTOR(BackendLogsObserver);
}
void BackendLogsObserver::completed(QDBusPendingCallWatcher* call) {
QDBusPendingReply<QString> reply = *call;
if (reply.isError()) {
logger.error() << "Error received from the DBus service";
m_callback("Failed to retrieve logs from the mozillavpn linuxdaemon.");
return;
}
QString status = reply.argumentAt<0>();
m_callback(status);
}

View file

@ -1,29 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BACKENDLOGSOBSERVER_H
#define BACKENDLOGSOBSERVER_H
#include <functional>
#include <QObject>
class QDBusPendingCallWatcher;
class BackendLogsObserver final : public QObject {
Q_OBJECT
Q_DISABLE_COPY_MOVE(BackendLogsObserver)
public:
BackendLogsObserver(QObject* parent,
std::function<void(const QString&)>&& callback);
~BackendLogsObserver();
public slots:
void completed(QDBusPendingCallWatcher* call);
private:
std::function<void(const QString&)> m_callback;
};
#endif // BACKENDLOGSOBSERVER_H

View file

@ -1,126 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "dbusclient.h"
#include "ipaddressrange.h"
#include "leakdetector.h"
#include "logger.h"
#include "models/device.h"
#include "models/keys.h"
#include "models/server.h"
#include "mozillavpn.h"
#include "settingsholder.h"
#include <QDBusPendingCall>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
constexpr const char* DBUS_SERVICE = "org.mozilla.vpn.dbus";
constexpr const char* DBUS_PATH = "/";
namespace {
Logger logger(LOG_LINUX, "DBusClient");
}
DBusClient::DBusClient(QObject* parent) : QObject(parent) {
MVPN_COUNT_CTOR(DBusClient);
m_dbus = new OrgMozillaVpnDbusInterface(DBUS_SERVICE, DBUS_PATH,
QDBusConnection::systemBus(), this);
connect(m_dbus, &OrgMozillaVpnDbusInterface::connected, this,
&DBusClient::connected);
connect(m_dbus, &OrgMozillaVpnDbusInterface::disconnected, this,
&DBusClient::disconnected);
}
DBusClient::~DBusClient() { MVPN_COUNT_DTOR(DBusClient); }
QDBusPendingCallWatcher* DBusClient::version() {
logger.debug() << "Version via DBus";
QDBusPendingReply<QString> reply = m_dbus->version();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}
QDBusPendingCallWatcher* DBusClient::activate(
const Server& server, const Device* device, const Keys* keys, int hopindex,
const QList<IPAddressRange>& allowedIPAddressRanges,
const QStringList& vpnDisabledApps, const QHostAddress& dnsServer) {
QJsonObject json;
json.insert("privateKey", QJsonValue(keys->privateKey()));
json.insert("deviceIpv4Address", QJsonValue(device->ipv4Address()));
json.insert("deviceIpv6Address", QJsonValue(device->ipv6Address()));
json.insert("serverIpv4Gateway", QJsonValue(server.ipv4Gateway()));
json.insert("serverIpv6Gateway", QJsonValue(server.ipv6Gateway()));
json.insert("serverPublicKey", QJsonValue(server.publicKey()));
json.insert("serverIpv4AddrIn", QJsonValue(server.ipv4AddrIn()));
json.insert("serverIpv6AddrIn", QJsonValue(server.ipv6AddrIn()));
json.insert("serverPort", QJsonValue((double)server.choosePort()));
json.insert("dnsServer", QJsonValue(dnsServer.toString()));
json.insert("hopindex", QJsonValue((double)hopindex));
QJsonArray allowedIPAddesses;
for (const IPAddressRange& i : allowedIPAddressRanges) {
QJsonObject range;
range.insert("address", QJsonValue(i.ipAddress()));
range.insert("range", QJsonValue((double)i.range()));
range.insert("isIpv6", QJsonValue(i.type() == IPAddressRange::IPv6));
allowedIPAddesses.append(range);
};
json.insert("allowedIPAddressRanges", allowedIPAddesses);
QJsonArray disabledApps;
for (const QString& i : vpnDisabledApps) {
disabledApps.append(QJsonValue(i));
logger.debug() << "Disabling:" << i;
}
json.insert("vpnDisabledApps", disabledApps);
logger.debug() << "Activate via DBus";
QDBusPendingReply<bool> reply =
m_dbus->activate(QJsonDocument(json).toJson(QJsonDocument::Compact));
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}
QDBusPendingCallWatcher* DBusClient::deactivate() {
logger.debug() << "Deactivate via DBus";
QDBusPendingReply<bool> reply = m_dbus->deactivate();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}
QDBusPendingCallWatcher* DBusClient::status() {
logger.debug() << "Status via DBus";
QDBusPendingReply<QString> reply = m_dbus->status();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}
QDBusPendingCallWatcher* DBusClient::getLogs() {
logger.debug() << "Get logs via DBus";
QDBusPendingReply<QString> reply = m_dbus->getLogs();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}
QDBusPendingCallWatcher* DBusClient::cleanupLogs() {
logger.debug() << "Cleanup logs via DBus";
QDBusPendingReply<QString> reply = m_dbus->cleanupLogs();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher,
&QDBusPendingCallWatcher::deleteLater);
return watcher;
}

View file

@ -1,51 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DBUSCLIENT_H
#define DBUSCLIENT_H
#include "dbus_interface.h"
#include <QList>
#include <QObject>
#include <QHostAddress>
class Server;
class Device;
class Keys;
class IPAddressRange;
class QDBusPendingCallWatcher;
class DBusClient final : public QObject {
Q_OBJECT
Q_DISABLE_COPY_MOVE(DBusClient)
public:
DBusClient(QObject* parent);
~DBusClient();
QDBusPendingCallWatcher* version();
QDBusPendingCallWatcher* activate(
const Server& server, const Device* device, const Keys* keys,
int hopindex, const QList<IPAddressRange>& allowedIPAddressRanges,
const QStringList& vpnDisabledApps, const QHostAddress& dnsServer);
QDBusPendingCallWatcher* deactivate();
QDBusPendingCallWatcher* status();
QDBusPendingCallWatcher* getLogs();
QDBusPendingCallWatcher* cleanupLogs();
signals:
void connected(int hopindex);
void disconnected(int hopindex);
private:
OrgMozillaVpnDbusInterface* m_dbus;
};
#endif // DBUSCLIENT_H

View file

@ -1,79 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxappimageprovider.h"
#include "logger.h"
#include "leakdetector.h"
#include <QDir>
#include <QDirIterator>
#include <QProcessEnvironment>
#include <QString>
#include <QSettings>
#include <QIcon>
constexpr const char* PIXMAP_FALLBACK_PATH = "/usr/share/pixmaps/";
constexpr const char* DESKTOP_ICON_LOCATION = "/usr/share/icons/";
namespace {
Logger logger(LOG_CONTROLLER, "LinuxAppImageProvider");
}
LinuxAppImageProvider::LinuxAppImageProvider(QObject* parent)
: AppImageProvider(parent, QQuickImageProvider::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading) {
MVPN_COUNT_CTOR(LinuxAppImageProvider);
QStringList searchPaths = QIcon::fallbackSearchPaths();
QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
if (pe.contains("XDG_DATA_DIRS")) {
QStringList parts = pe.value("XDG_DATA_DIRS").split(":");
for (const QString& part : parts) {
addFallbackPaths(part + "/icons", searchPaths);
}
} else {
addFallbackPaths(DESKTOP_ICON_LOCATION, searchPaths);
}
if (pe.contains("HOME")) {
addFallbackPaths(pe.value("HOME") + "/.local/share/icons", searchPaths);
}
searchPaths << PIXMAP_FALLBACK_PATH;
QIcon::setFallbackSearchPaths(searchPaths);
}
LinuxAppImageProvider::~LinuxAppImageProvider() {
MVPN_COUNT_DTOR(LinuxAppImageProvider);
}
void LinuxAppImageProvider::addFallbackPaths(const QString& iconDir,
QStringList& searchPaths) {
searchPaths << iconDir;
QDirIterator iter(iconDir, QDir::Dirs | QDir::NoDotAndDotDot);
while (iter.hasNext()) {
QFileInfo fileinfo(iter.next());
logger.debug() << "Adding QIcon fallback:" << fileinfo.absoluteFilePath();
searchPaths << fileinfo.absoluteFilePath();
}
}
// from QQuickImageProvider
QImage LinuxAppImageProvider::requestImage(const QString& id, QSize* size,
const QSize& requestedSize) {
QSettings entry(id, QSettings::IniFormat);
entry.beginGroup("Desktop Entry");
QString name = entry.value("Icon").toString();
QIcon icon = QIcon::fromTheme(name);
QPixmap pixmap = icon.pixmap(requestedSize);
size->setHeight(pixmap.height());
size->setWidth(pixmap.width());
logger.debug() << "Loaded icon" << icon.name() << "size:" << pixmap.width()
<< "x" << pixmap.height();
return pixmap.toImage();
}

View file

@ -1,22 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXAPPIMAGEPROVIDER_H
#define LINUXAPPIMAGEPROVIDER_H
#include "appimageprovider.h"
class LinuxAppImageProvider final : public AppImageProvider {
public:
LinuxAppImageProvider(QObject* parent);
~LinuxAppImageProvider();
QImage requestImage(const QString& id, QSize* size,
const QSize& requestedSize) override;
private:
static void addFallbackPaths(const QString& dataDir,
QStringList& fallbackPaths);
};
#endif // LINUXAPPIMAGEPROVIDER_H

View file

@ -1,74 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxapplistprovider.h"
#include "leakdetector.h"
#include <QProcess>
#include <QString>
#include <QDir>
#include <QDirIterator>
#include <QSettings>
#include <QProcessEnvironment>
#include "logger.h"
#include "leakdetector.h"
constexpr const char* DESKTOP_ENTRY_LOCATION = "/usr/share/applications/";
namespace {
Logger logger(LOG_CONTROLLER, "LinuxAppListProvider");
}
LinuxAppListProvider::LinuxAppListProvider(QObject* parent)
: AppListProvider(parent) {
MVPN_COUNT_CTOR(LinuxAppListProvider);
}
LinuxAppListProvider::~LinuxAppListProvider() {
MVPN_COUNT_DTOR(LinuxAppListProvider);
}
void LinuxAppListProvider::fetchEntries(const QString& dataDir,
QMap<QString, QString>& map) {
logger.debug() << "Fetch Application list from" << dataDir;
QDirIterator iter(dataDir, QStringList() << "*.desktop", QDir::Files);
while (iter.hasNext()) {
QFileInfo fileinfo(iter.next());
QSettings entry(fileinfo.filePath(), QSettings::IniFormat);
entry.beginGroup("Desktop Entry");
/* Filter out everything except visible applications. */
if (entry.value("Type").toString() != "Application") {
continue;
}
if (entry.value("NoDisplay", QVariant(false)).toBool()) {
continue;
}
map[fileinfo.absoluteFilePath()] = entry.value("Name").toString();
}
}
void LinuxAppListProvider::getApplicationList() {
logger.debug() << "Fetch Application list from Linux desktop";
QMap<QString, QString> out;
QProcessEnvironment pe = QProcessEnvironment::systemEnvironment();
if (pe.contains("XDG_DATA_DIRS")) {
QStringList parts = pe.value("XDG_DATA_DIRS").split(":");
for (const QString& part : parts) {
fetchEntries(part.trimmed() + "/applications", out);
}
} else {
fetchEntries(DESKTOP_ENTRY_LOCATION, out);
}
if (pe.contains("HOME")) {
fetchEntries(pe.value("HOME") + "/.local/share/applications", out);
}
emit newAppList(out);
}

View file

@ -1,23 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXAPPLISTPROVIDER_H
#define LINUXAPPLISTPROVIDER_H
#include <applistprovider.h>
#include <QObject>
#include <QProcess>
class LinuxAppListProvider final : public AppListProvider {
Q_OBJECT
public:
explicit LinuxAppListProvider(QObject* parent);
~LinuxAppListProvider();
void getApplicationList() override;
private:
void fetchEntries(const QString& dataDir, QMap<QString, QString>& map);
};
#endif // LINUXAPPLISTPROVIDER_H

View file

@ -1,213 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxcontroller.h"
#include "backendlogsobserver.h"
#include "dbusclient.h"
#include "errorhandler.h"
#include "ipaddressrange.h"
#include "leakdetector.h"
#include "logger.h"
#include "models/device.h"
#include "models/keys.h"
#include "models/server.h"
#include "mozillavpn.h"
#include <QDBusPendingCallWatcher>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QProcess>
#include <QString>
namespace {
Logger logger({LOG_LINUX, LOG_CONTROLLER}, "LinuxController");
}
LinuxController::LinuxController() {
MVPN_COUNT_CTOR(LinuxController);
m_dbus = new DBusClient(this);
connect(m_dbus, &DBusClient::connected, this, &LinuxController::hopConnected);
connect(m_dbus, &DBusClient::disconnected, this,
&LinuxController::hopDisconnected);
}
LinuxController::~LinuxController() { MVPN_COUNT_DTOR(LinuxController); }
void LinuxController::initialize(const Device* device, const Keys* keys) {
Q_UNUSED(device);
Q_UNUSED(keys);
QDBusPendingCallWatcher* watcher = m_dbus->status();
connect(watcher, &QDBusPendingCallWatcher::finished, this,
&LinuxController::initializeCompleted);
}
void LinuxController::initializeCompleted(QDBusPendingCallWatcher* call) {
QDBusPendingReply<QString> reply = *call;
if (reply.isError()) {
logger.error() << "Error received from the DBus service";
emit initialized(false, false, QDateTime());
return;
}
QString status = reply.argumentAt<0>();
logger.debug() << "Status:" << status;
QJsonDocument json = QJsonDocument::fromJson(status.toLocal8Bit());
Q_ASSERT(json.isObject());
QJsonObject obj = json.object();
Q_ASSERT(obj.contains("status"));
QJsonValue statusValue = obj.value("status");
Q_ASSERT(statusValue.isBool());
emit initialized(true, statusValue.toBool(), QDateTime::currentDateTime());
}
void LinuxController::activate(
const QList<Server>& serverList, const Device* device, const Keys* keys,
const QList<IPAddressRange>& allowedIPAddressRanges,
const QList<QString>& vpnDisabledApps, const QHostAddress& dnsServer,
Reason reason) {
Q_UNUSED(reason);
Q_UNUSED(vpnDisabledApps);
// Activate connections starting from the outermost tunnel
for (int hopindex = serverList.count() - 1; hopindex > 0; hopindex--) {
const Server& hop = serverList[hopindex];
const Server& next = serverList[hopindex - 1];
QList<IPAddressRange> hopAddressRanges = {
IPAddressRange(next.ipv4AddrIn()), IPAddressRange(next.ipv6AddrIn())};
logger.debug() << "LinuxController hopindex" << hopindex << "activated";
connect(m_dbus->activate(hop, device, keys, hopindex, hopAddressRanges,
QStringList(), QHostAddress(hop.ipv4Gateway())),
&QDBusPendingCallWatcher::finished, this,
&LinuxController::operationCompleted);
}
// Activate the final hop last
logger.debug() << "LinuxController activated";
const Server& server = serverList[0];
connect(m_dbus->activate(server, device, keys, 0, allowedIPAddressRanges,
vpnDisabledApps, dnsServer),
&QDBusPendingCallWatcher::finished, this,
&LinuxController::operationCompleted);
}
void LinuxController::deactivate(Reason reason) {
logger.debug() << "LinuxController deactivated";
if (reason == ReasonSwitching) {
logger.debug() << "No disconnect for quick server switching";
emit disconnected();
return;
}
connect(m_dbus->deactivate(), &QDBusPendingCallWatcher::finished, this,
&LinuxController::operationCompleted);
}
void LinuxController::operationCompleted(QDBusPendingCallWatcher* call) {
QDBusPendingReply<bool> reply = *call;
if (reply.isError()) {
logger.error() << "Error received from the DBus service";
MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError);
emit disconnected();
return;
}
bool status = reply.argumentAt<0>();
if (status) {
logger.debug() << "DBus service says: all good.";
// we will receive the connected/disconnected() signal;
return;
}
logger.error() << "DBus service says: error.";
MozillaVPN::instance()->errorHandle(ErrorHandler::ControllerError);
emit disconnected();
}
void LinuxController::hopConnected(int hopindex) {
if (hopindex == 0) {
logger.debug() << "LinuxController connected";
emit connected();
} else {
logger.debug() << "LinuxController hopindex" << hopindex << "connected";
}
}
void LinuxController::hopDisconnected(int hopindex) {
if (hopindex == 0) {
logger.debug() << "LinuxController disconnected";
emit disconnected();
} else {
logger.debug() << "LinuxController hopindex" << hopindex << "disconnected";
}
}
void LinuxController::checkStatus() {
logger.debug() << "Check status";
QDBusPendingCallWatcher* watcher = m_dbus->status();
connect(watcher, &QDBusPendingCallWatcher::finished, this,
&LinuxController::checkStatusCompleted);
}
void LinuxController::checkStatusCompleted(QDBusPendingCallWatcher* call) {
QDBusPendingReply<QString> reply = *call;
if (reply.isError()) {
logger.error() << "Error received from the DBus service";
return;
}
QString status = reply.argumentAt<0>();
logger.debug() << "Status:" << status;
QJsonDocument json = QJsonDocument::fromJson(status.toLocal8Bit());
Q_ASSERT(json.isObject());
QJsonObject obj = json.object();
Q_ASSERT(obj.contains("status"));
QJsonValue statusValue = obj.value("status");
Q_ASSERT(statusValue.isBool());
if (!statusValue.toBool()) {
logger.error() << "Unable to retrieve the status from the interface.";
return;
}
Q_ASSERT(obj.contains("serverIpv4Gateway"));
QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway");
Q_ASSERT(serverIpv4Gateway.isString());
Q_ASSERT(obj.contains("deviceIpv4Address"));
QJsonValue deviceIpv4Address = obj.value("deviceIpv4Address");
Q_ASSERT(deviceIpv4Address.isString());
Q_ASSERT(obj.contains("txBytes"));
QJsonValue txBytes = obj.value("txBytes");
Q_ASSERT(txBytes.isDouble());
Q_ASSERT(obj.contains("rxBytes"));
QJsonValue rxBytes = obj.value("rxBytes");
Q_ASSERT(rxBytes.isDouble());
emit statusUpdated(serverIpv4Gateway.toString(), deviceIpv4Address.toString(),
txBytes.toDouble(), rxBytes.toDouble());
}
void LinuxController::getBackendLogs(
std::function<void(const QString&)>&& a_callback) {
std::function<void(const QString&)> callback = std::move(a_callback);
QDBusPendingCallWatcher* watcher = m_dbus->getLogs();
connect(watcher, &QDBusPendingCallWatcher::finished,
new BackendLogsObserver(this, std::move(callback)),
&BackendLogsObserver::completed);
}
void LinuxController::cleanupBackendLogs() { m_dbus->cleanupLogs(); }

View file

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXCONTROLLER_H
#define LINUXCONTROLLER_H
#include "controllerimpl.h"
#include <QObject>
class DBusClient;
class QDBusPendingCallWatcher;
class LinuxController final : public ControllerImpl {
Q_DISABLE_COPY_MOVE(LinuxController)
public:
LinuxController();
~LinuxController();
void initialize(const Device* device, const Keys* keys) override;
void activate(const QList<Server>& serverList, const Device* device,
const Keys* keys,
const QList<IPAddressRange>& allowedIPAddressRanges,
const QList<QString>& vpnDisabledApps,
const QHostAddress& dnsServer, Reason reason) override;
void deactivate(Reason reason) override;
void checkStatus() override;
void getBackendLogs(std::function<void(const QString&)>&& callback) override;
void cleanupBackendLogs() override;
private slots:
void checkStatusCompleted(QDBusPendingCallWatcher* call);
void initializeCompleted(QDBusPendingCallWatcher* call);
void operationCompleted(QDBusPendingCallWatcher* call);
void hopConnected(int hopindex);
void hopDisconnected(int hopindex);
private:
DBusClient* m_dbus = nullptr;
};
#endif // LINUXCONTROLLER_H

View file

@ -1,17 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cryptosettings.h"
void CryptoSettings::resetKey() {}
bool CryptoSettings::getKey(uint8_t key[CRYPTO_SETTINGS_KEY_SIZE]) {
Q_UNUSED(key);
return false;
}
// static
CryptoSettings::Version CryptoSettings::getSupportedVersion() {
return CryptoSettings::NoEncryption;
}

View file

@ -1,127 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxdependencies.h"
#include "dbusclient.h"
#include "logger.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <mntent.h>
constexpr const char* WG_QUICK = "wg-quick";
namespace {
Logger logger(LOG_LINUX, "LinuxDependencies");
void showAlert(const QString& message) {
logger.debug() << "Show alert:" << message;
QMessageBox alert;
alert.setText(message);
alert.exec();
}
bool findInPath(const char* what) {
char* path = getenv("PATH");
Q_ASSERT(path);
QStringList parts = QString(path).split(":");
for (const QString& part : parts) {
QDir pathDir(part);
QFileInfo file(pathDir.filePath(what));
if (file.exists()) {
logger.debug() << what << "found" << file.filePath();
return true;
}
}
return false;
}
bool checkDaemonVersion() {
logger.debug() << "Check Daemon Version";
DBusClient* dbus = new DBusClient(nullptr);
QDBusPendingCallWatcher* watcher = dbus->version();
bool completed = false;
bool value = false;
QObject::connect(
watcher, &QDBusPendingCallWatcher::finished,
[completed = &completed, value = &value](QDBusPendingCallWatcher* call) {
*completed = true;
QDBusPendingReply<QString> reply = *call;
if (reply.isError()) {
logger.error() << "DBus message received - error";
*value = false;
return;
}
QString version = reply.argumentAt<0>();
*value = version == PROTOCOL_VERSION;
logger.debug() << "DBus message received - daemon version:" << version
<< " - current version:" << PROTOCOL_VERSION;
});
while (!completed) {
QCoreApplication::processEvents();
}
delete dbus;
return value;
}
} // namespace
// static
bool LinuxDependencies::checkDependencies() {
char* path = getenv("PATH");
if (!path) {
showAlert("No PATH env found.");
return false;
}
if (!findInPath(WG_QUICK)) {
showAlert("Unable to locate wg-quick");
return false;
}
if (!checkDaemonVersion()) {
showAlert("mozillavpn linuxdaemon needs to be updated or restarted.");
return false;
}
return true;
}
// static
QString LinuxDependencies::findCgroupPath(const QString& type) {
struct mntent entry;
char buf[PATH_MAX];
FILE* fp = fopen("/etc/mtab", "r");
if (fp == NULL) {
return QString();
}
while (getmntent_r(fp, &entry, buf, sizeof(buf)) != NULL) {
if (strcmp(entry.mnt_type, "cgroup") != 0) {
continue;
}
if (hasmntopt(&entry, type.toLocal8Bit().constData()) != NULL) {
fclose(fp);
return QString(entry.mnt_dir);
}
}
fclose(fp);
return QString();
}

View file

@ -1,22 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXDEPENDENCIES_H
#define LINUXDEPENDENCIES_H
#include <QObject>
class LinuxDependencies final {
public:
static bool checkDependencies();
static QString findCgroupPath(const QString& type);
private:
LinuxDependencies() = default;
~LinuxDependencies() = default;
Q_DISABLE_COPY(LinuxDependencies)
};
#endif // LINUXDEPENDENCIES_H

View file

@ -1,55 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxnetworkwatcher.h"
#include "linuxnetworkwatcherworker.h"
#include "leakdetector.h"
#include "logger.h"
#include "timersingleshot.h"
namespace {
Logger logger(LOG_LINUX, "LinuxNetworkWatcher");
}
LinuxNetworkWatcher::LinuxNetworkWatcher(QObject* parent)
: NetworkWatcherImpl(parent) {
MVPN_COUNT_CTOR(LinuxNetworkWatcher);
m_thread.start();
}
LinuxNetworkWatcher::~LinuxNetworkWatcher() {
MVPN_COUNT_DTOR(LinuxNetworkWatcher);
delete m_worker;
m_thread.quit();
m_thread.wait();
}
void LinuxNetworkWatcher::initialize() {
logger.debug() << "initialize";
m_worker = new LinuxNetworkWatcherWorker(&m_thread);
connect(this, &LinuxNetworkWatcher::checkDevicesInThread, m_worker,
&LinuxNetworkWatcherWorker::checkDevices);
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
&LinuxNetworkWatcher::unsecuredNetwork);
// Let's wait a few seconds to allow the UI to be fully loaded and shown.
// This is not strictly needed, but it's better for user experience because
// it makes the UI faster to appear, plus it gives a bit of delay between the
// UI to appear and the first notification.
TimerSingleShot::create(this, 2000, [this]() {
QMetaObject::invokeMethod(m_worker, "initialize", Qt::QueuedConnection);
});
}
void LinuxNetworkWatcher::start() {
logger.debug() << "actived";
NetworkWatcherImpl::start();
emit checkDevicesInThread();
}

View file

@ -1,33 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXNETWORKWATCHER_H
#define LINUXNETWORKWATCHER_H
#include "networkwatcherimpl.h"
#include <QThread>
class LinuxNetworkWatcherWorker;
class LinuxNetworkWatcher final : public NetworkWatcherImpl {
Q_OBJECT
public:
explicit LinuxNetworkWatcher(QObject* parent);
~LinuxNetworkWatcher();
void initialize() override;
void start() override;
signals:
void checkDevicesInThread();
private:
LinuxNetworkWatcherWorker* m_worker = nullptr;
QThread m_thread;
};
#endif // LINUXNETWORKWATCHER_H

View file

@ -1,175 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxnetworkwatcherworker.h"
#include "leakdetector.h"
#include "logger.h"
#include <QtDBus/QtDBus>
// https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NMDeviceType
#ifndef NM_DEVICE_TYPE_WIFI
# define NM_DEVICE_TYPE_WIFI 2
#endif
// https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html#NM80211ApFlags
// Wifi network has no security
#ifndef NM_802_11_AP_SEC_NONE
# define NM_802_11_AP_SEC_NONE 0x00000000
#endif
// Wifi network has WEP (40 bits)
#ifndef NM_802_11_AP_SEC_PAIR_WEP40
# define NM_802_11_AP_SEC_PAIR_WEP40 0x00000001
#endif
// Wifi network has WEP (104 bits)
#ifndef NM_802_11_AP_SEC_PAIR_WEP104
# define NM_802_11_AP_SEC_PAIR_WEP104 0x00000002
#endif
#define NM_802_11_AP_SEC_WEAK_CRYPTO \
(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)
constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager";
namespace {
Logger logger(LOG_LINUX, "LinuxNetworkWatcherWorker");
}
static inline bool checkUnsecureFlags(int rsnFlags, int wpaFlags) {
// If neither WPA nor WPA2/RSN are supported, then the network is unencrypted
if (rsnFlags == NM_802_11_AP_SEC_NONE && wpaFlags == NM_802_11_AP_SEC_NONE) {
return false;
}
// Consider the user of weak cryptography to be unsecure
if ((rsnFlags & NM_802_11_AP_SEC_WEAK_CRYPTO) ||
(wpaFlags & NM_802_11_AP_SEC_WEAK_CRYPTO)) {
return false;
}
// Otherwise, the network is secured with reasonable cryptography
return true;
}
LinuxNetworkWatcherWorker::LinuxNetworkWatcherWorker(QThread* thread) {
MVPN_COUNT_CTOR(LinuxNetworkWatcherWorker);
moveToThread(thread);
}
LinuxNetworkWatcherWorker::~LinuxNetworkWatcherWorker() {
MVPN_COUNT_DTOR(LinuxNetworkWatcherWorker);
}
void LinuxNetworkWatcherWorker::initialize() {
logger.debug() << "initialize";
logger.debug()
<< "Retrieving the list of wifi network devices from NetworkManager";
// To know the NeworkManager DBus methods and properties, read the official
// documentation:
// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
QDBusInterface nm(DBUS_NETWORKMANAGER, "/org/freedesktop/NetworkManager",
DBUS_NETWORKMANAGER, QDBusConnection::systemBus());
if (!nm.isValid()) {
logger.error()
<< "Failed to connect to the network manager via system dbus";
return;
}
QDBusMessage msg = nm.call("GetDevices");
QDBusArgument arg = msg.arguments().at(0).value<QDBusArgument>();
if (arg.currentType() != QDBusArgument::ArrayType) {
logger.error() << "Expected an array of devices";
return;
}
QList<QDBusObjectPath> paths = qdbus_cast<QList<QDBusObjectPath> >(arg);
for (const QDBusObjectPath& path : paths) {
QString devicePath = path.path();
QDBusInterface device(DBUS_NETWORKMANAGER, devicePath,
"org.freedesktop.NetworkManager.Device",
QDBusConnection::systemBus());
if (device.property("DeviceType").toInt() != NM_DEVICE_TYPE_WIFI) {
continue;
}
logger.debug() << "Found a wifi device:" << devicePath;
m_devicePaths.append(devicePath);
// Here we monitor the changes.
QDBusConnection::systemBus().connect(
DBUS_NETWORKMANAGER, devicePath, "org.freedesktop.DBus.Properties",
"PropertiesChanged", this,
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
}
if (m_devicePaths.isEmpty()) {
logger.warning() << "No wifi devices found";
return;
}
// We could be already be activated.
checkDevices();
}
void LinuxNetworkWatcherWorker::propertyChanged(QString interface,
QVariantMap properties,
QStringList list) {
Q_UNUSED(list);
logger.debug() << "Properties changed for interface" << interface;
if (!properties.contains("ActiveAccessPoint")) {
logger.debug() << "Access point did not changed. Ignoring the changes";
return;
}
checkDevices();
}
void LinuxNetworkWatcherWorker::checkDevices() {
logger.debug() << "Checking devices";
for (const QString& devicePath : m_devicePaths) {
QDBusInterface wifiDevice(DBUS_NETWORKMANAGER, devicePath,
"org.freedesktop.NetworkManager.Device.Wireless",
QDBusConnection::systemBus());
// Check the access point path
QString accessPointPath = wifiDevice.property("ActiveAccessPoint")
.value<QDBusObjectPath>()
.path();
if (accessPointPath.isEmpty()) {
logger.warning() << "No access point found";
continue;
}
QDBusInterface ap(DBUS_NETWORKMANAGER, accessPointPath,
"org.freedesktop.NetworkManager.AccessPoint",
QDBusConnection::systemBus());
QVariant rsnFlags = ap.property("RsnFlags");
QVariant wpaFlags = ap.property("WpaFlags");
if (!rsnFlags.isValid() || !wpaFlags.isValid()) {
// We are probably not connected.
continue;
}
if (!checkUnsecureFlags(rsnFlags.toInt(), wpaFlags.toInt())) {
QString ssid = ap.property("Ssid").toString();
QString bssid = ap.property("HwAddress").toString();
// We have found 1 unsecured network. We don't need to check other wifi
// network devices.
logger.warning() << "Unsecured AP detected!"
<< "rsnFlags:" << rsnFlags.toInt()
<< "wpaFlags:" << wpaFlags.toInt() << "ssid:" << ssid;
emit unsecuredNetwork(ssid, bssid);
break;
}
}
}

View file

@ -1,41 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXNETWORKWATCHERWORKER_H
#define LINUXNETWORKWATCHERWORKER_H
#include <QMap>
#include <QObject>
#include <QVariant>
class QThread;
class LinuxNetworkWatcherWorker final : public QObject {
Q_OBJECT
Q_DISABLE_COPY_MOVE(LinuxNetworkWatcherWorker)
public:
explicit LinuxNetworkWatcherWorker(QThread* thread);
~LinuxNetworkWatcherWorker();
void checkDevices();
signals:
void unsecuredNetwork(const QString& networkName, const QString& networkId);
public slots:
void initialize();
private slots:
void propertyChanged(QString interface, QVariantMap properties,
QStringList list);
private:
// We collect the list of DBus wifi network device paths during the
// initialization. When a property of them changes, we check if the access
// point is active and unsecure.
QStringList m_devicePaths;
};
#endif // LINUXNETWORKWATCHERWORKER_H

View file

@ -1,191 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "linuxpingsender.h"
#include "leakdetector.h"
#include "logger.h"
#include <QSocketNotifier>
#include <arpa/inet.h>
#include <errno.h>
#include <linux/filter.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <unistd.h>
namespace {
Logger logger({LOG_LINUX, LOG_NETWORKING}, "LinuxPingSender");
}
int LinuxPingSender::createSocket() {
// Try creating an ICMP socket. This would be the ideal choice, but it can
// fail depending on the kernel config (see: sys.net.ipv4.ping_group_range)
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (m_socket >= 0) {
m_ident = 0;
return m_socket;
}
if ((errno != EPERM) && (errno != EACCES)) {
return -1;
}
// As a fallback, create a raw socket, which requires root permissions
// or CAP_NET_RAW to be granted to the VPN client.
m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (m_socket < 0) {
return -1;
}
m_ident = getpid() & 0xffff;
// Attach a BPF filter to discard everything but replies to our echo.
struct sock_filter bpf_prog[] = {
BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. */
BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, m_ident, 1, 0), /* Ours? */
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected identifier. Reject. */
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected type. Reject. */
BPF_STMT(BPF_RET | BPF_K, ~0U), /* Packet passes the filter. */
};
struct sock_fprog filter = {
.len = sizeof(bpf_prog) / sizeof(struct sock_filter),
.filter = bpf_prog,
};
setsockopt(m_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
return m_socket;
}
LinuxPingSender::LinuxPingSender(const QString& source, QObject* parent)
: PingSender(parent), m_source(source) {
MVPN_COUNT_CTOR(LinuxPingSender);
logger.debug() << "LinuxPingSender(" + source + ") created";
m_socket = createSocket();
if (m_socket < 0) {
logger.error() << "Socket creation error: " << strerror(errno);
return;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
if (inet_aton(source.toLocal8Bit().constData(), &addr.sin_addr) == 0) {
logger.error() << "source" << source << "error:" << strerror(errno);
return;
}
if (bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
close(m_socket);
m_socket = -1;
logger.error() << "bind error:" << strerror(errno);
return;
}
m_notifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, this);
if (m_ident) {
connect(m_notifier, &QSocketNotifier::activated, this,
&LinuxPingSender::rawSocketReady);
} else {
connect(m_notifier, &QSocketNotifier::activated, this,
&LinuxPingSender::icmpSocketReady);
}
}
LinuxPingSender::~LinuxPingSender() {
MVPN_COUNT_DTOR(LinuxPingSender);
if (m_socket >= 0) {
close(m_socket);
}
}
void LinuxPingSender::sendPing(const QString& dest, quint16 sequence) {
// QProcess is not supported on iOS. Because of this we cannot use the `ping`
// app as fallback on this platform.
#ifndef MVPN_IOS
// Use the generic ping sender if we failed to open an ICMP socket.
if (m_socket < 0) {
QStringList args;
args << "-c"
<< "1";
args << "-I" << m_source;
args << dest;
genericSendPing(args, sequence);
return;
}
#endif
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
if (inet_aton(dest.toLocal8Bit().constData(), &addr.sin_addr) == 0) {
return;
}
struct icmphdr packet;
memset(&packet, 0, sizeof(packet));
packet.type = ICMP_ECHO;
packet.un.echo.id = htons(m_ident);
packet.un.echo.sequence = htons(sequence);
packet.checksum = inetChecksum(&packet, sizeof(packet));
int rc = sendto(m_socket, &packet, sizeof(packet), 0, (struct sockaddr*)&addr,
sizeof(addr));
if (rc < 0) {
logger.error() << "failed to send:" << strerror(errno);
}
}
void LinuxPingSender::icmpSocketReady() {
socklen_t slen = 0;
unsigned char data[2048];
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
if (rc <= 0) {
logger.error() << "recvfrom failed:" << strerror(errno);
return;
}
struct icmphdr packet;
if (rc >= (int)sizeof(packet)) {
memcpy(&packet, data, sizeof(packet));
if (packet.type == ICMP_ECHOREPLY) {
emit recvPing(htons(packet.un.echo.sequence));
}
}
}
void LinuxPingSender::rawSocketReady() {
socklen_t slen = 0;
unsigned char data[2048];
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
if (rc <= 0) {
logger.error() << "recvfrom failed:" << strerror(errno);
return;
}
// Check the IP header
const struct iphdr* ip = (struct iphdr*)data;
int iphdrlen = ip->ihl * 4;
if (rc < iphdrlen || iphdrlen < (int)sizeof(struct iphdr)) {
logger.error() << "malformed IP packet:" << strerror(errno);
return;
}
// Check the ICMP packet
struct icmphdr packet;
if (inetChecksum(data + iphdrlen, rc - iphdrlen) != 0) {
logger.warning() << "invalid checksum";
return;
}
if (rc >= (iphdrlen + (int)sizeof(packet))) {
memcpy(&packet, data + iphdrlen, sizeof(packet));
quint16 id = htons(m_ident);
if ((packet.type == ICMP_ECHOREPLY) && (packet.un.echo.id == id)) {
emit recvPing(htons(packet.un.echo.sequence));
}
}
}

View file

@ -1,38 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXPINGSENDER_H
#define LINUXPINGSENDER_H
#include "pingsender.h"
#include <QObject>
class QSocketNotifier;
class LinuxPingSender final : public PingSender {
Q_OBJECT
Q_DISABLE_COPY_MOVE(LinuxPingSender)
public:
LinuxPingSender(const QString& source, QObject* parent = nullptr);
~LinuxPingSender();
void sendPing(const QString& dest, quint16 sequence) override;
private:
int createSocket();
private slots:
void rawSocketReady();
void icmpSocketReady();
private:
QSocketNotifier* m_notifier = nullptr;
QString m_source;
int m_socket = 0;
quint16 m_ident = 0;
};
#endif // LINUXPINGSENDER_H

View file

@ -1,161 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "platforms/linux/linuxsystemtraynotificationhandler.h"
#include "constants.h"
#include "leakdetector.h"
#include "logger.h"
#include "defines.h"
#include <QtDBus/QtDBus>
#include <QDesktopServices>
constexpr const char* DBUS_ITEM = "org.freedesktop.Notifications";
constexpr const char* DBUS_PATH = "/org/freedesktop/Notifications";
constexpr const char* DBUS_INTERFACE = "org.freedesktop.Notifications";
constexpr const char* ACTION_ID = "mozilla_vpn_notification";
namespace {
Logger logger(LOG_LINUX, "LinuxSystemTrayNotificationHandler");
} // namespace
//static
bool LinuxSystemTrayNotificationHandler::requiredCustomImpl() {
//if (!QDBusConnection::sessionBus().isConnected()) {
// return false;
//}
//QDBusConnectionInterface* interface =
// QDBusConnection::sessionBus().interface();
//if (!interface) {
// return false;
//}
//// This custom systemTrayHandler implementation is required only on Unity.
//QStringList registeredServices = interface->registeredServiceNames().value();
//return registeredServices.contains("com.canonical.Unity");
}
LinuxSystemTrayNotificationHandler::LinuxSystemTrayNotificationHandler(
QObject* parent)
: SystemTrayNotificationHandler(parent) {
m_systemTrayIcon.show();
connect(&m_systemTrayIcon, &QSystemTrayIcon::activated, this, &LinuxSystemTrayNotificationHandler::onTrayActivated);
m_menu.addAction(QIcon(":/images/tray/application.png"), tr("Show") + " " + APPLICATION_NAME, this, [this](){
emit raiseRequested();
});
m_menu.addSeparator();
m_trayActionConnect = m_menu.addAction(tr("Connect"), this, [this](){ emit connectRequested(); });
m_trayActionDisconnect = m_menu.addAction(tr("Disconnect"), this, [this](){ emit disconnectRequested(); });
m_menu.addSeparator();
m_menu.addAction(QIcon(":/images/tray/link.png"), tr("Visit Website"), [&](){
QDesktopServices::openUrl(QUrl("https://amnezia.org"));
});
m_menu.addAction(QIcon(":/images/tray/cancel.png"), tr("Quit") + " " + APPLICATION_NAME, this, [&](){
qApp->quit();
});
m_systemTrayIcon.setContextMenu(&m_menu);
setTrayState(VpnProtocol::Disconnected);
}
void LinuxSystemTrayNotificationHandler::setTrayState(VpnProtocol::VpnConnectionState state)
{
qDebug() << "SystemTrayNotificationHandler::setTrayState" << state;
QString resourcesPath = ":/images/tray/%1";
switch (state) {
case VpnProtocol::Disconnected:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
case VpnProtocol::Preparing:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Connecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Connected:
setTrayIcon(QString(resourcesPath).arg(ConnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Disconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Reconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
break;
case VpnProtocol::Error:
setTrayIcon(QString(resourcesPath).arg(ErrorTrayIconName));
m_trayActionConnect->setEnabled(true);
m_trayActionDisconnect->setEnabled(false);
break;
case VpnProtocol::Unknown:
default:
m_trayActionConnect->setEnabled(false);
m_trayActionDisconnect->setEnabled(true);
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
}
//#ifdef Q_OS_MAC
// // Get theme from current user (note, this app can be launched as root application and in this case this theme can be different from theme of real current user )
// bool darkTaskBar = MacOSFunctions::instance().isMenuBarUseDarkTheme();
// darkTaskBar = forceUseBrightIcons ? true : darkTaskBar;
// resourcesPath = ":/images_mac/tray_icon/%1";
// useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
//#endif
}
void LinuxSystemTrayNotificationHandler::setTrayIcon(const QString &iconPath)
{
QIcon trayIconMask(QPixmap(iconPath).scaled(128,128));
trayIconMask.setIsMask(true);
m_systemTrayIcon.setIcon(trayIconMask);
}
void LinuxSystemTrayNotificationHandler::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
#ifndef Q_OS_MAC
if(reason == QSystemTrayIcon::DoubleClick || reason == QSystemTrayIcon::Trigger) {
emit raiseRequested();
}
#endif
}
LinuxSystemTrayNotificationHandler::~LinuxSystemTrayNotificationHandler() {
MVPN_COUNT_DTOR(LinuxSystemTrayNotificationHandler);
}
void LinuxSystemTrayNotificationHandler::notify(Message type,
const QString& title,
const QString& message,
int timerMsec) {
}
void LinuxSystemTrayNotificationHandler::actionInvoked(uint actionId,
QString action) {
logger.debug() << "Notification clicked" << actionId << action;
if (action == ACTION_ID && m_lastNotificationId == actionId) {
messageClickHandle();
}
}

View file

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LINUXNOTIFICATIONNOTIFICATIONHANDLER_H
#define LINUXNOTIFICATIONNOTIFICATIONHANDLER_H
#include "./ui/systemtray_notificationhandler.h"
#include <QObject>
class LinuxSystemTrayNotificationHandler final
: public SystemTrayNotificationHandler {
Q_OBJECT
Q_DISABLE_COPY_MOVE(LinuxSystemTrayNotificationHandler)
public:
static bool requiredCustomImpl();
LinuxSystemTrayNotificationHandler(QObject* parent);
~LinuxSystemTrayNotificationHandler();
private:
void notify(Message type, const QString& title, const QString& message,
int timerMsec) override;
void setTrayState(VpnProtocol::VpnConnectionState state);
void setTrayIcon(const QString &iconPath);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
private slots:
void actionInvoked(uint actionId, QString action);
private:
QMenu m_menu;
QSystemTrayIcon m_systemTrayIcon;
QAction* m_trayActionConnect = nullptr;
QAction* m_trayActionDisconnect = nullptr;
QAction* m_preferencesAction = nullptr;
QAction* m_statusLabel = nullptr;
QAction* m_separator = nullptr;
const QString ConnectedTrayIconName = "active.png";
const QString DisconnectedTrayIconName = "default.png";
const QString ErrorTrayIconName = "error.png";
uint m_lastNotificationId = 0;
};
#endif // LINUXNOTIFICATIONNOTIFICATIONHANDLER_H