Merge branch 'dev' into ios_main

This commit is contained in:
pokamest 2021-11-18 03:48:34 -08:00
commit fd9d54d2dd
98 changed files with 3280 additions and 2062 deletions

View file

@ -597,7 +597,7 @@ CQR_Encode::~CQR_Encode()
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// CQR_Encode::EncodeData // CQR_Encode::EncodeData
bool CQR_Encode::EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, char* lpsSource, int ncSource) bool CQR_Encode::EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, const char* lpsSource, int ncSource)
{ {
int i, j; int i, j;
@ -746,7 +746,7 @@ bool CQR_Encode::EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMas
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// CQR_Encode::GetEncodeVersion // CQR_Encode::GetEncodeVersion
int CQR_Encode::GetEncodeVersion(int nVersion, char* lpsSource, int ncLength) int CQR_Encode::GetEncodeVersion(int nVersion, const char* lpsSource, int ncLength)
{ {
int nVerGroup = nVersion >= 27 ? QR_VRESION_L : (nVersion >= 10 ? QR_VRESION_M : QR_VRESION_S); int nVerGroup = nVersion >= 27 ? QR_VRESION_L : (nVersion >= 10 ? QR_VRESION_M : QR_VRESION_S);
int i, j; int i, j;
@ -788,7 +788,7 @@ int CQR_Encode::GetEncodeVersion(int nVersion, char* lpsSource, int ncLength)
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// CQR_Encode::EncodeSourceData // CQR_Encode::EncodeSourceData
bool CQR_Encode::EncodeSourceData(char* lpsSource, int ncLength, int nVerGroup) bool CQR_Encode::EncodeSourceData(const char* lpsSource, int ncLength, int nVerGroup)
{ {
memset(m_nBlockLength, 0, sizeof(m_nBlockLength)); memset(m_nBlockLength, 0, sizeof(m_nBlockLength));

View file

@ -92,11 +92,11 @@ private:
unsigned char m_byRSWork[MAX_CODEBLOCK]; unsigned char m_byRSWork[MAX_CODEBLOCK];
public: public:
bool EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, char* lpsSource, int ncSource = 0); bool EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMaskingNo, const char* lpsSource, int ncSource = 0);
private: private:
int GetEncodeVersion(int nVersion, char* lpsSource, int ncLength); int GetEncodeVersion(int nVersion, const char* lpsSource, int ncLength);
bool EncodeSourceData(char* lpsSource, int ncLength, int nVerGroup); bool EncodeSourceData(const char* lpsSource, int ncLength, int nVerGroup);
int GetBitLength(unsigned char nMode, int ncData, int nVerGroup); int GetBitLength(unsigned char nMode, int ncData, int nVerGroup);

View file

@ -106,6 +106,8 @@ android {
resConfig "en" resConfig "en"
minSdkVersion = 24 minSdkVersion = 24
targetSdkVersion = 30 targetSdkVersion = 30
versionCode 2 // Change to a higher number
versionName "2.0.1" // Change to a higher number
} }
buildTypes { buildTypes {

View file

@ -287,46 +287,72 @@ class VPNService : android.net.VpnService() {
return null return null
} }
private fun parseConfigData(data: String): Map<String, Map<String, String>> {
val parseData = mutableMapOf<String, Map<String, String>>()
var currentSection: Pair<String, MutableMap<String, String>>? = null
data.lines().forEach { line ->
if (line.isNotEmpty()) {
if (line.startsWith('[')) {
currentSection?.let {
parseData.put(it.first, it.second)
}
currentSection = line.substring(1, line.indexOfLast { it == ']' }) to mutableMapOf()
} else {
val parameter = line.split("=", limit = 2)
currentSection!!.second.put(parameter.first().trim(), parameter.last().trim())
}
}
}
currentSection?.let {
parseData.put(it.first, it.second)
}
return parseData
}
/** /**
* Create a Wireguard [Config] from a [json] string - * Create a Wireguard [Config] from a [json] string -
* The [json] will be created in AndroidVpnProtocol.cpp * The [json] will be created in AndroidVpnProtocol.cpp
*/ */
private fun buildWireugardConfig(obj: JSONObject): Config { private fun buildWireugardConfig(obj: JSONObject): Config {
val confBuilder = Config.Builder() val confBuilder = Config.Builder()
val jServer = obj.getJSONObject("server") val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
val config = parseConfigData(wireguardConfigData.getString("config"))
val peerBuilder = Peer.Builder() val peerBuilder = Peer.Builder()
val ep = val peerConfig = config["Peer"]!!
InetEndpoint.parse(jServer.getString("ipv4AddrIn") + ":" + jServer.getString("port")) peerBuilder.setPublicKey(Key.fromBase64(peerConfig["PublicKey"]))
peerBuilder.setEndpoint(ep) peerConfig["PresharedKey"]?.let {
peerBuilder.setPublicKey(Key.fromBase64(jServer.getString("publicKey"))) peerBuilder.setPreSharedKey(Key.fromBase64(it))
}
val jAllowedIPList = obj.getJSONArray("allowedIPs") val allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
if (jAllowedIPList.length() == 0) { if (allowedIPList.isEmpty()) {
val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet. val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internet) peerBuilder.addAllowedIp(internet)
} else { } else {
(0 until jAllowedIPList.length()).toList().forEach { allowedIPList.forEach {
val network = InetNetwork.parse(jAllowedIPList.getString(it)) val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network) peerBuilder.addAllowedIp(network)
} }
} }
peerBuilder.setEndpoint(InetEndpoint.parse(peerConfig["Endpoint"]))
peerConfig["PersistentKeepalive"]?.let {
peerBuilder.setPersistentKeepalive(it.toInt())
}
confBuilder.addPeer(peerBuilder.build()) confBuilder.addPeer(peerBuilder.build())
val privateKey = obj.getJSONObject("keys").getString("privateKey")
val jDevice = obj.getJSONObject("device")
val ifaceBuilder = Interface.Builder() val ifaceBuilder = Interface.Builder()
ifaceBuilder.parsePrivateKey(privateKey) val ifaceConfig = config["Interface"]!!
ifaceBuilder.addAddress(InetNetwork.parse(jDevice.getString("ipv4Address"))) ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
ifaceBuilder.addAddress(InetNetwork.parse(jDevice.getString("ipv6Address"))) ifaceBuilder.addAddress(InetNetwork.parse(ifaceConfig["Address"]))
ifaceBuilder.addDnsServer(InetNetwork.parse(obj.getString("dns")).address) ifaceConfig["DNS"]!!.split(",").forEach {
val jExcludedApplication = obj.getJSONArray("excludedApps") ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
}
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
(0 until jExcludedApplication.length()).toList().forEach { (0 until jExcludedApplication.length()).toList().forEach {
val appName = jExcludedApplication.get(it).toString() val appName = jExcludedApplication.get(it).toString()
ifaceBuilder.excludeApplication(appName) ifaceBuilder.excludeApplication(appName)
} }*/
confBuilder.setInterface(ifaceBuilder.build()) confBuilder.setInterface(ifaceBuilder.build())
return confBuilder.build() return confBuilder.build()
} }

View file

@ -6,6 +6,7 @@
#include <QDebug> #include <QDebug>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QJsonDocument> #include <QJsonDocument>
#include <QUuid>
#include "sftpdefs.h" #include "sftpdefs.h"
@ -21,6 +22,7 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
connData.host = credentials.hostName; connData.host = credentials.hostName;
connData.clientId = Utils::getRandomString(16); connData.clientId = Utils::getRandomString(16);
connData.password = Utils::getRandomString(16); connData.password = Utils::getRandomString(16);
connData.password = "";
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12"; QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
@ -41,8 +43,11 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
.arg(certFileName); .arg(certFileName);
e = ServerController::runContainerScript(credentials, container, scriptExportCert); e = ServerController::runContainerScript(credentials, container, scriptExportCert);
connData.cert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e); connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e);
qDebug() << "Ikev2Configurator::ConnectionData cert size:" << connData.cert.size(); connData.caCert = ServerController::getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
return connData; return connData;
} }
@ -50,17 +55,62 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
{ {
Q_UNUSED(containerConfig)
ConnectionData connData = prepareIkev2Config(credentials, container, errorCode); ConnectionData connData = prepareIkev2Config(credentials, container, errorCode);
if (errorCode && *errorCode) { if (errorCode && *errorCode) {
return ""; return "";
} }
return genIkev2Config(connData);
}
QString Ikev2Configurator::genIkev2Config(const ConnectionData &connData)
{
QJsonObject config; QJsonObject config;
config[config_key::hostName] = connData.host; config[config_key::hostName] = connData.host;
config[config_key::userName] = connData.clientId; config[config_key::userName] = connData.clientId;
config[config_key::cert] = QString(connData.cert.toBase64()); config[config_key::cert] = QString(connData.clientCert.toBase64());
config[config_key::password] = connData.password; config[config_key::password] = connData.password;
return QJsonDocument(config).toJson(); return QJsonDocument(config).toJson();
} }
QString Ikev2Configurator::genMobileConfig(const ConnectionData &connData)
{
QFile file(":/server_scripts/ipsec/mobileconfig.plist");
file.open(QIODevice::ReadOnly);
QString config = QString(file.readAll());
config.replace("$CLIENT_NAME", connData.clientId);
config.replace("$UUID1", QUuid::createUuid().toString());
config.replace("$SERVER_ADDR", connData.host);
QString subStr("$(UUID_GEN)");
while (config.indexOf(subStr) > 0) {
config.replace(config.indexOf(subStr), subStr.size(), QUuid::createUuid().toString());
}
config.replace("$P12_BASE64", connData.clientCert.toBase64());
config.replace("$CA_BASE64", connData.caCert.toBase64());
return config;
}
QString Ikev2Configurator::genStrongSwanConfig(const ConnectionData &connData)
{
QFile file(":/server_scripts/ipsec/strongswan.profile");
file.open(QIODevice::ReadOnly);
QString config = QString(file.readAll());
config.replace("$CLIENT_NAME", connData.clientId);
config.replace("$UUID", QUuid::createUuid().toString());
config.replace("$SERVER_ADDR", connData.host);
QByteArray cert = connData.clientCert.toBase64();
cert.replace("\r", "").replace("\n", "");
config.replace("$P12_BASE64", cert);
return config;
}

View file

@ -12,7 +12,8 @@ class Ikev2Configurator
public: public:
struct ConnectionData { struct ConnectionData {
QByteArray cert; // p12 client cert QByteArray clientCert; // p12 client cert
QByteArray caCert; // p12 server cert
QString clientId; QString clientId;
QString password; // certificate password QString password; // certificate password
QString host; // host ip QString host; // host ip
@ -21,8 +22,10 @@ public:
static QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container, static QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
static QString genIkev2Config(const ConnectionData &connData);
static QString genMobileConfig(const ConnectionData &connData);
static QString genStrongSwanConfig(const ConnectionData &connData);
private:
static ConnectionData prepareIkev2Config(const ServerCredentials &credentials, static ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr); DockerContainer container, ErrorCode *errorCode = nullptr);
}; };

View file

@ -6,6 +6,11 @@
#include <QDebug> #include <QDebug>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "sftpdefs.h" #include "sftpdefs.h"
#include "core/server_defs.h" #include "core/server_defs.h"
@ -13,72 +18,34 @@
#include "core/scripts_registry.h" #include "core/scripts_registry.h"
#include "utils.h" #include "utils.h"
QProcessEnvironment WireguardConfigurator::prepareEnv()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString pathEnvVar = env.value("PATH");
#ifdef Q_OS_WIN
pathEnvVar.clear();
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\wireguard;");
#else
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
#endif
env.insert("PATH", pathEnvVar);
qDebug().noquote() << "ENV PATH" << pathEnvVar;
return env;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys() WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
{ {
// TODO review
constexpr size_t EDDSA_KEY_LENGTH = 32;
ConnectionData connData; ConnectionData connData;
QString program; unsigned char buff[EDDSA_KEY_LENGTH];
#ifdef Q_OS_WIN int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\wireguard\\wg.exe"; if (ret <=0) return connData;
#else
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS/wg";
#endif
#ifndef Q_OS_IOS EVP_PKEY * pKey = EVP_PKEY_new();
q_check_ptr(pKey);
pKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, &buff[0], EDDSA_KEY_LENGTH);
// Priv
{
QProcess p;
p.setProcessEnvironment(prepareEnv());
p.setProcessChannelMode(QProcess::MergedChannels);
p.setProgram(program);
p.setArguments(QStringList() << "genkey"); size_t keySize = EDDSA_KEY_LENGTH;
p.start(); // save private key
p.waitForFinished(); unsigned char priv[EDDSA_KEY_LENGTH];
EVP_PKEY_get_raw_private_key(pKey, priv, &keySize);
connData.clientPrivKey = QByteArray::fromRawData((char*)priv, keySize).toBase64();
connData.clientPrivKey = QString(p.readAll()); // save public key
connData.clientPrivKey.replace("\r", ""); unsigned char pub[EDDSA_KEY_LENGTH];
connData.clientPrivKey.replace("\n", ""); EVP_PKEY_get_raw_public_key(pKey, pub, &keySize);
} connData.clientPubKey = QByteArray::fromRawData((char*)pub, keySize).toBase64();
// Pub
{
QProcess p;
p.setProcessEnvironment(prepareEnv());
p.setProcessChannelMode(QProcess::MergedChannels);
p.setProgram(program);
p.setArguments(QStringList() << "pubkey");
p.start();
p.write(connData.clientPrivKey.toUtf8());
p.closeWriteChannel();
p.waitForFinished();
connData.clientPubKey = QString(p.readAll());
connData.clientPubKey.replace("\r", "");
connData.clientPubKey.replace("\n", "");
}
#endif
return connData; return connData;
} }

View file

@ -28,8 +28,6 @@ public:
private: private:
static QProcessEnvironment prepareEnv();
static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr); DockerContainer container, ErrorCode *errorCode = nullptr);

View file

@ -43,11 +43,14 @@ QVector<amnezia::Protocol> ContainerProps::protocolsForContainer(amnezia::Docker
return { Protocol::OpenVpn, Protocol::ShadowSocks, Protocol::Cloak }; return { Protocol::OpenVpn, Protocol::ShadowSocks, Protocol::Cloak };
case DockerContainer::Ipsec: case DockerContainer::Ipsec:
return { Protocol::Ikev2, Protocol::L2tp }; return { Protocol::Ikev2 /*, Protocol::L2tp */};
case DockerContainer::Dns: case DockerContainer::Dns:
return { }; return { };
case DockerContainer::Sftp:
return { Protocol::Sftp};
default: default:
return { defaultProtocol(container) }; return { defaultProtocol(container) };
} }
@ -72,11 +75,11 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"}, {DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"},
{DockerContainer::Cloak, "OpenVpn over Cloak"}, {DockerContainer::Cloak, "OpenVpn over Cloak"},
{DockerContainer::WireGuard, "WireGuard"}, {DockerContainer::WireGuard, "WireGuard"},
{DockerContainer::Ipsec, QObject::tr("IPsec container")}, {DockerContainer::Ipsec, QObject::tr("IPsec")},
{DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")}, {DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")},
{DockerContainer::Dns, QObject::tr("DNS Service")}, {DockerContainer::Dns, QObject::tr("DNS Service")},
{DockerContainer::FileShare, QObject::tr("SMB file sharing service")}, //{DockerContainer::FileShare, QObject::tr("SMB file sharing service")},
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service")} {DockerContainer::Sftp, QObject::tr("Sftp file sharing service")}
}; };
} }
@ -93,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")}, {DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")},
{DockerContainer::Dns, QObject::tr("DNS Service")}, {DockerContainer::Dns, QObject::tr("DNS Service")},
{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")}, //{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")},
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service")} {DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service")}
}; };
} }
@ -109,7 +112,7 @@ amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
case DockerContainer::Ipsec : return ServiceType::Vpn; case DockerContainer::Ipsec : return ServiceType::Vpn;
case DockerContainer::TorWebSite : return ServiceType::Other; case DockerContainer::TorWebSite : return ServiceType::Other;
case DockerContainer::Dns : return ServiceType::Other; case DockerContainer::Dns : return ServiceType::Other;
case DockerContainer::FileShare : return ServiceType::Other; //case DockerContainer::FileShare : return ServiceType::Other;
case DockerContainer::Sftp : return ServiceType::Other; case DockerContainer::Sftp : return ServiceType::Other;
default: return ServiceType::Other; default: return ServiceType::Other;
} }
@ -127,8 +130,9 @@ Protocol ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::TorWebSite : return Protocol::TorWebSite; case DockerContainer::TorWebSite : return Protocol::TorWebSite;
case DockerContainer::Dns : return Protocol::Dns; case DockerContainer::Dns : return Protocol::Dns;
case DockerContainer::FileShare : return Protocol::FileShare; //case DockerContainer::FileShare : return Protocol::FileShare;
case DockerContainer::Sftp : return Protocol::Sftp; case DockerContainer::Sftp : return Protocol::Sftp;
default: return Protocol::Any;
} }
} }

View file

@ -23,7 +23,7 @@ enum DockerContainer {
//non-vpn //non-vpn
TorWebSite, TorWebSite,
Dns, Dns,
FileShare, //FileShare,
Sftp Sftp
}; };
Q_ENUM_NS(DockerContainer) Q_ENUM_NS(DockerContainer)

View file

@ -1,38 +1,83 @@
#include "ipcclient.h" #include "ipcclient.h"
#include <QRemoteObjectNode> #include <QRemoteObjectNode>
IpcClient &IpcClient::Instance() IpcClient *IpcClient::m_instance = nullptr;
IpcClient::IpcClient(QObject *parent) : QObject(parent)
{ {
static IpcClient s;
return s;
} }
bool IpcClient::init() IpcClient::~IpcClient()
{ {
Instance().m_localSocket->waitForConnected(); if (m_localSocket) m_localSocket->close();
}
if (!Instance().m_ipcClient) { bool IpcClient::isSocketConnected() const
{
return m_isSocketConnected;
}
IpcClient *IpcClient::Instance()
{
return m_instance;
}
QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
{
if (!Instance()) return nullptr;
return Instance()->m_ipcClient;
}
bool IpcClient::init(IpcClient *instance)
{
m_instance = instance;
Instance()->m_localSocket = new QLocalSocket(Instance());
connect(Instance()->m_localSocket.data(), &QLocalSocket::connected, &Instance()->m_ClientNode, []() {
Instance()->m_ClientNode.addClientSideConnection(Instance()->m_localSocket.data());
Instance()->m_ipcClient.reset(Instance()->m_ClientNode.acquire<IpcInterfaceReplica>());
Instance()->m_ipcClient->waitForSource(1000);
if (!Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient replica is not connected!";
}
});
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
instance->m_isSocketConnected = false;
});
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
Instance()->m_localSocket->waitForConnected();
if (!Instance()->m_ipcClient) {
qDebug() << "IpcClient::init failed"; qDebug() << "IpcClient::init failed";
return false; return false;
} }
return Instance().m_ipcClient->isReplicaValid(); qDebug() << "IpcClient::init succeed";
return Instance()->m_ipcClient->isReplicaValid();
} }
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess() QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
{ {
#ifndef Q_OS_IOS #ifndef Q_OS_IOS
if (! Instance().m_ipcClient || ! Instance().m_ipcClient->isReplicaValid()) { if (! Instance()->m_ipcClient || ! Instance()->m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid"; qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
return nullptr; return nullptr;
} }
QRemoteObjectPendingReply<int> futureResult = Instance().m_ipcClient->createPrivilegedProcess(); QRemoteObjectPendingReply<int> futureResult = Instance()->m_ipcClient->createPrivilegedProcess();
futureResult.waitForFinished(1000); futureResult.waitForFinished(1000);
int pid = futureResult.returnValue(); int pid = futureResult.returnValue();
auto pd = QSharedPointer<ProcessDescriptor>(new ProcessDescriptor()); auto pd = QSharedPointer<ProcessDescriptor>(new ProcessDescriptor());
Instance().m_processNodes.insert(pid, pd); Instance()->m_processNodes.insert(pid, pd);
pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data())); pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data()));
@ -65,19 +110,4 @@ QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
#endif #endif
} }
IpcClient::IpcClient(QObject *parent) : QObject(parent)
{
m_localSocket.reset(new QLocalSocket(this));
connect(m_localSocket.data(), &QLocalSocket::connected, &m_ClientNode, [this]() {
m_ClientNode.addClientSideConnection(m_localSocket.data());
m_ipcClient.reset(m_ClientNode.acquire<IpcInterfaceReplica>());
m_ipcClient->waitForSource(1000);
if (!m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient replica is not connected!";
}
});
m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
}

View file

@ -19,19 +19,23 @@ class IpcClient : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static IpcClient &Instance(); explicit IpcClient(QObject *parent = nullptr);
static bool init();
static QSharedPointer<IpcInterfaceReplica> Interface() { return Instance().m_ipcClient; } static IpcClient *Instance();
static bool init(IpcClient *instance);
static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessInterfaceReplica> CreatePrivilegedProcess(); static QSharedPointer<IpcProcessInterfaceReplica> CreatePrivilegedProcess();
bool isSocketConnected() const;
signals: signals:
private: private:
explicit IpcClient(QObject *parent = nullptr); ~IpcClient() override;
QRemoteObjectNode m_ClientNode; QRemoteObjectNode m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient; QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QSharedPointer<QLocalSocket> m_localSocket; QPointer<QLocalSocket> m_localSocket;
struct ProcessDescriptor { struct ProcessDescriptor {
ProcessDescriptor () { ProcessDescriptor () {
@ -45,6 +49,9 @@ private:
}; };
QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes; QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes;
bool m_isSocketConnected {false};
static IpcClient *m_instance;
}; };
#endif // IPCCLIENT_H #endif // IPCCLIENT_H

View file

@ -15,7 +15,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::TorWebSite: return QLatin1String("website_tor"); case DockerContainer::TorWebSite: return QLatin1String("website_tor");
case DockerContainer::Dns: return QLatin1String("dns"); case DockerContainer::Dns: return QLatin1String("dns");
case DockerContainer::FileShare: return QLatin1String("file_share"); //case DockerContainer::FileShare: return QLatin1String("file_share");
case DockerContainer::Sftp: return QLatin1String("sftp"); case DockerContainer::Sftp: return QLatin1String("sftp");
default: return ""; default: return "";
} }

View file

@ -24,6 +24,12 @@
using namespace QSsh; using namespace QSsh;
Settings &ServerController::m_settings()
{
static Settings s;
return s;
}
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script, ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdOut, const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdOut,
const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdErr) const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdErr)
@ -127,16 +133,22 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr) const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr)
{ {
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh"; QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
QString mkdir = "sudo docker exec -i $CONTAINER_NAME mkdir -p /opt/amnezia/";
ErrorCode e = runScript(credentials,
replaceVars(mkdir, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
if (e) return e;
e = uploadTextFileToContainer(container, credentials, script, fileName);
if (e) return e; if (e) return e;
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName); QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
e = runScript(credentials, e = runScript(credentials,
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr); replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
// QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName); QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
// runScript(credentials, runScript(credentials,
// replaceVars(remover, genVarsForScript(credentials, container))); replaceVars(remover, genVarsForScript(credentials, container)));
return e; return e;
} }
@ -672,6 +684,8 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}}); vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
vars.append({{"$PRIMARY_SERVER_DNS", m_settings().primaryDns()}});
vars.append({{"$SECONDARY_SERVER_DNS", m_settings().secondaryDns()}});
// Sftp vars // Sftp vars

View file

@ -6,6 +6,8 @@
#include "sshconnection.h" #include "sshconnection.h"
#include "sshremoteprocess.h" #include "sshremoteprocess.h"
#include "defs.h" #include "defs.h"
#include "settings.h"
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "sftpdefs.h" #include "sftpdefs.h"
@ -75,6 +77,7 @@ private:
static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config); static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject()); static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static Settings &m_settings();
}; };
#endif // SERVERCONTROLLER_H #endif // SERVERCONTROLLER_H

BIN
client/images/animation.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
client/images/connected.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -116,6 +116,9 @@ int main(int argc, char *argv[])
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
qRegisterMetaType<VpnProtocol::ConnectionState>("VpnProtocol::ConnectionState");
qRegisterMetaType<ServerCredentials>("ServerCredentials");
qRegisterMetaType<DockerContainer>("DockerContainer"); qRegisterMetaType<DockerContainer>("DockerContainer");
qRegisterMetaType<TransportProto>("TransportProto"); qRegisterMetaType<TransportProto>("TransportProto");
qRegisterMetaType<Protocol>("Protocol"); qRegisterMetaType<Protocol>("Protocol");
@ -127,12 +130,14 @@ int main(int argc, char *argv[])
UiLogic *uiLogic = new UiLogic; UiLogic *uiLogic = new UiLogic;
QQmlApplicationEngine engine; QQmlApplicationEngine *engine = new QQmlApplicationEngine;
declareQmlPageEnum(); declareQmlPageEnum();
declareQmlProtocolEnum(); declareQmlProtocolEnum();
declareQmlContainerEnum(); declareQmlContainerEnum();
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
QScopedPointer<ContainerProps> containerProps(new ContainerProps); QScopedPointer<ContainerProps> containerProps(new ContainerProps);
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get()); qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get());
@ -140,29 +145,41 @@ int main(int argc, char *argv[])
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get()); qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get());
const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml")); const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) { &app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl) if (!obj && url == objUrl)
QCoreApplication::exit(-1); QCoreApplication::exit(-1);
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
engine.rootContext()->setContextProperty("UiLogic", uiLogic); engine->rootContext()->setContextProperty("UiLogic", uiLogic);
engine.rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic()); engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
engine.rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic()); engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic());
engine.rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic()); engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic());
engine.rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic()); engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
engine.rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic()); engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
engine.rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic()); engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
engine.rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic()); engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
engine.rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic()); engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic());
engine.rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic()); engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic());
engine.rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic()); engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic());
engine.rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic()); engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic());
engine.rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic()); engine->rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic());
engine.rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic()); engine->rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic());
engine.load(url); engine->load(url);
QObject::connect(&app, &QCoreApplication::aboutToQuit, uiLogic, [&engine, uiLogic](){
QObject::disconnect(engine, 0,0,0);
delete engine;
QObject::disconnect(uiLogic, 0,0,0);
delete uiLogic;
});
if (engine->rootObjects().size() > 0) {
uiLogic->setQmlRoot(engine->rootObjects().at(0));
}
// TODO - fix // TODO - fix
//#ifdef Q_OS_WIN //#ifdef Q_OS_WIN

View file

@ -1,18 +1,29 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QRegularExpression> //#include <QRegularExpression>
#include <QTcpSocket> //#include <QTcpSocket>
#include <QThread> #include <QThread>
#include <chrono>
#include "debug.h" #include "debug.h"
#include "ikev2_vpn_protocol.h" #include "ikev2_vpn_protocol.h"
#include "utils.h" #include "utils.h"
static Ikev2Protocol* self = nullptr;
static std::mutex rasDialFuncMutex;
extern "C" {
static void WINAPI RasDialFuncCallback(UINT unMsg,
RASCONNSTATE rasconnstate,
DWORD dwError );
}
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) : Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
VpnProtocol(configuration, parent) VpnProtocol(configuration, parent)
{ {
self = this;
//m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf"); //m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
readIkev2Configuration(configuration); readIkev2Configuration(configuration);
} }
@ -20,34 +31,214 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent)
Ikev2Protocol::~Ikev2Protocol() Ikev2Protocol::~Ikev2Protocol()
{ {
qDebug() << "IpsecProtocol::~IpsecProtocol()"; qDebug() << "IpsecProtocol::~IpsecProtocol()";
#ifdef Q_OS_WIN
disconnect_vpn();
#endif
Ikev2Protocol::stop(); Ikev2Protocol::stop();
QThread::msleep(200);
} }
void Ikev2Protocol::stop() void Ikev2Protocol::stop()
{ {
setConnectionState(VpnProtocol::Disconnecting);
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
{ {
setConnectionState(Disconnecting); if (! disconnect_vpn() ){
qDebug()<<"We don't disconnect";
auto disconnectProcess = new QProcess; setConnectionState(VpnProtocol::Error);
}
disconnectProcess->setProgram("rasdial"); else {
QString arguments = QString("\"%1\" /disconnect") setConnectionState(VpnProtocol::Disconnected);
.arg(tunnelName()); }
disconnectProcess->setNativeArguments(arguments);
// connect(connectProcess, &QProcess::readyRead, [connectProcess]() {
// qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll();
// });
disconnectProcess->start();
disconnectProcess->waitForFinished(5000);
setConnectionState(Disconnected);
} }
#endif #endif
} }
void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE rasconnstate, DWORD dwError)
{
Q_UNUSED(unMsg);
qDebug()<<"Recive the new event "<<static_cast<int>(rasconnstate);
switch (rasconnstate)
{
case RASCS_OpenPort:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_OpenPort = %d\n", _connection_state);
//printf ("Opening port...\n");
break;
case RASCS_PortOpened:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_PortOpened = %d\n", _connection_state);
//printf ("Port opened.\n");
break;
case RASCS_ConnectDevice:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_ConnectDevice = %d\n", _connection_state);
//printf ("Connecting device...\n");
break;
case RASCS_DeviceConnected:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_DeviceConnected = %d\n", _connection_state);
//printf ("Device connected.\n");
break;
case RASCS_AllDevicesConnected:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_AllDevicesConnected = %d\n", _connection_state);
//printf ("All devices connected.\n");
break;
case RASCS_Authenticate:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_Authenticate = %d\n", _connection_state);
// printf ("Authenticating...\n");
break;
case RASCS_AuthNotify:
qDebug()<<__FUNCTION__ << __LINE__;
if (dwError != 0) {
qDebug() << "have error" << dwError;
setConnectionState(Disconnected);
} else {
qDebug() << "RASCS_AuthNotify but no error" << dwError;
}
//printf ("RASCS_AuthNotify = %d\n", _connection_state);
// printf ("Authentication notify.\n");
break;
case RASCS_AuthRetry:
qDebug()<<__FUNCTION__ << __LINE__;
setConnectionState(Preparing);
//printf ("RASCS_AuthRetry = %d\n", _connection_state);
//printf ("Retrying authentication...\n");
break;
case RASCS_AuthCallback:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_AuthCallback = %d\n", _connection_state);
//printf ("Authentication callback...\n");
break;
case RASCS_AuthChangePassword:
qDebug()<<__FUNCTION__ << __LINE__;
// printf ("RASCS_AuthChangePassword = %d\n", _connection_state);
//printf ("Change password...\n");
break;
case RASCS_AuthProject:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_AuthProject = %d\n", _connection_state);
//printf ("Projection phase started...\n");
break;
case RASCS_AuthLinkSpeed:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_AuthLinkSpeed = %d\n", _connection_state);
//printf ("Negoting speed...\n");
break;
case RASCS_AuthAck:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_AuthAck = %d\n", _connection_state);
//printf ("Authentication acknowledge...\n");
break;
case RASCS_ReAuthenticate:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_ReAuthenticate = %d\n", _connection_state);
//printf ("Retrying Authentication...\n");
break;
case RASCS_Authenticated:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_Authenticated = %d\n", _connection_state);
//printf ("Authentication complete.\n");
break;
case RASCS_PrepareForCallback:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_PrepareForCallback = %d\n", _connection_state);
//printf ("Preparing for callback...\n");
break;
case RASCS_WaitForModemReset:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_WaitForModemReset = %d\n", _connection_state);
// printf ("Waiting for modem reset...\n");
break;
case RASCS_WaitForCallback:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_WaitForCallback = %d\n", _connection_state);
//printf ("Waiting for callback...\n");
break;
case RASCS_Projected:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_Projected = %d\n", _connection_state);
//printf ("Projection completed.\n");
break;
#if (WINVER >= 0x400)
case RASCS_StartAuthentication: // Windows 95 only
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_StartAuthentication = %d\n", _connection_state);
//printf ("Starting authentication...\n");
break;
case RASCS_CallbackComplete: // Windows 95 only
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_CallbackComplete = %d\n", rasconnstate);
//printf ("Callback complete.\n");
break;
case RASCS_LogonNetwork: // Windows 95 only
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_LogonNetwork = %d\n", _connection_state);
//printf ("Login to the network.\n");
break;
#endif
case RASCS_SubEntryConnected:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_SubEntryConnected = %d\n", _connection_state);
//printf ("Subentry connected.\n");
break;
case RASCS_SubEntryDisconnected:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_SubEntryDisconnected = %d\n", _connection_state);
//printf ("Subentry disconnected.\n");
break;
//PAUSED STATES:
case RASCS_Interactive:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_Interactive = %d\n", _connection_state);
//printf ("In Paused state: Interactive mode.\n");
break;
case RASCS_RetryAuthentication:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_RetryAuthentication = %d\n", _connection_state);
//printf ("In Paused state: Retry Authentication...\n");
break;
case RASCS_CallbackSetByCaller:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_CallbackSetByCaller = %d\n", _connection_state);
//printf ("In Paused state: Callback set by Caller.\n");
break;
case RASCS_PasswordExpired:
setConnectionState(Error);
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_PasswordExpired = %d\n", _connection_state);
//printf ("In Paused state: Password has expired...\n");
break;
case RASCS_Connected: // = RASCS_DONE:
setConnectionState(Connected);
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_Connected = %d\n", _connection_state);
//printf ("Connection completed.\n");
//SetEvent(gEvent_handle);
break;
case RASCS_Disconnected:
setConnectionState(Disconnected);
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("RASCS_Disconnected = %d\n", _connection_state);
//printf ("Disconnecting...\n");
break;
default:
qDebug()<<__FUNCTION__ << __LINE__;
//printf ("Unknown Status = %d\n", _connection_state);
//printf ("What are you going to do about it?\n");
break;
}
}
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration) void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
{ {
m_config = configuration.value(ProtocolProps::key_proto_config_data(Protocol::Ikev2)).toObject(); m_config = configuration.value(ProtocolProps::key_proto_config_data(Protocol::Ikev2)).toObject();
@ -57,7 +248,7 @@ ErrorCode Ikev2Protocol::start()
{ {
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()); QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
setConnectionState(ConnectionState::Connecting); setConnectionState(Connecting);
QTemporaryFile certFile; QTemporaryFile certFile;
certFile.setAutoRemove(false); certFile.setAutoRemove(false);
@ -65,7 +256,6 @@ ErrorCode Ikev2Protocol::start()
certFile.write(cert); certFile.write(cert);
certFile.close(); certFile.close();
{ {
auto certInstallProcess = IpcClient::CreatePrivilegedProcess(); auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
@ -87,64 +277,71 @@ ErrorCode Ikev2Protocol::start()
}); });
certInstallProcess->setArguments(arguments); certInstallProcess->setArguments(arguments);
// qDebug() << arguments.join(" "); // qDebug() << arguments.join(" ");
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) { // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) {
// qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error; // qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error;
// }); // });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) { // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) {
// qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState; // qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState;
// }); // });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() { // connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() {
// auto req = certInstallProcess->readAll(); // auto req = certInstallProcess->readAll();
// req.waitForFinished(); // req.waitForFinished();
// qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue(); // qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue();
// }); // });
certInstallProcess->start(); certInstallProcess->start();
} }
// /*
{ {
auto adapterRemoveProcess = new QProcess; // auto adapterRemoveProcess = new QProcess;
adapterRemoveProcess->setProgram("powershell"); // adapterRemoveProcess->setProgram("powershell");
QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName()); // QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName());
adapterRemoveProcess->setNativeArguments(arguments); // adapterRemoveProcess->setNativeArguments(arguments);
adapterRemoveProcess->start(); // adapterRemoveProcess->start();
adapterRemoveProcess->waitForFinished(5000); // adapterRemoveProcess->waitForFinished(5000);
if ( disconnect_vpn()){
qDebug()<<"VPN was disconnected";
}
if ( delete_vpn_connection (tunnelName())){
qDebug()<<"VPN was deleted";
}
} }
{ {
auto adapterInstallProcess = new QProcess; {
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
qDebug() <<"Can't create the VPN connect";
}
}
// auto adapterInstallProcess = new QProcess;
adapterInstallProcess->setProgram("powershell"); // adapterInstallProcess->setProgram("powershell");
QString arguments = QString("-command \"Add-VpnConnection " // QString arguments = QString("-command \"Add-VpnConnection "
"-ServerAddress '%1' " // "-ServerAddress '%1' "
"-Name '%2' " // "-Name '%2' "
"-TunnelType IKEv2 " // "-TunnelType IKEv2 "
"-AuthenticationMethod MachineCertificate " // "-AuthenticationMethod MachineCertificate "
"-EncryptionLevel Required " // "-EncryptionLevel Required "
"-PassThru\"") // "-PassThru\"")
.arg(m_config[config_key::hostName].toString()) // .arg(m_config[config_key::hostName].toString())
.arg(tunnelName()); // .arg(tunnelName());
adapterInstallProcess->setNativeArguments(arguments); // adapterInstallProcess->setNativeArguments(arguments);
// connect(adapterInstallProcess, &QProcess::readyRead, [adapterInstallProcess]() { // adapterInstallProcess->start();
// qDebug().noquote() << "adapterInstallProcess readyRead" << adapterInstallProcess->readAll(); // adapterInstallProcess->waitForFinished(5000);
// });
adapterInstallProcess->start();
adapterInstallProcess->waitForFinished(5000);
} }
{ {
auto adapterConfigProcess = new QProcess; auto adapterConfigProcess = new QProcess;
adapterConfigProcess->setProgram("powershell"); adapterConfigProcess->setProgram("powershell");
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\ " QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
"-ConnectionName '%1'\ " "-ConnectionName '%1' "
"-AuthenticationTransformConstants GCMAES128 " "-AuthenticationTransformConstants GCMAES128 "
"-CipherTransformConstants GCMAES128 " "-CipherTransformConstants GCMAES128 "
"-EncryptionMethod AES256 " "-EncryptionMethod AES256 "
@ -155,64 +352,95 @@ ErrorCode Ikev2Protocol::start()
.arg(tunnelName()); .arg(tunnelName());
adapterConfigProcess->setNativeArguments(arguments); adapterConfigProcess->setNativeArguments(arguments);
// connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() { // connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() {
// qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll(); // qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll();
// }); // });
adapterConfigProcess->start(); adapterConfigProcess->start();
adapterConfigProcess->waitForFinished(5000); adapterConfigProcess->waitForFinished(5000);
} }
//*/
{ {
// char buf[RASBUFFER]= {0}; if (!connect_to_vpn(tunnelName())) {
// DWORD err = 0; qDebug()<<"We can't connect to VPN";
// RASDIALPARAMSA *param = (RASDIALPARAMSA *)buf;
// param->dwSize = 1064;
// strcpy(param->szEntryName, tunnelName().toStdString().c_str());
// err = RasDialA(NULL, NULL, param, 0, (LPVOID)rasCallback, &g_h);
// qDebug() << "Ikev2Protocol::start() ret" << err;
auto connectProcess = new QProcess;
connectProcess->setProgram("rasdial");
QString arguments = QString("\"%1\"")
.arg(tunnelName());
connectProcess->setNativeArguments(arguments);
connect(connectProcess, &QProcess::readyRead, [connectProcess]() {
qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll();
});
connectProcess->start();
connectProcess->waitForFinished(5000);
} }
}
setConnectionState(Connected); //setConnectionState(Connecting);
return ErrorCode::NoError;
#else
return ErrorCode::NoError; return ErrorCode::NoError;
#endif #endif
return ErrorCode::NoError;
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err) bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
{ const QString & serv_addr){
if(err != 0) {
printf("Error: %d\n", err); if ( RasValidateEntryName(nullptr, vpn_name.toStdWString().c_str()) != ERROR_SUCCESS)
fflush(stdout); return false;
//g_done = 1; DWORD size = 0;
return 0; // stop the connection. ::RasGetEntryProperties(nullptr, L"", nullptr, &size, nullptr, nullptr);
} else { LPRASENTRY pras = static_cast<LPRASENTRY>(malloc(size));
//printf("%s\n", rasState(rascs)); memset(pras, 0, size);
fflush(stdout); pras->dwSize = size;
if(rascs == RASCS_Connected) { pras->dwType = RASET_Vpn;
printf("Success: Connected\n"); pras->dwRedialCount = 1;
fflush(stdout); pras->dwRedialPause = 60;
//g_done = 1; pras->dwfNetProtocols = RASNP_Ip|RASNP_Ipv6;
pras->dwEncryptionType = ET_RequireMax;
wcscpy_s(pras->szLocalPhoneNumber, serv_addr.toStdWString().c_str());
wcscpy_s(pras->szDeviceType, RASDT_Vpn);
pras->dwfOptions = RASEO_RemoteDefaultGateway;
pras->dwfOptions |= RASEO_RequireDataEncryption;
pras->dwfOptions2 |= RASEO2_RequireMachineCertificates;
pras->dwVpnStrategy = VS_Ikev2Only;
const auto nRet = ::RasSetEntryProperties(nullptr, vpn_name.toStdWString().c_str(), pras, pras->dwSize, NULL, 0);
free(pras);
if (nRet == ERROR_SUCCESS)
return true;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name){
if ( RasDeleteEntry(nullptr, vpn_name.toStdWString().c_str()) == ERROR_SUCCESS){
return true;
} }
return 1; return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
RASDIALPARAMS RasDialParams;
memset(&RasDialParams, 0x0, sizeof(RASDIALPARAMS));
RasDialParams.dwSize = sizeof(RASDIALPARAMS);
wcscpy_s(RasDialParams.szEntryName, vpn_name.toStdWString().c_str());
auto ret = RasDial(NULL, NULL, &RasDialParams, 0,
&RasDialFuncCallback,
&hRasConn);
if (ret == ERROR_SUCCESS){
return true;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Ikev2Protocol::disconnect_vpn(){
if ( hRasConn != nullptr ){
if ( RasHangUp(hRasConn) != ERROR_SUCCESS)
return false;
}
QThread::msleep(3000);
return true;
}
void WINAPI RasDialFuncCallback(UINT unMsg,
RASCONNSTATE rasconnstate,
DWORD dwError ){
std::lock_guard<std::mutex> guard(rasDialFuncMutex);
if (self) {
self->newConnectionStateEventReceived(unMsg, rasconnstate, dwError);
} }
} }
#endif #endif

View file

@ -11,20 +11,26 @@
#include "core/ipcclient.h" #include "core/ipcclient.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <stdio.h> #include <string>
#include <stdlib.h> #include <memory>
#include <string.h> #include <atomic>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <stdio.h>
#include <windows.h> #include <windows.h>
#include <ras.h> #include <Ras.h>
#include <raserror.h> #include <raserror.h>
#include <shlwapi.h> #include <shlwapi.h>
#include <wincrypt.h>
#pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "rasapi32.lib") #pragma comment(lib, "rasapi32.lib")
#pragma comment(lib, "Crypt32.lib")
#define RASBUFFER 0x1000
#define RASMAXENUM 0x100
#endif #endif
class Ikev2Protocol : public VpnProtocol class Ikev2Protocol : public VpnProtocol
@ -40,17 +46,32 @@ public:
static QString tunnelName() { return "AmneziaVPN IKEv2"; } static QString tunnelName() { return "AmneziaVPN IKEv2"; }
public:
void newConnectionStateEventReceived(UINT unMsg,
RASCONNSTATE rasconnstate,
DWORD dwError);
private: private:
void readIkev2Configuration(const QJsonObject &configuration); void readIkev2Configuration(const QJsonObject &configuration);
#ifdef Q_OS_WIN
//certificates variables
#endif
private: private:
QJsonObject m_config; QJsonObject m_config;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
HRASCONN g_h; //RAS functions and parametrs
int g_done = 0; HRASCONN hRasConn{nullptr};
bool create_new_vpn(const QString & vpn_name,
const QString & serv_addr);
bool delete_vpn_connection(const QString &vpn_name);
bool connect_to_vpn(const QString & vpn_name);
bool disconnect_vpn();
#endif #endif
}; };
#ifdef Q_OS_WIN #ifdef Q_OS_WIN

View file

@ -73,6 +73,9 @@ QMap<amnezia::Protocol, QString> ProtocolProps::protocolHumanNames()
{Protocol::ShadowSocks, "ShadowSocks"}, {Protocol::ShadowSocks, "ShadowSocks"},
{Protocol::Cloak, "Cloak"}, {Protocol::Cloak, "Cloak"},
{Protocol::WireGuard, "WireGuard"}, {Protocol::WireGuard, "WireGuard"},
{Protocol::Ikev2, "IKEv2"},
{Protocol::L2tp, "L2TP"},
{Protocol::TorWebSite, "Web site in TOR network"}, {Protocol::TorWebSite, "Web site in TOR network"},
{Protocol::Dns, "DNS Service"}, {Protocol::Dns, "DNS Service"},
{Protocol::FileShare, "File Sharing Service"}, {Protocol::FileShare, "File Sharing Service"},

View file

@ -51,7 +51,7 @@ void WireguardProtocol::stop()
m_wireguardStopProcess->setProgram(wireguardExecPath()); m_wireguardStopProcess->setProgram(wireguardExecPath());
QStringList arguments({"/uninstalltunnelservice", serviceName(), }); QStringList arguments({"--remove", configPath()});
m_wireguardStopProcess->setArguments(arguments); m_wireguardStopProcess->setArguments(arguments);
qDebug() << arguments.join(" "); qDebug() << arguments.join(" ");
@ -114,7 +114,7 @@ void WireguardProtocol::updateRouteGateway(QString line)
QString WireguardProtocol::wireguardExecPath() const QString WireguardProtocol::wireguardExecPath() const
{ {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
return Utils::executable("wireguard/wireguard", true); return Utils::executable("wireguard/wireguard-service", true);
#elif defined Q_OS_LINUX #elif defined Q_OS_LINUX
return Utils::usrExecutable("wg"); return Utils::usrExecutable("wg");
#else #else
@ -163,7 +163,7 @@ ErrorCode WireguardProtocol::start()
m_wireguardStartProcess->setProgram(wireguardExecPath()); m_wireguardStartProcess->setProgram(wireguardExecPath());
QStringList arguments({"/installtunnelservice", configPath(), }); QStringList arguments({"--add", configPath()});
m_wireguardStartProcess->setArguments(arguments); m_wireguardStartProcess->setArguments(arguments);
qDebug() << arguments.join(" "); qDebug() << arguments.join(" ");

View file

@ -16,8 +16,6 @@
<file>images/tray/default.png</file> <file>images/tray/default.png</file>
<file>images/tray/error.png</file> <file>images/tray/error.png</file>
<file>images/arrow_left.png</file> <file>images/arrow_left.png</file>
<file>images/connect_button_connected.png</file>
<file>images/connect_button_disconnected.png</file>
<file>fonts/Lato-Black.ttf</file> <file>fonts/Lato-Black.ttf</file>
<file>fonts/Lato-BlackItalic.ttf</file> <file>fonts/Lato-BlackItalic.ttf</file>
<file>fonts/Lato-Bold.ttf</file> <file>fonts/Lato-Bold.ttf</file>
@ -126,5 +124,22 @@
<file>server_scripts/ipsec/Dockerfile</file> <file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/run_container.sh</file> <file>server_scripts/ipsec/run_container.sh</file>
<file>server_scripts/ipsec/start.sh</file> <file>server_scripts/ipsec/start.sh</file>
<file>ui/qml/Pages/Share/PageShareProtoCloak.qml</file>
<file>ui/qml/Pages/Share/PageShareProtocolBase.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoOpenVPN.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoSftp.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoShadowSocks.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoTorWebSite.qml</file>
<file>ui/qml/Controls/TextAreaType.qml</file>
<file>ui/qml/Controls/ContextMenu.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoAmnezia.qml</file>
<file>ui/qml/Controls/ShareConnectionButtonCopyType.qml</file>
<file>ui/qml/Pages/Share/PageShareProtoWireGuard.qml</file>
<file>server_scripts/ipsec/mobileconfig.plist</file>
<file>ui/qml/Pages/Share/PageShareProtoIkev2.qml</file>
<file>server_scripts/ipsec/strongswan.profile</file>
<file>images/animation.gif</file>
<file>images/connected.png</file>
<file>images/disconnected.png</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1 +1 @@
sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER --build-arg SERVER_ARCH=$(uname -m)

View file

@ -120,8 +120,8 @@ proxyarp
lcp-echo-failure 4 lcp-echo-failure 4
lcp-echo-interval 30 lcp-echo-interval 30
connect-delay 5000 connect-delay 5000
ms-dns $PRIMARY_DNS ms-dns $PRIMARY_SERVER_DNS
ms-dns $SECONDARY_DNS ms-dns $SECONDARY_SERVER_DNS
EOF EOF
@ -222,6 +222,8 @@ certutil -z <(head -c 1024 /dev/urandom) \
--extKeyUsage serverAuth \ --extKeyUsage serverAuth \
--extSAN "ip:$SERVER_IP_ADDRESS,dns:$SERVER_IP_ADDRESS" --extSAN "ip:$SERVER_IP_ADDRESS,dns:$SERVER_IP_ADDRESS"
certutil -L -d sql:/etc/ipsec.d -n "IKEv2 VPN CA" -a | grep -v CERTIFICATE > /etc/ipsec.d/ca_cert_base64.p12
cat > /etc/ipsec.d/ikev2.conf <<EOF cat > /etc/ipsec.d/ikev2.conf <<EOF
conn ikev2-cp conn ikev2-cp
left=%defaultroute left=%defaultroute
@ -248,7 +250,7 @@ conn ikev2-cp
ikelifetime=24h ikelifetime=24h
salifetime=24h salifetime=24h
encapsulation=yes encapsulation=yes
modecfgdns=$PRIMARY_DNS,$SECONDARY_DNS modecfgdns=$PRIMARY_SERVER_DNS,$SECONDARY_SERVER_DNS
EOF EOF
ipsec auto --add ikev2-cp ipsec auto --add ikev2-cp

View file

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>IKEv2</key>
<dict>
<key>AuthenticationMethod</key>
<string>Certificate</string>
<key>ChildSecurityAssociationParameters</key>
<dict>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
<key>EncryptionAlgorithm</key>
<string>AES-128-GCM</string>
<key>LifeTimeInMinutes</key>
<integer>1410</integer>
</dict>
<key>DeadPeerDetectionRate</key>
<string>Medium</string>
<key>DisableRedirect</key>
<true/>
<key>EnableCertificateRevocationCheck</key>
<integer>0</integer>
<key>EnablePFS</key>
<integer>0</integer>
<key>IKESecurityAssociationParameters</key>
<dict>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
<key>EncryptionAlgorithm</key>
<string>AES-256</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-256</string>
<key>LifeTimeInMinutes</key>
<integer>1410</integer>
</dict>
<key>LocalIdentifier</key>
<string>$CLIENT_NAME</string>
<key>PayloadCertificateUUID</key>
<string>$UUID1</string>
<key>OnDemandEnabled</key>
<integer>0</integer>
<key>OnDemandRules</key>
<array>
<dict>
<key>Action</key>
<string>Connect</string>
</dict>
</array>
<key>RemoteAddress</key>
<string>$SERVER_ADDR</string>
<key>RemoteIdentifier</key>
<string>$SERVER_ADDR</string>
<key>UseConfigurationAttributeInternalIPSubnet</key>
<integer>0</integer>
</dict>
<key>IPv4</key>
<dict>
<key>OverridePrimary</key>
<integer>1</integer>
</dict>
<key>PayloadDescription</key>
<string>Configures VPN settings</string>
<key>PayloadDisplayName</key>
<string>VPN</string>
<key>PayloadOrganization</key>
<string>IKEv2 VPN</string>
<key>PayloadIdentifier</key>
<string>com.apple.vpn.managed.$(UUID_GEN)</string>
<key>PayloadType</key>
<string>com.apple.vpn.managed</string>
<key>PayloadUUID</key>
<string>$(UUID_GEN)</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>Proxies</key>
<dict>
<key>HTTPEnable</key>
<integer>0</integer>
<key>HTTPSEnable</key>
<integer>0</integer>
</dict>
<key>UserDefinedName</key>
<string>$SERVER_ADDR</string>
<key>VPNType</key>
<string>IKEv2</string>
</dict>
<dict>
<key>PayloadCertificateFileName</key>
<string>$CLIENT_NAME</string>
<key>PayloadContent</key>
<data>
$P12_BASE64
</data>
<key>PayloadDescription</key>
<string>Adds a PKCS#12-formatted certificate</string>
<key>PayloadDisplayName</key>
<string>$CLIENT_NAME</string>
<key>PayloadIdentifier</key>
<string>com.apple.security.pkcs12.$(UUID_GEN)</string>
<key>PayloadType</key>
<string>com.apple.security.pkcs12</string>
<key>PayloadUUID</key>
<string>$UUID1</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
<dict>
<key>PayloadContent</key>
<data>
$CA_BASE64
</data>
<key>PayloadCertificateFileName</key>
<string>ikev2vpnca</string>
<key>PayloadDescription</key>
<string>Adds a CA root certificate</string>
<key>PayloadDisplayName</key>
<string>Certificate Authority (CA)</string>
<key>PayloadIdentifier</key>
<string>com.apple.security.root.$(UUID_GEN)</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadUUID</key>
<string>$(UUID_GEN)</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>IKEv2 VPN ($SERVER_ADDR)</string>
<key>PayloadIdentifier</key>
<string>com.apple.vpn.managed.$(UUID_GEN)</string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>$(UUID_GEN)</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>

View file

@ -0,0 +1,14 @@
{
"uuid": "$UUID",
"name": "IKEv2 VPN ($SERVER_ADDR)",
"type": "ikev2-cert",
"remote": {
"addr": "$SERVER_ADDR"
},
"local": {
"p12": "$P12_BASE64",
"rsa-pss": "true"
},
"ike-proposal": "aes256-sha256-modp2048",
"esp-proposal": "aes128gcm16"
}

View file

@ -1,7 +1,9 @@
FROM alpine:latest FROM alpine:latest
LABEL maintainer="AmneziaVPN" LABEL maintainer="AmneziaVPN"
ARG SS_RELEASE="v1.11.2"
ARG SERVER_ARCH
#Install required packages #Install required packages
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools xz RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools xz
RUN apk --update upgrade --no-cache RUN apk --update upgrade --no-cache
@ -13,9 +15,9 @@ RUN mkdir -p /opt/amnezia
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
RUN chmod a+x /opt/amnezia/start.sh RUN chmod a+x /opt/amnezia/start.sh
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.10.9/shadowsocks-v1.10.9.x86_64-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/${SS_RELEASE}/shadowsocks-${SS_RELEASE}.${SERVER_ARCH}-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz;\
RUN tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/ tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/;\
RUN chmod a+x /usr/bin/ssserver chmod a+x /usr/bin/ssserver;
# Tune network # Tune network
RUN echo -e " \n\ RUN echo -e " \n\

View file

@ -1,3 +1,6 @@
# Run container # Run container
sudo docker stop amnezia-tor
sudo docker rm amnezia-tor
sudo docker run -d -p 80:80 --restart always --name $CONTAINER_NAME tutum/wordpress sudo docker run -d -p 80:80 --restart always --name $CONTAINER_NAME tutum/wordpress
sudo docker run -d --link $CONTAINER_NAME --name amnezia-tor goldy/tor-hidden-service sudo docker run -d --link $CONTAINER_NAME --name amnezia-tor goldy/tor-hidden-service
sudo docker exec -i amnezia-tor apk add bash

View file

@ -24,7 +24,7 @@ QHash<int, QByteArray> ProtocolsModel::roleNames() const {
QVariant ProtocolsModel::data(const QModelIndex &index, int role) const QVariant ProtocolsModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid() || index.row() < 0 if (!index.isValid() || index.row() < 0
|| index.row() >= ContainerProps::allContainers().size()) { || index.row() >= ProtocolProps::allProtocols().size()) {
return QVariant(); return QVariant();
} }

View file

@ -4,6 +4,19 @@
#include <QObject> #include <QObject>
#include <QQmlEngine> #include <QQmlEngine>
class PageType : public QObject
{
Q_GADGET
public:
enum Type {
Basic,
Proto,
ShareProto
};
Q_ENUM(Type)
};
namespace PageEnumNS namespace PageEnumNS
{ {
Q_NAMESPACE Q_NAMESPACE
@ -11,7 +24,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn,
Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress, Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress,
GeneralSettings, AppSettings, NetworkSettings, ServerSettings, GeneralSettings, AppSettings, NetworkSettings, ServerSettings,
ServerContainers, ServersList, ShareConnection, Sites, ServerContainers, ServersList, ShareConnection, Sites,
ProtocolSettings}; ProtocolSettings, ProtocolShare};
Q_ENUM_NS(Page) Q_ENUM_NS(Page)
static void declareQmlPageEnum() { static void declareQmlPageEnum() {

View file

@ -2,6 +2,7 @@
#include "ShareConnectionLogic.h" #include "ShareConnectionLogic.h"
#include "../uilogic.h" #include "../uilogic.h"
#include "../models/protocols_model.h"
GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent): GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent) PageLogicBase(logic, parent)
@ -11,13 +12,18 @@ GeneralSettingsLogic::GeneralSettingsLogic(UiLogic *logic, QObject *parent):
void GeneralSettingsLogic::onUpdatePage() void GeneralSettingsLogic::onUpdatePage()
{ {
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
set_pushButtonGeneralSettingsShareConnectionEnable(m_settings.haveAuthData(m_settings.defaultServerIndex())); set_pushButtonGeneralSettingsShareConnectionEnable(m_settings.haveAuthData(m_settings.defaultServerIndex()));
} }
void GeneralSettingsLogic::onPushButtonGeneralSettingsServerSettingsClicked() void GeneralSettingsLogic::onPushButtonGeneralSettingsServerSettingsClicked()
{ {
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
uiLogic()->goToPage(Page::ServerSettings); uiLogic()->selectedDockerContainer = m_settings.defaultContainer(m_settings.defaultServerIndex());
emit uiLogic()->goToPage(Page::ServerSettings);
} }
void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked() void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked()
@ -25,6 +31,9 @@ void GeneralSettingsLogic::onPushButtonGeneralSettingsShareConnectionClicked()
uiLogic()->selectedServerIndex = m_settings.defaultServerIndex(); uiLogic()->selectedServerIndex = m_settings.defaultServerIndex();
uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex); uiLogic()->selectedDockerContainer = m_settings.defaultContainer(uiLogic()->selectedServerIndex);
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer); qobject_cast<ProtocolsModel *>(uiLogic()->protocolsModel())->setSelectedServerIndex(uiLogic()->selectedServerIndex);
uiLogic()->goToPage(Page::ShareConnection); qobject_cast<ProtocolsModel *>(uiLogic()->protocolsModel())->setSelectedDockerContainer(uiLogic()->selectedDockerContainer);
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
emit uiLogic()->goToPage(Page::ShareConnection);
} }

View file

@ -18,6 +18,11 @@ ServerConfiguringProgressLogic::ServerConfiguringProgressLogic(UiLogic *logic, Q
} }
void ServerConfiguringProgressLogic::onUpdatePage()
{
set_progressBarValue(0);
}
ErrorCode ServerConfiguringProgressLogic::doInstallAction(const std::function<ErrorCode()> &action) ErrorCode ServerConfiguringProgressLogic::doInstallAction(const std::function<ErrorCode()> &action)
{ {

View file

@ -22,6 +22,7 @@ public:
explicit ServerConfiguringProgressLogic(UiLogic *uiLogic, QObject *parent = nullptr); explicit ServerConfiguringProgressLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~ServerConfiguringProgressLogic() = default; ~ServerConfiguringProgressLogic() = default;
void onUpdatePage() override;
ErrorCode doInstallAction(const std::function<ErrorCode()> &action); ErrorCode doInstallAction(const std::function<ErrorCode()> &action);
private: private:

View file

@ -43,12 +43,12 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c,
void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c) void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c)
{ {
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c); m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
onUpdatePage(); uiLogic()->onUpdateAllPages();
} }
void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c) void ServerContainersLogic::onPushButtonShareClicked(DockerContainer c)
{ {
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), c); uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, c);
emit uiLogic()->goToPage(Page::ShareConnection); emit uiLogic()->goToPage(Page::ShareConnection);
} }
@ -64,7 +64,7 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container)
if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None); if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first()); else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first());
} }
onUpdatePage(); uiLogic()->onUpdateAllPages();
} }
void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp) void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp)
@ -85,6 +85,6 @@ void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int p
} }
} }
onUpdatePage(); uiLogic()->onUpdateAllPages();
emit uiLogic()->closePage(); emit uiLogic()->closePage();
} }

View file

@ -14,7 +14,7 @@ ServerListLogic::ServerListLogic(UiLogic *logic, QObject *parent):
void ServerListLogic::onServerListPushbuttonDefaultClicked(int index) void ServerListLogic::onServerListPushbuttonDefaultClicked(int index)
{ {
m_settings.setDefaultServer(index); m_settings.setDefaultServer(index);
onUpdatePage(); uiLogic()->onUpdateAllPages();
} }
void ServerListLogic::onServerListPushbuttonSettingsClicked(int index) void ServerListLogic::onServerListPushbuttonSettingsClicked(int index)

View file

@ -37,7 +37,7 @@ void ServerSettingsLogic::onUpdatePage()
.arg(port)); .arg(port));
set_lineEditDescriptionText(server.value(config_key::description).toString()); set_lineEditDescriptionText(server.value(config_key::description).toString());
QString selectedContainerName = m_settings.defaultContainerName(uiLogic()->selectedServerIndex); QString selectedContainerName = m_settings.defaultContainerName(uiLogic()->selectedServerIndex);
set_labelCurrentVpnProtocolText(tr("Protocol: ") + selectedContainerName); set_labelCurrentVpnProtocolText(tr("Service: ") + selectedContainerName);
} }
void ServerSettingsLogic::onPushButtonClearServer() void ServerSettingsLogic::onPushButtonClearServer()
@ -90,8 +90,7 @@ void ServerSettingsLogic::onPushButtonForgetServer()
uiLogic()->selectedServerIndex = -1; uiLogic()->selectedServerIndex = -1;
uiLogic()->onUpdateAllPages();
uiLogic()->serverListLogic()->onUpdatePage();
if (m_settings.serversCount() == 0) { if (m_settings.serversCount() == 0) {
uiLogic()->setStartPage(Page::Start); uiLogic()->setStartPage(Page::Start);
@ -121,11 +120,11 @@ void ServerSettingsLogic::onLineEditDescriptionEditingFinished()
QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex); QJsonObject server = m_settings.server(uiLogic()->selectedServerIndex);
server.insert(config_key::description, newText); server.insert(config_key::description, newText);
m_settings.editServer(uiLogic()->selectedServerIndex, server); m_settings.editServer(uiLogic()->selectedServerIndex, server);
uiLogic()->serverListLogic()->onUpdatePage(); uiLogic()->onUpdateAllPages();
} }
void ServerSettingsLogic::onPushButtonShareFullClicked() void ServerSettingsLogic::onPushButtonShareFullClicked()
{ {
uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), DockerContainer::None); uiLogic()->shareConnectionLogic()->updateSharingPage(uiLogic()->selectedServerIndex, DockerContainer::None);
uiLogic()->goToPage(Page::ShareConnection); emit uiLogic()->goToShareProtocolPage(Protocol::Any);
} }

View file

@ -5,6 +5,7 @@
#include <QTimer> #include <QTimer>
#include <QSaveFile> #include <QSaveFile>
#include <QStandardPaths> #include <QStandardPaths>
#include <QImage>
#include "ShareConnectionLogic.h" #include "ShareConnectionLogic.h"
@ -12,6 +13,8 @@
#include "configurators/vpn_configurator.h" #include "configurators/vpn_configurator.h"
#include "configurators/openvpn_configurator.h" #include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h" #include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "configurators/ikev2_configurator.h"
#include "configurators/ssh_configurator.h" #include "configurators/ssh_configurator.h"
#include "defines.h" #include "defines.h"
@ -21,125 +24,47 @@
ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent): ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent), PageLogicBase(logic, parent),
m_pageShareAmneziaVisible{true},
m_pageShareOpenVpnVisible{true},
m_pageShareShadowSocksVisible{true},
m_pageShareCloakVisible{true},
m_pageShareFullAccessVisible{true},
m_textEditShareOpenVpnCodeText{}, m_textEditShareOpenVpnCodeText{},
m_pushButtonShareOpenVpnCopyEnabled{false},
m_pushButtonShareOpenVpnSaveEnabled{false},
m_toolBoxShareConnectionCurrentIndex{-1},
m_pushButtonShareShadowSocksCopyEnabled{false},
m_lineEditShareShadowSocksStringText{}, m_lineEditShareShadowSocksStringText{},
m_labelShareShadowSocksQrCodeText{}, m_shareShadowSocksQrCodeText{},
m_labelShareShadowSocksServerText{}, m_textEditShareCloakText{},
m_labelShareShadowSocksPortText{}, m_textEditShareAmneziaCodeText{}
m_labelShareShadowSocksMethodText{},
m_labelShareShadowSocksPasswordText{},
m_plainTextEditShareCloakText{},
m_pushButtonShareCloakCopyEnabled{false},
m_textEditShareFullCodeText{},
m_textEditShareAmneziaCodeText{},
m_pushButtonShareFullCopyText{tr("Copy")},
m_pushButtonShareAmneziaCopyText{tr("Copy")},
m_pushButtonShareOpenVpnCopyText{tr("Copy")},
m_pushButtonShareShadowSocksCopyText{tr("Copy")},
m_pushButtonShareCloakCopyText{tr("Copy")},
m_pushButtonShareAmneziaGenerateEnabled{true},
m_pushButtonShareAmneziaCopyEnabled{true},
m_pushButtonShareAmneziaGenerateText{tr("Generate config")},
m_pushButtonShareOpenVpnGenerateEnabled{true},
m_pushButtonShareOpenVpnGenerateText{tr("Generate config")}
{ {
// TODO consider move to Component.onCompleted
updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer);
} }
void ShareConnectionLogic::onUpdatePage()
void ShareConnectionLogic::onPushButtonShareFullCopyClicked()
{ {
QGuiApplication::clipboard()->setText(textEditShareFullCodeText()); set_textEditShareAmneziaCodeText(tr(""));
set_pushButtonShareFullCopyText(tr("Copied")); set_shareAmneziaQrCodeText("");
QTimer::singleShot(3000, this, [this]() { set_textEditShareOpenVpnCodeText("");
set_pushButtonShareFullCopyText(tr("Copy"));
});
}
void ShareConnectionLogic::onPushButtonShareFullSaveClicked() set_shareShadowSocksQrCodeText("");
{ set_textEditShareShadowSocksText("");
if (textEditShareFullCodeText().isEmpty()) return; set_lineEditShareShadowSocksStringText("");
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save AmneziaVPN config"), set_textEditShareCloakText("");
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia");
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(textEditShareFullCodeText().toUtf8());
save.commit();
}
void ShareConnectionLogic::onPushButtonShareAmneziaCopyClicked() set_textEditShareWireGuardCodeText("");
{ set_shareWireGuardQrCodeText("");
if (textEditShareAmneziaCodeText().isEmpty()) return;
QGuiApplication::clipboard()->setText(textEditShareAmneziaCodeText()); set_textEditShareIkev2CertText("");
set_pushButtonShareAmneziaCopyText(tr("Copied")); set_textEditShareIkev2MobileConfigText("");
set_textEditShareIkev2StrongSwanConfigText("");
QTimer::singleShot(3000, this, [this]() {
set_pushButtonShareAmneziaCopyText(tr("Copy"));
});
}
void ShareConnectionLogic::onPushButtonShareAmneziaSaveClicked()
{
if (textEditShareAmneziaCodeText().isEmpty()) return;
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save AmneziaVPN config"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia");
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(textEditShareAmneziaCodeText().toUtf8());
save.commit();
}
void ShareConnectionLogic::onPushButtonShareOpenVpnCopyClicked()
{
QGuiApplication::clipboard()->setText(textEditShareOpenVpnCodeText());
set_pushButtonShareOpenVpnCopyText(tr("Copied"));
QTimer::singleShot(3000, this, [this]() {
set_pushButtonShareOpenVpnCopyText(tr("Copy"));
});
}
void ShareConnectionLogic::onPushButtonShareShadowSocksCopyClicked()
{
QGuiApplication::clipboard()->setText(lineEditShareShadowSocksStringText());
set_pushButtonShareShadowSocksCopyText(tr("Copied"));
QTimer::singleShot(3000, this, [this]() {
set_pushButtonShareShadowSocksCopyText(tr("Copy"));
});
}
void ShareConnectionLogic::onPushButtonShareCloakCopyClicked()
{
QGuiApplication::clipboard()->setText(plainTextEditShareCloakText());
set_pushButtonShareCloakCopyText(tr("Copied"));
QTimer::singleShot(3000, this, [this]() {
set_pushButtonShareCloakCopyText(tr("Copy"));
});
} }
void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked() void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
{ {
set_pushButtonShareAmneziaGenerateEnabled(false); set_textEditShareAmneziaCodeText("");
set_pushButtonShareAmneziaCopyEnabled(false); set_shareAmneziaQrCodeText("");
set_pushButtonShareAmneziaGenerateText(tr("Generating..."));
qApp->processEvents();
QJsonObject serverConfig;
// Full access
if (shareFullAccess()) {
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
}
// Container share
else {
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex); ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
@ -154,104 +79,52 @@ void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
break; break;
} }
protoConfig.insert(config_key::last_config, cfg); protoConfig.insert(config_key::last_config, cfg);
containerConfig.insert(ProtocolProps::protoToString(p), protoConfig); containerConfig.insert(ProtocolProps::protoToString(p), protoConfig);
} }
QByteArray ba; QByteArray ba;
if (!e) { if (!e) {
QJsonObject serverConfig = m_settings.server(uiLogic()->selectedServerIndex); serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig.remove(config_key::userName); serverConfig.remove(config_key::userName);
serverConfig.remove(config_key::password); serverConfig.remove(config_key::password);
serverConfig.remove(config_key::port); serverConfig.remove(config_key::port);
serverConfig.insert(config_key::containers, QJsonArray {containerConfig}); serverConfig.insert(config_key::containers, QJsonArray {containerConfig});
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer)); serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
ba = QJsonDocument(serverConfig).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
set_textEditShareAmneziaCodeText(QString("vpn://%1").arg(QString(ba)));
} }
else { else {
set_textEditShareAmneziaCodeText(tr("Error while generating connection profile")); set_textEditShareAmneziaCodeText(tr("Error while generating connection profile"));
return;
}
} }
set_pushButtonShareAmneziaGenerateEnabled(true); QByteArray ba = QJsonDocument(serverConfig).toBinaryData();
set_pushButtonShareAmneziaCopyEnabled(true); ba = qCompress(ba, 8);
set_pushButtonShareAmneziaGenerateText(tr("Generate config")); QString code = QString("vpn://%1").arg(QString(ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
set_textEditShareAmneziaCodeText(code);
if (ba.size() < 2900) {
QImage qr = updateQRCodeImage(ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
set_shareAmneziaQrCodeText(imageToBase64(qr));
}
} }
void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked() void ShareConnectionLogic::onPushButtonShareOpenVpnGenerateClicked()
{ {
set_pushButtonShareOpenVpnGenerateEnabled(false);
set_pushButtonShareOpenVpnCopyEnabled(false);
set_pushButtonShareOpenVpnSaveEnabled(false);
set_pushButtonShareOpenVpnGenerateText(tr("Generating..."));
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex); ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer); const QJsonObject &containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
ErrorCode e = ErrorCode::NoError; ErrorCode e = ErrorCode::NoError;
QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, &e); QString cfg = OpenVpnConfigurator::genOpenVpnConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, &e);
cfg = OpenVpnConfigurator::processConfigWithExportSettings(cfg); cfg = VpnConfigurator::processConfigWithExportSettings(uiLogic()->selectedDockerContainer, Protocol::OpenVpn, cfg);
set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString()); set_textEditShareOpenVpnCodeText(QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString());
set_pushButtonShareOpenVpnGenerateEnabled(true);
set_pushButtonShareOpenVpnCopyEnabled(true);
set_pushButtonShareOpenVpnSaveEnabled(true);
set_pushButtonShareOpenVpnGenerateText(tr("Generate config"));
} }
void ShareConnectionLogic::onPushButtonShareOpenVpnSaveClicked() void ShareConnectionLogic::onPushButtonShareShadowSocksGenerateClicked()
{ {
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save OpenVPN config"), int serverIndex = uiLogic()->selectedServerIndex;
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.ovpn"); DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(textEditShareOpenVpnCodeText().toUtf8());
save.commit();
}
void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCredentials &credentials,
DockerContainer container)
{
uiLogic()->selectedDockerContainer = container;
uiLogic()->selectedServerIndex = serverIndex;
//const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
set_pageShareAmneziaVisible(false);
set_pageShareOpenVpnVisible(false);
set_pageShareShadowSocksVisible(false);
set_pageShareCloakVisible(false);
set_pageShareFullAccessVisible(false);
enum currentWidget {
full_access = 0,
share_amezia,
share_openvpn,
share_shadowshock,
share_cloak
};
if (container == DockerContainer::OpenVpn) {
set_pageShareAmneziaVisible(true);
set_pageShareOpenVpnVisible(true);
QString cfg = tr("Press Generate config");
set_textEditShareOpenVpnCodeText(cfg);
set_pushButtonShareOpenVpnCopyEnabled(false);
set_pushButtonShareOpenVpnSaveEnabled(false);
set_toolBoxShareConnectionCurrentIndex(share_openvpn);
}
if (container == DockerContainer::ShadowSocks ||
container == DockerContainer::Cloak) {
set_pageShareAmneziaVisible(true);
set_pageShareShadowSocksVisible(true);
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks); QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks);
QString cfg = protoConfig.value(config_key::last_config).toString(); QString cfg = protoConfig.value(config_key::last_config).toString();
@ -261,8 +134,6 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden
ErrorCode e = ErrorCode::NoError; ErrorCode e = ErrorCode::NoError;
cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e); cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e);
set_pushButtonShareShadowSocksCopyEnabled(true);
} }
QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
@ -275,22 +146,27 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden
ssString = "ss://" + ssString.toUtf8().toBase64(); ssString = "ss://" + ssString.toUtf8().toBase64();
set_lineEditShareShadowSocksStringText(ssString); set_lineEditShareShadowSocksStringText(ssString);
updateQRCodeImage(ssString, [this](const QString& labelText) ->void {
set_labelShareShadowSocksQrCodeText(labelText);
});
set_labelShareShadowSocksServerText(ssConfig.value("server").toString()); QImage qr = updateQRCodeImage(ssString.toUtf8());
set_labelShareShadowSocksPortText(ssConfig.value("server_port").toString()); set_shareShadowSocksQrCodeText(imageToBase64(qr));
set_labelShareShadowSocksMethodText(ssConfig.value("method").toString());
set_labelShareShadowSocksPasswordText(ssConfig.value("password").toString());
set_toolBoxShareConnectionCurrentIndex(share_shadowshock); QString humanString = QString("Server: %3\n"
} "Port: %4\n"
"Encryption: %1\n"
"Password: %2")
.arg(ssConfig.value("method").toString())
.arg(ssConfig.value("password").toString())
.arg(ssConfig.value("server").toString())
.arg(ssConfig.value("server_port").toString());
if (container == DockerContainer::Cloak) { set_textEditShareShadowSocksText(humanString);
//ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); }
set_pageShareCloakVisible(true);
set_plainTextEditShareCloakText(QString("")); void ShareConnectionLogic::onPushButtonShareCloakGenerateClicked()
{
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak); QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak);
QString cfg = protoConfig.value(config_key::last_config).toString(); QString cfg = protoConfig.value(config_key::last_config).toString();
@ -300,54 +176,74 @@ void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCreden
ErrorCode e = ErrorCode::NoError; ErrorCode e = ErrorCode::NoError;
cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e); cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e);
set_pushButtonShareCloakCopyEnabled(true);
} }
QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object(); QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
cloakConfig.remove(config_key::transport_proto); cloakConfig.remove(config_key::transport_proto);
cloakConfig.insert("ProxyMethod", "shadowsocks"); cloakConfig.insert("ProxyMethod", "shadowsocks");
set_plainTextEditShareCloakText(QJsonDocument(cloakConfig).toJson()); set_textEditShareCloakText(QJsonDocument(cloakConfig).toJson());
} }
// Full access void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked()
if (container == DockerContainer::None) { {
set_pageShareFullAccessVisible(true); int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex); const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
QByteArray ba = QJsonDocument(server).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); ErrorCode e = ErrorCode::NoError;
QString cfg = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, &e);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Protocol::WireGuard, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::config].toString();
set_textEditShareFullCodeText(QString("vpn://%1").arg(QString(ba))); set_textEditShareWireGuardCodeText(cfg);
set_toolBoxShareConnectionCurrentIndex(full_access);
}
//ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client")); QImage qr = updateQRCodeImage(cfg.toUtf8());
set_shareWireGuardQrCodeText(imageToBase64(qr));
}
// Amnezia sharing void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked()
// QJsonObject exportContainer; {
// for (Protocol p: protocolsForContainer(container)) { int serverIndex = uiLogic()->selectedServerIndex;
// QJsonObject protocolConfig = containerConfig.value(ProtocolProps::protoToString(p)).toObject(); DockerContainer container = uiLogic()->selectedDockerContainer;
// protocolConfig.remove(config_key::last_config); ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
// exportContainer.insert(ProtocolProps::protoToString(p), protocolConfig);
// }
// exportContainer.insert(config_key::container, containerToString(container));
// ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson()); //const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container);
QString cfg = Ikev2Configurator::genIkev2Config(connData);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Protocol::Ikev2, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString();
set_textEditShareIkev2CertText(cfg);
QString mobileCfg = Ikev2Configurator::genMobileConfig(connData);
set_textEditShareIkev2MobileConfigText(mobileCfg);
QString strongSwanCfg = Ikev2Configurator::genStrongSwanConfig(connData);
set_textEditShareIkev2StrongSwanConfigText(strongSwanCfg);
set_textEditShareAmneziaCodeText(tr(""));
} }
void ShareConnectionLogic::updateQRCodeImage(const QString &text, const std::function<void(const QString&)>& set_labelFunc) void ShareConnectionLogic::updateSharingPage(int serverIndex, DockerContainer container)
{
uiLogic()->selectedDockerContainer = container;
uiLogic()->selectedServerIndex = serverIndex;
set_shareFullAccess(container == DockerContainer::None);
}
QImage ShareConnectionLogic::updateQRCodeImage(const QByteArray &data)
{ {
int levelIndex = 1; int levelIndex = 1;
int versionIndex = 0; int versionIndex = 0;
bool bExtent = true; bool bExtent = true;
int maskIndex = -1; int maskIndex = -1;
m_qrEncode.EncodeData( levelIndex, versionIndex, bExtent, maskIndex, text.toUtf8().data() ); m_qrEncode.EncodeData( levelIndex, versionIndex, bExtent, maskIndex, data.data() );
int qrImageSize = m_qrEncode.m_nSymbleSize; int qrImageSize = m_qrEncode.m_nSymbleSize;
@ -361,10 +257,14 @@ void ShareConnectionLogic::updateQRCodeImage(const QString &text, const std::fun
if ( m_qrEncode.m_byModuleData[i][j] ) if ( m_qrEncode.m_byModuleData[i][j] )
encodeImage.setPixel( i + QR_MARGIN, j + QR_MARGIN, 0 ); encodeImage.setPixel( i + QR_MARGIN, j + QR_MARGIN, 0 );
QByteArray byteArray; return encodeImage;
QBuffer buffer(&byteArray); }
encodeImage.save(&buffer, "PNG"); // writes the image in PNG format inside the buffer
QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data()); QString ShareConnectionLogic::imageToBase64(const QImage &image)
{
set_labelFunc(iconBase64); QByteArray ba;
QBuffer bu(&ba);
bu.open(QIODevice::WriteOnly);
image.save(&bu, "PNG");
return "data:image/png;base64," + QString::fromLatin1(ba.toBase64().data());
} }

View file

@ -11,56 +11,43 @@ class ShareConnectionLogic: public PageLogicBase
Q_OBJECT Q_OBJECT
public: public:
AUTO_PROPERTY(bool, pageShareAmneziaVisible) AUTO_PROPERTY(bool, shareFullAccess)
AUTO_PROPERTY(bool, pageShareOpenVpnVisible)
AUTO_PROPERTY(bool, pageShareShadowSocksVisible)
AUTO_PROPERTY(bool, pageShareCloakVisible)
AUTO_PROPERTY(bool, pageShareFullAccessVisible)
AUTO_PROPERTY(QString, textEditShareOpenVpnCodeText)
AUTO_PROPERTY(bool, pushButtonShareOpenVpnCopyEnabled)
AUTO_PROPERTY(bool, pushButtonShareOpenVpnSaveEnabled)
AUTO_PROPERTY(int, toolBoxShareConnectionCurrentIndex)
AUTO_PROPERTY(bool, pushButtonShareShadowSocksCopyEnabled)
AUTO_PROPERTY(QString, lineEditShareShadowSocksStringText)
AUTO_PROPERTY(QString, labelShareShadowSocksQrCodeText)
AUTO_PROPERTY(QString, labelShareShadowSocksServerText)
AUTO_PROPERTY(QString, labelShareShadowSocksPortText)
AUTO_PROPERTY(QString, labelShareShadowSocksMethodText)
AUTO_PROPERTY(QString, labelShareShadowSocksPasswordText)
AUTO_PROPERTY(QString, plainTextEditShareCloakText)
AUTO_PROPERTY(bool, pushButtonShareCloakCopyEnabled)
AUTO_PROPERTY(QString, textEditShareFullCodeText)
AUTO_PROPERTY(QString, textEditShareAmneziaCodeText) AUTO_PROPERTY(QString, textEditShareAmneziaCodeText)
AUTO_PROPERTY(QString, pushButtonShareFullCopyText) AUTO_PROPERTY(QString, shareAmneziaQrCodeText)
AUTO_PROPERTY(QString, pushButtonShareAmneziaCopyText)
AUTO_PROPERTY(QString, pushButtonShareOpenVpnCopyText) AUTO_PROPERTY(QString, textEditShareOpenVpnCodeText)
AUTO_PROPERTY(QString, pushButtonShareShadowSocksCopyText)
AUTO_PROPERTY(QString, pushButtonShareCloakCopyText) AUTO_PROPERTY(QString, textEditShareShadowSocksText)
AUTO_PROPERTY(bool, pushButtonShareAmneziaGenerateEnabled) AUTO_PROPERTY(QString, lineEditShareShadowSocksStringText)
AUTO_PROPERTY(bool, pushButtonShareAmneziaCopyEnabled) AUTO_PROPERTY(QString, shareShadowSocksQrCodeText)
AUTO_PROPERTY(QString, pushButtonShareAmneziaGenerateText)
AUTO_PROPERTY(bool, pushButtonShareOpenVpnGenerateEnabled) AUTO_PROPERTY(QString, textEditShareCloakText)
AUTO_PROPERTY(QString, pushButtonShareOpenVpnGenerateText)
AUTO_PROPERTY(QString, textEditShareWireGuardCodeText)
AUTO_PROPERTY(QString, shareWireGuardQrCodeText)
AUTO_PROPERTY(QString, textEditShareIkev2CertText)
AUTO_PROPERTY(QString, textEditShareIkev2MobileConfigText)
AUTO_PROPERTY(QString, textEditShareIkev2StrongSwanConfigText)
public: public:
Q_INVOKABLE void onPushButtonShareFullCopyClicked();
Q_INVOKABLE void onPushButtonShareFullSaveClicked();
Q_INVOKABLE void onPushButtonShareAmneziaCopyClicked();
Q_INVOKABLE void onPushButtonShareAmneziaSaveClicked();
Q_INVOKABLE void onPushButtonShareOpenVpnCopyClicked();
Q_INVOKABLE void onPushButtonShareShadowSocksCopyClicked();
Q_INVOKABLE void onPushButtonShareCloakCopyClicked();
Q_INVOKABLE void onPushButtonShareAmneziaGenerateClicked(); Q_INVOKABLE void onPushButtonShareAmneziaGenerateClicked();
Q_INVOKABLE void onPushButtonShareOpenVpnGenerateClicked(); Q_INVOKABLE void onPushButtonShareOpenVpnGenerateClicked();
Q_INVOKABLE void onPushButtonShareOpenVpnSaveClicked(); Q_INVOKABLE void onPushButtonShareShadowSocksGenerateClicked();
Q_INVOKABLE void onPushButtonShareCloakGenerateClicked();
Q_INVOKABLE void onPushButtonShareWireGuardGenerateClicked();
Q_INVOKABLE void onPushButtonShareIkev2GenerateClicked();
Q_INVOKABLE virtual void onUpdatePage() override;
public: public:
explicit ShareConnectionLogic(UiLogic *uiLogic, QObject *parent = nullptr); explicit ShareConnectionLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~ShareConnectionLogic() = default; ~ShareConnectionLogic() = default;
void updateSharingPage(int serverIndex, const ServerCredentials &credentials, void updateSharingPage(int serverIndex, DockerContainer container);
DockerContainer container); QImage updateQRCodeImage(const QByteArray &data);
void updateQRCodeImage(const QString &text, const std::function<void(const QString&)>& setLabelFunc); QString imageToBase64(const QImage &image);
private: private:
CQR_Encode m_qrEncode; CQR_Encode m_qrEncode;

View file

@ -22,7 +22,7 @@ SitesLogic::SitesLogic(UiLogic *logic, QObject *parent):
sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites)); sitesModels.insert(Settings::VpnAllExceptSites, new SitesModel(Settings::VpnAllExceptSites));
} }
void SitesLogic::updateSitesPage() void SitesLogic::onUpdatePage()
{ {
Settings::RouteMode m = m_settings.routeMode(); Settings::RouteMode m = m_settings.routeMode();
if (m == Settings::VpnAllSites) return; if (m == Settings::VpnAllSites) return;
@ -71,7 +71,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
uiLogic()->m_vpnConnection->flushDns(); uiLogic()->m_vpnConnection->flushDns();
} }
updateSitesPage(); onUpdatePage();
}; };
const auto &cbResolv = [this, cbProcess](const QHostInfo &hostInfo){ const auto &cbResolv = [this, cbProcess](const QHostInfo &hostInfo){
@ -93,7 +93,7 @@ void SitesLogic::onPushButtonAddCustomSitesClicked()
} }
else { else {
cbProcess(newSite, ""); cbProcess(newSite, "");
updateSitesPage(); onUpdatePage();
QHostInfo::lookupHost(newSite, this, cbResolv); QHostInfo::lookupHost(newSite, this, cbResolv);
} }
} }
@ -123,7 +123,7 @@ void SitesLogic::onPushButtonSitesDeleteClicked(int row)
uiLogic()->m_vpnConnection->flushDns(); uiLogic()->m_vpnConnection->flushDns();
} }
updateSitesPage(); onUpdatePage();
} }
void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName) void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
@ -153,6 +153,6 @@ void SitesLogic::onPushButtonSitesImportClicked(const QString& fileName)
uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips); uiLogic()->m_vpnConnection->addRoutes(QStringList() << ips);
uiLogic()->m_vpnConnection->flushDns(); uiLogic()->m_vpnConnection->flushDns();
updateSitesPage(); onUpdatePage();
} }

View file

@ -15,7 +15,7 @@ class SitesLogic : public PageLogicBase
AUTO_PROPERTY(QString, lineEditSitesAddCustomText) AUTO_PROPERTY(QString, lineEditSitesAddCustomText)
public: public:
Q_INVOKABLE void updateSitesPage(); Q_INVOKABLE void onUpdatePage() override;
Q_INVOKABLE void onPushButtonAddCustomSitesClicked(); Q_INVOKABLE void onPushButtonAddCustomSitesClicked();
Q_INVOKABLE void onPushButtonSitesDeleteClicked(int row); Q_INVOKABLE void onPushButtonSitesDeleteClicked(int row);

View file

@ -35,6 +35,8 @@ void StartPageLogic::onUpdatePage()
set_pushButtonConnectVisible(true); set_pushButtonConnectVisible(true);
set_pushButtonConnectKeyChecked(false); set_pushButtonConnectKeyChecked(false);
set_pushButtonBackFromStartVisible(uiLogic()->pagesStackDepth() > 0);
} }
void StartPageLogic::onPushButtonConnect() void StartPageLogic::onPushButtonConnect()

View file

@ -24,6 +24,9 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
connect(uiLogic()->m_vpnConnection, &VpnConnection::connectionStateChanged, this, &VpnLogic::onConnectionStateChanged); connect(uiLogic()->m_vpnConnection, &VpnConnection::connectionStateChanged, this, &VpnLogic::onConnectionStateChanged);
connect(uiLogic()->m_vpnConnection, &VpnConnection::vpnProtocolError, this, &VpnLogic::onVpnProtocolError); connect(uiLogic()->m_vpnConnection, &VpnConnection::vpnProtocolError, this, &VpnLogic::onVpnProtocolError);
connect(this, &VpnLogic::connectToVpn, uiLogic()->m_vpnConnection, &VpnConnection::connectToVpn, Qt::QueuedConnection);
connect(this, &VpnLogic::disconnectFromVpn, uiLogic()->m_vpnConnection, &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) { if (m_settings.isAutoConnect() && m_settings.defaultServerIndex() >= 0) {
QTimer::singleShot(1000, this, [this](){ QTimer::singleShot(1000, this, [this](){
set_pushButtonConnectEnabled(false); set_pushButtonConnectEnabled(false);
@ -33,13 +36,22 @@ VpnLogic::VpnLogic(UiLogic *logic, QObject *parent):
} }
void VpnLogic::updateVpnPage() void VpnLogic::onUpdatePage()
{ {
Settings::RouteMode mode = m_settings.routeMode(); Settings::RouteMode mode = m_settings.routeMode();
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites); set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites);
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites); set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites);
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites); set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites);
set_pushButtonVpnAddSiteEnabled(mode != Settings::VpnAllSites); set_pushButtonVpnAddSiteEnabled(mode != Settings::VpnAllSites);
const QJsonObject &server = uiLogic()->m_settings.defaultServer();
QString serverString = QString("%2 (%3)")
.arg(server.value(config_key::description).toString())
.arg(server.value(config_key::hostName).toString());
set_labelCurrentServer(serverString);
QString selectedContainerName = m_settings.defaultContainerName(m_settings.defaultServerIndex());
set_labelCurrentService(selectedContainerName);
} }
@ -76,6 +88,7 @@ void VpnLogic::onConnectionStateChanged(VpnProtocol::ConnectionState state)
bool pbConnectEnabled = false; bool pbConnectEnabled = false;
bool rbModeEnabled = false; bool rbModeEnabled = false;
bool pbConnectVisible = false;
set_labelStateText(VpnProtocol::textConnectionState(state)); set_labelStateText(VpnProtocol::textConnectionState(state));
uiLogic()->setTrayState(state); uiLogic()->setTrayState(state);
@ -85,39 +98,48 @@ void VpnLogic::onConnectionStateChanged(VpnProtocol::ConnectionState state)
onBytesChanged(0,0); onBytesChanged(0,0);
set_pushButtonConnectChecked(false); set_pushButtonConnectChecked(false);
pbConnectEnabled = true; pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true; rbModeEnabled = true;
break; break;
case VpnProtocol::Preparing: case VpnProtocol::Preparing:
pbConnectEnabled = false; pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false; rbModeEnabled = false;
break; break;
case VpnProtocol::Connecting: case VpnProtocol::Connecting:
pbConnectEnabled = false; pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false; rbModeEnabled = false;
break; break;
case VpnProtocol::Connected: case VpnProtocol::Connected:
pbConnectEnabled = true; pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = false; rbModeEnabled = false;
break; break;
case VpnProtocol::Disconnecting: case VpnProtocol::Disconnecting:
pbConnectEnabled = false; pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false; rbModeEnabled = false;
break; break;
case VpnProtocol::Reconnecting: case VpnProtocol::Reconnecting:
pbConnectEnabled = true; pbConnectEnabled = true;
pbConnectVisible = false;
rbModeEnabled = false; rbModeEnabled = false;
break; break;
case VpnProtocol::Error: case VpnProtocol::Error:
set_pushButtonConnectEnabled(false); set_pushButtonConnectEnabled(false);
pbConnectEnabled = true; pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true; rbModeEnabled = true;
break; break;
case VpnProtocol::Unknown: case VpnProtocol::Unknown:
pbConnectEnabled = true; pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true; rbModeEnabled = true;
} }
set_pushButtonConnectEnabled(pbConnectEnabled); set_pushButtonConnectEnabled(pbConnectEnabled);
set_pushButtonConnectVisible(pbConnectVisible);
set_widgetVpnModeEnabled(rbModeEnabled); set_widgetVpnModeEnabled(rbModeEnabled);
} }
@ -166,20 +188,19 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent
qApp->processEvents(); qApp->processEvents();
ErrorCode errorCode = uiLogic()->m_vpnConnection->connectToVpn( emit connectToVpn(serverIndex, credentials, container, containerConfig);
serverIndex, credentials, container, containerConfig);
if (errorCode) { // if (errorCode) {
//ui->pushButton_connect->setChecked(false); // //ui->pushButton_connect->setChecked(false);
uiLogic()->setDialogConnectErrorText(errorString(errorCode)); // uiLogic()->setDialogConnectErrorText(errorString(errorCode));
emit uiLogic()->showConnectErrorDialog(); // emit uiLogic()->showConnectErrorDialog();
return; // return;
} // }
} }
void VpnLogic::onDisconnect() void VpnLogic::onDisconnect()
{ {
set_pushButtonConnectChecked(false); set_pushButtonConnectChecked(false);
uiLogic()->m_vpnConnection->disconnectFromVpn(); emit disconnectFromVpn();
} }

View file

@ -14,7 +14,10 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(QString, labelSpeedReceivedText) AUTO_PROPERTY(QString, labelSpeedReceivedText)
AUTO_PROPERTY(QString, labelSpeedSentText) AUTO_PROPERTY(QString, labelSpeedSentText)
AUTO_PROPERTY(QString, labelStateText) AUTO_PROPERTY(QString, labelStateText)
AUTO_PROPERTY(QString, labelCurrentServer)
AUTO_PROPERTY(QString, labelCurrentService)
AUTO_PROPERTY(bool, pushButtonConnectEnabled) AUTO_PROPERTY(bool, pushButtonConnectEnabled)
AUTO_PROPERTY(bool, pushButtonConnectVisible)
AUTO_PROPERTY(bool, widgetVpnModeEnabled) AUTO_PROPERTY(bool, widgetVpnModeEnabled)
AUTO_PROPERTY(QString, labelErrorText) AUTO_PROPERTY(QString, labelErrorText)
AUTO_PROPERTY(bool, pushButtonVpnAddSiteEnabled) AUTO_PROPERTY(bool, pushButtonVpnAddSiteEnabled)
@ -24,7 +27,7 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked) AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked)
public: public:
Q_INVOKABLE void updateVpnPage(); Q_INVOKABLE void onUpdatePage() override;
Q_INVOKABLE void onRadioButtonVpnModeAllSitesToggled(bool checked); Q_INVOKABLE void onRadioButtonVpnModeAllSitesToggled(bool checked);
Q_INVOKABLE void onRadioButtonVpnModeForwardSitesToggled(bool checked); Q_INVOKABLE void onRadioButtonVpnModeForwardSitesToggled(bool checked);
@ -48,5 +51,10 @@ public slots:
void onConnectionStateChanged(VpnProtocol::ConnectionState state); void onConnectionStateChanged(VpnProtocol::ConnectionState state);
void onVpnProtocolError(amnezia::ErrorCode errorCode); void onVpnProtocolError(amnezia::ErrorCode errorCode);
signals:
void connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
}; };
#endif // VPN_LOGIC_H #endif // VPN_LOGIC_H

View file

@ -15,6 +15,7 @@ WizardLogic::WizardLogic(UiLogic *logic, QObject *parent):
void WizardLogic::onUpdatePage() void WizardLogic::onUpdatePage()
{ {
set_lineEditHighWebsiteMaskingText(protocols::cloak::defaultRedirSite); set_lineEditHighWebsiteMaskingText(protocols::cloak::defaultRedirSite);
set_radioButtonMediumChecked(true);
} }
QMap<DockerContainer, QJsonObject> WizardLogic::getInstallConfigsFromWizardPage() const QMap<DockerContainer, QJsonObject> WizardLogic::getInstallConfigsFromWizardPage() const

View file

@ -8,17 +8,17 @@ using namespace PageEnumNS;
CloakLogic::CloakLogic(UiLogic *logic, QObject *parent): CloakLogic::CloakLogic(UiLogic *logic, QObject *parent):
PageProtocolLogicBase(logic, parent), PageProtocolLogicBase(logic, parent),
m_comboBoxProtoCloakCipherText{"chacha20-poly1305"}, m_comboBoxCipherText{"chacha20-poly1305"},
m_lineEditProtoCloakSiteText{"tile.openstreetmap.org"}, m_lineEditSiteText{"tile.openstreetmap.org"},
m_lineEditProtoCloakPortText{}, m_lineEditPortText{},
m_pushButtonCloakSaveVisible{false}, m_pushButtonSaveVisible{false},
m_progressBarProtoCloakResetVisible{false}, m_progressBarResetVisible{false},
m_lineEditProtoCloakPortEnabled{false}, m_lineEditPortEnabled{false},
m_pageProtoCloakEnabled{true}, m_pageEnabled{true},
m_labelProtoCloakInfoVisible{true}, m_labelInfoVisible{true},
m_labelProtoCloakInfoText{}, m_labelInfoText{},
m_progressBarProtoCloakResetValue{0}, m_progressBarResetValue{0},
m_progressBarProtoCloakResetMaximium{100} m_progressBarResetMaximium{100}
{ {
} }
@ -26,31 +26,31 @@ CloakLogic::CloakLogic(UiLogic *logic, QObject *parent):
void CloakLogic::updateProtocolPage(const QJsonObject &ckConfig, DockerContainer container, bool haveAuthData) void CloakLogic::updateProtocolPage(const QJsonObject &ckConfig, DockerContainer container, bool haveAuthData)
{ {
set_pageEnabled(haveAuthData); set_pageEnabled(haveAuthData);
set_pushButtonCloakSaveVisible(haveAuthData); set_pushButtonSaveVisible(haveAuthData);
set_progressBarProtoCloakResetVisible(haveAuthData); set_progressBarResetVisible(haveAuthData);
set_comboBoxProtoCloakCipherText(ckConfig.value(config_key::cipher). set_comboBoxCipherText(ckConfig.value(config_key::cipher).
toString(protocols::cloak::defaultCipher)); toString(protocols::cloak::defaultCipher));
set_lineEditProtoCloakSiteText(ckConfig.value(config_key::site). set_lineEditSiteText(ckConfig.value(config_key::site).
toString(protocols::cloak::defaultRedirSite)); toString(protocols::cloak::defaultRedirSite));
set_lineEditProtoCloakPortText(ckConfig.value(config_key::port). set_lineEditPortText(ckConfig.value(config_key::port).
toString(protocols::cloak::defaultPort)); toString(protocols::cloak::defaultPort));
set_lineEditProtoCloakPortEnabled(container == DockerContainer::Cloak); set_lineEditPortEnabled(container == DockerContainer::Cloak);
} }
QJsonObject CloakLogic::getProtocolConfigFromPage(QJsonObject oldConfig) QJsonObject CloakLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
{ {
oldConfig.insert(config_key::cipher, comboBoxProtoCloakCipherText()); oldConfig.insert(config_key::cipher, comboBoxCipherText());
oldConfig.insert(config_key::site, lineEditProtoCloakSiteText()); oldConfig.insert(config_key::site, lineEditSiteText());
oldConfig.insert(config_key::port, lineEditProtoCloakPortText()); oldConfig.insert(config_key::port, lineEditPortText());
return oldConfig; return oldConfig;
} }
void CloakLogic::onPushButtonProtoCloakSaveClicked() void CloakLogic::onPushButtonSaveClicked()
{ {
QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Protocol::Cloak); QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Protocol::Cloak);
protocolConfig = getProtocolConfigFromPage(protocolConfig); protocolConfig = getProtocolConfigFromPage(protocolConfig);
@ -59,40 +59,40 @@ void CloakLogic::onPushButtonProtoCloakSaveClicked()
QJsonObject newContainerConfig = containerConfig; QJsonObject newContainerConfig = containerConfig;
newContainerConfig.insert(ProtocolProps::protoToString(Protocol::Cloak), protocolConfig); newContainerConfig.insert(ProtocolProps::protoToString(Protocol::Cloak), protocolConfig);
UiLogic::PageFunc page_proto_cloak; UiLogic::PageFunc page_func;
page_proto_cloak.setEnabledFunc = [this] (bool enabled) -> void { page_func.setEnabledFunc = [this] (bool enabled) -> void {
set_pageProtoCloakEnabled(enabled); set_pageEnabled(enabled);
}; };
UiLogic::ButtonFunc pushButton_proto_cloak_save; UiLogic::ButtonFunc pushButton_save_func;
pushButton_proto_cloak_save.setVisibleFunc = [this] (bool visible) ->void { pushButton_save_func.setVisibleFunc = [this] (bool visible) ->void {
set_pushButtonCloakSaveVisible(visible); set_pushButtonSaveVisible(visible);
}; };
UiLogic::LabelFunc label_proto_cloak_info; UiLogic::LabelFunc label_info_func;
label_proto_cloak_info.setVisibleFunc = [this] (bool visible) ->void { label_info_func.setVisibleFunc = [this] (bool visible) ->void {
set_labelProtoCloakInfoVisible(visible); set_labelInfoVisible(visible);
}; };
label_proto_cloak_info.setTextFunc = [this] (const QString& text) ->void { label_info_func.setTextFunc = [this] (const QString& text) ->void {
set_labelProtoCloakInfoText(text); set_labelInfoText(text);
}; };
UiLogic::ProgressFunc progressBar_proto_cloak_reset; UiLogic::ProgressFunc progressBar_reset;
progressBar_proto_cloak_reset.setVisibleFunc = [this] (bool visible) ->void { progressBar_reset.setVisibleFunc = [this] (bool visible) ->void {
set_progressBarProtoCloakResetVisible(visible); set_progressBarResetVisible(visible);
}; };
progressBar_proto_cloak_reset.setValueFunc = [this] (int value) ->void { progressBar_reset.setValueFunc = [this] (int value) ->void {
set_progressBarProtoCloakResetValue(value); set_progressBarResetValue(value);
}; };
progressBar_proto_cloak_reset.getValueFunc = [this] (void) -> int { progressBar_reset.getValueFunc = [this] (void) -> int {
return progressBarProtoCloakResetValue(); return progressBarResetValue();
}; };
progressBar_proto_cloak_reset.getMaximiumFunc = [this] (void) -> int { progressBar_reset.getMaximiumFunc = [this] (void) -> int {
return progressBarProtoCloakResetMaximium(); return progressBarResetMaximium();
}; };
ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){
return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig);
}, },
page_proto_cloak, progressBar_proto_cloak_reset, page_func, progressBar_reset,
pushButton_proto_cloak_save, label_proto_cloak_info); pushButton_save_func, label_info_func);
if (!e) { if (!e) {
m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig); m_settings.setContainerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, newContainerConfig);

View file

@ -9,20 +9,20 @@ class CloakLogic : public PageProtocolLogicBase
{ {
Q_OBJECT Q_OBJECT
AUTO_PROPERTY(QString, comboBoxProtoCloakCipherText) AUTO_PROPERTY(QString, comboBoxCipherText)
AUTO_PROPERTY(QString, lineEditProtoCloakSiteText) AUTO_PROPERTY(QString, lineEditSiteText)
AUTO_PROPERTY(QString, lineEditProtoCloakPortText) AUTO_PROPERTY(QString, lineEditPortText)
AUTO_PROPERTY(bool, pushButtonCloakSaveVisible) AUTO_PROPERTY(bool, pushButtonSaveVisible)
AUTO_PROPERTY(bool, progressBarProtoCloakResetVisible) AUTO_PROPERTY(bool, progressBarResetVisible)
AUTO_PROPERTY(bool, lineEditProtoCloakPortEnabled) AUTO_PROPERTY(bool, lineEditPortEnabled)
AUTO_PROPERTY(bool, pageProtoCloakEnabled) AUTO_PROPERTY(bool, pageEnabled)
AUTO_PROPERTY(bool, labelProtoCloakInfoVisible) AUTO_PROPERTY(bool, labelInfoVisible)
AUTO_PROPERTY(QString, labelProtoCloakInfoText) AUTO_PROPERTY(QString, labelInfoText)
AUTO_PROPERTY(int, progressBarProtoCloakResetValue) AUTO_PROPERTY(int, progressBarResetValue)
AUTO_PROPERTY(int, progressBarProtoCloakResetMaximium) AUTO_PROPERTY(int, progressBarResetMaximium)
public: public:
Q_INVOKABLE void onPushButtonProtoCloakSaveClicked(); Q_INVOKABLE void onPushButtonSaveClicked();
public: public:
explicit CloakLogic(UiLogic *uiLogic, QObject *parent = nullptr); explicit CloakLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View file

@ -8,16 +8,15 @@ using namespace PageEnumNS;
ShadowSocksLogic::ShadowSocksLogic(UiLogic *logic, QObject *parent): ShadowSocksLogic::ShadowSocksLogic(UiLogic *logic, QObject *parent):
PageProtocolLogicBase(logic, parent), PageProtocolLogicBase(logic, parent),
m_comboBoxProtoShadowSocksCipherText{"chacha20-poly1305"}, m_comboBoxCipherText{"chacha20-poly1305"},
m_lineEditProtoShadowSocksPortText{}, m_lineEditPortText{},
m_pushButtonShadowSocksSaveVisible{false}, m_pushButtonSaveVisible{false},
m_progressBarProtoShadowSocksResetVisible{false}, m_progressBaResetVisible{false},
m_lineEditProtoShadowSocksPortEnabled{false}, m_lineEditPortEnabled{false},
m_pageProtoShadowSocksEnabled{true}, m_labelInfoVisible{true},
m_labelProtoShadowSocksInfoVisible{true}, m_labelInfoText{},
m_labelProtoShadowSocksInfoText{}, m_progressBaResetValue{0},
m_progressBarProtoShadowSocksResetValue{0}, m_progressBaResetMaximium{100}
m_progressBarProtoShadowSocksResetMaximium{100}
{ {
} }
@ -25,27 +24,27 @@ ShadowSocksLogic::ShadowSocksLogic(UiLogic *logic, QObject *parent):
void ShadowSocksLogic::updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData) void ShadowSocksLogic::updateProtocolPage(const QJsonObject &ssConfig, DockerContainer container, bool haveAuthData)
{ {
set_pageEnabled(haveAuthData); set_pageEnabled(haveAuthData);
set_pushButtonShadowSocksSaveVisible(haveAuthData); set_pushButtonSaveVisible(haveAuthData);
set_progressBarProtoShadowSocksResetVisible(haveAuthData); set_progressBaResetVisible(haveAuthData);
set_comboBoxProtoShadowSocksCipherText(ssConfig.value(config_key::cipher). set_comboBoxCipherText(ssConfig.value(config_key::cipher).
toString(protocols::shadowsocks::defaultCipher)); toString(protocols::shadowsocks::defaultCipher));
set_lineEditProtoShadowSocksPortText(ssConfig.value(config_key::port). set_lineEditPortText(ssConfig.value(config_key::port).
toString(protocols::shadowsocks::defaultPort)); toString(protocols::shadowsocks::defaultPort));
set_lineEditProtoShadowSocksPortEnabled(container == DockerContainer::ShadowSocks); set_lineEditPortEnabled(container == DockerContainer::ShadowSocks);
} }
QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig) QJsonObject ShadowSocksLogic::getProtocolConfigFromPage(QJsonObject oldConfig)
{ {
oldConfig.insert(config_key::cipher, comboBoxProtoShadowSocksCipherText()); oldConfig.insert(config_key::cipher, comboBoxCipherText());
oldConfig.insert(config_key::port, lineEditProtoShadowSocksPortText()); oldConfig.insert(config_key::port, lineEditPortText());
return oldConfig; return oldConfig;
} }
void ShadowSocksLogic::onPushButtonProtoShadowSocksSaveClicked() void ShadowSocksLogic::onPushButtonSaveClicked()
{ {
QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Protocol::ShadowSocks); QJsonObject protocolConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, Protocol::ShadowSocks);
//protocolConfig = getShadowSocksConfigFromPage(protocolConfig); //protocolConfig = getShadowSocksConfigFromPage(protocolConfig);
@ -55,37 +54,37 @@ void ShadowSocksLogic::onPushButtonProtoShadowSocksSaveClicked()
newContainerConfig.insert(ProtocolProps::protoToString(Protocol::ShadowSocks), protocolConfig); newContainerConfig.insert(ProtocolProps::protoToString(Protocol::ShadowSocks), protocolConfig);
UiLogic::PageFunc page_proto_shadowsocks; UiLogic::PageFunc page_proto_shadowsocks;
page_proto_shadowsocks.setEnabledFunc = [this] (bool enabled) -> void { page_proto_shadowsocks.setEnabledFunc = [this] (bool enabled) -> void {
set_pageProtoShadowSocksEnabled(enabled); set_pageEnabled(enabled);
}; };
UiLogic::ButtonFunc pushButton_proto_shadowsocks_save; UiLogic::ButtonFunc pushButton_proto_shadowsocks_save;
pushButton_proto_shadowsocks_save.setVisibleFunc = [this] (bool visible) ->void { pushButton_proto_shadowsocks_save.setVisibleFunc = [this] (bool visible) ->void {
set_pushButtonShadowSocksSaveVisible(visible); set_pushButtonSaveVisible(visible);
}; };
UiLogic::LabelFunc label_proto_shadowsocks_info; UiLogic::LabelFunc label_proto_shadowsocks_info;
label_proto_shadowsocks_info.setVisibleFunc = [this] (bool visible) ->void { label_proto_shadowsocks_info.setVisibleFunc = [this] (bool visible) ->void {
set_labelProtoShadowSocksInfoVisible(visible); set_labelInfoVisible(visible);
}; };
label_proto_shadowsocks_info.setTextFunc = [this] (const QString& text) ->void { label_proto_shadowsocks_info.setTextFunc = [this] (const QString& text) ->void {
set_labelProtoShadowSocksInfoText(text); set_labelInfoText(text);
}; };
UiLogic::ProgressFunc progressBar_proto_shadowsocks_reset; UiLogic::ProgressFunc progressBar_reset;
progressBar_proto_shadowsocks_reset.setVisibleFunc = [this] (bool visible) ->void { progressBar_reset.setVisibleFunc = [this] (bool visible) ->void {
set_progressBarProtoShadowSocksResetVisible(visible); set_progressBaResetVisible(visible);
}; };
progressBar_proto_shadowsocks_reset.setValueFunc = [this] (int value) ->void { progressBar_reset.setValueFunc = [this] (int value) ->void {
set_progressBarProtoShadowSocksResetValue(value); set_progressBaResetValue(value);
}; };
progressBar_proto_shadowsocks_reset.getValueFunc = [this] (void) -> int { progressBar_reset.getValueFunc = [this] (void) -> int {
return progressBarProtoShadowSocksResetValue(); return progressBaResetValue();
}; };
progressBar_proto_shadowsocks_reset.getMaximiumFunc = [this] (void) -> int { progressBar_reset.getMaximiumFunc = [this] (void) -> int {
return progressBarProtoShadowSocksResetMaximium(); return progressBaResetMaximium();
}; };
ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){ ErrorCode e = uiLogic()->doInstallAction([this, containerConfig, &newContainerConfig](){
return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig); return ServerController::updateContainer(m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer, containerConfig, newContainerConfig);
}, },
page_proto_shadowsocks, progressBar_proto_shadowsocks_reset, page_proto_shadowsocks, progressBar_reset,
pushButton_proto_shadowsocks_save, label_proto_shadowsocks_info); pushButton_proto_shadowsocks_save, label_proto_shadowsocks_info);
if (!e) { if (!e) {

View file

@ -9,19 +9,18 @@ class ShadowSocksLogic : public PageProtocolLogicBase
{ {
Q_OBJECT Q_OBJECT
AUTO_PROPERTY(QString, comboBoxProtoShadowSocksCipherText) AUTO_PROPERTY(QString, comboBoxCipherText)
AUTO_PROPERTY(QString, lineEditProtoShadowSocksPortText) AUTO_PROPERTY(QString, lineEditPortText)
AUTO_PROPERTY(bool, pushButtonShadowSocksSaveVisible) AUTO_PROPERTY(bool, pushButtonSaveVisible)
AUTO_PROPERTY(bool, progressBarProtoShadowSocksResetVisible) AUTO_PROPERTY(bool, progressBaResetVisible)
AUTO_PROPERTY(bool, lineEditProtoShadowSocksPortEnabled) AUTO_PROPERTY(bool, lineEditPortEnabled)
AUTO_PROPERTY(bool, pageProtoShadowSocksEnabled) AUTO_PROPERTY(bool, labelInfoVisible)
AUTO_PROPERTY(bool, labelProtoShadowSocksInfoVisible) AUTO_PROPERTY(QString, labelInfoText)
AUTO_PROPERTY(QString, labelProtoShadowSocksInfoText) AUTO_PROPERTY(int, progressBaResetValue)
AUTO_PROPERTY(int, progressBarProtoShadowSocksResetValue) AUTO_PROPERTY(int, progressBaResetMaximium)
AUTO_PROPERTY(int, progressBarProtoShadowSocksResetMaximium)
public: public:
Q_INVOKABLE void onPushButtonProtoShadowSocksSaveClicked(); Q_INVOKABLE void onPushButtonSaveClicked();
public: public:
explicit ShadowSocksLogic(UiLogic *uiLogic, QObject *parent = nullptr); explicit ShadowSocksLogic(UiLogic *uiLogic, QObject *parent = nullptr);

View file

@ -6,8 +6,6 @@ BasicButtonType {
id: root id: root
width: parent.width - 80 width: parent.width - 80
height: 40 height: 40
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
background: Rectangle { background: Rectangle {
anchors.fill: parent anchors.fill: parent

View file

@ -0,0 +1,33 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Qt.labs.platform 1.0
Menu {
property var textObj
MenuItem {
text: qsTr("C&ut")
shortcut: StandardKey.Cut
enabled: textObj.selectedText
onTriggered: textObj.cut()
}
MenuItem {
text: qsTr("&Copy")
shortcut: StandardKey.Copy
enabled: textObj.selectedText
onTriggered: textObj.copy()
}
MenuItem {
text: qsTr("&Paste")
shortcut: StandardKey.Paste
enabled: textObj.canPaste
onTriggered: textObj.paste()
}
MenuItem {
text: qsTr("&SelectAll")
shortcut: StandardKey.SelectAll
enabled: textObj.length > 0
onTriggered: textObj.selectAll()
}
}

View file

@ -0,0 +1,26 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
ShareConnectionButtonType {
property string start_text: qsTr("Copy")
property string end_text: qsTr("Copied")
property string copyText
enabled: copyText.length > 0
visible: copyText.length > 0
Timer {
id: timer
interval: 1000; running: false; repeat: false
onTriggered: text = start_text
}
text: start_text
onClicked: {
text = end_text
timer.running = true
UiLogic.copyToClipboard(copyText)
}
}

View file

@ -4,10 +4,13 @@ import QtQuick.Controls 2.12
BasicButtonType { BasicButtonType {
id: root id: root
height: 40
background: Rectangle { background: Rectangle {
anchors.fill: parent anchors.fill: parent
radius: 4 radius: 4
color: root.containsMouse ? "#282932" : "#181922" color: root.enabled
? (root.containsMouse ? "#282932" : "#181922")
: "#484952"
} }
font.pixelSize: 16 font.pixelSize: 16
contentItem: Text { contentItem: Text {

View file

@ -5,9 +5,7 @@ import QtGraphicalEffects 1.12
Item { Item {
id: root id: root
property bool active: false property bool active: false
property Component content: undefined
property string text: "" property string text: ""
width: 360
height: active ? contentLoader.item.height + 40 + 5 * 2 : 40 height: active ? contentLoader.item.height + 40 + 5 * 2 : 40
signal clicked() signal clicked()
@ -64,12 +62,5 @@ Item {
onClicked: root.clicked() onClicked: root.clicked()
} }
} }
Loader {
x: 0
y: 40 + 5
id: contentLoader
sourceComponent: root.content
visible: root.active
}
} }

View file

@ -0,0 +1,63 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Qt.labs.platform 1.0
import "../Config"
Flickable
{
property alias textArea: root
id: flickable
flickableDirection: Flickable.VerticalFlick
clip: true
TextArea.flickable:
TextArea {
id: root
property bool error: false
height: 40
anchors.topMargin: 5
selectByMouse: false
selectionColor: "darkgray"
font.pixelSize: 16
color: "#333333"
background: Rectangle {
implicitWidth: 200
implicitHeight: 40
border.width: 1
color: {
if (root.error) {
return Qt.rgba(213, 40, 60, 255)
}
return root.enabled ? "#F4F4F4" : Qt.rgba(127, 127, 127, 255)
}
border.color: {
if (!root.enabled) {
return Qt.rgba(127, 127, 127, 255)
}
if (root.error) {
return Qt.rgba(213, 40, 60, 255)
}
if (root.focus) {
return "#A7A7A7"
}
return "#A7A7A7"
}
}
// MouseArea {
// anchors.fill: root
// enabled: GC.isDesktop()
// acceptedButtons: Qt.RightButton
// onClicked: contextMenu.open()
// }
// ContextMenu {
// id: contextMenu
// textObj: root
// }
}
}

View file

@ -44,29 +44,8 @@ TextField {
onClicked: contextMenu.open() onClicked: contextMenu.open()
} }
Menu { ContextMenu {
id: contextMenu id: contextMenu
textObj: root
onAboutToShow: console.log("aboutToShow")
onAboutToHide: console.log("aboutToHide")
MenuItem {
text: qsTr("C&ut")
shortcut: StandardKey.Cut
enabled: root.selectedText
onTriggered: root.cut()
}
MenuItem {
text: qsTr("&Copy")
shortcut: StandardKey.Copy
enabled: root.selectedText
onTriggered: root.copy()
}
MenuItem {
text: qsTr("&Paste")
shortcut: StandardKey.Paste
enabled: root.canPaste
onTriggered: root.paste()
}
} }
} }

View file

@ -20,7 +20,7 @@ Drawer {
height: parent.height height: parent.height
modal: true modal: true
interactive: true interactive: activeFocus
SortFilterProxyModel { SortFilterProxyModel {
id: proxyModel id: proxyModel

View file

@ -13,82 +13,49 @@ PageBase {
BackButton { BackButton {
id: back id: back
} }
// ---------- App settings ------------
Rectangle { Rectangle {
y: 40 id: l1
visible: !GC.isMobile()
anchors.top: back.bottom
x: 20 x: 20
width: parent.width - 40 width: parent.width - 40
height: 1 height: GC.isMobile() ? 0: 1
color: "#DDDDDD"
}
Rectangle {
y: 100
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
Rectangle {
y: 160
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
Rectangle {
y: 220
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
Rectangle {
y: 280
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
Rectangle {
y: 340
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
Rectangle {
y: 400
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD" color: "#DDDDDD"
} }
SettingButtonType { SettingButtonType {
id: b1
visible: !GC.isMobile()
anchors.top: l1.bottom
anchors.topMargin: GC.isMobile() ? 0: 15
x: 30 x: 30
y: 355 width: parent.width - 40
width: 330 height: GC.isMobile() ? 0: 30
height: 30
icon.source: "qrc:/images/plus.png"
text: qsTr("Add server")
onClicked: {
UiLogic.goToPage(PageEnum.Start)
}
}
SettingButtonType {
x: 30
y: 55
width: 330
height: 30
icon.source: "qrc:/images/settings.png" icon.source: "qrc:/images/settings.png"
text: qsTr("App settings") text: qsTr("App settings")
onClicked: { onClicked: {
UiLogic.goToPage(PageEnum.AppSettings) UiLogic.goToPage(PageEnum.AppSettings)
} }
} }
// ---------- Network settings ------------
Rectangle {
id: l2
anchors.top: b1.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType { SettingButtonType {
id: b2
x: 30 x: 30
y: 115 anchors.top: l2.bottom
width: 330 anchors.topMargin: 15
width: parent.width - 40
height: 30 height: 30
icon.source: "qrc:/images/settings.png" icon.source: "qrc:/images/settings.png"
text: qsTr("Network settings") text: qsTr("Network settings")
@ -96,31 +63,46 @@ PageBase {
UiLogic.goToPage(PageEnum.NetworkSettings) UiLogic.goToPage(PageEnum.NetworkSettings)
} }
} }
// ---------- Server settings ------------
Rectangle {
id: l3
anchors.top: b2.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType { SettingButtonType {
id: b3
x: 30 x: 30
y: 175 anchors.top: l3.bottom
anchors.topMargin: 15
width: 330 width: 330
height: 30 height: 30
icon.source: "qrc:/images/server_settings.png" icon.source: "qrc:/images/server_settings.png"
text: qsTr("Server management") text: qsTr("Server Settings")
onClicked: { onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked() GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked()
} }
} }
SettingButtonType {
x: 30 // ---------- Share connection ------------
y: 295 Rectangle {
width: 330 id: l4
height: 30 anchors.top: b3.bottom
icon.source: "qrc:/images/server_settings.png" anchors.topMargin: 15
text: qsTr("Servers") x: 20
onClicked: { width: parent.width - 40
UiLogic.goToPage(PageEnum.ServersList) height: 1
} color: "#DDDDDD"
} }
SettingButtonType { SettingButtonType {
id: b4
x: 30 x: 30
y: 235 anchors.top: l4.bottom
anchors.topMargin: 15
width: 330 width: 330
height: 30 height: 30
icon.source: "qrc:/images/share.png" icon.source: "qrc:/images/share.png"
@ -130,6 +112,66 @@ PageBase {
GeneralSettingsLogic.onPushButtonGeneralSettingsShareConnectionClicked() GeneralSettingsLogic.onPushButtonGeneralSettingsShareConnectionClicked()
} }
} }
// ---------- Servers ------------
Rectangle {
id: l5
anchors.top: b4.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b5
x: 30
anchors.top: l5.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
text: qsTr("Servers")
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
}
}
// ---------- Add server ------------
Rectangle {
id: l6
anchors.top: b5.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b6
x: 30
anchors.top: l6.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/plus.png"
text: qsTr("Add server")
onClicked: {
UiLogic.goToPage(PageEnum.Start)
}
}
Rectangle {
id: l7
anchors.top: b6.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType { SettingButtonType {
x: 30 x: 30
anchors.bottom: parent.bottom anchors.bottom: parent.bottom

View file

@ -30,6 +30,7 @@ PageBase {
id: pushButtonWizard id: pushButtonWizard
text: qsTr("Run Setup Wizard") text: qsTr("Run Setup Wizard")
anchors.top: labelWizard.bottom anchors.top: labelWizard.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10 anchors.topMargin: 10
onClicked: { onClicked: {
UiLogic.goToPage(PageEnum.Wizard); UiLogic.goToPage(PageEnum.Wizard);

View file

@ -147,172 +147,4 @@ PageBase {
} }
} }
} }
// ScrollView {
// id: scrollView
// width: parent.width - 40
// anchors.horizontalCenter: parent.horizontalCenter
// anchors.top: pb_add_container.bottom
// anchors.topMargin: 10
// anchors.bottom: pushButtonConfigure.top
// anchors.bottomMargin: 10
// clip: true
// Column {
// width: scrollView.width
// anchors.horizontalCenter: parent.horizontalCenter
// spacing: 5
// InstallSettingsBase {
// containerDescription: qsTr("OpenVPN and ShadowSocks\n with masking using Cloak plugin")
// onContainerChecked: NewServerProtocolsLogic.checkBoxCloakChecked = checked
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Port (TCP)")
// }
// TextFieldType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: NewServerProtocolsLogic.lineEditCloakPortText
// onEditingFinished: {
// NewServerProtocolsLogic.lineEditCloakPortText = text
// }
// }
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Fake Web Site")
// }
// TextFieldType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: NewServerProtocolsLogic.lineEditCloakSiteText
// onEditingFinished: {
// NewServerProtocolsLogic.lineEditCloakSiteText = text
// }
// }
// }
// InstallSettingsBase {
// containerDescription: qsTr("ShadowSocks")
// onContainerChecked: NewServerProtocolsLogic.checkBoxSsChecked = checked
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Port (TCP)")
// }
// TextFieldType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: NewServerProtocolsLogic.lineEditSsPortText
// onEditingFinished: {
// NewServerProtocolsLogic.lineEditSsPortText = text
// }
// }
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Encryption")
// }
// ComboBoxType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// model: [
// qsTr("chacha20-ietf-poly1305"),
// qsTr("xchacha20-ietf-poly1305"),
// qsTr("aes-256-gcm"),
// qsTr("aes-192-gcm"),
// qsTr("aes-128-gcm")
// ]
// currentIndex: {
// for (let i = 0; i < model.length; ++i) {
// if (NewServerProtocolsLogic.comboBoxSsCipherText === model[i]) {
// return i
// }
// }
// return -1
// }
// onCurrentTextChanged: {
// NewServerProtocolsLogic.comboBoxSsCipherText = currentText
// }
// }
// }
// InstallSettingsBase {
// containerDescription: qsTr("OpenVPN")
// onContainerChecked: NewServerProtocolsLogic.checkBoxOpenVpnChecked = checked
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Port (TCP/UDP)")
// }
// TextFieldType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: NewServerProtocolsLogic.lineEditOpenvpnPortText
// onEditingFinished: {
// NewServerProtocolsLogic.lineEditOpenvpnPortText = text
// }
// }
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// text: qsTr("Protocol")
// }
// ComboBoxType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2) / 2
// model: [
// qsTr("udp"),
// qsTr("tcp"),
// ]
// currentIndex: {
// for (let i = 0; i < model.length; ++i) {
// if (NewServerProtocolsLogic.comboBoxOpenvpnProtoText === model[i]) {
// return i
// }
// }
// return -1
// }
// onCurrentTextChanged: {
// NewServerProtocolsLogic.comboBoxOpenvpnProtoText = currentText
// }
// }
// }
// InstallSettingsBase {
// visible: false
// containerDescription: qsTr("WireGuard")
// onContainerChecked: NewServerProtocolsLogic.checkBoxWireGuardChecked = checked
// LabelType {
// width: 130
// height: (parent.height - parent.spacing - parent.topPadding * 2)
// text: qsTr("Port (UDP)")
// }
// TextFieldType {
// width: parent.width - 130 - parent.spacing - parent.leftPadding * 2
// height: (parent.height - parent.spacing - parent.topPadding * 2)
// text: "32767"
// }
// }
// }
// }
} }

View file

@ -1,5 +1,6 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import ContainerProps 1.0 import ContainerProps 1.0
@ -292,21 +293,32 @@ PageBase {
} }
ImageButtonType { ImageButtonType {
id: button_default id: button_remove
visible: service_type_role == ProtocolEnum.Vpn visible: index === tb_c.currentIndex
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checkable: true checkable: true
img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png" icon.source: "qrc:/images/delete.png"
implicitWidth: 30 implicitWidth: 30
implicitHeight: 30 implicitHeight: 30
checked: default_role checked: default_role
onClicked: {
ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index)) MessageDialog {
id: dialogRemove
standardButtons: StandardButton.Yes | StandardButton.Cancel
title: "AmneziaVPN"
text: qsTr("Remove container") + " " + name_role + "?" + "\n" + qsTr("This action will erase all data of this container on the server.")
onAccepted: {
tb_c.currentIndex = -1
ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index))
} }
} }
onClicked: dialogRemove.open()
VisibleBehavior on visible { }
}
ImageButtonType { ImageButtonType {
id: button_share id: button_share
visible: index === tb_c.currentIndex visible: index === tb_c.currentIndex
@ -322,23 +334,20 @@ PageBase {
} }
ImageButtonType { ImageButtonType {
id: button_remove id: button_default
visible: index === tb_c.currentIndex visible: service_type_role == ProtocolEnum.Vpn
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
checkable: true checkable: true
icon.source: "qrc:/images/delete.png" img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png"
implicitWidth: 30 implicitWidth: 30
implicitHeight: 30 implicitHeight: 30
checked: default_role checked: default_role
onClicked: { onClicked: {
tb_c.currentIndex = -1 ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index))
ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index))
} }
VisibleBehavior on visible { }
} }
} }

View file

@ -49,7 +49,13 @@ PageBase {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
if (GC.isMobile()) {
ServerListLogic.onServerListPushbuttonSettingsClicked(index)
}
else {
listWidget_servers.currentIndex = index listWidget_servers.currentIndex = index
}
mouse.accepted = false mouse.accepted = false
} }
onEntered: { onEntered: {
@ -104,22 +110,11 @@ PageBase {
wrapMode: Text.Wrap wrapMode: Text.Wrap
text: desc text: desc
} }
ImageButtonType {
x: 212
y: 25
width: 32
height: 24
checkable: true
iconMargin: 0
icon.source: checked ? "qrc:/images/connect_button_connected.png"
: "qrc:/images/connect_button_disconnected.png"
visible: false
}
ImageButtonType { ImageButtonType {
x: parent.width - 30 x: parent.width - 30
y: 25 y: 15
width: 24 width: 30
height: 24 height: 30
checkable: true checkable: true
icon.source: checked ? "qrc:/images/check.png" icon.source: checked ? "qrc:/images/check.png"
: "qrc:/images/uncheck.png" : "qrc:/images/uncheck.png"
@ -131,10 +126,10 @@ PageBase {
} }
ImageButtonType { ImageButtonType {
id: pushButtonSetting id: pushButtonSetting
x: parent.width - 60 x: parent.width - 70
y: 25 y: 15
width: 24 width: 30
height: 24 height: 30
icon.source: "qrc:/images/settings.png" icon.source: "qrc:/images/settings.png"
opacity: 0 opacity: 0

View file

@ -1,6 +1,13 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.15
import QtGraphicalEffects 1.12
import SortFilterProxyModel 0.2
import ContainerProps 1.0
import ProtocolProps 1.0
import PageEnum 1.0 import PageEnum 1.0
import ProtocolEnum 1.0
import "./" import "./"
import "../Controls" import "../Controls"
import "../Config" import "../Config"
@ -13,400 +20,69 @@ PageBase {
BackButton { BackButton {
id: back id: back
} }
ScrollView {
x: 10 Caption {
y: 40 id: caption
width: 360 text: qsTr("Share protocol config")
height: 580 width: undefined
Item {
id: ct
width: parent.width
height: childrenRect.height + 10
property var contentList: [
full_access,
share_amezia,
share_openvpn,
share_shadowshock,
share_cloak
]
property int currentIndex: ShareConnectionLogic.toolBoxShareConnectionCurrentIndex
onCurrentIndexChanged: {
ShareConnectionLogic.toolBoxShareConnectionCurrentIndex = currentIndex
for (let i = 0; i < contentList.length; ++i) {
if (i == currentIndex) {
contentList[i].active = true
} else {
contentList[i].active = false
} }
Flickable {
clip: true
width: parent.width
anchors.top: caption.bottom
anchors.bottom: root.bottom
contentHeight: col.height
Column {
id: col
anchors {
left: parent.left;
right: parent.right;
}
topPadding: 20
spacing: 10
SortFilterProxyModel {
id: proxyProtocolsModel
sourceModel: UiLogic.protocolsModel
filters: ValueFilter {
roleName: "is_installed_role"
value: true
} }
} }
function clearActive() {
for (let i = 0; i < contentList.length; ++i) {
contentList[i].active = false
}
currentIndex = -1;
}
Column {
spacing: 5
ShareConnectionContent { ShareConnectionContent {
id: full_access
x: 0
text: qsTr("Full access")
visible: ShareConnectionLogic.pageShareFullAccessVisible
content: Component {
Item {
width: 360
height: 380
Text {
x: 10 x: 10
y: 250 text: qsTr("Share for Amnezia")
width: 341
height: 111
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: "#181922"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
text: qsTr("Anyone who logs in with this code will have the same permissions to use VPN and your server as you. \nThis code includes your server credentials!\nProvide this code only to TRUSTED users.")
}
ShareConnectionButtonType {
x: 10
y: 130
width: 341
height: 40 height: 40
text: ShareConnectionLogic.pushButtonShareFullCopyText width: tb_c.width - 10
onClicked: { onClicked: UiLogic.onGotoShareProtocolPage(ProtocolEnum.Any)
ShareConnectionLogic.onPushButtonShareFullCopyClicked()
} }
}
ShareConnectionButtonType { ListView {
id: tb_c
x: 10 x: 10
y: 180 width: parent.width - 10
width: 341 height: tb_c.contentItem.height
height: 40 currentIndex: -1
text: qsTr("Save file") spacing: 10
onClicked: { clip: true
ShareConnectionLogic.onPushButtonShareFullSaveClicked() interactive: false
} model: proxyProtocolsModel
}
TextFieldType { delegate: Item {
x: 10 implicitWidth: tb_c.width - 10
y: 10 implicitHeight: c_item.height
width: 341
height: 100
verticalAlignment: Text.AlignTop
text: ShareConnectionLogic.textEditShareFullCodeText
onEditingFinished: {
ShareConnectionLogic.textEditShareFullCodeText = text
}
}
}
}
onClicked: {
if (active) {
ct.currentIndex = -1
} else {
ct.clearActive()
ct.currentIndex = 0
}
}
}
ShareConnectionContent { ShareConnectionContent {
id: share_amezia id: c_item
x: 0 text: qsTr("Share for ") + name_role
text: qsTr("Share for Amnezia client")
visible: ShareConnectionLogic.pageShareAmneziaVisible
content: Component {
Item {
width: 360
height: 380
Text {
x: 10
y: 280
width: 341
height: 111
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: "#181922"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
text: qsTr("Anyone who logs in with this code will be able to connect to this VPN server. \nThis code does not include server credentials.")
}
ShareConnectionButtonType {
x: 10
y: 180
width: 341
height: 40 height: 40
text: ShareConnectionLogic.pushButtonShareAmneziaCopyText width: tb_c.width - 10
onClicked: { onClicked: UiLogic.onGotoShareProtocolPage(proxyProtocolsModel.mapToSource(index))
ShareConnectionLogic.onPushButtonShareAmneziaCopyClicked()
}
enabled: ShareConnectionLogic.pushButtonShareAmneziaCopyEnabled
}
ShareConnectionButtonType {
x: 10
y: 130
width: 341
height: 40
text: ShareConnectionLogic.pushButtonShareAmneziaGenerateText
enabled: ShareConnectionLogic.pushButtonShareAmneziaGenerateEnabled
onClicked: {
ShareConnectionLogic.onPushButtonShareAmneziaGenerateClicked()
}
}
ShareConnectionButtonType {
x: 10
y: 230
width: 341
height: 40
text: qsTr("Save file")
onClicked: {
ShareConnectionLogic.onPushButtonShareAmneziaSaveClicked()
}
}
TextFieldType {
x: 10
y: 10
width: 341
height: 100
verticalAlignment: Text.AlignTop
text: ShareConnectionLogic.textEditShareAmneziaCodeText
onEditingFinished: {
ShareConnectionLogic.textEditShareAmneziaCodeText = text
}
}
}
}
onClicked: {
if (active) {
ct.currentIndex = -1
} else {
ct.clearActive()
ct.currentIndex = 1
}
}
}
ShareConnectionContent {
id: share_openvpn
x: 0
text: qsTr("Share for OpenVPN client")
visible: ShareConnectionLogic.pageShareOpenVpnVisible
content: Component {
Item {
width: 360
height: 380
ShareConnectionButtonType {
x: 10
y: 180
width: 341
height: 40
text: ShareConnectionLogic.pushButtonShareOpenVpnCopyText
enabled: ShareConnectionLogic.pushButtonShareOpenVpnCopyEnabled
onClicked: {
ShareConnectionLogic.onPushButtonShareOpenVpnCopyClicked()
}
}
ShareConnectionButtonType {
x: 10
y: 130
width: 341
height: 40
text: ShareConnectionLogic.pushButtonShareOpenVpnGenerateText
onClicked: {
ShareConnectionLogic.onPushButtonShareOpenVpnGenerateClicked()
}
enabled: ShareConnectionLogic.pushButtonShareOpenVpnGenerateEnabled
}
ShareConnectionButtonType {
x: 10
y: 230
width: 341
height: 40
text: qsTr("Save file")
enabled: ShareConnectionLogic.pushButtonShareOpenVpnSaveEnabled
onClicked: {
ShareConnectionLogic.onPushButtonShareOpenVpnSaveClicked()
}
}
TextFieldType {
x: 10
y: 10
width: 341
height: 100
verticalAlignment: Text.AlignTop
text: ShareConnectionLogic.textEditShareOpenVpnCodeText
onEditingFinished: {
ShareConnectionLogic.textEditShareOpenVpnCodeText = text
}
}
}
}
onClicked: {
if (active) {
ct.currentIndex = -1
} else {
ct.clearActive()
ct.currentIndex = 2
}
}
}
ShareConnectionContent {
id: share_shadowshock
x: 0
text: qsTr("Share for ShadowSocks client")
visible: ShareConnectionLogic.pageShareShadowSocksVisible
content: Component {
Item {
width: 360
height: 380
LabelType {
x: 10
y: 70
width: 100
height: 20
text: qsTr("Password")
}
LabelType {
x: 10
y: 10
width: 100
height: 20
text: qsTr("Server:")
}
LabelType {
x: 10
y: 50
width: 100
height: 20
text: qsTr("Encryption:")
}
LabelType {
x: 10
y: 30
width: 100
height: 20
text: qsTr("Port:")
}
LabelType {
x: 10
y: 100
width: 191
height: 20
text: qsTr("Connection string")
}
LabelType {
x: 130
y: 70
width: 100
height: 20
text: ShareConnectionLogic.labelShareShadowSocksPasswordText
}
LabelType {
x: 130
y: 10
width: 100
height: 20
text: ShareConnectionLogic.labelShareShadowSocksServerText
}
LabelType {
x: 130
y: 50
width: 100
height: 20
text: ShareConnectionLogic.labelShareShadowSocksMethodText
}
LabelType {
x: 130
y: 30
width: 100
height: 20
text: ShareConnectionLogic.labelShareShadowSocksPortText
}
Image {
id: label_share_ss_qr_code
x: 85
y: 235
width: 200
height: 200
source: ShareConnectionLogic.labelShareShadowSocksQrCodeText === "" ? "" : "data:image/png;base64," + UiLogic.labelShareShadowSocksQrCodeText
}
ShareConnectionButtonType {
x: 10
y: 180
width: 331
height: 40
text: ShareConnectionLogic.pushButtonShareShadowSocksCopyText
enabled: ShareConnectionLogic.pushButtonShareShadowSocksCopyEnabled
onClicked: {
ShareConnectionLogic.onPushButtonShareShadowSocksCopyClicked()
}
}
TextFieldType {
x: 10
y: 130
width: 331
height: 100
horizontalAlignment: Text.AlignHCenter
text: ShareConnectionLogic.lineEditShareShadowSocksStringText
onEditingFinished: {
ShareConnectionLogic.lineEditShareShadowSocksStringText = text
}
}
}
}
onClicked: {
if (active) {
ct.currentIndex = -1
} else {
ct.clearActive()
ct.currentIndex = 3
}
}
}
ShareConnectionContent {
id: share_cloak
x: 0
text: qsTr("Share for Cloak client")
visible: ShareConnectionLogic.pageShareCloakVisible
content: Component {
Item {
width: 360
height: 380
ShareConnectionButtonType {
x: 10
y: 290
width: 331
height: 40
text: ShareConnectionLogic.pushButtonShareCloakCopyText
enabled: ShareConnectionLogic.pushButtonShareCloakCopyEnabled
onClicked: {
ShareConnectionLogic.onPushButtonShareCloakCopyClicked()
}
}
TextInput {
x: 10
y: 30
width: 331
height: 100
text: ShareConnectionLogic.plainTextEditShareCloakText
onEditingFinished: {
ShareConnectionLogic.plainTextEditShareCloakText = text
}
}
}
}
onClicked: {
if (active) {
ct.currentIndex = -1
} else {
ct.clearActive()
ct.currentIndex = 4
}
} }
} }
} }

View file

@ -15,36 +15,30 @@ PageBase {
BackButton { BackButton {
id: back id: back
} }
Text {
font.family: "Lato" Caption {
font.styleName: "normal" id: caption
font.pixelSize: 16 text: SitesLogic.labelSitesAddCustomText
}
LabelType {
id: lb_addr
color: "#333333" color: "#333333"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: qsTr("Web site/Hostname/IP address/Subnet") text: qsTr("Web site/Hostname/IP address/Subnet")
x: 20 x: 20
y: 110 anchors.top: caption.bottom
width: 311 anchors.topMargin: 10
width: parent.width
height: 21 height: 21
} }
Text {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 20
color: "#100A44"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignTop
text: SitesLogic.labelSitesAddCustomText
x: 20
y: 40
width: 340
height: 60
}
TextFieldType { TextFieldType {
x: 20 anchors.top: lb_addr.bottom
y: 140 anchors.topMargin: 10
width: 231 anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: sites_add.left
anchors.rightMargin: 10
height: 31 height: 31
placeholderText: qsTr("yousite.com or IP address") placeholderText: qsTr("yousite.com or IP address")
text: SitesLogic.lineEditSitesAddCustomText text: SitesLogic.lineEditSitesAddCustomText
@ -55,10 +49,13 @@ PageBase {
SitesLogic.onPushButtonAddCustomSitesClicked() SitesLogic.onPushButtonAddCustomSitesClicked()
} }
} }
BlueButtonType { BlueButtonType {
id: sites_add id: sites_add
x: 260 anchors.right: sites_import.left
y: 140 anchors.rightMargin: 10
anchors.top: lb_addr.bottom
anchors.topMargin: 10
width: 51 width: 51
height: 31 height: 31
font.pixelSize: 24 font.pixelSize: 24
@ -67,23 +64,13 @@ PageBase {
SitesLogic.onPushButtonAddCustomSitesClicked() SitesLogic.onPushButtonAddCustomSitesClicked()
} }
} }
BlueButtonType {
id: sites_delete
x: 80
y: 589
width: 231
height: 31
font.pixelSize: 16
text: qsTr("Delete selected")
onClicked: {
SitesLogic.onPushButtonSitesDeleteClicked(tb.currentRow)
}
}
BasicButtonType { BasicButtonType {
id: sites_import id: sites_import
x: 320 anchors.right: parent.right
y: 140 anchors.rightMargin: 20
anchors.top: lb_addr.bottom
anchors.topMargin: 10
width: 51 width: 51
height: 31 height: 31
background: Rectangle { background: Rectangle {
@ -116,12 +103,15 @@ PageBase {
SitesLogic.onPushButtonSitesImportClicked(fileUrl) SitesLogic.onPushButtonSitesImportClicked(fileUrl)
} }
} }
ListView { ListView {
id: tb id: tb
x: 20 x: 20
y: 200 anchors.top: sites_add.bottom
width: 341 anchors.topMargin: 10
height: 371 width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1 spacing: 1
clip: true clip: true
property int currentRow: -1 property int currentRow: -1
@ -187,4 +177,17 @@ PageBase {
} }
} }
} }
BlueButtonType {
id: sites_delete
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
height: 31
font.pixelSize: 16
text: qsTr("Delete selected")
onClicked: {
SitesLogic.onPushButtonSitesDeleteClicked(tb.currentRow)
}
}
} }

View file

@ -128,7 +128,7 @@ PageBase {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 5 anchors.topMargin: 5
text: qsTr("Where to get connection data →") text: qsTr("How to get own server? →")
background: Item { background: Item {
anchors.fill: parent anchors.fill: parent
} }
@ -147,7 +147,7 @@ PageBase {
checkable: true checkable: true
checked: true checked: true
onClicked: { onClicked: {
Qt.openUrlExternally("https://amnezia.org") Qt.openUrlExternally("https://amnezia.org/instruction.html")
} }
} }
LabelType { LabelType {

View file

@ -1,5 +1,6 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0 import PageEnum 1.0
import "./" import "./"
import "../Controls" import "../Controls"
@ -11,12 +12,11 @@ PageBase {
logic: VpnLogic logic: VpnLogic
Image { Image {
id: bg_top
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: 0 y: 0
width: parent.width width: parent.width
height: parent.height * 0.28
// width: 380
// height: 325
source: "qrc:/images/background_connected.png" source: "qrc:/images/background_connected.png"
} }
@ -31,38 +31,26 @@ PageBase {
} }
} }
LabelType { AnimatedImage {
id: error_text id: connect_anim
x: 0 source: "qrc:/images/animation.gif"
y: 280 anchors.top: bg_top.bottom
width: 381 anchors.topMargin: 10
height: 61 anchors.horizontalCenter: root.horizontalCenter
horizontalAlignment: Text.AlignHCenter width: Math.min(parent.width, parent.height) / 4
verticalAlignment: Text.AlignVCenter height: width
wrapMode: Text.Wrap
text: VpnLogic.labelErrorText visible: !VpnLogic.pushButtonConnectVisible
} paused: VpnLogic.pushButtonConnectVisible
Text { //VisibleBehavior on visible { }
anchors.horizontalCenter: parent.horizontalCenter
y: 250
width: 380
height: 31
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 15
color: "#181922"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
text: VpnLogic.labelStateText
} }
BasicButtonType { BasicButtonType {
id: button_connect id: button_connect
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: connect_anim.horizontalCenter
y: 200 anchors.verticalCenter: connect_anim.verticalCenter
width: 80 width: connect_anim.width
height: 40 height: width
checkable: true checkable: true
checked: VpnLogic.pushButtonConnectChecked checked: VpnLogic.pushButtonConnectChecked
onCheckedChanged: { onCheckedChanged: {
@ -71,18 +59,102 @@ PageBase {
} }
background: Image { background: Image {
anchors.fill: parent anchors.fill: parent
source: button_connect.checked ? "qrc:/images/connect_button_connected.png" source: button_connect.checked ? "qrc:/images/connected.png"
: "qrc:/images/connect_button_disconnected.png" : "qrc:/images/disconnected.png"
} }
contentItem: Item {} contentItem: Item {}
antialiasing: true antialiasing: true
enabled: VpnLogic.pushButtonConnectEnabled enabled: VpnLogic.pushButtonConnectEnabled
opacity: VpnLogic.pushButtonConnectVisible ? 1 : 0
// transitions: Transition {
// NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad; duration: 500 }
// }
}
LabelType {
id: lb_state
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: button_connect.bottom
width: parent.width
height: 21
horizontalAlignment: Text.AlignHCenter
text: VpnLogic.labelStateText
}
RowLayout {
id: layout1
anchors.top: lb_state.bottom
//anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
height: 21
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("Server") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentServer
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
}
}
}
RowLayout {
id: layout2
anchors.top: layout1.bottom
anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
height: 21
LabelType {
Layout.alignment: Qt.AlignRight
height: 21
text: qsTr("Service") + ": "
}
BasicButtonType {
Layout.alignment: Qt.AlignLeft
height: 21
background: Item {}
text: VpnLogic.labelCurrentService
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
onClicked: {
UiLogic.onGotoCurrentProtocolsPage()
}
}
}
LabelType {
id: error_text
anchors.top: layout2.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: 21
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: VpnLogic.labelErrorText
} }
Item { Item {
x: 0 x: 0
anchors.bottom: line.top anchors.bottom: line.top
anchors.bottomMargin: 10 anchors.bottomMargin: GC.isMobile() ? 0 :10
width: parent.width width: parent.width
height: 51 height: 51
Image { Image {
@ -136,7 +208,7 @@ PageBase {
x: 20 x: 20
width: parent.width - 40 width: parent.width - 40
height: 1 height: 1
anchors.bottom: conn_type_label.top anchors.bottom: GC.isMobile() ? root.bottom : conn_type_label.top
anchors.bottomMargin: 10 anchors.bottomMargin: 10
color: "#DDDDDD" color: "#DDDDDD"
} }
@ -146,7 +218,7 @@ PageBase {
visible: !GC.isMobile() visible: !GC.isMobile()
x: 20 x: 20
anchors.bottom: conn_type_group.top anchors.bottom: conn_type_group.top
anchors.bottomMargin: 10 anchors.bottomMargin: GC.isMobile() ? 0 :10
width: 281 width: 281
height: GC.isMobile() ? 0: 21 height: GC.isMobile() ? 0: 21
font.family: "Lato" font.family: "Lato"
@ -208,11 +280,11 @@ PageBase {
BasicButtonType { BasicButtonType {
id: button_add_site id: button_add_site
visible: !GC.isMobile()
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: parent.height - 60 y: parent.height - 60
//anchors.bottom: parent.bottom
width: parent.width - 40 width: parent.width - 40
height: 40 height: GC.isMobile() ? 0: 40
text: qsTr("+ Add site") text: qsTr("+ Add site")
enabled: VpnLogic.pushButtonVpnAddSiteEnabled enabled: VpnLogic.pushButtonVpnAddSiteEnabled
background: Rectangle { background: Rectangle {

View file

@ -1,5 +1,6 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0 import ProtocolEnum 1.0
import "../" import "../"
import "../../Controls" import "../../Controls"
@ -10,20 +11,38 @@ PageProtocolBase {
protocol: ProtocolEnum.Cloak protocol: ProtocolEnum.Cloak
logic: UiLogic.protocolLogic(protocol) logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageProtoCloakEnabled enabled: logic.pageEnabled
BackButton { BackButton {
id: back id: back
} }
Item {
x: 0 Caption {
y: 40 id: caption
width: 380 text: qsTr("Cloak Settings")
height: 600 }
ColumnLayout {
id: content
enabled: logic.pageEnabled enabled: logic.pageEnabled
anchors.top: caption.bottom
anchors.left: root.left
anchors.right: root.right
anchors.bottom: pb_save.top
anchors.margins: 20
anchors.topMargin: 10
RowLayout {
Layout.fillWidth: true
LabelType {
height: 31
text: qsTr("Cipher")
Layout.preferredWidth: 0.3 * root.width - 10
}
ComboBoxType { ComboBoxType {
x: 190 Layout.fillWidth: true
y: 60
width: 151
height: 31 height: 31
model: [ model: [
qsTr("chacha20-poly1305"), qsTr("chacha20-poly1305"),
@ -33,92 +52,82 @@ PageProtocolBase {
] ]
currentIndex: { currentIndex: {
for (let i = 0; i < model.length; ++i) { for (let i = 0; i < model.length; ++i) {
if (logic.comboBoxProtoCloakCipherText === model[i]) { if (logic.comboBoxCipherText === model[i]) {
return i return i
} }
} }
return -1 return -1
} }
onCurrentTextChanged: { onCurrentTextChanged: {
logic.comboBoxProtoCloakCipherText = currentText logic.comboBoxCipherText = currentText
} }
} }
}
RowLayout {
Layout.fillWidth: true
LabelType { LabelType {
x: 30 Layout.preferredWidth: 0.3 * root.width - 10
y: 60
width: 151
height: 31 height: 31
text: qsTr("Cipher") text: qsTr("Fake Web Site")
} }
TextFieldType {
id: lineEdit_proto_cloak_site
Layout.fillWidth: true
height: 31
text: logic.lineEditSiteText
onEditingFinished: {
logic.lineEditSiteText = text
}
}
}
RowLayout {
Layout.fillWidth: true
LabelType { LabelType {
x: 30 Layout.preferredWidth: 0.3 * root.width - 10
y: 160
width: 151
height: 31 height: 31
text: qsTr("Port") text: qsTr("Port")
} }
Text {
font.family: "Lato" TextFieldType {
font.styleName: "normal" id: lineEdit_proto_cloak_port
font.pixelSize: 24 Layout.fillWidth: true
color: "#100A44"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: qsTr("Cloak Settings")
x: 20
y: 0
width: 340
height: 30
}
LabelType {
x: 30
y: 110
width: 151
height: 31 height: 31
text: qsTr("Fake Web Site") text: logic.lineEditPortText
onEditingFinished: {
logic.lineEditPortText = text
}
enabled: logic.lineEditPortEnabled
}
}
Item {
Layout.fillHeight: true
}
} }
LabelType { LabelType {
id: label_proto_cloak_info id: label_proto_cloak_info
x: 30 x: 30
y: 550 anchors.bottom: pb_save.top
width: 321 anchors.bottomMargin: 10
height: 41 width: parent.width - 40
visible: logic.labelProtoCloakInfoVisible visible: logic.labelInfoVisible
text: logic.labelProtoCloakInfoText text: logic.labelInfoText
}
TextFieldType {
id: lineEdit_proto_cloak_port
x: 190
y: 160
width: 151
height: 31
text: logic.lineEditProtoCloakPortText
onEditingFinished: {
logic.lineEditProtoCloakPortText = text
}
enabled: logic.lineEditProtoCloakPortEnabled
}
TextFieldType {
id: lineEdit_proto_cloak_site
x: 190
y: 110
width: 151
height: 31
text: logic.lineEditProtoCloakSiteText
onEditingFinished: {
logic.lineEditProtoCloakSiteText = text
}
} }
ProgressBar { ProgressBar {
id: progressBar_proto_cloak_reset id: progressBar_proto_cloak_reset
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: 500 anchors.fill: pb_save
width: 321
height: 40
from: 0 from: 0
to: logic.progressBarProtoCloakResetMaximium to: logic.progressBarResetMaximium
value: logic.progressBarProtoCloakResetValue value: logic.progressBarResetValue
background: Rectangle { background: Rectangle {
implicitWidth: parent.width implicitWidth: parent.width
implicitHeight: parent.height implicitHeight: parent.height
@ -136,18 +145,21 @@ PageProtocolBase {
color: Qt.rgba(255, 255, 255, 0.15); color: Qt.rgba(255, 255, 255, 0.15);
} }
} }
visible: logic.progressBarProtoCloakResetVisible visible: logic.progressBarResetVisible
} }
BlueButtonType { BlueButtonType {
id: pb_save
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: 500 enabled: logic.pageEnabled
width: 321 anchors.bottom: root.bottom
anchors.bottomMargin: 20
width: root.width - 60
height: 40 height: 40
text: qsTr("Save and restart VPN") text: qsTr("Save and restart VPN")
visible: logic.pushButtonCloakSaveVisible visible: logic.pushButtonSaveVisible
onClicked: { onClicked: {
logic.onPushButtonProtoCloakSaveClicked() logic.onPushButtonSaveClicked()
}
} }
} }
} }

View file

@ -338,9 +338,6 @@ PageProtocolBase {
} }
LabelType { LabelType {
id: label_proto_openvpn_info id: label_proto_openvpn_info
@ -349,8 +346,6 @@ PageProtocolBase {
text: logic.labelProtoOpenVpnInfoText text: logic.labelProtoOpenVpnInfoText
} }
Rectangle { Rectangle {
id: it_save id: it_save
implicitWidth: parent.width implicitWidth: parent.width

View file

@ -1,5 +1,6 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0 import ProtocolEnum 1.0
import "../" import "../"
import "../../Controls" import "../../Controls"
@ -10,21 +11,42 @@ PageProtocolBase {
protocol: ProtocolEnum.ShadowSocks protocol: ProtocolEnum.ShadowSocks
logic: UiLogic.protocolLogic(protocol) logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageProtoShadowSocksEnabled enabled: logic.pageEnabled
BackButton { BackButton {
id: back id: back
} }
Item {
x: 0 Caption {
y: 40 id: caption
width: 380 text: qsTr("ShadowSocks Settings")
height: 600 }
ColumnLayout {
id: content
enabled: logic.pageEnabled enabled: logic.pageEnabled
ComboBoxType { anchors.top: caption.bottom
x: 190 anchors.left: root.left
y: 60 anchors.right: root.right
width: 151 anchors.bottom: pb_save.top
anchors.margins: 20
anchors.topMargin: 10
RowLayout {
Layout.fillWidth: true
LabelType {
height: 31 height: 31
text: qsTr("Cipher")
Layout.preferredWidth: 0.3 * root.width - 10
}
ComboBoxType {
height: 31
Layout.fillWidth: true
model: [ model: [
qsTr("chacha20-ietf-poly1305"), qsTr("chacha20-ietf-poly1305"),
qsTr("xchacha20-ietf-poly1305"), qsTr("xchacha20-ietf-poly1305"),
@ -34,71 +56,60 @@ PageProtocolBase {
] ]
currentIndex: { currentIndex: {
for (let i = 0; i < model.length; ++i) { for (let i = 0; i < model.length; ++i) {
if (logic.comboBoxProtoShadowSocksCipherText === model[i]) { if (logic.comboBoxCipherText === model[i]) {
return i return i
} }
} }
return -1 return -1
} }
} }
LabelType {
x: 30
y: 60
width: 151
height: 31
text: qsTr("Cipher")
} }
RowLayout {
Layout.fillWidth: true
LabelType { LabelType {
x: 30 Layout.preferredWidth: 0.3 * root.width - 10
y: 110
width: 151
height: 31 height: 31
text: qsTr("Port") text: qsTr("Port")
} }
Text {
font.family: "Lato" TextFieldType {
font.styleName: "normal" id: lineEdit_proto_shadowsocks_port
font.pixelSize: 24 Layout.fillWidth: true
color: "#100A44" height: 31
horizontalAlignment: Text.AlignHCenter text: logic.lineEditPortText
verticalAlignment: Text.AlignVCenter onEditingFinished: {
text: qsTr("ShadowSocks Settings") logic.lineEditPortText = text
x: 30
y: 0
width: 340
height: 30
} }
enabled: logic.lineEditPortEnabled
}
}
Item {
Layout.fillHeight: true
}
}
LabelType { LabelType {
id: label_proto_shadowsocks_info id: label_proto_shadowsocks_info
x: 30 x: 30
y: 550 anchors.bottom: pb_save.top
width: 321 anchors.bottomMargin: 10
width: parent.width - 40
height: 41 height: 41
visible: logic.labelProtoShadowSocksInfoVisible visible: logic.labelInfoVisible
text: logic.labelProtoShadowSocksInfoText text: logic.labelInfoText
}
TextFieldType {
id: lineEdit_proto_shadowsocks_port
x: 190
y: 110
width: 151
height: 31
text: logic.lineEditProtoShadowSocksPortText
onEditingFinished: {
logic.lineEditProtoShadowSocksPortText = text
}
enabled: logic.lineEditProtoShadowSocksPortEnabled
} }
ProgressBar { ProgressBar {
id: progressBar_proto_shadowsocks_reset id: progressBar_reset
anchors.horizontalCenter: parent.horizontalCenter anchors.fill: pb_save
y: 500
width: 321
height: 40
from: 0 from: 0
to: logic.progressBarProtoShadowSocksResetMaximium to: logic.progressBaResetMaximium
value: logic.progressBarProtoShadowSocksResetValue value: logic.progressBaResetValue
visible: logic.progressBarProtoShadowSocksResetVisible visible: logic.progressBaResetVisible
background: Rectangle { background: Rectangle {
implicitWidth: parent.width implicitWidth: parent.width
implicitHeight: parent.height implicitHeight: parent.height
@ -110,23 +121,26 @@ PageProtocolBase {
implicitWidth: parent.width implicitWidth: parent.width
implicitHeight: parent.height implicitHeight: parent.height
Rectangle { Rectangle {
width: progressBar_proto_shadowsocks_reset.visualPosition * parent.width width: progressBar_reset.visualPosition * parent.width
height: parent.height height: parent.height
radius: 4 radius: 4
color: Qt.rgba(255, 255, 255, 0.15); color: Qt.rgba(255, 255, 255, 0.15);
} }
} }
} }
BlueButtonType { BlueButtonType {
id: pb_save
enabled: logic.pageEnabled
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: 500 anchors.bottom: root.bottom
width: 321 anchors.bottomMargin: 20
width: root.width - 60
height: 40 height: 40
text: qsTr("Save and restart VPN") text: qsTr("Save and restart VPN")
visible: logic.pushButtonShadowSocksSaveVisible visible: logic.pushButtonSaveVisible
onClicked: { onClicked: {
logic.onPushButtonProtoShadowSocksSaveClicked() logic.onPushButtonSaveClicked()
}
} }
} }
} }

View file

@ -0,0 +1,133 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.Any
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share for Amnezia")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height + 20
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Text {
id: lb_desc
Layout.fillWidth: true
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
color: "#181922"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
text: ShareConnectionLogic.shareFullAccess
? qsTr("Anyone who logs in with this code will have the same permissions to use VPN and YOUR SERVER as you. \n
This code includes your server credentials!\n
Provide this code only to TRUSTED users.")
: qsTr("Anyone who logs in with this code will be able to connect to this VPN server. \n
This code does not include server credentials.\n
New encryption keys pair will be generated.")
}
ShareConnectionButtonType {
Layout.topMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: 40
text: ShareConnectionLogic.shareFullAccess
? showConfigText
: (genConfigProcess ? generatingConfigText : generateConfigText)
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareAmneziaGenerateClicked()
enabled = true
genConfigProcess = false
}
}
TextAreaType {
id: tfShareCode
Layout.topMargin: 20
Layout.bottomMargin: 20
Layout.preferredHeight: 200
Layout.fillWidth: true
textArea.readOnly: true
textArea.wrapMode: TextEdit.WrapAnywhere
textArea.verticalAlignment: Text.AlignTop
textArea.text: ShareConnectionLogic.textEditShareAmneziaCodeText
visible: tfShareCode.textArea.length > 0
}
ShareConnectionButtonCopyType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
copyText: tfShareCode.textArea.text
}
ShareConnectionButtonType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: qsTr("Save to file")
enabled: tfShareCode.textArea.length > 0
visible: tfShareCode.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Save AmneziaVPN config"), "*.vpn", tfShareCode.textArea.text)
}
}
Image {
id: label_share_code
Layout.topMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: width
smooth: false
source: ShareConnectionLogic.shareAmneziaQrCodeText
visible: ShareConnectionLogic.shareAmneziaQrCodeText.length > 0
}
LabelType {
height: 20
text: qsTr("Config too long to be displayed as QR code")
visible: ShareConnectionLogic.shareAmneziaQrCodeText.length == 0 && tfShareCode.textArea.length > 0
}
}
}
}

View file

@ -0,0 +1,109 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.Cloak
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share Cloak Settings")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
id: lb_desc
Layout.fillWidth: true
Layout.topMargin: 10
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: qsTr("Note: Cloak protocol using same password for all connections")
}
ShareConnectionButtonType {
Layout.topMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: genConfigProcess ? generatingConfigText : generateConfigText
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareCloakGenerateClicked()
enabled = true
genConfigProcess = false
}
}
TextAreaType {
id: tfShareCode
Layout.topMargin: 20
Layout.bottomMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: 200
textArea.readOnly: true
textArea.text: ShareConnectionLogic.textEditShareCloakText
visible: tfShareCode.textArea.length > 0
}
ShareConnectionButtonCopyType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
copyText: tfShareCode.textArea.text
}
ShareConnectionButtonType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: qsTr("Save to file")
enabled: tfShareCode.textArea.length > 0
visible: tfShareCode.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Save AmneziaVPN config"), "*.json", tfShareCode.textArea.text)
}
}
}
}
}

View file

@ -0,0 +1,140 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.Ikev2
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share IKEv2 Settings")
}
TextAreaType {
id: tfCert
textArea.readOnly: true
textArea.text: ShareConnectionLogic.textEditShareIkev2CertText
visible: false
}
TextAreaType {
id: tfMobileConfig
textArea.readOnly: true
textArea.text: ShareConnectionLogic.textEditShareIkev2MobileConfigText
visible: false
}
TextAreaType {
id: tfStrongSwanConfig
textArea.readOnly: true
textArea.text: ShareConnectionLogic.textEditShareIkev2StrongSwanConfigText
visible: false
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
// LabelType {
// id: lb_desc
// Layout.fillWidth: true
// Layout.topMargin: 10
// horizontalAlignment: Text.AlignHCenter
// wrapMode: Text.Wrap
// text: qsTr("Note: ShadowSocks protocol using same password for all connections")
// }
ShareConnectionButtonType {
Layout.topMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: genConfigProcess ? generatingConfigText : generateConfigText
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareIkev2GenerateClicked()
enabled = true
genConfigProcess = false
}
}
ShareConnectionButtonType {
Layout.topMargin: 30
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
width: parent.width - 60
text: qsTr("Export p12 certificate")
enabled: tfCert.textArea.length > 0
visible: tfCert.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Export p12 certificate"), "*.p12", tfCert.textArea.text)
}
}
ShareConnectionButtonType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
width: parent.width - 60
text: qsTr("Export config for Apple")
enabled: tfMobileConfig.textArea.length > 0
visible: tfMobileConfig.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Export config for Apple"), "*.plist", tfMobileConfig.textArea.text)
}
}
ShareConnectionButtonType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
width: parent.width - 60
text: qsTr("Export config for StrongSwan")
enabled: tfStrongSwanConfig.textArea.length > 0
visible: tfStrongSwanConfig.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Export config for StrongSwan"), "*.profile", tfStrongSwanConfig.textArea.text)
}
}
}
}
}

View file

@ -0,0 +1,106 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.OpenVpn
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share OpenVPN Settings")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
id: lb_desc
Layout.fillWidth: true
Layout.topMargin: 10
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: qsTr("New encryption keys pair will be generated.")
}
ShareConnectionButtonType {
Layout.topMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: 40
text: genConfigProcess ? generatingConfigText : generateConfigText
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareOpenVpnGenerateClicked()
genConfigProcess = false
enabled = true
}
}
TextAreaType {
id: tfShareCode
Layout.topMargin: 20
Layout.preferredHeight: 200
Layout.fillWidth: true
textArea.readOnly: true
textArea.verticalAlignment: Text.AlignTop
textArea.text: ShareConnectionLogic.textEditShareOpenVpnCodeText
visible: tfShareCode.textArea.length > 0
}
ShareConnectionButtonCopyType {
Layout.preferredHeight: 40
Layout.fillWidth: true
copyText: tfShareCode.textArea.text
}
ShareConnectionButtonType {
Layout.bottomMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
width: parent.width - 60
text: qsTr("Save to file")
enabled: tfShareCode.textArea.length > 0
visible: tfShareCode.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Save OpenVPN config"), "*.ovpn", tfShareCode.textArea.text)
}
}
}
}
}

View file

@ -0,0 +1,21 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.Sftp
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share SFTF settings")
}
}

View file

@ -0,0 +1,124 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.ShadowSocks
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share ShadowSocks Settings")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelType {
id: lb_desc
Layout.fillWidth: true
Layout.topMargin: 10
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: qsTr("Note: ShadowSocks protocol using same password for all connections")
}
ShareConnectionButtonType {
Layout.topMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: genConfigProcess ? generatingConfigText : generateConfigText
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareShadowSocksGenerateClicked()
enabled = true
genConfigProcess = false
}
}
TextAreaType {
id: tfShareCode
Layout.topMargin: 20
Layout.preferredHeight: 200
Layout.fillWidth: true
textArea.readOnly: true
textArea.wrapMode: TextEdit.WrapAnywhere
textArea.verticalAlignment: Text.AlignTop
textArea.text: ShareConnectionLogic.textEditShareShadowSocksText
visible: tfShareCode.textArea.length > 0
}
ShareConnectionButtonCopyType {
Layout.preferredHeight: 40
Layout.fillWidth: true
Layout.bottomMargin: 20
start_text: qsTr("Copy config")
copyText: tfShareCode.textArea.text
}
LabelType {
height: 20
visible: tfConnString.length > 0
text: qsTr("Connection string")
}
TextFieldType {
id: tfConnString
height: 100
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: ShareConnectionLogic.lineEditShareShadowSocksStringText
visible: tfConnString.length > 0
readOnly: true
}
ShareConnectionButtonCopyType {
Layout.preferredHeight: 40
Layout.fillWidth: true
start_text: qsTr("Copy string")
copyText: tfConnString.text
}
Image {
id: label_share_ss_qr_code
Layout.topMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: width
smooth: false
source: ShareConnectionLogic.shareShadowSocksQrCodeText
}
}
}
}

View file

@ -0,0 +1,20 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.TorWebSite
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share TOR Web site")
}
}

View file

@ -0,0 +1,112 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageShareProtocolBase {
id: root
protocol: ProtocolEnum.WireGuard
BackButton {
id: back
}
Caption {
id: caption
text: qsTr("Share WireGuard Settings")
}
Flickable {
id: fl
width: root.width
anchors.top: caption.bottom
anchors.topMargin: 20
anchors.bottom: root.bottom
anchors.bottomMargin: 20
anchors.left: root.left
anchors.leftMargin: 30
anchors.right: root.right
anchors.rightMargin: 30
contentHeight: content.height
clip: true
ColumnLayout {
id: content
enabled: logic.pageEnabled
anchors.top: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
LabelType {
id: lb_desc
Layout.fillWidth: true
Layout.topMargin: 10
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: qsTr("New encryption keys pair will be generated.")
}
ShareConnectionButtonType {
Layout.topMargin: 10
Layout.fillWidth: true
Layout.preferredHeight: 40
text: genConfigProcess ? generatingConfigText : generateConfigText
onClicked: {
enabled = false
genConfigProcess = true
ShareConnectionLogic.onPushButtonShareWireGuardGenerateClicked()
enabled = true
genConfigProcess = false
}
}
TextAreaType {
id: tfShareCode
Layout.topMargin: 20
Layout.preferredHeight: 200
Layout.fillWidth: true
textArea.readOnly: true
textArea.wrapMode: TextEdit.WrapAnywhere
textArea.verticalAlignment: Text.AlignTop
textArea.text: ShareConnectionLogic.textEditShareWireGuardCodeText
visible: tfShareCode.textArea.length > 0
}
ShareConnectionButtonCopyType {
Layout.preferredHeight: 40
Layout.fillWidth: true
copyText: tfShareCode.textArea.text
}
ShareConnectionButtonType {
Layout.preferredHeight: 40
Layout.fillWidth: true
text: qsTr("Save to file")
enabled: tfShareCode.textArea.length > 0
visible: tfShareCode.textArea.length > 0
onClicked: {
UiLogic.saveTextFile(qsTr("Save OpenVPN config"), "*.conf", tfShareCode.textArea.text)
}
}
Image {
Layout.topMargin: 20
Layout.fillWidth: true
Layout.preferredHeight: width
smooth: false
source: ShareConnectionLogic.shareWireGuardQrCodeText
}
}
}
}

View file

@ -0,0 +1,19 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import PageEnum 1.0
import ProtocolEnum 1.0
import "./.."
import "../../Controls"
import "../../Config"
PageBase {
id: root
property var protocol: ProtocolEnum.Any
page: PageEnum.ProtocolShare
logic: ShareConnectionLogic
readonly property string generateConfigText: qsTr("Generate config")
readonly property string generatingConfigText: qsTr("Generating config...")
readonly property string showConfigText: qsTr("Show config")
property bool genConfigProcess: false
}

View file

@ -3,17 +3,20 @@ import QtQuick.Window 2.14
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12 import QtQuick.Controls.Material 2.12
import PageEnum 1.0 import PageEnum 1.0
import PageType 1.0
import Qt.labs.platform 1.1 import Qt.labs.platform 1.1
import Qt.labs.folderlistmodel 2.12 import Qt.labs.folderlistmodel 2.12
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import "./" import "./"
import "Pages" import "Pages"
import "Pages/Protocols" import "Pages/Protocols"
import "Pages/Share"
import "Config" import "Config"
Window { Window {
property var pages: ({}) property var pages: ({})
property var protocolPages: ({}) property var protocolPages: ({})
property var sharePages: ({})
id: root id: root
visible: true visible: true
@ -28,73 +31,28 @@ Window {
//flags: Qt.FramelessWindowHint //flags: Qt.FramelessWindowHint
title: "AmneziaVPN" title: "AmneziaVPN"
function gotoPage(page, reset, slide) { function gotoPage(type, page, reset, slide) {
let p_obj;
if (type === PageType.Basic) p_obj = pages[page]
else if (type === PageType.Proto) p_obj = protocolPages[page]
else if (type === PageType.ShareProto) p_obj = sharePages[page]
else return
console.debug("QML gotoPage " + type + " " + page + " " + p_obj)
if (slide) {
pageLoader.push(p_obj, {}, StackView.PushTransition)
} else {
pageLoader.push(p_obj, {}, StackView.Immediate)
}
if (reset) { if (reset) {
if (page === PageEnum.ServerSettings) { p_obj.logic.onUpdatePage();
ServerSettingsLogic.onUpdatePage();
}
if (page === PageEnum.ShareConnection) {
}
if (page === PageEnum.Wizard) {
WizardLogic.radioButtonMediumChecked = true
}
if (page === PageEnum.WizardHigh) {
WizardLogic.onUpdatePage();
}
if (page === PageEnum.ServerConfiguringProgress) {
ServerConfiguringProgressLogic.progressBarValue = 0;
}
if (page === PageEnum.GeneralSettings) {
GeneralSettingsLogic.onUpdatePage();
}
if (page === PageEnum.ServersList) {
ServerListLogic.onUpdatePage();
}
if (page === PageEnum.Start) {
StartPageLogic.pushButtonBackFromStartVisible = !pageLoader.empty
StartPageLogic.onUpdatePage();
}
if (page === PageEnum.NewServerProtocols) {
NewServerProtocolsLogic.onUpdatePage()
}
if (page === PageEnum.ServerContainers) {
ServerContainersLogic.onUpdatePage()
}
if (page === PageEnum.AppSettings) {
AppSettingsLogic.onUpdatePage()
}
if (page === PageEnum.NetworkSettings) {
NetworkSettingsLogic.onUpdatePage()
}
if (page === PageEnum.Sites) {
SitesLogic.updateSitesPage()
}
if (page === PageEnum.Vpn) {
VpnLogic.updateVpnPage()
}
} }
if (slide) { p_obj.activated(reset)
pageLoader.push(pages[page], {}, StackView.PushTransition)
} else {
pageLoader.push(pages[page], {}, StackView.Immediate)
}
pages[page].activated(reset)
}
function gotoProtocolPage(protocol, reset, slide) {
if (reset && protocolPages[protocol] !== "undefined") {
protocolPages[protocol].logic.onUpdatePage();
}
if (slide) {
pageLoader.push(protocolPages[protocol], {}, StackView.PushTransition)
} else {
pageLoader.push(protocolPages[protocol], {}, StackView.Immediate)
}
protocolPages[protocol].activated(reset)
} }
function close_page() { function close_page() {
@ -146,6 +104,8 @@ Window {
color: "white" color: "white"
} }
//PageShareProtoAmnezia {}
StackView { StackView {
id: pageLoader id: pageLoader
y: GC.isDesktop() ? titleBar.height : 0 y: GC.isDesktop() ? titleBar.height : 0
@ -157,6 +117,10 @@ Window {
UiLogic.currentPageValue = currentItem.page UiLogic.currentPageValue = currentItem.page
} }
onDepthChanged: {
UiLogic.pagesStackDepth = depth
}
Keys.onPressed: { Keys.onPressed: {
UiLogic.keyPressEvent(event.key) UiLogic.keyPressEvent(event.key)
event.accepted = true event.accepted = true
@ -171,7 +135,7 @@ Window {
onStatusChanged: if (status == FolderListModel.Ready) { onStatusChanged: if (status == FolderListModel.Ready) {
for (var i=0; i<folderModelPages.count; i++) { for (var i=0; i<folderModelPages.count; i++) {
createPagesObjects(folderModelPages.get(i, "filePath"), false); createPagesObjects(folderModelPages.get(i, "filePath"), PageType.Basic);
} }
UiLogic.initalizeUiLogic() UiLogic.initalizeUiLogic()
} }
@ -185,40 +149,56 @@ Window {
onStatusChanged: if (status == FolderListModel.Ready) { onStatusChanged: if (status == FolderListModel.Ready) {
for (var i=0; i<folderModelProtocols.count; i++) { for (var i=0; i<folderModelProtocols.count; i++) {
createPagesObjects(folderModelProtocols.get(i, "filePath"), true); createPagesObjects(folderModelProtocols.get(i, "filePath"), PageType.Proto);
} }
} }
} }
function createPagesObjects(file, isProtocol) { FolderListModel {
id: folderModelShareProtocols
folder: "qrc:/ui/qml/Pages/Share/"
nameFilters: ["*.qml"]
showDirs: false
onStatusChanged: if (status == FolderListModel.Ready) {
for (var i=0; i<folderModelShareProtocols.count; i++) {
createPagesObjects(folderModelShareProtocols.get(i, "filePath"), PageType.ShareProto);
}
}
}
function createPagesObjects(file, type) {
if (file.indexOf("Base") !== -1) return; // skip Base Pages if (file.indexOf("Base") !== -1) return; // skip Base Pages
//console.debug("Creating compenent " + file + " for " + type);
var c = Qt.createComponent("qrc" + file); var c = Qt.createComponent("qrc" + file);
var finishCreation = function (component){ var finishCreation = function (component){
if (component.status == Component.Ready) { if (component.status === Component.Ready) {
var obj = component.createObject(root); var obj = component.createObject(root);
if (obj == null) { if (obj === null) {
console.debug("Error creating object " + component.url); console.debug("Error creating object " + component.url);
} }
else { else {
obj.visible = false obj.visible = false
if (isProtocol) { if (type === PageType.Basic) {
protocolPages[obj.protocol] = obj
}
else {
pages[obj.page] = obj pages[obj.page] = obj
} }
else if (type === PageType.Proto) {
protocolPages[obj.protocol] = obj
} }
} else if (component.status == Component.Error) { else if (type === PageType.ShareProto) {
sharePages[obj.protocol] = obj
}
//console.debug("Created compenent " + component.url + " for " + type);
}
} else if (component.status === Component.Error) {
console.debug("Error loading component:", component.errorString()); console.debug("Error loading component:", component.errorString());
} }
} }
if (c.status == Component.Ready) if (c.status === Component.Ready)
finishCreation(c); finishCreation(c);
else { else {
console.debug("Warning: Pages components are not ready"); console.debug("Warning: Pages components are not ready");
@ -228,13 +208,19 @@ Window {
Connections { Connections {
target: UiLogic target: UiLogic
function onGoToPage(page, reset, slide) { function onGoToPage(page, reset, slide) {
console.debug("Connections onGoToPage " + page); console.debug("Qml Connections onGoToPage " + page);
root.gotoPage(page, reset, slide) root.gotoPage(PageType.Basic, page, reset, slide)
} }
function onGoToProtocolPage(protocol, reset, slide) { function onGoToProtocolPage(protocol, reset, slide) {
console.debug("Connections onGoToProtocolPage " + protocol); console.debug("Qml Connections onGoToProtocolPage " + protocol);
root.gotoProtocolPage(protocol, reset, slide) root.gotoPage(PageType.Proto, protocol, reset, slide)
} }
function onGoToShareProtocolPage(protocol, reset, slide) {
console.debug("Qml Connections onGoToShareProtocolPage " + protocol);
root.gotoPage(PageType.ShareProto, protocol, reset, slide)
}
function onClosePage() { function onClosePage() {
root.close_page() root.close_page()
} }
@ -253,6 +239,11 @@ Window {
function onHide() { function onHide() {
root.hide() root.hide()
} }
function onRaise() {
root.show()
root.raise()
root.requestActivate()
}
} }
MessageDialog { MessageDialog {
@ -267,62 +258,6 @@ Window {
} }
visible: false visible: false
} }
SystemTrayIcon {
visible: true
icon.source: UiLogic.trayIconUrl
onActivated: {
if (Qt.platform.os == "osx" ||
Qt.platform.os == "linux") {
if (reason === SystemTrayIcon.DoubleClick ||
reason === SystemTrayIcon.Trigger) {
root.show()
root.raise()
root.requestActivate()
}
}
}
menu: Menu {
MenuItem {
iconSource: "qrc:/images/tray/application.png"
text: qsTr("Show") + " " + "AmneziaVPN"
onTriggered: {
root.show()
root.raise()
}
}
MenuSeparator { }
MenuItem {
text: qsTr("Connect")
enabled: UiLogic.trayActionConnectEnabled
onTriggered: {
UiLogic.onConnect()
}
}
MenuItem {
text: qsTr("Disconnect")
enabled: UiLogic.trayActionDisconnectEnabled
onTriggered: {
UiLogic.onDisconnect()
}
}
MenuSeparator { }
MenuItem {
iconSource: "qrc:/images/tray/link.png"
text: qsTr("Visit Website")
onTriggered: {
Qt.openUrlExternally("https://amnezia.org")
}
}
MenuItem {
iconSource: "qrc:/images/tray/cancel.png"
text: qsTr("Quit") + " " + "AmneziaVPN"
onTriggered: {
closePrompt.open()
}
}
}
}
MessageDialog { MessageDialog {
id: publicKeyWarning id: publicKeyWarning
title: "AmneziaVPN" title: "AmneziaVPN"

View file

@ -69,15 +69,13 @@ using namespace PageEnumNS;
UiLogic::UiLogic(QObject *parent) : UiLogic::UiLogic(QObject *parent) :
QObject(parent), QObject(parent),
m_currentPageValue{0},
m_trayIconUrl{},
m_trayActionDisconnectEnabled{true},
m_trayActionConnectEnabled{true},
m_dialogConnectErrorText{} m_dialogConnectErrorText{}
{ {
m_containersModel = new ContainersModel(this); m_containersModel = new ContainersModel(this);
m_protocolsModel = new ProtocolsModel(this); m_protocolsModel = new ProtocolsModel(this);
m_vpnConnection = new VpnConnection(this); m_vpnConnection = new VpnConnection();
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
m_appSettingsLogic = new AppSettingsLogic(this); m_appSettingsLogic = new AppSettingsLogic(this);
m_generalSettingsLogic = new GeneralSettingsLogic(this); m_generalSettingsLogic = new GeneralSettingsLogic(this);
@ -104,6 +102,30 @@ UiLogic::UiLogic(QObject *parent) :
} }
UiLogic::~UiLogic()
{
m_tray = nullptr;
emit hide();
if (m_vpnConnection->connectionState() != VpnProtocol::ConnectionState::Disconnected) {
m_vpnConnection->disconnectFromVpn();
for (int i = 0; i < 50; i++) {
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(100);
if (m_vpnConnection->isDisconnected()) {
break;
}
}
}
m_vpnConnectionThread.quit();
m_vpnConnectionThread.wait(3000);
delete m_vpnConnection;
qDebug() << "Application closed";
}
void UiLogic::initalizeUiLogic() void UiLogic::initalizeUiLogic()
{ {
qDebug() << "UiLogic::initalizeUiLogic()"; qDebug() << "UiLogic::initalizeUiLogic()";
@ -168,86 +190,8 @@ void UiLogic::initalizeUiLogic()
// ui->lineEdit_proto_shadowsocks_port->setValidator(&m_ipPortValidator); // ui->lineEdit_proto_shadowsocks_port->setValidator(&m_ipPortValidator);
// ui->lineEdit_proto_cloak_port->setValidator(&m_ipPortValidator); // ui->lineEdit_proto_cloak_port->setValidator(&m_ipPortValidator);
} }
int UiLogic::getCurrentPageValue() const
{
return m_currentPageValue;
}
void UiLogic::setCurrentPageValue(int currentPageValue)
{
if (m_currentPageValue != currentPageValue) {
m_currentPageValue = currentPageValue;
emit currentPageValueChanged();
}
}
QString UiLogic::getTrayIconUrl() const
{
return m_trayIconUrl;
}
void UiLogic::setTrayIconUrl(const QString &trayIconUrl)
{
if (m_trayIconUrl != trayIconUrl) {
m_trayIconUrl = trayIconUrl;
emit trayIconUrlChanged();
}
}
bool UiLogic::getTrayActionDisconnectEnabled() const
{
return m_trayActionDisconnectEnabled;
}
void UiLogic::setTrayActionDisconnectEnabled(bool trayActionDisconnectEnabled)
{
if (m_trayActionDisconnectEnabled != trayActionDisconnectEnabled) {
m_trayActionDisconnectEnabled = trayActionDisconnectEnabled;
emit trayActionDisconnectEnabledChanged();
}
}
bool UiLogic::getTrayActionConnectEnabled() const
{
return m_trayActionConnectEnabled;
}
void UiLogic::setTrayActionConnectEnabled(bool trayActionConnectEnabled)
{
if (m_trayActionConnectEnabled != trayActionConnectEnabled) {
m_trayActionConnectEnabled = trayActionConnectEnabled;
emit trayActionConnectEnabledChanged();
}
}
QString UiLogic::getDialogConnectErrorText() const QString UiLogic::getDialogConnectErrorText() const
{ {
return m_dialogConnectErrorText; return m_dialogConnectErrorText;
@ -261,24 +205,6 @@ void UiLogic::setDialogConnectErrorText(const QString &dialogConnectErrorText)
} }
} }
UiLogic::~UiLogic()
{
hide();
m_vpnConnection->disconnectFromVpn();
for (int i = 0; i < 50; i++) {
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(100);
if (m_vpnConnection->isDisconnected()) {
break;
}
}
delete m_vpnConnection;
qDebug() << "Application closed";
}
void UiLogic::showOnStartup() void UiLogic::showOnStartup()
{ {
if (! m_settings.isStartMinimized()) { if (! m_settings.isStartMinimized()) {
@ -290,6 +216,26 @@ void UiLogic::showOnStartup()
} }
} }
void UiLogic::onUpdateAllPages()
{
for (PageLogicBase *logic : {
(PageLogicBase *) m_appSettingsLogic,
(PageLogicBase *) m_generalSettingsLogic,
(PageLogicBase *) m_networkSettingsLogic,
(PageLogicBase *) m_serverConfiguringProgressLogic,
(PageLogicBase *) m_newServerProtocolsLogic,
(PageLogicBase *) m_serverListLogic,
(PageLogicBase *) m_serverSettingsLogic,
(PageLogicBase *) m_serverVpnProtocolsLogic,
(PageLogicBase *) m_shareConnectionLogic,
(PageLogicBase *) m_sitesLogic,
(PageLogicBase *) m_startPageLogic,
(PageLogicBase *) m_vpnLogic,
(PageLogicBase *) m_wizardLogic
}) {
logic->onUpdatePage();
}
}
void UiLogic::keyPressEvent(Qt::Key key) void UiLogic::keyPressEvent(Qt::Key key)
{ {
@ -326,9 +272,7 @@ void UiLogic::keyPressEvent(Qt::Key key)
emit goToPage(Page::ServerSettings); emit goToPage(Page::ServerSettings);
break; break;
case Qt::Key_P: case Qt::Key_P:
selectedServerIndex = m_settings.defaultServerIndex(); onGotoCurrentProtocolsPage();
selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex);
emit goToPage(Page::ServerContainers);
break; break;
case Qt::Key_T: case Qt::Key_T:
SshConfigurator::openSshTerminal(m_settings.serverCredentials(m_settings.defaultServerIndex())); SshConfigurator::openSshTerminal(m_settings.serverCredentials(m_settings.defaultServerIndex()));
@ -371,6 +315,13 @@ QString UiLogic::containerDesc(int container)
} }
void UiLogic::onGotoCurrentProtocolsPage()
{
selectedServerIndex = m_settings.defaultServerIndex();
selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex);
emit goToPage(Page::ServerContainers);
}
//void UiLogic::showEvent(QShowEvent *event) //void UiLogic::showEvent(QShowEvent *event)
@ -650,12 +601,22 @@ ErrorCode UiLogic::doInstallAction(const std::function<ErrorCode()> &action,
void UiLogic::setupTray() void UiLogic::setupTray()
{ {
m_tray = new QSystemTrayIcon(qmlRoot());
setTrayState(VpnProtocol::Disconnected); setTrayState(VpnProtocol::Disconnected);
m_tray->show();
connect(m_tray, &QSystemTrayIcon::activated, this, &UiLogic::onTrayActivated);
} }
void UiLogic::setTrayIcon(const QString &iconPath) void UiLogic::setTrayIcon(const QString &iconPath)
{ {
setTrayIconUrl(iconPath); if (m_tray) m_tray->setIcon(QIcon(QPixmap(iconPath).scaled(128,128)));
}
void UiLogic::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
emit raise();
} }
PageProtocolLogicBase *UiLogic::protocolLogic(Protocol p) { PageProtocolLogicBase *UiLogic::protocolLogic(Protocol p) {
@ -667,17 +628,24 @@ PageProtocolLogicBase *UiLogic::protocolLogic(Protocol p) {
} }
} }
QObject *UiLogic::qmlRoot() const
{
return m_qmlRoot;
}
void UiLogic::setQmlRoot(QObject *newQmlRoot)
{
m_qmlRoot = newQmlRoot;
}
PageEnumNS::Page UiLogic::currentPage() PageEnumNS::Page UiLogic::currentPage()
{ {
return static_cast<PageEnumNS::Page>(getCurrentPageValue()); return static_cast<PageEnumNS::Page>(currentPageValue());
} }
void UiLogic::setTrayState(VpnProtocol::ConnectionState state) void UiLogic::setTrayState(VpnProtocol::ConnectionState state)
{ {
QString resourcesPath = "qrc:/images/tray/%1"; QString resourcesPath = ":/images/tray/%1";
setTrayActionDisconnectEnabled(state == VpnProtocol::Connected);
setTrayActionConnectEnabled(state == VpnProtocol::Disconnected);
switch (state) { switch (state) {
case VpnProtocol::Disconnected: case VpnProtocol::Disconnected:
@ -713,8 +681,40 @@ void UiLogic::setTrayState(VpnProtocol::ConnectionState state)
// resourcesPath = ":/images_mac/tray_icon/%1"; // resourcesPath = ":/images_mac/tray_icon/%1";
// useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png"); // useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
//#endif //#endif
} }
bool UiLogic::saveTextFile(const QString& desc, const QString& ext, const QString& data)
{
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(data.toUtf8());
QFileInfo fi(fileName);
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
return save.commit();
}
bool UiLogic::saveBinaryFile(const QString &desc, const QString &ext, const QString &data)
{
QString fileName = QFileDialog::getSaveFileName(nullptr, desc,
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), ext);
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(QByteArray::fromBase64(data.toUtf8()));
QFileInfo fi(fileName);
QDesktopServices::openUrl(fi.absoluteDir().absolutePath());
return save.commit();
}
void UiLogic::copyToClipboard(const QString &text)
{
qApp->clipboard()->setText(text);
}

View file

@ -5,6 +5,8 @@
#include <QQmlEngine> #include <QQmlEngine>
#include <functional> #include <functional>
#include <QKeyEvent> #include <QKeyEvent>
#include <QThread>
#include <QSystemTrayIcon>
#include "property_helper.h" #include "property_helper.h"
#include "pages.h" #include "pages.h"
@ -45,15 +47,13 @@ class UiLogic : public QObject
Q_OBJECT Q_OBJECT
AUTO_PROPERTY(bool, pageEnabled) AUTO_PROPERTY(bool, pageEnabled)
AUTO_PROPERTY(int, pagesStackDepth)
AUTO_PROPERTY(int, currentPageValue)
READONLY_PROPERTY(QObject *, containersModel) READONLY_PROPERTY(QObject *, containersModel)
READONLY_PROPERTY(QObject *, protocolsModel) READONLY_PROPERTY(QObject *, protocolsModel)
Q_PROPERTY(int currentPageValue READ getCurrentPageValue WRITE setCurrentPageValue NOTIFY currentPageValueChanged) // TODO: review
Q_PROPERTY(QString trayIconUrl READ getTrayIconUrl WRITE setTrayIconUrl NOTIFY trayIconUrlChanged)
Q_PROPERTY(bool trayActionDisconnectEnabled READ getTrayActionDisconnectEnabled WRITE setTrayActionDisconnectEnabled NOTIFY trayActionDisconnectEnabledChanged)
Q_PROPERTY(bool trayActionConnectEnabled READ getTrayActionConnectEnabled WRITE setTrayActionConnectEnabled NOTIFY trayActionConnectEnabledChanged)
Q_PROPERTY(QString dialogConnectErrorText READ getDialogConnectErrorText WRITE setDialogConnectErrorText NOTIFY dialogConnectErrorTextChanged) Q_PROPERTY(QString dialogConnectErrorText READ getDialogConnectErrorText WRITE setDialogConnectErrorText NOTIFY dialogConnectErrorTextChanged)
public: public:
@ -82,6 +82,9 @@ public:
friend class OtherProtocolsLogic; friend class OtherProtocolsLogic;
Q_INVOKABLE virtual void onUpdatePage() {} // UiLogic is set as logic class for some qml pages
Q_INVOKABLE void onUpdateAllPages();
Q_INVOKABLE void initalizeUiLogic(); Q_INVOKABLE void initalizeUiLogic();
Q_INVOKABLE void onCloseWindow(); Q_INVOKABLE void onCloseWindow();
@ -90,24 +93,20 @@ public:
Q_INVOKABLE void onGotoPage(PageEnumNS::Page p, bool reset = true, bool slide = true) { emit goToPage(p, reset, slide); } Q_INVOKABLE void onGotoPage(PageEnumNS::Page p, bool reset = true, bool slide = true) { emit goToPage(p, reset, slide); }
Q_INVOKABLE void onGotoProtocolPage(Protocol p, bool reset = true, bool slide = true) { emit goToProtocolPage(p, reset, slide); } Q_INVOKABLE void onGotoProtocolPage(Protocol p, bool reset = true, bool slide = true) { emit goToProtocolPage(p, reset, slide); }
Q_INVOKABLE void onGotoShareProtocolPage(Protocol p, bool reset = true, bool slide = true) { emit goToShareProtocolPage(p, reset, slide); }
Q_INVOKABLE void onGotoCurrentProtocolsPage();
Q_INVOKABLE void keyPressEvent(Qt::Key key); Q_INVOKABLE void keyPressEvent(Qt::Key key);
Q_INVOKABLE bool saveTextFile(const QString& desc, const QString& ext, const QString& data);
int getCurrentPageValue() const; Q_INVOKABLE bool saveBinaryFile(const QString& desc, const QString& ext, const QString& data);
void setCurrentPageValue(int currentPageValue); Q_INVOKABLE void copyToClipboard(const QString& text);
QString getTrayIconUrl() const;
void setTrayIconUrl(const QString &trayIconUrl);
bool getTrayActionDisconnectEnabled() const;
void setTrayActionDisconnectEnabled(bool trayActionDisconnectEnabled);
bool getTrayActionConnectEnabled() const;
void setTrayActionConnectEnabled(bool trayActionConnectEnabled);
QString getDialogConnectErrorText() const; QString getDialogConnectErrorText() const;
void setDialogConnectErrorText(const QString &dialogConnectErrorText); void setDialogConnectErrorText(const QString &dialogConnectErrorText);
signals: signals:
void currentPageValueChanged();
void trayIconUrlChanged(); void trayIconUrlChanged();
void trayActionDisconnectEnabledChanged(); void trayActionDisconnectEnabledChanged();
void trayActionConnectEnabledChanged(); void trayActionConnectEnabledChanged();
@ -116,18 +115,18 @@ signals:
void goToPage(PageEnumNS::Page page, bool reset = true, bool slide = true); void goToPage(PageEnumNS::Page page, bool reset = true, bool slide = true);
void goToProtocolPage(Protocol protocol, bool reset = true, bool slide = true); void goToProtocolPage(Protocol protocol, bool reset = true, bool slide = true);
void goToShareProtocolPage(Protocol protocol, bool reset = true, bool slide = true);
void closePage(); void closePage();
void setStartPage(PageEnumNS::Page page, bool slide = true); void setStartPage(PageEnumNS::Page page, bool slide = true);
void showPublicKeyWarning(); void showPublicKeyWarning();
void showConnectErrorDialog(); void showConnectErrorDialog();
void show(); void show();
void hide(); void hide();
void raise();
private: private:
int m_currentPageValue; QSystemTrayIcon *m_tray;
QString m_trayIconUrl;
bool m_trayActionDisconnectEnabled;
bool m_trayActionConnectEnabled;
QString m_dialogConnectErrorText; QString m_dialogConnectErrorText;
@ -136,6 +135,7 @@ private slots:
void installServer(QMap<DockerContainer, QJsonObject> &containers); void installServer(QMap<DockerContainer, QJsonObject> &containers);
void setTrayState(VpnProtocol::ConnectionState state); void setTrayState(VpnProtocol::ConnectionState state);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
private: private:
PageEnumNS::Page currentPage(); PageEnumNS::Page currentPage();
@ -192,7 +192,12 @@ public:
Q_INVOKABLE PageProtocolLogicBase *protocolLogic(Protocol p); Q_INVOKABLE PageProtocolLogicBase *protocolLogic(Protocol p);
QObject *qmlRoot() const;
void setQmlRoot(QObject *newQmlRoot);
private: private:
QObject *m_qmlRoot{nullptr};
AppSettingsLogic *m_appSettingsLogic; AppSettingsLogic *m_appSettingsLogic;
GeneralSettingsLogic *m_generalSettingsLogic; GeneralSettingsLogic *m_generalSettingsLogic;
NetworkSettingsLogic *m_networkSettingsLogic; NetworkSettingsLogic *m_networkSettingsLogic;
@ -210,6 +215,7 @@ private:
QMap<Protocol, PageProtocolLogicBase *> m_protocolLogicMap; QMap<Protocol, PageProtocolLogicBase *> m_protocolLogicMap;
VpnConnection* m_vpnConnection; VpnConnection* m_vpnConnection;
QThread m_vpnConnectionThread;
Settings m_settings; Settings m_settings;

View file

@ -23,12 +23,7 @@
VpnConnection::VpnConnection(QObject* parent) : QObject(parent) VpnConnection::VpnConnection(QObject* parent) : QObject(parent)
{ {
QTimer::singleShot(0, this, [this](){
if (!IpcClient::init()) {
qWarning() << "Error occured when init IPC client";
emit serviceIsNotReady();
}
});
} }
VpnConnection::~VpnConnection() VpnConnection::~VpnConnection()
@ -190,10 +185,6 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
for (ProtocolEnumNS::Protocol proto : ContainerProps::protocolsForContainer(container)) { for (ProtocolEnumNS::Protocol proto : ContainerProps::protocolsForContainer(container)) {
// QString vpnConfigData =
// createVpnConfigurationForProto(
// serverIndex, credentials, container, containerConfig, proto, &e);
QJsonObject vpnConfigData = QJsonDocument::fromJson( QJsonObject vpnConfigData = QJsonDocument::fromJson(
createVpnConfigurationForProto( createVpnConfigurationForProto(
serverIndex, credentials, container, containerConfig, proto, &e).toUtf8()). serverIndex, credentials, container, containerConfig, proto, &e).toUtf8()).
@ -205,7 +196,6 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
} }
vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData); vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData);
} }
Protocol proto = ContainerProps::defaultProtocol(container); Protocol proto = ContainerProps::defaultProtocol(container);
@ -214,11 +204,27 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
return vpnConfiguration; return vpnConfiguration;
} }
ErrorCode VpnConnection::connectToVpn(int serverIndex, void VpnConnection::connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig) const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{ {
qDebug() << QString("СonnectToVpn, Server index is %1, container is %2, route mode is") qDebug() << QString("СonnectToVpn, Server index is %1, container is %2, route mode is")
.arg(serverIndex).arg(ContainerProps::containerToString(container)) << m_settings.routeMode(); .arg(serverIndex).arg(ContainerProps::containerToString(container)) << m_settings.routeMode();
#if !defined (Q_OS_ANDROID) && !defined (Q_OS_IOS)
if (!m_IpcClient) {
m_IpcClient = new IpcClient;
}
if (!m_IpcClient->isSocketConnected()) {
if (!IpcClient::init(m_IpcClient)) {
qWarning() << "Error occured when init IPC client";
emit serviceIsNotReady();
emit connectionStateChanged(VpnProtocol::Error);
return;
}
}
#endif
m_remoteAddress = credentials.hostName; m_remoteAddress = credentials.hostName;
emit connectionStateChanged(VpnProtocol::Connecting); emit connectionStateChanged(VpnProtocol::Connecting);
@ -233,26 +239,26 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex,
m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig); m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig);
if (e) { if (e) {
emit connectionStateChanged(VpnProtocol::Error); emit connectionStateChanged(VpnProtocol::Error);
return e; return;
} }
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration)); m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration));
if (!m_vpnProtocol) { if (!m_vpnProtocol) {
return ErrorCode::InternalError; emit VpnProtocol::Error;
return;
} }
m_vpnProtocol->prepare(); m_vpnProtocol->prepare();
#else #else
Protocol proto = ContainerProps::defaultProtocol(container); Protocol proto = ContainerProps::defaultProtocol(container);
AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration); AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration);
if (!androidVpnProtocol->initialize()) { if (!androidVpnProtocol->initialize()) {
qDebug() << QString("Init failed") ; qDebug() << QString("Init failed") ;
return UnknownError; emit VpnProtocol::Error;
return;
} }
m_vpnProtocol.reset(androidVpnProtocol); m_vpnProtocol.reset(androidVpnProtocol);
#endif #endif
@ -263,7 +269,8 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex,
ServerController::disconnectFromHost(credentials); ServerController::disconnectFromHost(credentials);
return m_vpnProtocol.data()->start(); e = m_vpnProtocol.data()->start();
if (e) emit VpnProtocol::Error;
} }
QString VpnConnection::bytesPerSecToText(quint64 bytes) QString VpnConnection::bytesPerSecToText(quint64 bytes)

View file

@ -34,10 +34,7 @@ public:
const ServerCredentials &credentials, DockerContainer container, const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ErrorCode connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
bool isConnected() const; bool isConnected() const;
bool isDisconnected() const; bool isDisconnected() const;
@ -51,6 +48,12 @@ public:
const QString &remoteAddress() const; const QString &remoteAddress() const;
public slots:
void connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
signals: signals:
void bytesChanged(quint64 receivedBytes, quint64 sentBytes); void bytesChanged(quint64 receivedBytes, quint64 sentBytes);
void connectionStateChanged(VpnProtocol::ConnectionState state); void connectionStateChanged(VpnProtocol::ConnectionState state);
@ -70,6 +73,7 @@ private:
QJsonObject m_vpnConfiguration; QJsonObject m_vpnConfiguration;
QJsonObject m_routeMode; QJsonObject m_routeMode;
QString m_remoteAddress; QString m_remoteAddress;
IpcClient *m_IpcClient {nullptr};
}; };

View file

@ -82,6 +82,7 @@ signtool sign /v /sm /s My /n "Privacy Technologies OU" /fd sha256 /tr http://ti
echo "Copying deploy data..." echo "Copying deploy data..."
xcopy %DEPLOY_DATA_DIR% %OUT_APP_DIR% /s /e /y /i /f xcopy %DEPLOY_DATA_DIR% %OUT_APP_DIR% /s /e /y /i /f
copy "%WORK_DIR:"=%\service\wireguard-service\release\wireguard-service.exe" %OUT_APP_DIR%\wireguard\
del %OUT_APP_DIR%\botand.dll del %OUT_APP_DIR%\botand.dll

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -4,4 +4,7 @@
include(common.pri) include(common.pri)
qtservice-uselib:SUBDIRS=buildlib qtservice-uselib:SUBDIRS=buildlib
SUBDIRS+=server SUBDIRS+=server
win32 {
SUBDIRS+=wireguard-service
}
} }

View file

@ -0,0 +1,31 @@
#include "wireguardtunnelservice.h"
#include <strsafe.h>
#include <Windows.h>
int wmain(int argc, wchar_t** argv)
{
if (argc != 3) {
debug_log(L"Wrong argument provided");
return 1;
}
TCHAR option[20];
TCHAR configFile[5000];
StringCchCopy(option, 20, argv[1]);
StringCchCopy(configFile, 5000, argv[2]);
WireguardTunnelService tunnel(configFile);
if (lstrcmpi(option, TEXT("--run")) == 0) {
debug_log(L"start tunnel");
tunnel.startTunnel();
} else if (lstrcmpi(option, TEXT("--add")) == 0) {
tunnel.addService();
} else if (lstrcmpi(option, TEXT("--remove")) == 0) {
tunnel.removeService();
} else {
debug_log(L"Wrong argument provided");
return 1;
}
return 0;
}

View file

@ -0,0 +1,23 @@
TARGET = wireguard-service
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
LIBS += \
-luser32 \
-lrasapi32 \
-lshlwapi \
-liphlpapi \
-lws2_32 \
-liphlpapi \
-lgdi32 \
-lAdvapi32 \
-lKernel32
HEADERS = \
wireguardtunnelservice.h
SOURCES = \
main.cpp \
wireguardtunnelservice.cpp

View file

@ -0,0 +1,160 @@
#include "wireguardtunnelservice.h"
#include <Windows.h>
#include <thread>
#include <chrono>
#include <strsafe.h>
#include <iostream>
#include <fstream>
#include <stdint.h>
void debug_log(const std::wstring& msg)
{
std::wcerr << msg << std::endl;
}
WireguardTunnelService::WireguardTunnelService(const std::wstring& configFile):
m_configFile{configFile}
{
}
void WireguardTunnelService::addService()
{
SC_HANDLE scm;
SC_HANDLE service;
scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == scm) {
debug_log(L"OpenSCManager failed");
return;
}
WCHAR szFileName[MAX_PATH];
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
std::wstring runCommand = szFileName;
runCommand += TEXT(" --run ");
runCommand += m_configFile;
debug_log(runCommand);
// check if service is already running
service = OpenServiceW(
scm,
SVCNAME,
SERVICE_ALL_ACCESS
);
if (NULL != service) {
//service is already running, remove it before add new service
debug_log(L"service is already running, remove it before add new service");
CloseServiceHandle(service);
removeService();
}
service = CreateServiceW(
scm,
SVCNAME,
SVCNAME,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
runCommand.c_str(),
NULL,
NULL,
TEXT("Nsi\0TcpIp"),
NULL,
NULL);
if (NULL == service) {
debug_log(L"CreateServiceW failed");
CloseServiceHandle(scm);
return;
}
SERVICE_SID_INFO info;
info.dwServiceSidType = SERVICE_SID_TYPE_UNRESTRICTED;
if (ChangeServiceConfig2W(service,
SERVICE_CONFIG_SERVICE_SID_INFO,
&info) == 0) {
debug_log(L"ChangeServiceConfig2 failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
if (StartServiceW(service, 0, NULL) == 0) {
debug_log(L"StartServiceW failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
if (DeleteService(service) == 0) {
debug_log(L"DeleteService failed");
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
void WireguardTunnelService::removeService()
{
SC_HANDLE scm;
SC_HANDLE service;
scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == scm) {
debug_log(L"OpenSCManager failed");
return;
}
service = OpenServiceW(
scm,
SVCNAME,
SERVICE_ALL_ACCESS
);
if (NULL == service) {
debug_log(L"OpenServiceW failed");
CloseServiceHandle(scm);
return;
}
SERVICE_STATUS stt;
if (ControlService(service, SERVICE_CONTROL_STOP, &stt) == 0) {
debug_log(L"ControlService failed");
DeleteService(service);
CloseServiceHandle(service);
CloseServiceHandle(scm);
return;
}
for (int i = 0;
i < 180 && QueryServiceStatus(scm, &stt) && stt.dwCurrentState != SERVICE_STOPPED;
++i) {
std::this_thread::sleep_for(std::chrono::seconds{1});
}
DeleteService(service);
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
int WireguardTunnelService::startTunnel()
{
debug_log(TEXT(__FUNCTION__));
HMODULE tunnelLib = LoadLibrary(TEXT("tunnel.dll"));
if (!tunnelLib) {
debug_log(L"Failed to load tunnel.dll");
return 1;
}
typedef bool WireGuardTunnelService(const LPCWSTR settings);
WireGuardTunnelService* tunnelProc = (WireGuardTunnelService*)GetProcAddress(
tunnelLib, "WireGuardTunnelService");
if (!tunnelProc) {
debug_log(L"Failed to get WireGuardTunnelService function");
return 1;
}
debug_log(m_configFile.c_str());
if (!tunnelProc(m_configFile.c_str())) {
debug_log(L"Failed to activate the tunnel service");
return 1;
}
return 0;
}

View file

@ -0,0 +1,22 @@
#ifndef WIREGUARDTUNNELSERVICE_H
#define WIREGUARDTUNNELSERVICE_H
#include <Windows.h>
#include <string>
#define SVCNAME TEXT("AmneziaVPNWireGuardService")
class WireguardTunnelService
{
public:
WireguardTunnelService(const std::wstring& configFile);
void addService();
void removeService();
int startTunnel();
private:
std::wstring m_configFile;
};
void debug_log(const std::wstring& msg);
#endif // WIREGUARDTUNNELSERVICE_H