Merge branch 'feature/android_qt6_moving' into feature/android_bandwidth_counter
# Conflicts: # client/platforms/android/android_controller.cpp # client/platforms/android/android_controller.h
This commit is contained in:
commit
39736e865e
255 changed files with 4322 additions and 7218 deletions
|
@ -1,9 +1,7 @@
|
|||
#include <QAndroidBinder>
|
||||
#include <QAndroidIntent>
|
||||
#include <QAndroidJniEnvironment>
|
||||
#include <QAndroidJniObject>
|
||||
#include <QAndroidParcel>
|
||||
#include <QAndroidServiceConnection>
|
||||
/* 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 <QDebug>
|
||||
#include <QHostAddress>
|
||||
#include <QJsonArray>
|
||||
|
@ -12,51 +10,132 @@
|
|||
#include <QRandomGenerator>
|
||||
#include <QTextCodec>
|
||||
#include <QTimer>
|
||||
#include <QtAndroid>
|
||||
|
||||
#include "android_controller.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "private/qandroidextras_p.h"
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
|
||||
// Binder Codes for VPNServiceBinder
|
||||
// See also - VPNServiceBinder.kt
|
||||
// Actions that are Requestable
|
||||
const int ACTION_ACTIVATE = 1;
|
||||
const int ACTION_DEACTIVATE = 2;
|
||||
const int ACTION_REGISTER_LISTENER = 3;
|
||||
const int ACTION_REQUEST_STATISTIC = 4;
|
||||
const int ACTION_REQUEST_GET_LOG = 5;
|
||||
const int ACTION_REQUEST_CLEANUP_LOG = 6;
|
||||
const int ACTION_RESUME_ACTIVATE = 7;
|
||||
const int ACTION_SET_NOTIFICATION_TEXT = 8;
|
||||
const int ACTION_SET_NOTIFICATION_FALLBACK = 9;
|
||||
const int ACTION_SHARE_CONFIG = 10;
|
||||
|
||||
// Event Types that will be Dispatched after registration
|
||||
const int EVENT_INIT = 0;
|
||||
const int EVENT_CONNECTED = 1;
|
||||
const int EVENT_DISCONNECTED = 2;
|
||||
const int EVENT_STATISTIC_UPDATE = 3;
|
||||
const int EVENT_BACKEND_LOGS = 4;
|
||||
const int EVENT_ACTIVATION_ERROR = 5;
|
||||
const int EVENT_CONFIG_IMPORT = 6;
|
||||
#include "androidvpnactivity.h"
|
||||
#include "androidutils.h"
|
||||
|
||||
namespace {
|
||||
AndroidController* s_instance = nullptr;
|
||||
|
||||
constexpr auto PERMISSIONHELPER_CLASS =
|
||||
"org/amnezia/vpn/qt/VPNPermissionHelper";
|
||||
|
||||
} // namespace
|
||||
|
||||
AndroidController::AndroidController():
|
||||
m_binder(this)
|
||||
AndroidController::AndroidController() : QObject()
|
||||
{
|
||||
connect(this, &AndroidController::scheduleStatusCheckSignal, this, &AndroidController::scheduleStatusCheckSlot);
|
||||
|
||||
s_instance = this;
|
||||
|
||||
auto activity = AndroidVPNActivity::instance();
|
||||
|
||||
connect(activity, &AndroidVPNActivity::serviceConnected, this, []() {
|
||||
qDebug() << "Transact: service connected";
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, "");
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventInitialized, this,
|
||||
[this](const QString& parcelBody) {
|
||||
// We might get multiple Init events as widgets, or fragments
|
||||
// might query this.
|
||||
if (m_init) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Transact: init";
|
||||
|
||||
m_init = true;
|
||||
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
qlonglong time = doc.object()["time"].toVariant().toLongLong();
|
||||
|
||||
isConnected = doc.object()["connected"].toBool();
|
||||
|
||||
emit initialized(
|
||||
true, isConnected,
|
||||
time > 0 ? QDateTime::fromMSecsSinceEpoch(time) : QDateTime());
|
||||
|
||||
setFallbackConnectedNotification();
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventConnected, this,
|
||||
[this](const QString& parcelBody) {
|
||||
Q_UNUSED(parcelBody);
|
||||
qDebug() << "Transact: connected";
|
||||
|
||||
isConnected = true;
|
||||
|
||||
emit scheduleStatusCheckSignal();
|
||||
|
||||
emit connectionStateChanged(VpnProtocol::Connected);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: disconnected";
|
||||
|
||||
isConnected = false;
|
||||
|
||||
emit connectionStateChanged(VpnProtocol::Disconnected);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventStatisticUpdate, this,
|
||||
[this](const QString& parcelBody) {
|
||||
qDebug() << "Transact: update";
|
||||
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
|
||||
QString rx = doc.object()["rx_bytes"].toString();
|
||||
QString tx = doc.object()["tx_bytes"].toString();
|
||||
QString endpoint = doc.object()["endpoint"].toString();
|
||||
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
||||
|
||||
emit statusUpdated(rx, tx, endpoint, deviceIPv4);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventBackendLogs, this,
|
||||
[this](const QString& parcelBody) {
|
||||
qDebug() << "Transact: backend logs";
|
||||
|
||||
QString buffer = parcelBody.toUtf8();
|
||||
if (m_logCallback) {
|
||||
m_logCallback(buffer);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventActivationError, this,
|
||||
[this](const QString& parcelBody) {
|
||||
Q_UNUSED(parcelBody)
|
||||
qDebug() << "Transact: error";
|
||||
emit connectionStateChanged(VpnProtocol::Error);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::eventConfigImport, this,
|
||||
[this](const QString& parcelBody) {
|
||||
qDebug() << "Transact: config import";
|
||||
auto doc = QJsonDocument::fromJson(parcelBody.toUtf8());
|
||||
|
||||
QString buffer = doc.object()["config"].toString();
|
||||
qDebug() << "Transact: config string" << buffer;
|
||||
importConfig(buffer);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(activity, &AndroidVPNActivity::serviceDisconnected, this,
|
||||
[this]() {
|
||||
qDebug() << "Transact: service disconnected";
|
||||
m_serviceConnected = false;
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
AndroidController* AndroidController::instance() {
|
||||
if (!s_instance) s_instance = new AndroidController();
|
||||
if (!s_instance) {
|
||||
s_instance = new AndroidController();
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
@ -70,71 +149,43 @@ bool AndroidController::initialize(StartPageLogic *startPageLogic)
|
|||
JNINativeMethod methods[]{{"startActivityForResult",
|
||||
"(Landroid/content/Intent;)V",
|
||||
reinterpret_cast<void*>(startActivityForResult)}};
|
||||
QAndroidJniObject javaClass(PERMISSIONHELPER_CLASS);
|
||||
QAndroidJniEnvironment env;
|
||||
QJniObject javaClass(PERMISSIONHELPER_CLASS);
|
||||
QJniEnvironment env;
|
||||
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
||||
env->RegisterNatives(objectClass, methods,
|
||||
sizeof(methods) / sizeof(methods[0]));
|
||||
env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
|
||||
env->DeleteLocalRef(objectClass);
|
||||
|
||||
auto appContext = QtAndroid::androidActivity().callObjectMethod(
|
||||
"getApplicationContext", "()Landroid/content/Context;");
|
||||
AndroidVPNActivity::connectService();
|
||||
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
"org/amnezia/vpn/VPNService", "startService",
|
||||
"(Landroid/content/Context;)V", appContext.object());
|
||||
|
||||
// Start the VPN Service (if not yet) and Bind to it
|
||||
const bool bindResult = QtAndroid::bindService(
|
||||
QAndroidIntent(appContext.object(), "org.amnezia.vpn.VPNService"),
|
||||
*this, QtAndroid::BindFlag::AutoCreate);
|
||||
qDebug() << "Binding to the service..." << bindResult;
|
||||
|
||||
return bindResult;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorCode AndroidController::start()
|
||||
{
|
||||
|
||||
//qDebug().noquote() << "AndroidController::start" << QJsonDocument(m_rawConfig).toJson();
|
||||
qDebug() << "Prompting for VPN permission";
|
||||
auto appContext = QtAndroid::androidActivity().callObjectMethod(
|
||||
QJniObject activity = AndroidUtils::getActivity();
|
||||
auto appContext = activity.callObjectMethod(
|
||||
"getApplicationContext", "()Landroid/content/Context;");
|
||||
QAndroidJniObject::callStaticMethod<void>(
|
||||
QJniObject::callStaticMethod<void>(
|
||||
PERMISSIONHELPER_CLASS, "startService", "(Landroid/content/Context;)V",
|
||||
appContext.object());
|
||||
|
||||
QAndroidParcel sendData;
|
||||
sendData.writeData(QJsonDocument(m_vpnConfig).toJson());
|
||||
bool activateResult = false;
|
||||
while (!activateResult){
|
||||
activateResult = m_serviceBinder.transact(ACTION_ACTIVATE, sendData, nullptr);
|
||||
}
|
||||
QJsonDocument doc(m_vpnConfig);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_ACTIVATE, doc.toJson());
|
||||
|
||||
return activateResult ? NoError : UnknownError;
|
||||
return NoError;
|
||||
}
|
||||
|
||||
void AndroidController::stop() {
|
||||
qDebug() << "AndroidController::stop";
|
||||
|
||||
// if (reason != ReasonNone) {
|
||||
// // Just show that we're disconnected
|
||||
// // we're doing the actual disconnect once
|
||||
// // the vpn-service has the new server ready in Action->Activate
|
||||
// emit disconnected();
|
||||
// qCritical() << "deactivation skipped for Switching";
|
||||
// return;
|
||||
// }
|
||||
|
||||
QAndroidParcel nullData;
|
||||
m_serviceBinder.transact(ACTION_DEACTIVATE, nullData, nullptr);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_DEACTIVATE, QString());
|
||||
}
|
||||
|
||||
// Activates the tunnel that is currently set
|
||||
// in the VPN Service
|
||||
void AndroidController::resumeStart() {
|
||||
QAndroidParcel nullData;
|
||||
m_serviceBinder.transact(ACTION_RESUME_ACTIVATE, nullData, nullptr);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_RESUME_ACTIVATE, QString());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -143,14 +194,13 @@ void AndroidController::resumeStart() {
|
|||
void AndroidController::setNotificationText(const QString& title,
|
||||
const QString& message,
|
||||
int timerSec) {
|
||||
QJsonObject args;
|
||||
args["title"] = title;
|
||||
args["message"] = message;
|
||||
args["sec"] = timerSec;
|
||||
QJsonDocument doc(args);
|
||||
QAndroidParcel data;
|
||||
data.writeData(doc.toJson());
|
||||
m_serviceBinder.transact(ACTION_SET_NOTIFICATION_TEXT, data, nullptr);
|
||||
QJsonObject args;
|
||||
args["title"] = title;
|
||||
args["message"] = message;
|
||||
args["sec"] = timerSec;
|
||||
QJsonDocument doc(args);
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_TEXT, doc.toJson());
|
||||
}
|
||||
|
||||
void AndroidController::shareConfig(const QString& configContent, const QString& suggestedName) {
|
||||
|
@ -158,9 +208,8 @@ void AndroidController::shareConfig(const QString& configContent, const QString&
|
|||
rootObject["data"] = configContent;
|
||||
rootObject["suggestedName"] = suggestedName;
|
||||
QJsonDocument doc(rootObject);
|
||||
QAndroidParcel parcel;
|
||||
parcel.writeData(doc.toJson());
|
||||
m_serviceBinder.transact(ACTION_SHARE_CONFIG, parcel, nullptr);
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SHARE_CONFIG, doc.toJson());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -169,64 +218,40 @@ void AndroidController::shareConfig(const QString& configContent, const QString&
|
|||
* e.g via always-on vpn
|
||||
*/
|
||||
void AndroidController::setFallbackConnectedNotification() {
|
||||
QJsonObject args;
|
||||
args["title"] = tr("AmneziaVPN");
|
||||
//% "Ready for you to connect"
|
||||
//: Refers to the app - which is currently running the background and waiting
|
||||
args["message"] = tr("VPN Connected");
|
||||
QJsonDocument doc(args);
|
||||
QAndroidParcel data;
|
||||
data.writeData(doc.toJson());
|
||||
m_serviceBinder.transact(ACTION_SET_NOTIFICATION_FALLBACK, data, nullptr);
|
||||
QJsonObject args;
|
||||
args["title"] = tr("AmneziaVPN");
|
||||
//% "Ready for you to connect"
|
||||
//: Refers to the app - which is currently running the background and waiting
|
||||
args["message"] = tr("VPN Connected");
|
||||
QJsonDocument doc(args);
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_SET_NOTIFICATION_FALLBACK, doc.toJson());
|
||||
}
|
||||
|
||||
void AndroidController::checkStatus() {
|
||||
qDebug() << "check status";
|
||||
qDebug() << "check status";
|
||||
|
||||
QAndroidParcel nullParcel;
|
||||
m_serviceBinder.transact(ACTION_REQUEST_STATISTIC, nullParcel, nullptr);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_STATISTIC, QString());
|
||||
}
|
||||
|
||||
void AndroidController::getBackendLogs(std::function<void(const QString&)>&& a_callback) {
|
||||
qDebug() << "get logs";
|
||||
qDebug() << "get logs";
|
||||
|
||||
m_logCallback = std::move(a_callback);
|
||||
QAndroidParcel nullData, replyData;
|
||||
m_serviceBinder.transact(ACTION_REQUEST_GET_LOG, nullData, &replyData);
|
||||
m_logCallback = std::move(a_callback);
|
||||
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_GET_LOG, QString());
|
||||
}
|
||||
|
||||
void AndroidController::cleanupBackendLogs() {
|
||||
qDebug() << "cleanup logs";
|
||||
qDebug() << "cleanup logs";
|
||||
|
||||
QAndroidParcel nullParcel;
|
||||
m_serviceBinder.transact(ACTION_REQUEST_CLEANUP_LOG, nullParcel, nullptr);
|
||||
AndroidVPNActivity::sendToService(ServiceAction::ACTION_REQUEST_CLEANUP_LOG, QString());
|
||||
}
|
||||
|
||||
void AndroidController::importConfig(const QString& data){
|
||||
m_startPageLogic->importConnectionFromCode(data);
|
||||
}
|
||||
|
||||
void AndroidController::onServiceConnected(
|
||||
const QString& name, const QAndroidBinder& serviceBinder) {
|
||||
qDebug() << "Server " + name + " connected";
|
||||
|
||||
Q_UNUSED(name);
|
||||
|
||||
m_serviceBinder = serviceBinder;
|
||||
|
||||
// Send the Service our Binder to recive incoming Events
|
||||
QAndroidParcel binderParcel;
|
||||
binderParcel.writeBinder(m_binder);
|
||||
m_serviceBinder.transact(ACTION_REGISTER_LISTENER, binderParcel, nullptr);
|
||||
}
|
||||
|
||||
void AndroidController::onServiceDisconnected(const QString& name) {
|
||||
qDebug() << "Server disconnected";
|
||||
m_serviceConnected = false;
|
||||
Q_UNUSED(name);
|
||||
// TODO: Maybe restart? Or crash?
|
||||
}
|
||||
|
||||
const QJsonObject &AndroidController::vpnConfig() const
|
||||
{
|
||||
return m_vpnConfig;
|
||||
|
@ -242,113 +267,11 @@ void AndroidController::scheduleStatusCheckSlot()
|
|||
QTimer::singleShot(1000, [this]() {
|
||||
if (isConnected) {
|
||||
checkStatus();
|
||||
emit scheduleStatusCheckSignal();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AndroidController::VPNBinder::onTransact
|
||||
* @param code the Event-Type we get From the VPNService See
|
||||
* @param data - Might contain UTF-8 JSON in case the Event has a payload
|
||||
* @param reply - always null
|
||||
* @param flags - unused
|
||||
* @return Returns true is the code was a valid Event Code
|
||||
*/
|
||||
bool AndroidController::VPNBinder::onTransact(int code,
|
||||
const QAndroidParcel& data,
|
||||
const QAndroidParcel& reply,
|
||||
QAndroidBinder::CallType flags) {
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(reply);
|
||||
Q_UNUSED(flags);
|
||||
|
||||
QJsonDocument doc;
|
||||
QString buffer;
|
||||
switch (code) {
|
||||
case EVENT_INIT:
|
||||
{
|
||||
qDebug() << "Transact: init";
|
||||
doc = QJsonDocument::fromJson(data.readData());
|
||||
|
||||
bool isConnected = doc.object()["connected"].toBool();
|
||||
QDateTime time = QDateTime::fromMSecsSinceEpoch(
|
||||
doc.object()["time"].toVariant().toLongLong());
|
||||
|
||||
emit m_controller->initialized(true, isConnected, time);
|
||||
|
||||
// Pass a localised version of the Fallback string for the Notification
|
||||
m_controller->setFallbackConnectedNotification();
|
||||
|
||||
m_controller->isConnected = isConnected;
|
||||
|
||||
if (isConnected) {
|
||||
emit m_controller->scheduleStatusCheckSignal();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EVENT_CONNECTED:
|
||||
qDebug() << "Transact: connected";
|
||||
emit m_controller->connectionStateChanged(VpnProtocol::Connected);
|
||||
m_controller->isConnected = true;
|
||||
emit m_controller->scheduleStatusCheckSignal();
|
||||
break;
|
||||
case EVENT_DISCONNECTED:
|
||||
qDebug() << "Transact: disconnected";
|
||||
emit m_controller->connectionStateChanged(VpnProtocol::Disconnected);
|
||||
m_controller->isConnected = false;
|
||||
break;
|
||||
case EVENT_STATISTIC_UPDATE:
|
||||
{
|
||||
qDebug() << "Transact:: update";
|
||||
|
||||
doc = QJsonDocument::fromJson(data.readData());
|
||||
|
||||
QString rx = doc.object()["rx_bytes"].toString();
|
||||
QString tx = doc.object()["tx_bytes"].toString();
|
||||
QString endpoint = doc.object()["endpoint"].toString();
|
||||
QString deviceIPv4 = doc.object()["deviceIpv4"].toString();
|
||||
|
||||
emit m_controller->statusUpdated(rx, tx, endpoint, deviceIPv4);
|
||||
|
||||
if (m_controller->isConnected) {
|
||||
emit m_controller->scheduleStatusCheckSignal();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EVENT_BACKEND_LOGS:
|
||||
qDebug() << "Transact: backend logs";
|
||||
|
||||
buffer = readUTF8Parcel(data);
|
||||
if (m_controller->m_logCallback) {
|
||||
m_controller->m_logCallback(buffer);
|
||||
}
|
||||
break;
|
||||
case EVENT_ACTIVATION_ERROR:
|
||||
qDebug() << "Transact: error";
|
||||
emit m_controller->connectionStateChanged(VpnProtocol::Error);
|
||||
break;
|
||||
case EVENT_CONFIG_IMPORT:
|
||||
qDebug() << "Transact: config import";
|
||||
doc = QJsonDocument::fromJson(data.readData());
|
||||
buffer = doc.object()["config"].toString();
|
||||
qDebug() << "Transact: config string" << buffer;
|
||||
m_controller->importConfig(buffer);
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Transact: Invalid!";
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString AndroidController::VPNBinder::readUTF8Parcel(QAndroidParcel data) {
|
||||
// 106 is the Code for UTF-8
|
||||
return QTextCodec::codecForMib(106)->toUnicode(data.readData());
|
||||
}
|
||||
|
||||
const int ACTIVITY_RESULT_OK = 0xffffffff;
|
||||
/**
|
||||
* @brief Starts the Given intent in Context of the QTActivity
|
||||
|
@ -357,34 +280,34 @@ const int ACTIVITY_RESULT_OK = 0xffffffff;
|
|||
*/
|
||||
void AndroidController::startActivityForResult(JNIEnv *env, jobject, jobject intent)
|
||||
{
|
||||
qDebug() << "start activity";
|
||||
qDebug() << "start vpnPermissionHelper";
|
||||
Q_UNUSED(env);
|
||||
QtAndroid::startActivity(intent, 1337,
|
||||
[](int receiverRequestCode, int resultCode,
|
||||
const QAndroidJniObject& data) {
|
||||
// Currently this function just used in
|
||||
// VPNService.kt::checkPersmissions. So the result
|
||||
// we're getting is if the User gave us the
|
||||
// Vpn.bind permission. In case of NO we should
|
||||
// abort.
|
||||
Q_UNUSED(receiverRequestCode);
|
||||
Q_UNUSED(data);
|
||||
|
||||
AndroidController* controller =
|
||||
AndroidController::instance();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
QtAndroidPrivate::startActivity(intent, 1337,
|
||||
[](int receiverRequestCode, int resultCode,
|
||||
const QJniObject& data) {
|
||||
// Currently this function just used in
|
||||
// VPNService.kt::checkPersmissions. So the result
|
||||
// we're getting is if the User gave us the
|
||||
// Vpn.bind permission. In case of NO we should
|
||||
// abort.
|
||||
Q_UNUSED(receiverRequestCode);
|
||||
Q_UNUSED(data);
|
||||
|
||||
if (resultCode == ACTIVITY_RESULT_OK) {
|
||||
qDebug() << "VPN PROMPT RESULT - Accepted";
|
||||
controller->resumeStart();
|
||||
return;
|
||||
}
|
||||
// If the request got rejected abort the current
|
||||
// connection.
|
||||
qWarning() << "VPN PROMPT RESULT - Rejected";
|
||||
emit controller->connectionStateChanged(VpnProtocol::Disconnected);
|
||||
});
|
||||
AndroidController* controller = AndroidController::instance();
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultCode == ACTIVITY_RESULT_OK) {
|
||||
qDebug() << "VPN PROMPT RESULT - Accepted";
|
||||
controller->resumeStart();
|
||||
return;
|
||||
}
|
||||
// If the request got rejected abort the current
|
||||
// connection.
|
||||
qWarning() << "VPN PROMPT RESULT - Rejected";
|
||||
emit controller->connectionStateChanged(VpnProtocol::Disconnected);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
/* 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 ANDROID_CONTROLLER_H
|
||||
#define ANDROID_CONTROLLER_H
|
||||
|
||||
#include <QAndroidBinder>
|
||||
#include <QAndroidServiceConnection>
|
||||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
|
||||
#include "ui/uilogic.h"
|
||||
#include "ui/pages_logic/StartPageLogic.h"
|
||||
|
||||
#include "protocols/vpnprotocol.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
|
||||
class AndroidController : public QObject, public QAndroidServiceConnection
|
||||
class AndroidController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -35,10 +39,6 @@ public:
|
|||
void cleanupBackendLogs();
|
||||
void importConfig(const QString& data);
|
||||
|
||||
// from QAndroidServiceConnection
|
||||
void onServiceConnected(const QString& name, const QAndroidBinder& serviceBinder) override;
|
||||
void onServiceDisconnected(const QString& name) override;
|
||||
|
||||
const QJsonObject &vpnConfig() const;
|
||||
void setVpnConfig(const QJsonObject &newVpnConfig);
|
||||
|
||||
|
@ -63,7 +63,8 @@ protected:
|
|||
|
||||
|
||||
private:
|
||||
//Protocol m_protocol;
|
||||
bool m_init = false;
|
||||
|
||||
QJsonObject m_vpnConfig;
|
||||
|
||||
StartPageLogic *m_startPageLogic;
|
||||
|
@ -71,28 +72,11 @@ private:
|
|||
bool m_serviceConnected = false;
|
||||
std::function<void(const QString&)> m_logCallback;
|
||||
|
||||
QAndroidBinder m_serviceBinder;
|
||||
class VPNBinder : public QAndroidBinder {
|
||||
public:
|
||||
VPNBinder(AndroidController* controller) : m_controller(controller) {}
|
||||
|
||||
bool onTransact(int code, const QAndroidParcel& data,
|
||||
const QAndroidParcel& reply,
|
||||
QAndroidBinder::CallType flags) override;
|
||||
|
||||
QString readUTF8Parcel(QAndroidParcel data);
|
||||
|
||||
private:
|
||||
AndroidController* m_controller = nullptr;
|
||||
};
|
||||
|
||||
VPNBinder m_binder;
|
||||
static void startActivityForResult(JNIEnv* env, jobject /*thiz*/, jobject intent);
|
||||
|
||||
bool isConnected = false;
|
||||
|
||||
void scheduleStatusCheck();
|
||||
|
||||
static void startActivityForResult(JNIEnv* env, jobject /*thiz*/, jobject intent);
|
||||
};
|
||||
|
||||
#endif // ANDROID_CONTROLLER_H
|
||||
|
|
174
client/platforms/android/androidutils.cpp
Normal file
174
client/platforms/android/androidutils.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* 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 "androidutils.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkCookieJar>
|
||||
#include <QUrlQuery>
|
||||
#include <QTimer>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
namespace {
|
||||
AndroidUtils* s_instance = nullptr;
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
QString AndroidUtils::GetDeviceName() {
|
||||
QJniEnvironment env;
|
||||
jclass BUILD = env->FindClass("android/os/Build");
|
||||
jfieldID model = env->GetStaticFieldID(BUILD, "MODEL", "Ljava/lang/String;");
|
||||
jstring value = (jstring)env->GetStaticObjectField(BUILD, model);
|
||||
|
||||
if (!value) {
|
||||
return QString("Android Device");
|
||||
}
|
||||
|
||||
const char* buffer = env->GetStringUTFChars(value, nullptr);
|
||||
if (!buffer) {
|
||||
return QString("Android Device");
|
||||
}
|
||||
|
||||
QString res(buffer);
|
||||
env->ReleaseStringUTFChars(value, buffer);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
// static
|
||||
AndroidUtils* AndroidUtils::instance() {
|
||||
if (!s_instance) {
|
||||
Q_ASSERT(qApp);
|
||||
s_instance = new AndroidUtils(qApp);
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
AndroidUtils::AndroidUtils(QObject* parent) : QObject(parent) {
|
||||
Q_ASSERT(!s_instance);
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
AndroidUtils::~AndroidUtils() {
|
||||
Q_ASSERT(s_instance == this);
|
||||
s_instance = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void AndroidUtils::dispatchToMainThread(std::function<void()> callback) {
|
||||
QTimer* timer = new QTimer();
|
||||
timer->moveToThread(qApp->thread());
|
||||
timer->setSingleShot(true);
|
||||
QObject::connect(timer, &QTimer::timeout, [=]() {
|
||||
callback();
|
||||
timer->deleteLater();
|
||||
});
|
||||
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
// static
|
||||
QByteArray AndroidUtils::getQByteArrayFromJString(JNIEnv* env, jstring data) {
|
||||
const char* buffer = env->GetStringUTFChars(data, nullptr);
|
||||
if (!buffer) {
|
||||
qDebug() << "getQByteArrayFromJString - failed to parse data.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray out(buffer);
|
||||
env->ReleaseStringUTFChars(data, buffer);
|
||||
return out;
|
||||
}
|
||||
|
||||
// static
|
||||
QString AndroidUtils::getQStringFromJString(JNIEnv* env, jstring data) {
|
||||
const char* buffer = env->GetStringUTFChars(data, nullptr);
|
||||
if (!buffer) {
|
||||
qDebug() << "getQStringFromJString - failed to parse data.";
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString out(buffer);
|
||||
env->ReleaseStringUTFChars(data, buffer);
|
||||
return out;
|
||||
}
|
||||
|
||||
// static
|
||||
QJsonObject AndroidUtils::getQJsonObjectFromJString(JNIEnv* env, jstring data) {
|
||||
QByteArray raw(getQByteArrayFromJString(env, data));
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument json = QJsonDocument::fromJson(raw, &jsonError);
|
||||
if (QJsonParseError::NoError != jsonError.error) {
|
||||
qDebug() << "getQJsonObjectFromJstring - error parsing json. Code: "
|
||||
<< jsonError.error << "Offset: " << jsonError.offset
|
||||
<< "Message: " << jsonError.errorString()
|
||||
<< "Data: " << raw;
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
if (!json.isObject()) {
|
||||
qDebug() << "getQJsonObjectFromJString - object expected.";
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
return json.object();
|
||||
}
|
||||
|
||||
QJniObject AndroidUtils::getActivity() {
|
||||
return QNativeInterface::QAndroidApplication::context();
|
||||
}
|
||||
|
||||
int AndroidUtils::GetSDKVersion() {
|
||||
QJniEnvironment env;
|
||||
jclass versionClass = env->FindClass("android/os/Build$VERSION");
|
||||
jfieldID sdkIntFieldID = env->GetStaticFieldID(versionClass, "SDK_INT", "I");
|
||||
int sdk = env->GetStaticIntField(versionClass, sdkIntFieldID);
|
||||
|
||||
return sdk;
|
||||
}
|
||||
|
||||
QString AndroidUtils::GetManufacturer() {
|
||||
QJniEnvironment env;
|
||||
jclass buildClass = env->FindClass("android/os/Build");
|
||||
jfieldID manuFacturerField =
|
||||
env->GetStaticFieldID(buildClass, "MANUFACTURER", "Ljava/lang/String;");
|
||||
jstring value =
|
||||
(jstring)env->GetStaticObjectField(buildClass, manuFacturerField);
|
||||
|
||||
const char* buffer = env->GetStringUTFChars(value, nullptr);
|
||||
|
||||
if (!buffer) {
|
||||
qDebug() << "Failed to fetch MANUFACTURER";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QString res(buffer);
|
||||
qDebug() << "MANUFACTURER: " << res;
|
||||
env->ReleaseStringUTFChars(value, buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
void AndroidUtils::runOnAndroidThreadSync(const std::function<void()> runnable) {
|
||||
QNativeInterface::QAndroidApplication::runOnAndroidMainThread(runnable)
|
||||
.waitForFinished();
|
||||
}
|
||||
|
||||
void AndroidUtils::runOnAndroidThreadAsync(const std::function<void()> runnable) {
|
||||
QNativeInterface::QAndroidApplication::runOnAndroidMainThread(runnable);
|
||||
}
|
||||
|
||||
// Static
|
||||
// Creates a copy of the passed QByteArray in the JVM and passes back a ref
|
||||
jbyteArray AndroidUtils::tojByteArray(const QByteArray& data) {
|
||||
QJniEnvironment env;
|
||||
jbyteArray out = env->NewByteArray(data.size());
|
||||
env->SetByteArrayRegion(out, 0, data.size(),
|
||||
reinterpret_cast<const jbyte*>(data.constData()));
|
||||
return out;
|
||||
}
|
49
client/platforms/android/androidutils.h
Normal file
49
client/platforms/android/androidutils.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* 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 ANDROIDUTILS_H
|
||||
#define ANDROIDUTILS_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
class AndroidUtils final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(AndroidUtils)
|
||||
|
||||
public:
|
||||
static QString GetDeviceName();
|
||||
|
||||
static int GetSDKVersion();
|
||||
static QString GetManufacturer();
|
||||
|
||||
static AndroidUtils* instance();
|
||||
|
||||
static void dispatchToMainThread(std::function<void()> callback);
|
||||
|
||||
static QByteArray getQByteArrayFromJString(JNIEnv* env, jstring data);
|
||||
|
||||
static jbyteArray tojByteArray(const QByteArray& data);
|
||||
|
||||
static QString getQStringFromJString(JNIEnv* env, jstring data);
|
||||
|
||||
static QJsonObject getQJsonObjectFromJString(JNIEnv* env, jstring data);
|
||||
|
||||
static QJniObject getActivity();
|
||||
|
||||
static void runOnAndroidThreadSync(const std::function<void()> runnable);
|
||||
static void runOnAndroidThreadAsync(const std::function<void()> runnable);
|
||||
|
||||
private:
|
||||
AndroidUtils(QObject* parent);
|
||||
~AndroidUtils();
|
||||
};
|
||||
|
||||
#endif // ANDROIDUTILS_H
|
136
client/platforms/android/androidvpnactivity.cpp
Normal file
136
client/platforms/android/androidvpnactivity.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* 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 "androidvpnactivity.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QJniEnvironment>
|
||||
#include <QJniObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "androidutils.h"
|
||||
#include "jni.h"
|
||||
|
||||
namespace {
|
||||
AndroidVPNActivity* s_instance = nullptr;
|
||||
constexpr auto CLASSNAME = "org.amnezia.vpn.qt.VPNActivity";
|
||||
}
|
||||
|
||||
AndroidVPNActivity::AndroidVPNActivity() {
|
||||
AndroidUtils::runOnAndroidThreadAsync([]() {
|
||||
JNINativeMethod methods[]{
|
||||
{"handleBackButton", "()Z", reinterpret_cast<bool*>(handleBackButton)},
|
||||
{"onServiceMessage", "(ILjava/lang/String;)V",
|
||||
reinterpret_cast<void*>(onServiceMessage)},
|
||||
{"qtOnServiceConnected", "()V",
|
||||
reinterpret_cast<void*>(onServiceConnected)},
|
||||
{"qtOnServiceDisconnected", "()V",
|
||||
reinterpret_cast<void*>(onServiceDisconnected)},
|
||||
};
|
||||
|
||||
QJniObject javaClass(CLASSNAME);
|
||||
QJniEnvironment env;
|
||||
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
||||
env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0]));
|
||||
env->DeleteLocalRef(objectClass);
|
||||
});
|
||||
}
|
||||
|
||||
void AndroidVPNActivity::maybeInit() {
|
||||
if (s_instance == nullptr) {
|
||||
s_instance = new AndroidVPNActivity();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool AndroidVPNActivity::handleBackButton(JNIEnv* env, jobject thiz) {
|
||||
Q_UNUSED(env);
|
||||
Q_UNUSED(thiz);
|
||||
}
|
||||
|
||||
void AndroidVPNActivity::connectService() {
|
||||
QJniObject::callStaticMethod<void>(CLASSNAME, "connectService", "()V");
|
||||
}
|
||||
|
||||
// static
|
||||
AndroidVPNActivity* AndroidVPNActivity::instance() {
|
||||
if (s_instance == nullptr) {
|
||||
AndroidVPNActivity::maybeInit();
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
// static
|
||||
void AndroidVPNActivity::sendToService(ServiceAction type, const QString& data) {
|
||||
int messageType = (int)type;
|
||||
|
||||
QJniEnvironment env;
|
||||
QJniObject::callStaticMethod<void>(
|
||||
CLASSNAME, "sendToService", "(ILjava/lang/String;)V",
|
||||
static_cast<int>(messageType),
|
||||
QJniObject::fromString(data).object<jstring>());
|
||||
}
|
||||
|
||||
// static
|
||||
void AndroidVPNActivity::onServiceMessage(JNIEnv* env, jobject thiz,
|
||||
jint messageType, jstring body) {
|
||||
Q_UNUSED(thiz);
|
||||
const char* buffer = env->GetStringUTFChars(body, nullptr);
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString parcelBody(buffer);
|
||||
env->ReleaseStringUTFChars(body, buffer);
|
||||
AndroidUtils::dispatchToMainThread([messageType, parcelBody] {
|
||||
AndroidVPNActivity::instance()->handleServiceMessage(messageType,
|
||||
parcelBody);
|
||||
});
|
||||
}
|
||||
|
||||
void AndroidVPNActivity::handleServiceMessage(int code, const QString& data) {
|
||||
auto mode = (ServiceEvents)code;
|
||||
|
||||
switch (mode) {
|
||||
case ServiceEvents::EVENT_INIT:
|
||||
emit eventInitialized(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_CONNECTED:
|
||||
emit eventConnected(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_DISCONNECTED:
|
||||
emit eventDisconnected(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_STATISTIC_UPDATE:
|
||||
emit eventStatisticUpdate(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_BACKEND_LOGS:
|
||||
emit eventBackendLogs(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_ACTIVATION_ERROR:
|
||||
emit eventActivationError(data);
|
||||
break;
|
||||
case ServiceEvents::EVENT_CONFIG_IMPORT:
|
||||
emit eventConfigImport(data);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidVPNActivity::onServiceConnected(JNIEnv* env, jobject thiz) {
|
||||
Q_UNUSED(env);
|
||||
Q_UNUSED(thiz);
|
||||
|
||||
emit AndroidVPNActivity::instance()->serviceConnected();
|
||||
}
|
||||
|
||||
void AndroidVPNActivity::onServiceDisconnected(JNIEnv* env, jobject thiz) {
|
||||
Q_UNUSED(env);
|
||||
Q_UNUSED(thiz);
|
||||
|
||||
emit AndroidVPNActivity::instance()->serviceDisconnected();
|
||||
}
|
93
client/platforms/android/androidvpnactivity.h
Normal file
93
client/platforms/android/androidvpnactivity.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* 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 ANDROIDVPNACTIVITY_H
|
||||
#define ANDROIDVPNACTIVITY_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
// Binder Codes for VPNServiceBinder
|
||||
// See also - VPNServiceBinder.kt
|
||||
// Actions that are Requestable
|
||||
enum ServiceAction {
|
||||
// Activate the vpn. Body requires a json wg-conf
|
||||
ACTION_ACTIVATE = 1,
|
||||
// Deactivate the vpn. Body is empty
|
||||
ACTION_DEACTIVATE = 2,
|
||||
// Register an IBinder to recieve events body is an Ibinder
|
||||
ACTION_REGISTERLISTENER = 3,
|
||||
// Requests an EVENT_STATISTIC_UPDATE to be send
|
||||
ACTION_REQUEST_STATISTIC = 4,
|
||||
ACTION_REQUEST_GET_LOG = 5,
|
||||
// Requests to clean up the internal log
|
||||
ACTION_REQUEST_CLEANUP_LOG = 6,
|
||||
// Retry activation using the last config
|
||||
// Used when the activation is aborted for VPN-Permission prompt
|
||||
ACTION_RESUME_ACTIVATE = 7,
|
||||
// Sets the current notification text.
|
||||
// Does nothing if there is no notification
|
||||
ACTION_SET_NOTIFICATION_TEXT = 8,
|
||||
// Sets the fallback text if the OS triggered the VPN-Service
|
||||
// to show a notification
|
||||
ACTION_SET_NOTIFICATION_FALLBACK = 9,
|
||||
// Share used config
|
||||
ACTION_SHARE_CONFIG = 10,
|
||||
};
|
||||
typedef enum ServiceAction ServiceAction;
|
||||
|
||||
// Event Types that will be Dispatched after registration
|
||||
enum ServiceEvents {
|
||||
// The Service has Accecpted our Binder
|
||||
// Responds with the current status of the vpn.
|
||||
EVENT_INIT = 0,
|
||||
// WG-Go has enabled the adapter (empty response)
|
||||
EVENT_CONNECTED = 1,
|
||||
// WG-Go has disabled the adapter (empty response)
|
||||
EVENT_DISCONNECTED = 2,
|
||||
// Contains the Current transfered bytes to endpoint x.
|
||||
EVENT_STATISTIC_UPDATE = 3,
|
||||
EVENT_BACKEND_LOGS = 4,
|
||||
// An Error happened during activation
|
||||
// Contains the error message
|
||||
EVENT_ACTIVATION_ERROR = 5,
|
||||
EVENT_NEED_PERMISSION = 6,
|
||||
// Import of existing config
|
||||
EVENT_CONFIG_IMPORT = 7,
|
||||
};
|
||||
typedef enum ServiceEvents ServiceEvents;
|
||||
|
||||
class AndroidVPNActivity : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void maybeInit();
|
||||
static AndroidVPNActivity* instance();
|
||||
static bool handleBackButton(JNIEnv* env, jobject thiz);
|
||||
static void sendToService(ServiceAction type, const QString& data);
|
||||
static void connectService();
|
||||
|
||||
signals:
|
||||
void serviceConnected();
|
||||
void serviceDisconnected();
|
||||
void eventInitialized(const QString& data);
|
||||
void eventConnected(const QString& data);
|
||||
void eventDisconnected(const QString& data);
|
||||
void eventStatisticUpdate(const QString& data);
|
||||
void eventBackendLogs(const QString& data);
|
||||
void eventActivationError(const QString& data);
|
||||
void eventConfigImport(const QString& data);
|
||||
|
||||
private:
|
||||
AndroidVPNActivity();
|
||||
|
||||
static void onServiceMessage(JNIEnv* env, jobject thiz, jint messageType, jstring body);
|
||||
static void onServiceConnected(JNIEnv* env, jobject thiz);
|
||||
static void onServiceDisconnected(JNIEnv* env, jobject thiz);
|
||||
void handleServiceMessage(int code, const QString& data);
|
||||
};
|
||||
|
||||
#endif // ANDROIDVPNACTIVITY_H
|
|
@ -2,7 +2,6 @@
|
|||
* 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 "wireguard-go-version.h"
|
||||
#include "3rd/wireguard-apple/Sources/WireGuardKitC/WireGuardKitC.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
|
|
@ -37,7 +37,7 @@ public class Logger {
|
|||
appVersion += " (\(appBuild))"
|
||||
}
|
||||
|
||||
let goBackendVersion = WIREGUARD_GO_VERSION
|
||||
let goBackendVersion = "1"
|
||||
Logger.global?.log(message: "App version: \(appVersion); Go backend version: \(goBackendVersion)")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import os
|
|||
import Darwin
|
||||
import OpenVPNAdapter
|
||||
//import Tun2socks
|
||||
|
||||
enum TunnelProtoType: String {
|
||||
case wireguard, openvpn, shadowsocks, none
|
||||
}
|
||||
|
@ -415,9 +414,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -- Leaf provider methods
|
||||
|
||||
private func prepareConfig(onInterface iface: String, fromSSConfig ssConfig: Data, andOvpnConfig ovpnConfig: Data) -> UnsafePointer<CChar>? {
|
||||
guard let ssConfig = try? JSONSerialization.jsonObject(with: ssConfig, options: []) as? [String: Any] else {
|
||||
self.ssCompletion?(0, NSError(domain: Bundle.main.bundleIdentifier ?? "unknown",
|
||||
|
@ -425,7 +422,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
userInfo: [NSLocalizedDescriptionKey: "Cannot parse json for ss in tunnel"]))
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let remoteHost = ssConfig[Constants.ssRemoteHost] as? String,
|
||||
let remotePort = ssConfig[Constants.ssRemotePort] as? Int,
|
||||
let method = ssConfig[Constants.ssCipherKey] as? String,
|
||||
|
@ -435,19 +431,16 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
userInfo: [NSLocalizedDescriptionKey: "Cannot asign profile params for ss in tunnel"]))
|
||||
return nil
|
||||
}
|
||||
|
||||
var insettings: [String: Any] = .init()
|
||||
insettings["name"] = iface
|
||||
insettings["address"] = "127.0.0.2"
|
||||
insettings["netmask"] = "255.255.255.0"
|
||||
insettings["gateway"] = "127.0.0.1"
|
||||
insettings["mtu"] = 1600
|
||||
|
||||
var inbounds: [String: Any] = .init()
|
||||
inbounds["protocol"] = "tun"
|
||||
inbounds["settings"] = insettings
|
||||
inbounds["tag"] = "tun_in"
|
||||
|
||||
var outbounds: [String: Any] = .init()
|
||||
var outsettings: [String: Any] = .init()
|
||||
outsettings["address"] = remoteHost
|
||||
|
@ -457,18 +450,13 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
outbounds["protocol"] = "shadowsocks"
|
||||
outbounds["settings"] = outsettings
|
||||
outbounds["tag"] = "shadowsocks_out"
|
||||
|
||||
var params: [String: Any] = .init()
|
||||
params["inbounds"] = [inbounds]
|
||||
params["outbounds"] = [outbounds]
|
||||
|
||||
wg_log(.error, message: "Config dictionary: \(params)")
|
||||
|
||||
guard let jsonData = try? JSONSerialization.data(withJSONObject: params, options: .prettyPrinted),
|
||||
let jsonString = String(data: jsonData, encoding: .utf8) else { return nil }
|
||||
|
||||
wg_log(.error, message: "JSON String: \(jsonString)")
|
||||
|
||||
var path = ""
|
||||
if let documentDirectory = FileManager.default.urls(for: .documentDirectory,
|
||||
in: .userDomainMask).first {
|
||||
|
@ -538,7 +526,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
private func stopLeafRedirector(completion: @escaping () -> Void) {
|
||||
leafProvider?.stopTunnel { error in
|
||||
// TODO: handle errors
|
||||
|
@ -571,7 +558,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
wg_log(.error, message: "Error starting ShadowSocks: \(String(describing: errorCode))")
|
||||
return
|
||||
}
|
||||
|
||||
// self.setupAndHandleOpenVPNOverSSConnection(withConfig: ovpnConfig)
|
||||
self.startAndHandleTunnelOverSS(completionHandler: completion)
|
||||
}
|
||||
|
@ -735,12 +721,12 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
|
|||
|
||||
startHandler = completionHandler
|
||||
ovpnAdapter.connect(using: packetFlow)
|
||||
|
||||
// let ifaces = Interface.allInterfaces()
|
||||
// .filter { $0.family == .ipv4 }
|
||||
// .map { iface in iface.name }
|
||||
|
||||
let ifaces = Interface.allInterfaces()
|
||||
.filter { $0.family == .ipv4 }
|
||||
.map { iface in iface.name }
|
||||
|
||||
wg_log(.error, message: "Available TUN Interfaces: \(ifaces)")
|
||||
// wg_log(.error, message: "Available TUN Interfaces: \(ifaces)")
|
||||
}
|
||||
|
||||
// MARK: -- Network observing methods
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue