clean up /platform/linux/ folder
This commit is contained in:
parent
ac7de6213a
commit
271e948c1f
21 changed files with 0 additions and 1611 deletions
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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(); }
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue