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
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;
@ -746,7 +746,7 @@ bool CQR_Encode::EncodeData(int nLevel, int nVersion, bool bAutoExtent, int nMas
/////////////////////////////////////////////////////////////////////////////
// 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 i, j;
@ -788,7 +788,7 @@ int CQR_Encode::GetEncodeVersion(int nVersion, char* lpsSource, int ncLength)
/////////////////////////////////////////////////////////////////////////////
// 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));

View file

@ -92,11 +92,11 @@ private:
unsigned char m_byRSWork[MAX_CODEBLOCK];
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:
int GetEncodeVersion(int nVersion, char* lpsSource, int ncLength);
bool EncodeSourceData(char* lpsSource, int ncLength, int nVerGroup);
int GetEncodeVersion(int nVersion, const char* lpsSource, int ncLength);
bool EncodeSourceData(const char* lpsSource, int ncLength, int nVerGroup);
int GetBitLength(unsigned char nMode, int ncData, int nVerGroup);

View file

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

View file

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

View file

@ -6,6 +6,7 @@
#include <QDebug>
#include <QTemporaryFile>
#include <QJsonDocument>
#include <QUuid>
#include "sftpdefs.h"
@ -21,6 +22,7 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
connData.host = credentials.hostName;
connData.clientId = Utils::getRandomString(16);
connData.password = Utils::getRandomString(16);
connData.password = "";
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
@ -41,8 +43,11 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
.arg(certFileName);
e = ServerController::runContainerScript(credentials, container, scriptExportCert);
connData.cert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e);
qDebug() << "Ikev2Configurator::ConnectionData cert size:" << connData.cert.size();
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, certFileName, &e);
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;
}
@ -50,17 +55,62 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
{
Q_UNUSED(containerConfig)
ConnectionData connData = prepareIkev2Config(credentials, container, errorCode);
if (errorCode && *errorCode) {
return "";
}
return genIkev2Config(connData);
}
QString Ikev2Configurator::genIkev2Config(const ConnectionData &connData)
{
QJsonObject config;
config[config_key::hostName] = connData.host;
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;
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:
struct ConnectionData {
QByteArray cert; // p12 client cert
QByteArray clientCert; // p12 client cert
QByteArray caCert; // p12 server cert
QString clientId;
QString password; // certificate password
QString host; // host ip
@ -21,8 +22,10 @@ public:
static QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
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,
DockerContainer container, ErrorCode *errorCode = nullptr);
};

View file

@ -6,6 +6,11 @@
#include <QDebug>
#include <QTemporaryFile>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "sftpdefs.h"
#include "core/server_defs.h"
@ -13,72 +18,34 @@
#include "core/scripts_registry.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()
{
// TODO review
constexpr size_t EDDSA_KEY_LENGTH = 32;
ConnectionData connData;
QString program;
#ifdef Q_OS_WIN
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\wireguard\\wg.exe";
#else
program = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS/wg";
#endif
unsigned char buff[EDDSA_KEY_LENGTH];
int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
if (ret <=0) return connData;
#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();
p.waitForFinished();
// save private key
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());
connData.clientPrivKey.replace("\r", "");
connData.clientPrivKey.replace("\n", "");
}
// save public key
unsigned char pub[EDDSA_KEY_LENGTH];
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;
}

View file

@ -28,8 +28,6 @@ public:
private:
static QProcessEnvironment prepareEnv();
static ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
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 };
case DockerContainer::Ipsec:
return { Protocol::Ikev2, Protocol::L2tp };
return { Protocol::Ikev2 /*, Protocol::L2tp */};
case DockerContainer::Dns:
return { };
case DockerContainer::Sftp:
return { Protocol::Sftp};
default:
return { defaultProtocol(container) };
}
@ -72,11 +75,11 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"},
{DockerContainer::Cloak, "OpenVpn over Cloak"},
{DockerContainer::WireGuard, "WireGuard"},
{DockerContainer::Ipsec, QObject::tr("IPsec container")},
{DockerContainer::Ipsec, QObject::tr("IPsec")},
{DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")},
{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")}
};
}
@ -93,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{DockerContainer::TorWebSite, QObject::tr("Web site in TOR network")},
{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")}
};
}
@ -109,7 +112,7 @@ amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
case DockerContainer::Ipsec : return ServiceType::Vpn;
case DockerContainer::TorWebSite : 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;
default: return ServiceType::Other;
}
@ -127,8 +130,9 @@ Protocol ContainerProps::defaultProtocol(DockerContainer c)
case DockerContainer::TorWebSite : return Protocol::TorWebSite;
case DockerContainer::Dns : return Protocol::Dns;
case DockerContainer::FileShare : return Protocol::FileShare;
//case DockerContainer::FileShare : return Protocol::FileShare;
case DockerContainer::Sftp : return Protocol::Sftp;
default: return Protocol::Any;
}
}

View file

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

View file

@ -1,38 +1,83 @@
#include "ipcclient.h"
#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";
return false;
}
return Instance().m_ipcClient->isReplicaValid();
qDebug() << "IpcClient::init succeed";
return Instance()->m_ipcClient->isReplicaValid();
}
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
{
#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";
return nullptr;
}
QRemoteObjectPendingReply<int> futureResult = Instance().m_ipcClient->createPrivilegedProcess();
QRemoteObjectPendingReply<int> futureResult = Instance()->m_ipcClient->createPrivilegedProcess();
futureResult.waitForFinished(1000);
int pid = futureResult.returnValue();
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()));
@ -65,19 +110,4 @@ QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
#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
public:
static IpcClient &Instance();
static bool init();
static QSharedPointer<IpcInterfaceReplica> Interface() { return Instance().m_ipcClient; }
explicit IpcClient(QObject *parent = nullptr);
static IpcClient *Instance();
static bool init(IpcClient *instance);
static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessInterfaceReplica> CreatePrivilegedProcess();
bool isSocketConnected() const;
signals:
private:
explicit IpcClient(QObject *parent = nullptr);
~IpcClient() override;
QRemoteObjectNode m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QSharedPointer<QLocalSocket> m_localSocket;
QPointer<QLocalSocket> m_localSocket;
struct ProcessDescriptor {
ProcessDescriptor () {
@ -45,6 +49,9 @@ private:
};
QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes;
bool m_isSocketConnected {false};
static IpcClient *m_instance;
};
#endif // IPCCLIENT_H

View file

@ -15,7 +15,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
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");
default: return "";
}

View file

@ -24,6 +24,12 @@
using namespace QSsh;
Settings &ServerController::m_settings()
{
static Settings s;
return s;
}
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>)> &cbReadStdErr)
@ -127,16 +133,22 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
const std::function<void (const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr)
{
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;
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
e = runScript(credentials,
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
// QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
// runScript(credentials,
// replaceVars(remover, genVarsForScript(credentials, container)));
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
runScript(credentials,
replaceVars(remover, genVarsForScript(credentials, container)));
return e;
}
@ -672,6 +684,8 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
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

View file

@ -6,6 +6,8 @@
#include "sshconnection.h"
#include "sshremoteprocess.h"
#include "defs.h"
#include "settings.h"
#include "containers/containers_defs.h"
#include "sftpdefs.h"
@ -75,6 +77,7 @@ private:
static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static Settings &m_settings();
};
#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);
qRegisterMetaType<VpnProtocol::ConnectionState>("VpnProtocol::ConnectionState");
qRegisterMetaType<ServerCredentials>("ServerCredentials");
qRegisterMetaType<DockerContainer>("DockerContainer");
qRegisterMetaType<TransportProto>("TransportProto");
qRegisterMetaType<Protocol>("Protocol");
@ -127,12 +130,14 @@ int main(int argc, char *argv[])
UiLogic *uiLogic = new UiLogic;
QQmlApplicationEngine engine;
QQmlApplicationEngine *engine = new QQmlApplicationEngine;
declareQmlPageEnum();
declareQmlProtocolEnum();
declareQmlContainerEnum();
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
QScopedPointer<ContainerProps> containerProps(new ContainerProps);
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", containerProps.get());
@ -140,29 +145,41 @@ int main(int argc, char *argv[])
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", protocolProps.get());
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) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.rootContext()->setContextProperty("UiLogic", uiLogic);
engine->rootContext()->setContextProperty("UiLogic", uiLogic);
engine.rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
engine.rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic());
engine.rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic());
engine.rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
engine.rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
engine.rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
engine.rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
engine.rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic());
engine.rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic());
engine.rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic());
engine.rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic());
engine.rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic());
engine.rootContext()->setContextProperty("WizardLogic", uiLogic->wizardLogic());
engine->rootContext()->setContextProperty("AppSettingsLogic", uiLogic->appSettingsLogic());
engine->rootContext()->setContextProperty("GeneralSettingsLogic", uiLogic->generalSettingsLogic());
engine->rootContext()->setContextProperty("NetworkSettingsLogic", uiLogic->networkSettingsLogic());
engine->rootContext()->setContextProperty("ServerConfiguringProgressLogic", uiLogic->serverConfiguringProgressLogic());
engine->rootContext()->setContextProperty("NewServerProtocolsLogic", uiLogic->newServerProtocolsLogic());
engine->rootContext()->setContextProperty("ServerListLogic", uiLogic->serverListLogic());
engine->rootContext()->setContextProperty("ServerSettingsLogic", uiLogic->serverSettingsLogic());
engine->rootContext()->setContextProperty("ServerContainersLogic", uiLogic->serverVpnProtocolsLogic());
engine->rootContext()->setContextProperty("ShareConnectionLogic", uiLogic->shareConnectionLogic());
engine->rootContext()->setContextProperty("SitesLogic", uiLogic->sitesLogic());
engine->rootContext()->setContextProperty("StartPageLogic", uiLogic->startPageLogic());
engine->rootContext()->setContextProperty("VpnLogic", uiLogic->vpnLogic());
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
//#ifdef Q_OS_WIN

View file

@ -1,18 +1,29 @@
#include <QCoreApplication>
#include <QFileInfo>
#include <QProcess>
#include <QRegularExpression>
#include <QTcpSocket>
//#include <QRegularExpression>
//#include <QTcpSocket>
#include <QThread>
#include <chrono>
#include "debug.h"
#include "ikev2_vpn_protocol.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) :
VpnProtocol(configuration, parent)
{
self = this;
//m_configFile.setFileTemplate(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
readIkev2Configuration(configuration);
}
@ -20,34 +31,214 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent)
Ikev2Protocol::~Ikev2Protocol()
{
qDebug() << "IpsecProtocol::~IpsecProtocol()";
#ifdef Q_OS_WIN
disconnect_vpn();
#endif
Ikev2Protocol::stop();
QThread::msleep(200);
}
void Ikev2Protocol::stop()
{
setConnectionState(VpnProtocol::Disconnecting);
#ifdef Q_OS_WINDOWS
{
setConnectionState(Disconnecting);
auto disconnectProcess = new QProcess;
disconnectProcess->setProgram("rasdial");
QString arguments = QString("\"%1\" /disconnect")
.arg(tunnelName());
disconnectProcess->setNativeArguments(arguments);
// connect(connectProcess, &QProcess::readyRead, [connectProcess]() {
// qDebug().noquote() << "connectProcess readyRead" << connectProcess->readAll();
// });
disconnectProcess->start();
disconnectProcess->waitForFinished(5000);
setConnectionState(Disconnected);
if (! disconnect_vpn() ){
qDebug()<<"We don't disconnect";
setConnectionState(VpnProtocol::Error);
}
else {
setConnectionState(VpnProtocol::Disconnected);
}
}
#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)
{
m_config = configuration.value(ProtocolProps::key_proto_config_data(Protocol::Ikev2)).toObject();
@ -57,7 +248,7 @@ ErrorCode Ikev2Protocol::start()
{
#ifdef Q_OS_WINDOWS
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
setConnectionState(ConnectionState::Connecting);
setConnectionState(Connecting);
QTemporaryFile certFile;
certFile.setAutoRemove(false);
@ -65,7 +256,6 @@ ErrorCode Ikev2Protocol::start()
certFile.write(cert);
certFile.close();
{
auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
@ -87,64 +277,71 @@ ErrorCode Ikev2Protocol::start()
});
certInstallProcess->setArguments(arguments);
// qDebug() << arguments.join(" ");
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) {
// qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error;
// });
// qDebug() << arguments.join(" ");
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::errorOccurred, [certInstallProcess](QProcess::ProcessError error) {
// qDebug() << "IpcProcessInterfaceReplica errorOccurred" << error;
// });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) {
// qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState;
// });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::stateChanged, [certInstallProcess](QProcess::ProcessState newState) {
// qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState;
// });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() {
// auto req = certInstallProcess->readAll();
// req.waitForFinished();
// qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue();
// });
// connect(certInstallProcess.data(), &IpcProcessInterfaceReplica::readyRead, [certInstallProcess]() {
// auto req = certInstallProcess->readAll();
// req.waitForFinished();
// qDebug() << "IpcProcessInterfaceReplica readyRead" << req.returnValue();
// });
certInstallProcess->start();
}
// /*
{
auto adapterRemoveProcess = new QProcess;
// auto adapterRemoveProcess = new QProcess;
adapterRemoveProcess->setProgram("powershell");
QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName());
adapterRemoveProcess->setNativeArguments(arguments);
// adapterRemoveProcess->setProgram("powershell");
// QString arguments = QString("-command \"Remove-VpnConnection -Name '%1' -Force\"").arg(tunnelName());
// adapterRemoveProcess->setNativeArguments(arguments);
adapterRemoveProcess->start();
adapterRemoveProcess->waitForFinished(5000);
// adapterRemoveProcess->start();
// 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");
QString arguments = QString("-command \"Add-VpnConnection "
"-ServerAddress '%1' "
"-Name '%2' "
"-TunnelType IKEv2 "
"-AuthenticationMethod MachineCertificate "
"-EncryptionLevel Required "
"-PassThru\"")
.arg(m_config[config_key::hostName].toString())
.arg(tunnelName());
adapterInstallProcess->setNativeArguments(arguments);
// connect(adapterInstallProcess, &QProcess::readyRead, [adapterInstallProcess]() {
// qDebug().noquote() << "adapterInstallProcess readyRead" << adapterInstallProcess->readAll();
// });
adapterInstallProcess->start();
adapterInstallProcess->waitForFinished(5000);
// adapterInstallProcess->setProgram("powershell");
// QString arguments = QString("-command \"Add-VpnConnection "
// "-ServerAddress '%1' "
// "-Name '%2' "
// "-TunnelType IKEv2 "
// "-AuthenticationMethod MachineCertificate "
// "-EncryptionLevel Required "
// "-PassThru\"")
// .arg(m_config[config_key::hostName].toString())
// .arg(tunnelName());
// adapterInstallProcess->setNativeArguments(arguments);
// adapterInstallProcess->start();
// adapterInstallProcess->waitForFinished(5000);
}
{
auto adapterConfigProcess = new QProcess;
adapterConfigProcess->setProgram("powershell");
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\ "
"-ConnectionName '%1'\ "
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
"-ConnectionName '%1' "
"-AuthenticationTransformConstants GCMAES128 "
"-CipherTransformConstants GCMAES128 "
"-EncryptionMethod AES256 "
@ -152,67 +349,98 @@ ErrorCode Ikev2Protocol::start()
"-PfsGroup None "
"-DHGroup Group14 "
"-PassThru -Force\"")
.arg(tunnelName());
.arg(tunnelName());
adapterConfigProcess->setNativeArguments(arguments);
// connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() {
// qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll();
// });
// connect(adapterConfigProcess, &QProcess::readyRead, [adapterConfigProcess]() {
// qDebug().noquote() << "adapterConfigProcess readyRead" << adapterConfigProcess->readAll();
// });
adapterConfigProcess->start();
adapterConfigProcess->waitForFinished(5000);
}
//*/
{
// char buf[RASBUFFER]= {0};
// DWORD err = 0;
// 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);
return ErrorCode::NoError;
#endif
return ErrorCode::NoError;
}
#ifdef Q_OS_WINDOWS
DWORD CALLBACK rasCallback(UINT msg, RASCONNSTATE rascs, DWORD err)
{
if(err != 0) {
printf("Error: %d\n", err);
fflush(stdout);
//g_done = 1;
return 0; // stop the connection.
} else {
//printf("%s\n", rasState(rascs));
fflush(stdout);
if(rascs == RASCS_Connected) {
printf("Success: Connected\n");
fflush(stdout);
//g_done = 1;
if (!connect_to_vpn(tunnelName())) {
qDebug()<<"We can't connect to VPN";
}
return 1;
}
//setConnectionState(Connecting);
return ErrorCode::NoError;
#else
return ErrorCode::NoError;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef Q_OS_WINDOWS
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
const QString & serv_addr){
if ( RasValidateEntryName(nullptr, vpn_name.toStdWString().c_str()) != ERROR_SUCCESS)
return false;
DWORD size = 0;
::RasGetEntryProperties(nullptr, L"", nullptr, &size, nullptr, nullptr);
LPRASENTRY pras = static_cast<LPRASENTRY>(malloc(size));
memset(pras, 0, size);
pras->dwSize = size;
pras->dwType = RASET_Vpn;
pras->dwRedialCount = 1;
pras->dwRedialPause = 60;
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 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

View file

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

View file

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

View file

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

View file

@ -16,8 +16,6 @@
<file>images/tray/default.png</file>
<file>images/tray/error.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-BlackItalic.ttf</file>
<file>fonts/Lato-Bold.ttf</file>
@ -126,5 +124,22 @@
<file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/run_container.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>
</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-interval 30
connect-delay 5000
ms-dns $PRIMARY_DNS
ms-dns $SECONDARY_DNS
ms-dns $PRIMARY_SERVER_DNS
ms-dns $SECONDARY_SERVER_DNS
EOF
@ -222,6 +222,8 @@ certutil -z <(head -c 1024 /dev/urandom) \
--extKeyUsage serverAuth \
--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
conn ikev2-cp
left=%defaultroute
@ -248,7 +250,7 @@ conn ikev2-cp
ikelifetime=24h
salifetime=24h
encapsulation=yes
modecfgdns=$PRIMARY_DNS,$SECONDARY_DNS
modecfgdns=$PRIMARY_SERVER_DNS,$SECONDARY_SERVER_DNS
EOF
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
LABEL maintainer="AmneziaVPN"
ARG SS_RELEASE="v1.11.2"
ARG SERVER_ARCH
#Install required packages
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools xz
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 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 tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/
RUN chmod a+x /usr/bin/ssserver
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;\
tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/;\
chmod a+x /usr/bin/ssserver;
# Tune network
RUN echo -e " \n\

View file

@ -1,3 +1,6 @@
# 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 --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
{
if (!index.isValid() || index.row() < 0
|| index.row() >= ContainerProps::allContainers().size()) {
|| index.row() >= ProtocolProps::allProtocols().size()) {
return QVariant();
}

View file

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

View file

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

View file

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

View file

@ -43,12 +43,12 @@ void ServerContainersLogic::onPushButtonProtoSettingsClicked(DockerContainer c,
void ServerContainersLogic::onPushButtonDefaultClicked(DockerContainer c)
{
m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c);
onUpdatePage();
uiLogic()->onUpdateAllPages();
}
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);
}
@ -64,7 +64,7 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container)
if (c.isEmpty()) m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, DockerContainer::None);
else m_settings.setDefaultContainer(uiLogic()->selectedServerIndex, c.keys().first());
}
onUpdatePage();
uiLogic()->onUpdateAllPages();
}
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();
}

View file

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

View file

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

View file

@ -5,6 +5,7 @@
#include <QTimer>
#include <QSaveFile>
#include <QStandardPaths>
#include <QImage>
#include "ShareConnectionLogic.h"
@ -12,6 +13,8 @@
#include "configurators/vpn_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "configurators/ikev2_configurator.h"
#include "configurators/ssh_configurator.h"
#include "defines.h"
@ -21,333 +24,226 @@
ShareConnectionLogic::ShareConnectionLogic(UiLogic *logic, QObject *parent):
PageLogicBase(logic, parent),
m_pageShareAmneziaVisible{true},
m_pageShareOpenVpnVisible{true},
m_pageShareShadowSocksVisible{true},
m_pageShareCloakVisible{true},
m_pageShareFullAccessVisible{true},
m_textEditShareOpenVpnCodeText{},
m_pushButtonShareOpenVpnCopyEnabled{false},
m_pushButtonShareOpenVpnSaveEnabled{false},
m_toolBoxShareConnectionCurrentIndex{-1},
m_pushButtonShareShadowSocksCopyEnabled{false},
m_lineEditShareShadowSocksStringText{},
m_labelShareShadowSocksQrCodeText{},
m_labelShareShadowSocksServerText{},
m_labelShareShadowSocksPortText{},
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")}
m_shareShadowSocksQrCodeText{},
m_textEditShareCloakText{},
m_textEditShareAmneziaCodeText{}
{
// TODO consider move to Component.onCompleted
updateSharingPage(uiLogic()->selectedServerIndex, m_settings.serverCredentials(uiLogic()->selectedServerIndex), uiLogic()->selectedDockerContainer);
}
void ShareConnectionLogic::onPushButtonShareFullCopyClicked()
void ShareConnectionLogic::onUpdatePage()
{
QGuiApplication::clipboard()->setText(textEditShareFullCodeText());
set_pushButtonShareFullCopyText(tr("Copied"));
set_textEditShareAmneziaCodeText(tr(""));
set_shareAmneziaQrCodeText("");
QTimer::singleShot(3000, this, [this]() {
set_pushButtonShareFullCopyText(tr("Copy"));
});
}
set_textEditShareOpenVpnCodeText("");
void ShareConnectionLogic::onPushButtonShareFullSaveClicked()
{
if (textEditShareFullCodeText().isEmpty()) return;
set_shareShadowSocksQrCodeText("");
set_textEditShareShadowSocksText("");
set_lineEditShareShadowSocksStringText("");
QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save AmneziaVPN config"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.amnezia");
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(textEditShareFullCodeText().toUtf8());
save.commit();
}
set_textEditShareCloakText("");
void ShareConnectionLogic::onPushButtonShareAmneziaCopyClicked()
{
if (textEditShareAmneziaCodeText().isEmpty()) return;
set_textEditShareWireGuardCodeText("");
set_shareWireGuardQrCodeText("");
QGuiApplication::clipboard()->setText(textEditShareAmneziaCodeText());
set_pushButtonShareAmneziaCopyText(tr("Copied"));
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"));
});
set_textEditShareIkev2CertText("");
set_textEditShareIkev2MobileConfigText("");
set_textEditShareIkev2StrongSwanConfigText("");
}
void ShareConnectionLogic::onPushButtonShareAmneziaGenerateClicked()
{
set_pushButtonShareAmneziaGenerateEnabled(false);
set_pushButtonShareAmneziaCopyEnabled(false);
set_pushButtonShareAmneziaGenerateText(tr("Generating..."));
qApp->processEvents();
set_textEditShareAmneziaCodeText("");
set_shareAmneziaQrCodeText("");
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
ErrorCode e = ErrorCode::NoError;
for (Protocol p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) {
QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e);
if (e) {
cfg = "Error generating config";
break;
}
protoConfig.insert(config_key::last_config, cfg);
containerConfig.insert(ProtocolProps::protoToString(p), protoConfig);
}
QByteArray ba;
if (!e) {
QJsonObject serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig.remove(config_key::userName);
serverConfig.remove(config_key::password);
serverConfig.remove(config_key::port);
serverConfig.insert(config_key::containers, QJsonArray {containerConfig});
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)));
QJsonObject serverConfig;
// Full access
if (shareFullAccess()) {
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
}
// Container share
else {
set_textEditShareAmneziaCodeText(tr("Error while generating connection profile"));
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
QJsonObject containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
containerConfig.insert(config_key::container, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
ErrorCode e = ErrorCode::NoError;
for (Protocol p: ContainerProps::protocolsForContainer(uiLogic()->selectedDockerContainer)) {
QJsonObject protoConfig = m_settings.protocolConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer, p);
QString cfg = VpnConfigurator::genVpnProtocolConfig(credentials, uiLogic()->selectedDockerContainer, containerConfig, p, &e);
if (e) {
cfg = "Error generating config";
break;
}
protoConfig.insert(config_key::last_config, cfg);
containerConfig.insert(ProtocolProps::protoToString(p), protoConfig);
}
QByteArray ba;
if (!e) {
serverConfig = m_settings.server(uiLogic()->selectedServerIndex);
serverConfig.remove(config_key::userName);
serverConfig.remove(config_key::password);
serverConfig.remove(config_key::port);
serverConfig.insert(config_key::containers, QJsonArray {containerConfig});
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(uiLogic()->selectedDockerContainer));
}
else {
set_textEditShareAmneziaCodeText(tr("Error while generating connection profile"));
return;
}
}
set_pushButtonShareAmneziaGenerateEnabled(true);
set_pushButtonShareAmneziaCopyEnabled(true);
set_pushButtonShareAmneziaGenerateText(tr("Generate config"));
QByteArray ba = QJsonDocument(serverConfig).toBinaryData();
ba = qCompress(ba, 8);
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()
{
set_pushButtonShareOpenVpnGenerateEnabled(false);
set_pushButtonShareOpenVpnCopyEnabled(false);
set_pushButtonShareOpenVpnSaveEnabled(false);
set_pushButtonShareOpenVpnGenerateText(tr("Generating..."));
ServerCredentials credentials = m_settings.serverCredentials(uiLogic()->selectedServerIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(uiLogic()->selectedServerIndex, uiLogic()->selectedDockerContainer);
ErrorCode e = ErrorCode::NoError;
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_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"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), "*.ovpn");
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QSaveFile save(fileName);
save.open(QIODevice::WriteOnly);
save.write(textEditShareOpenVpnCodeText().toUtf8());
save.commit();
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks);
QString cfg = protoConfig.value(config_key::last_config).toString();
if (cfg.isEmpty()) {
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ErrorCode e = ErrorCode::NoError;
cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e);
}
QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
QString ssString = QString("%1:%2@%3:%4")
.arg(ssConfig.value("method").toString())
.arg(ssConfig.value("password").toString())
.arg(ssConfig.value("server").toString())
.arg(ssConfig.value("server_port").toString());
ssString = "ss://" + ssString.toUtf8().toBase64();
set_lineEditShareShadowSocksStringText(ssString);
QImage qr = updateQRCodeImage(ssString.toUtf8());
set_shareShadowSocksQrCodeText(imageToBase64(qr));
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());
set_textEditShareShadowSocksText(humanString);
}
void ShareConnectionLogic::updateSharingPage(int serverIndex, const ServerCredentials &credentials,
DockerContainer container)
void ShareConnectionLogic::onPushButtonShareCloakGenerateClicked()
{
uiLogic()->selectedDockerContainer = container;
uiLogic()->selectedServerIndex = serverIndex;
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak);
QString cfg = protoConfig.value(config_key::last_config).toString();
if (cfg.isEmpty()) {
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ErrorCode e = ErrorCode::NoError;
cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e);
}
QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
cloakConfig.remove(config_key::transport_proto);
cloakConfig.insert("ProxyMethod", "shadowsocks");
set_textEditShareCloakText(QJsonDocument(cloakConfig).toJson());
}
void ShareConnectionLogic::onPushButtonShareWireGuardGenerateClicked()
{
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
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_textEditShareWireGuardCodeText(cfg);
QImage qr = updateQRCodeImage(cfg.toUtf8());
set_shareWireGuardQrCodeText(imageToBase64(qr));
}
void ShareConnectionLogic::onPushButtonShareIkev2GenerateClicked()
{
int serverIndex = uiLogic()->selectedServerIndex;
DockerContainer container = uiLogic()->selectedDockerContainer;
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
//const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
set_pageShareAmneziaVisible(false);
set_pageShareOpenVpnVisible(false);
set_pageShareShadowSocksVisible(false);
set_pageShareCloakVisible(false);
set_pageShareFullAccessVisible(false);
Ikev2Configurator::ConnectionData connData = Ikev2Configurator::prepareIkev2Config(credentials, container);
enum currentWidget {
full_access = 0,
share_amezia,
share_openvpn,
share_shadowshock,
share_cloak
};
QString cfg = Ikev2Configurator::genIkev2Config(connData);
cfg = VpnConfigurator::processConfigWithExportSettings(container, Protocol::Ikev2, cfg);
cfg = QJsonDocument::fromJson(cfg.toUtf8()).object()[config_key::cert].toString();
if (container == DockerContainer::OpenVpn) {
set_pageShareAmneziaVisible(true);
set_pageShareOpenVpnVisible(true);
set_textEditShareIkev2CertText(cfg);
QString cfg = tr("Press Generate config");
set_textEditShareOpenVpnCodeText(cfg);
set_pushButtonShareOpenVpnCopyEnabled(false);
set_pushButtonShareOpenVpnSaveEnabled(false);
QString mobileCfg = Ikev2Configurator::genMobileConfig(connData);
set_textEditShareIkev2MobileConfigText(mobileCfg);
set_toolBoxShareConnectionCurrentIndex(share_openvpn);
}
QString strongSwanCfg = Ikev2Configurator::genStrongSwanConfig(connData);
set_textEditShareIkev2StrongSwanConfigText(strongSwanCfg);
if (container == DockerContainer::ShadowSocks ||
container == DockerContainer::Cloak) {
set_pageShareAmneziaVisible(true);
set_pageShareShadowSocksVisible(true);
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::ShadowSocks);
QString cfg = protoConfig.value(config_key::last_config).toString();
if (cfg.isEmpty()) {
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ErrorCode e = ErrorCode::NoError;
cfg = ShadowSocksConfigurator::genShadowSocksConfig(credentials, container, containerConfig, &e);
set_pushButtonShareShadowSocksCopyEnabled(true);
}
QJsonObject ssConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
QString ssString = QString("%1:%2@%3:%4")
.arg(ssConfig.value("method").toString())
.arg(ssConfig.value("password").toString())
.arg(ssConfig.value("server").toString())
.arg(ssConfig.value("server_port").toString());
ssString = "ss://" + ssString.toUtf8().toBase64();
set_lineEditShareShadowSocksStringText(ssString);
updateQRCodeImage(ssString, [this](const QString& labelText) ->void {
set_labelShareShadowSocksQrCodeText(labelText);
});
set_labelShareShadowSocksServerText(ssConfig.value("server").toString());
set_labelShareShadowSocksPortText(ssConfig.value("server_port").toString());
set_labelShareShadowSocksMethodText(ssConfig.value("method").toString());
set_labelShareShadowSocksPasswordText(ssConfig.value("password").toString());
set_toolBoxShareConnectionCurrentIndex(share_shadowshock);
}
if (container == DockerContainer::Cloak) {
//ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client"));
set_pageShareCloakVisible(true);
set_plainTextEditShareCloakText(QString(""));
QJsonObject protoConfig = m_settings.protocolConfig(serverIndex, container, Protocol::Cloak);
QString cfg = protoConfig.value(config_key::last_config).toString();
if (cfg.isEmpty()) {
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
ErrorCode e = ErrorCode::NoError;
cfg = CloakConfigurator::genCloakConfig(credentials, container, containerConfig, &e);
set_pushButtonShareCloakCopyEnabled(true);
}
QJsonObject cloakConfig = QJsonDocument::fromJson(cfg.toUtf8()).object();
cloakConfig.remove(config_key::transport_proto);
cloakConfig.insert("ProxyMethod", "shadowsocks");
set_plainTextEditShareCloakText(QJsonDocument(cloakConfig).toJson());
}
// Full access
if (container == DockerContainer::None) {
set_pageShareFullAccessVisible(true);
const QJsonObject &server = m_settings.server(uiLogic()->selectedServerIndex);
QByteArray ba = QJsonDocument(server).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
set_textEditShareFullCodeText(QString("vpn://%1").arg(QString(ba)));
set_toolBoxShareConnectionCurrentIndex(full_access);
}
//ui->toolBox_share_connection->addItem(ui->page_share_amnezia, tr(" Share for Amnezia client"));
// Amnezia sharing
// QJsonObject exportContainer;
// for (Protocol p: protocolsForContainer(container)) {
// QJsonObject protocolConfig = containerConfig.value(ProtocolProps::protoToString(p)).toObject();
// protocolConfig.remove(config_key::last_config);
// exportContainer.insert(ProtocolProps::protoToString(p), protocolConfig);
// }
// exportContainer.insert(config_key::container, containerToString(container));
// ui->textEdit_share_amnezia_code->setPlainText(QJsonDocument(exportContainer).toJson());
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 versionIndex = 0;
bool bExtent = true;
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;
@ -361,10 +257,14 @@ void ShareConnectionLogic::updateQRCodeImage(const QString &text, const std::fun
if ( m_qrEncode.m_byModuleData[i][j] )
encodeImage.setPixel( i + QR_MARGIN, j + QR_MARGIN, 0 );
QByteArray byteArray;
QBuffer buffer(&byteArray);
encodeImage.save(&buffer, "PNG"); // writes the image in PNG format inside the buffer
QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data());
set_labelFunc(iconBase64);
return encodeImage;
}
QString ShareConnectionLogic::imageToBase64(const QImage &image)
{
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
public:
AUTO_PROPERTY(bool, pageShareAmneziaVisible)
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(bool, shareFullAccess)
AUTO_PROPERTY(QString, textEditShareAmneziaCodeText)
AUTO_PROPERTY(QString, pushButtonShareFullCopyText)
AUTO_PROPERTY(QString, pushButtonShareAmneziaCopyText)
AUTO_PROPERTY(QString, pushButtonShareOpenVpnCopyText)
AUTO_PROPERTY(QString, pushButtonShareShadowSocksCopyText)
AUTO_PROPERTY(QString, pushButtonShareCloakCopyText)
AUTO_PROPERTY(bool, pushButtonShareAmneziaGenerateEnabled)
AUTO_PROPERTY(bool, pushButtonShareAmneziaCopyEnabled)
AUTO_PROPERTY(QString, pushButtonShareAmneziaGenerateText)
AUTO_PROPERTY(bool, pushButtonShareOpenVpnGenerateEnabled)
AUTO_PROPERTY(QString, pushButtonShareOpenVpnGenerateText)
AUTO_PROPERTY(QString, shareAmneziaQrCodeText)
AUTO_PROPERTY(QString, textEditShareOpenVpnCodeText)
AUTO_PROPERTY(QString, textEditShareShadowSocksText)
AUTO_PROPERTY(QString, lineEditShareShadowSocksStringText)
AUTO_PROPERTY(QString, shareShadowSocksQrCodeText)
AUTO_PROPERTY(QString, textEditShareCloakText)
AUTO_PROPERTY(QString, textEditShareWireGuardCodeText)
AUTO_PROPERTY(QString, shareWireGuardQrCodeText)
AUTO_PROPERTY(QString, textEditShareIkev2CertText)
AUTO_PROPERTY(QString, textEditShareIkev2MobileConfigText)
AUTO_PROPERTY(QString, textEditShareIkev2StrongSwanConfigText)
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 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:
explicit ShareConnectionLogic(UiLogic *uiLogic, QObject *parent = nullptr);
~ShareConnectionLogic() = default;
void updateSharingPage(int serverIndex, const ServerCredentials &credentials,
DockerContainer container);
void updateQRCodeImage(const QString &text, const std::function<void(const QString&)>& setLabelFunc);
void updateSharingPage(int serverIndex, DockerContainer container);
QImage updateQRCodeImage(const QByteArray &data);
QString imageToBase64(const QImage &image);
private:
CQR_Encode m_qrEncode;

View file

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

View file

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

View file

@ -35,6 +35,8 @@ void StartPageLogic::onUpdatePage()
set_pushButtonConnectVisible(true);
set_pushButtonConnectKeyChecked(false);
set_pushButtonBackFromStartVisible(uiLogic()->pagesStackDepth() > 0);
}
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::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) {
QTimer::singleShot(1000, this, [this](){
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();
set_radioButtonVpnModeAllSitesChecked(mode == Settings::VpnAllSites);
set_radioButtonVpnModeForwardSitesChecked(mode == Settings::VpnOnlyForwardSites);
set_radioButtonVpnModeExceptSitesChecked(mode == Settings::VpnAllExceptSites);
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 rbModeEnabled = false;
bool pbConnectVisible = false;
set_labelStateText(VpnProtocol::textConnectionState(state));
uiLogic()->setTrayState(state);
@ -85,39 +98,48 @@ void VpnLogic::onConnectionStateChanged(VpnProtocol::ConnectionState state)
onBytesChanged(0,0);
set_pushButtonConnectChecked(false);
pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true;
break;
case VpnProtocol::Preparing:
pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false;
break;
case VpnProtocol::Connecting:
pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false;
break;
case VpnProtocol::Connected:
pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = false;
break;
case VpnProtocol::Disconnecting:
pbConnectEnabled = false;
pbConnectVisible = false;
rbModeEnabled = false;
break;
case VpnProtocol::Reconnecting:
pbConnectEnabled = true;
pbConnectVisible = false;
rbModeEnabled = false;
break;
case VpnProtocol::Error:
set_pushButtonConnectEnabled(false);
pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true;
break;
case VpnProtocol::Unknown:
pbConnectEnabled = true;
pbConnectVisible = true;
rbModeEnabled = true;
}
set_pushButtonConnectEnabled(pbConnectEnabled);
set_pushButtonConnectVisible(pbConnectVisible);
set_widgetVpnModeEnabled(rbModeEnabled);
}
@ -166,20 +188,19 @@ void VpnLogic::onConnectWorker(int serverIndex, const ServerCredentials &credent
qApp->processEvents();
ErrorCode errorCode = uiLogic()->m_vpnConnection->connectToVpn(
serverIndex, credentials, container, containerConfig);
emit connectToVpn(serverIndex, credentials, container, containerConfig);
if (errorCode) {
//ui->pushButton_connect->setChecked(false);
uiLogic()->setDialogConnectErrorText(errorString(errorCode));
emit uiLogic()->showConnectErrorDialog();
return;
}
// if (errorCode) {
// //ui->pushButton_connect->setChecked(false);
// uiLogic()->setDialogConnectErrorText(errorString(errorCode));
// emit uiLogic()->showConnectErrorDialog();
// return;
// }
}
void VpnLogic::onDisconnect()
{
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, labelSpeedSentText)
AUTO_PROPERTY(QString, labelStateText)
AUTO_PROPERTY(QString, labelCurrentServer)
AUTO_PROPERTY(QString, labelCurrentService)
AUTO_PROPERTY(bool, pushButtonConnectEnabled)
AUTO_PROPERTY(bool, pushButtonConnectVisible)
AUTO_PROPERTY(bool, widgetVpnModeEnabled)
AUTO_PROPERTY(QString, labelErrorText)
AUTO_PROPERTY(bool, pushButtonVpnAddSiteEnabled)
@ -24,7 +27,7 @@ class VpnLogic : public PageLogicBase
AUTO_PROPERTY(bool, radioButtonVpnModeExceptSitesChecked)
public:
Q_INVOKABLE void updateVpnPage();
Q_INVOKABLE void onUpdatePage() override;
Q_INVOKABLE void onRadioButtonVpnModeAllSitesToggled(bool checked);
Q_INVOKABLE void onRadioButtonVpnModeForwardSitesToggled(bool checked);
@ -48,5 +51,10 @@ public slots:
void onConnectionStateChanged(VpnProtocol::ConnectionState state);
void onVpnProtocolError(amnezia::ErrorCode errorCode);
signals:
void connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
};
#endif // VPN_LOGIC_H

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,8 +6,6 @@ BasicButtonType {
id: root
width: parent.width - 80
height: 40
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
background: Rectangle {
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 {
id: root
height: 40
background: Rectangle {
anchors.fill: parent
radius: 4
color: root.containsMouse ? "#282932" : "#181922"
color: root.enabled
? (root.containsMouse ? "#282932" : "#181922")
: "#484952"
}
font.pixelSize: 16
contentItem: Text {

View file

@ -5,9 +5,7 @@ import QtGraphicalEffects 1.12
Item {
id: root
property bool active: false
property Component content: undefined
property string text: ""
width: 360
height: active ? contentLoader.item.height + 40 + 5 * 2 : 40
signal clicked()
@ -64,12 +62,5 @@ Item {
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()
}
Menu {
ContextMenu {
id: contextMenu
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()
}
textObj: root
}
}

View file

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

View file

@ -13,82 +13,49 @@ PageBase {
BackButton {
id: back
}
// ---------- App settings ------------
Rectangle {
y: 40
id: l1
visible: !GC.isMobile()
anchors.top: back.bottom
x: 20
width: parent.width - 40
height: 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
height: GC.isMobile() ? 0: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b1
visible: !GC.isMobile()
anchors.top: l1.bottom
anchors.topMargin: GC.isMobile() ? 0: 15
x: 30
y: 355
width: 330
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
width: parent.width - 40
height: GC.isMobile() ? 0: 30
icon.source: "qrc:/images/settings.png"
text: qsTr("App settings")
onClicked: {
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 {
id: b2
x: 30
y: 115
width: 330
anchors.top: l2.bottom
anchors.topMargin: 15
width: parent.width - 40
height: 30
icon.source: "qrc:/images/settings.png"
text: qsTr("Network settings")
@ -96,31 +63,46 @@ PageBase {
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 {
id: b3
x: 30
y: 175
anchors.top: l3.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
text: qsTr("Server management")
text: qsTr("Server Settings")
onClicked: {
GeneralSettingsLogic.onPushButtonGeneralSettingsServerSettingsClicked()
}
}
SettingButtonType {
x: 30
y: 295
width: 330
height: 30
icon.source: "qrc:/images/server_settings.png"
text: qsTr("Servers")
onClicked: {
UiLogic.goToPage(PageEnum.ServersList)
}
// ---------- Share connection ------------
Rectangle {
id: l4
anchors.top: b3.bottom
anchors.topMargin: 15
x: 20
width: parent.width - 40
height: 1
color: "#DDDDDD"
}
SettingButtonType {
id: b4
x: 30
y: 235
anchors.top: l4.bottom
anchors.topMargin: 15
width: 330
height: 30
icon.source: "qrc:/images/share.png"
@ -130,6 +112,66 @@ PageBase {
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 {
x: 30
anchors.bottom: parent.bottom

View file

@ -30,6 +30,7 @@ PageBase {
id: pushButtonWizard
text: qsTr("Run Setup Wizard")
anchors.top: labelWizard.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 10
onClicked: {
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.Controls 2.12
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2
import ContainerProps 1.0
@ -292,19 +293,30 @@ PageBase {
}
ImageButtonType {
id: button_default
visible: service_type_role == ProtocolEnum.Vpn
id: button_remove
visible: index === tb_c.currentIndex
Layout.alignment: Qt.AlignRight
checkable: true
img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png"
icon.source: "qrc:/images/delete.png"
implicitWidth: 30
implicitHeight: 30
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 {
@ -322,23 +334,20 @@ PageBase {
}
ImageButtonType {
id: button_remove
visible: index === tb_c.currentIndex
id: button_default
visible: service_type_role == ProtocolEnum.Vpn
Layout.alignment: Qt.AlignRight
checkable: true
icon.source: "qrc:/images/delete.png"
img.source: checked ? "qrc:/images/check.png" : "qrc:/images/uncheck.png"
implicitWidth: 30
implicitHeight: 30
checked: default_role
onClicked: {
tb_c.currentIndex = -1
ServerContainersLogic.onPushButtonRemoveClicked(proxyContainersModel.mapToSource(index))
ServerContainersLogic.onPushButtonDefaultClicked(proxyContainersModel.mapToSource(index))
}
VisibleBehavior on visible { }
}
}

View file

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

View file

@ -1,6 +1,13 @@
import QtQuick 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 ProtocolEnum 1.0
import "./"
import "../Controls"
import "../Config"
@ -13,400 +20,69 @@ PageBase {
BackButton {
id: back
}
ScrollView {
x: 10
y: 40
width: 360
height: 580
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
}
Caption {
id: caption
text: qsTr("Share protocol config")
width: undefined
}
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;
ShareConnectionContent {
x: 10
text: qsTr("Share for Amnezia")
height: 40
width: tb_c.width - 10
onClicked: UiLogic.onGotoShareProtocolPage(ProtocolEnum.Any)
}
Column {
spacing: 5
ShareConnectionContent {
id: full_access
x: 0
text: qsTr("Full access")
visible: ShareConnectionLogic.pageShareFullAccessVisible
content: Component {
Item {
width: 360
height: 380
Text {
x: 10
y: 250
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
text: ShareConnectionLogic.pushButtonShareFullCopyText
onClicked: {
ShareConnectionLogic.onPushButtonShareFullCopyClicked()
}
}
ShareConnectionButtonType {
x: 10
y: 180
width: 341
height: 40
text: qsTr("Save file")
onClicked: {
ShareConnectionLogic.onPushButtonShareFullSaveClicked()
}
}
TextFieldType {
x: 10
y: 10
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 {
id: share_amezia
x: 0
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
text: ShareConnectionLogic.pushButtonShareAmneziaCopyText
onClicked: {
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
}
ListView {
id: tb_c
x: 10
width: parent.width - 10
height: tb_c.contentItem.height
currentIndex: -1
spacing: 10
clip: true
interactive: false
model: proxyProtocolsModel
delegate: Item {
implicitWidth: tb_c.width - 10
implicitHeight: c_item.height
ShareConnectionContent {
id: c_item
text: qsTr("Share for ") + name_role
height: 40
width: tb_c.width - 10
onClicked: UiLogic.onGotoShareProtocolPage(proxyProtocolsModel.mapToSource(index))
}
}
}

View file

@ -15,36 +15,30 @@ PageBase {
BackButton {
id: back
}
Text {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 16
Caption {
id: caption
text: SitesLogic.labelSitesAddCustomText
}
LabelType {
id: lb_addr
color: "#333333"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: qsTr("Web site/Hostname/IP address/Subnet")
x: 20
y: 110
width: 311
anchors.top: caption.bottom
anchors.topMargin: 10
width: parent.width
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 {
x: 20
y: 140
width: 231
anchors.top: lb_addr.bottom
anchors.topMargin: 10
anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: sites_add.left
anchors.rightMargin: 10
height: 31
placeholderText: qsTr("yousite.com or IP address")
text: SitesLogic.lineEditSitesAddCustomText
@ -55,10 +49,13 @@ PageBase {
SitesLogic.onPushButtonAddCustomSitesClicked()
}
}
BlueButtonType {
id: sites_add
x: 260
y: 140
anchors.right: sites_import.left
anchors.rightMargin: 10
anchors.top: lb_addr.bottom
anchors.topMargin: 10
width: 51
height: 31
font.pixelSize: 24
@ -67,23 +64,13 @@ PageBase {
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 {
id: sites_import
x: 320
y: 140
anchors.right: parent.right
anchors.rightMargin: 20
anchors.top: lb_addr.bottom
anchors.topMargin: 10
width: 51
height: 31
background: Rectangle {
@ -116,12 +103,15 @@ PageBase {
SitesLogic.onPushButtonSitesImportClicked(fileUrl)
}
}
ListView {
id: tb
x: 20
y: 200
width: 341
height: 371
anchors.top: sites_add.bottom
anchors.topMargin: 10
width: parent.width - 40
anchors.bottom: sites_delete.top
anchors.bottomMargin: 10
spacing: 1
clip: true
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.topMargin: 5
text: qsTr("Where to get connection data →")
text: qsTr("How to get own server? →")
background: Item {
anchors.fill: parent
}
@ -147,7 +147,7 @@ PageBase {
checkable: true
checked: true
onClicked: {
Qt.openUrlExternally("https://amnezia.org")
Qt.openUrlExternally("https://amnezia.org/instruction.html")
}
}
LabelType {

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import PageEnum 1.0
import "./"
import "../Controls"
@ -11,12 +12,11 @@ PageBase {
logic: VpnLogic
Image {
id: bg_top
anchors.horizontalCenter: parent.horizontalCenter
y: 0
width: parent.width
// width: 380
// height: 325
height: parent.height * 0.28
source: "qrc:/images/background_connected.png"
}
@ -31,38 +31,26 @@ PageBase {
}
}
LabelType {
id: error_text
x: 0
y: 280
width: 381
height: 61
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.Wrap
text: VpnLogic.labelErrorText
}
Text {
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
AnimatedImage {
id: connect_anim
source: "qrc:/images/animation.gif"
anchors.top: bg_top.bottom
anchors.topMargin: 10
anchors.horizontalCenter: root.horizontalCenter
width: Math.min(parent.width, parent.height) / 4
height: width
visible: !VpnLogic.pushButtonConnectVisible
paused: VpnLogic.pushButtonConnectVisible
//VisibleBehavior on visible { }
}
BasicButtonType {
id: button_connect
anchors.horizontalCenter: parent.horizontalCenter
y: 200
width: 80
height: 40
anchors.horizontalCenter: connect_anim.horizontalCenter
anchors.verticalCenter: connect_anim.verticalCenter
width: connect_anim.width
height: width
checkable: true
checked: VpnLogic.pushButtonConnectChecked
onCheckedChanged: {
@ -71,18 +59,102 @@ PageBase {
}
background: Image {
anchors.fill: parent
source: button_connect.checked ? "qrc:/images/connect_button_connected.png"
: "qrc:/images/connect_button_disconnected.png"
source: button_connect.checked ? "qrc:/images/connected.png"
: "qrc:/images/disconnected.png"
}
contentItem: Item {}
antialiasing: true
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 {
x: 0
anchors.bottom: line.top
anchors.bottomMargin: 10
anchors.bottomMargin: GC.isMobile() ? 0 :10
width: parent.width
height: 51
Image {
@ -136,7 +208,7 @@ PageBase {
x: 20
width: parent.width - 40
height: 1
anchors.bottom: conn_type_label.top
anchors.bottom: GC.isMobile() ? root.bottom : conn_type_label.top
anchors.bottomMargin: 10
color: "#DDDDDD"
}
@ -146,7 +218,7 @@ PageBase {
visible: !GC.isMobile()
x: 20
anchors.bottom: conn_type_group.top
anchors.bottomMargin: 10
anchors.bottomMargin: GC.isMobile() ? 0 :10
width: 281
height: GC.isMobile() ? 0: 21
font.family: "Lato"
@ -208,11 +280,11 @@ PageBase {
BasicButtonType {
id: button_add_site
visible: !GC.isMobile()
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height - 60
//anchors.bottom: parent.bottom
width: parent.width - 40
height: 40
height: GC.isMobile() ? 0: 40
text: qsTr("+ Add site")
enabled: VpnLogic.pushButtonVpnAddSiteEnabled
background: Rectangle {

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
@ -10,144 +11,155 @@ PageProtocolBase {
protocol: ProtocolEnum.Cloak
logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageProtoCloakEnabled
enabled: logic.pageEnabled
BackButton {
id: back
}
Item {
x: 0
y: 40
width: 380
height: 600
Caption {
id: caption
text: qsTr("Cloak Settings")
}
ColumnLayout {
id: content
enabled: logic.pageEnabled
ComboBoxType {
x: 190
y: 60
width: 151
height: 31
model: [
qsTr("chacha20-poly1305"),
qsTr("aes-256-gcm"),
qsTr("aes-192-gcm"),
qsTr("aes-128-gcm")
]
currentIndex: {
for (let i = 0; i < model.length; ++i) {
if (logic.comboBoxProtoCloakCipherText === model[i]) {
return i
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 {
Layout.fillWidth: true
height: 31
model: [
qsTr("chacha20-poly1305"),
qsTr("aes-256-gcm"),
qsTr("aes-192-gcm"),
qsTr("aes-128-gcm")
]
currentIndex: {
for (let i = 0; i < model.length; ++i) {
if (logic.comboBoxCipherText === model[i]) {
return i
}
}
return -1
}
return -1
}
onCurrentTextChanged: {
logic.comboBoxProtoCloakCipherText = currentText
}
}
LabelType {
x: 30
y: 60
width: 151
height: 31
text: qsTr("Cipher")
}
LabelType {
x: 30
y: 160
width: 151
height: 31
text: qsTr("Port")
}
Text {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 24
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
text: qsTr("Fake Web Site")
}
LabelType {
id: label_proto_cloak_info
x: 30
y: 550
width: 321
height: 41
visible: logic.labelProtoCloakInfoVisible
text: logic.labelProtoCloakInfoText
}
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 {
id: progressBar_proto_cloak_reset
anchors.horizontalCenter: parent.horizontalCenter
y: 500
width: 321
height: 40
from: 0
to: logic.progressBarProtoCloakResetMaximium
value: logic.progressBarProtoCloakResetValue
background: Rectangle {
implicitWidth: parent.width
implicitHeight: parent.height
color: "#100A44"
radius: 4
}
contentItem: Item {
implicitWidth: parent.width
implicitHeight: parent.height
Rectangle {
width: progressBar_proto_cloak_reset.visualPosition * parent.width
height: parent.height
radius: 4
color: Qt.rgba(255, 255, 255, 0.15);
onCurrentTextChanged: {
logic.comboBoxCipherText = currentText
}
}
visible: logic.progressBarProtoCloakResetVisible
}
BlueButtonType {
anchors.horizontalCenter: parent.horizontalCenter
y: 500
width: 321
height: 40
text: qsTr("Save and restart VPN")
visible: logic.pushButtonCloakSaveVisible
onClicked: {
logic.onPushButtonProtoCloakSaveClicked()
RowLayout {
Layout.fillWidth: true
LabelType {
Layout.preferredWidth: 0.3 * root.width - 10
height: 31
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 {
Layout.preferredWidth: 0.3 * root.width - 10
height: 31
text: qsTr("Port")
}
TextFieldType {
id: lineEdit_proto_cloak_port
Layout.fillWidth: true
height: 31
text: logic.lineEditPortText
onEditingFinished: {
logic.lineEditPortText = text
}
enabled: logic.lineEditPortEnabled
}
}
Item {
Layout.fillHeight: true
}
}
LabelType {
id: label_proto_cloak_info
x: 30
anchors.bottom: pb_save.top
anchors.bottomMargin: 10
width: parent.width - 40
visible: logic.labelInfoVisible
text: logic.labelInfoText
}
ProgressBar {
id: progressBar_proto_cloak_reset
anchors.horizontalCenter: parent.horizontalCenter
anchors.fill: pb_save
from: 0
to: logic.progressBarResetMaximium
value: logic.progressBarResetValue
background: Rectangle {
implicitWidth: parent.width
implicitHeight: parent.height
color: "#100A44"
radius: 4
}
contentItem: Item {
implicitWidth: parent.width
implicitHeight: parent.height
Rectangle {
width: progressBar_proto_cloak_reset.visualPosition * parent.width
height: parent.height
radius: 4
color: Qt.rgba(255, 255, 255, 0.15);
}
}
visible: logic.progressBarResetVisible
}
BlueButtonType {
id: pb_save
anchors.horizontalCenter: parent.horizontalCenter
enabled: logic.pageEnabled
anchors.bottom: root.bottom
anchors.bottomMargin: 20
width: root.width - 60
height: 40
text: qsTr("Save and restart VPN")
visible: logic.pushButtonSaveVisible
onClicked: {
logic.onPushButtonSaveClicked()
}
}
}

View file

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

View file

@ -1,5 +1,6 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
import ProtocolEnum 1.0
import "../"
import "../../Controls"
@ -10,123 +11,136 @@ PageProtocolBase {
protocol: ProtocolEnum.ShadowSocks
logic: UiLogic.protocolLogic(protocol)
enabled: logic.pageProtoShadowSocksEnabled
enabled: logic.pageEnabled
BackButton {
id: back
}
Item {
x: 0
y: 40
width: 380
height: 600
Caption {
id: caption
text: qsTr("ShadowSocks Settings")
}
ColumnLayout {
id: content
enabled: logic.pageEnabled
ComboBoxType {
x: 190
y: 60
width: 151
height: 31
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 (logic.comboBoxProtoShadowSocksCipherText === model[i]) {
return i
}
}
return -1
}
}
LabelType {
x: 30
y: 60
width: 151
height: 31
text: qsTr("Cipher")
}
LabelType {
x: 30
y: 110
width: 151
height: 31
text: qsTr("Port")
}
Text {
font.family: "Lato"
font.styleName: "normal"
font.pixelSize: 24
color: "#100A44"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: qsTr("ShadowSocks Settings")
x: 30
y: 0
width: 340
height: 30
}
LabelType {
id: label_proto_shadowsocks_info
x: 30
y: 550
width: 321
height: 41
visible: logic.labelProtoShadowSocksInfoVisible
text: logic.labelProtoShadowSocksInfoText
}
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 {
id: progressBar_proto_shadowsocks_reset
anchors.horizontalCenter: parent.horizontalCenter
y: 500
width: 321
height: 40
from: 0
to: logic.progressBarProtoShadowSocksResetMaximium
value: logic.progressBarProtoShadowSocksResetValue
visible: logic.progressBarProtoShadowSocksResetVisible
background: Rectangle {
implicitWidth: parent.width
implicitHeight: parent.height
color: "#100A44"
radius: 4
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
}
contentItem: Item {
implicitWidth: parent.width
implicitHeight: parent.height
Rectangle {
width: progressBar_proto_shadowsocks_reset.visualPosition * parent.width
height: parent.height
radius: 4
color: Qt.rgba(255, 255, 255, 0.15);
ComboBoxType {
height: 31
Layout.fillWidth: true
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 (logic.comboBoxCipherText === model[i]) {
return i
}
}
return -1
}
}
}
BlueButtonType {
anchors.horizontalCenter: parent.horizontalCenter
y: 500
width: 321
height: 40
text: qsTr("Save and restart VPN")
visible: logic.pushButtonShadowSocksSaveVisible
onClicked: {
logic.onPushButtonProtoShadowSocksSaveClicked()
RowLayout {
Layout.fillWidth: true
LabelType {
Layout.preferredWidth: 0.3 * root.width - 10
height: 31
text: qsTr("Port")
}
TextFieldType {
id: lineEdit_proto_shadowsocks_port
Layout.fillWidth: true
height: 31
text: logic.lineEditPortText
onEditingFinished: {
logic.lineEditPortText = text
}
enabled: logic.lineEditPortEnabled
}
}
Item {
Layout.fillHeight: true
}
}
LabelType {
id: label_proto_shadowsocks_info
x: 30
anchors.bottom: pb_save.top
anchors.bottomMargin: 10
width: parent.width - 40
height: 41
visible: logic.labelInfoVisible
text: logic.labelInfoText
}
ProgressBar {
id: progressBar_reset
anchors.fill: pb_save
from: 0
to: logic.progressBaResetMaximium
value: logic.progressBaResetValue
visible: logic.progressBaResetVisible
background: Rectangle {
implicitWidth: parent.width
implicitHeight: parent.height
color: "#100A44"
radius: 4
}
contentItem: Item {
implicitWidth: parent.width
implicitHeight: parent.height
Rectangle {
width: progressBar_reset.visualPosition * parent.width
height: parent.height
radius: 4
color: Qt.rgba(255, 255, 255, 0.15);
}
}
}
BlueButtonType {
id: pb_save
enabled: logic.pageEnabled
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: root.bottom
anchors.bottomMargin: 20
width: root.width - 60
height: 40
text: qsTr("Save and restart VPN")
visible: logic.pushButtonSaveVisible
onClicked: {
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.Material 2.12
import PageEnum 1.0
import PageType 1.0
import Qt.labs.platform 1.1
import Qt.labs.folderlistmodel 2.12
import QtQuick.Dialogs 1.1
import "./"
import "Pages"
import "Pages/Protocols"
import "Pages/Share"
import "Config"
Window {
property var pages: ({})
property var protocolPages: ({})
property var sharePages: ({})
id: root
visible: true
@ -28,73 +31,28 @@ Window {
//flags: Qt.FramelessWindowHint
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 (page === PageEnum.ServerSettings) {
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()
}
p_obj.logic.onUpdatePage();
}
if (slide) {
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)
p_obj.activated(reset)
}
function close_page() {
@ -146,6 +104,8 @@ Window {
color: "white"
}
//PageShareProtoAmnezia {}
StackView {
id: pageLoader
y: GC.isDesktop() ? titleBar.height : 0
@ -157,6 +117,10 @@ Window {
UiLogic.currentPageValue = currentItem.page
}
onDepthChanged: {
UiLogic.pagesStackDepth = depth
}
Keys.onPressed: {
UiLogic.keyPressEvent(event.key)
event.accepted = true
@ -171,7 +135,7 @@ Window {
onStatusChanged: if (status == FolderListModel.Ready) {
for (var i=0; i<folderModelPages.count; i++) {
createPagesObjects(folderModelPages.get(i, "filePath"), false);
createPagesObjects(folderModelPages.get(i, "filePath"), PageType.Basic);
}
UiLogic.initalizeUiLogic()
}
@ -185,40 +149,56 @@ Window {
onStatusChanged: if (status == FolderListModel.Ready) {
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
//console.debug("Creating compenent " + file + " for " + type);
var c = Qt.createComponent("qrc" + file);
var finishCreation = function (component){
if (component.status == Component.Ready) {
if (component.status === Component.Ready) {
var obj = component.createObject(root);
if (obj == null) {
if (obj === null) {
console.debug("Error creating object " + component.url);
}
else {
obj.visible = false
if (isProtocol) {
protocolPages[obj.protocol] = obj
}
else {
if (type === PageType.Basic) {
pages[obj.page] = obj
}
else if (type === PageType.Proto) {
protocolPages[obj.protocol] = obj
}
else if (type === PageType.ShareProto) {
sharePages[obj.protocol] = obj
}
//console.debug("Created compenent " + component.url + " for " + type);
}
} else if (component.status == Component.Error) {
} else if (component.status === Component.Error) {
console.debug("Error loading component:", component.errorString());
}
}
if (c.status == Component.Ready)
if (c.status === Component.Ready)
finishCreation(c);
else {
console.debug("Warning: Pages components are not ready");
@ -228,13 +208,19 @@ Window {
Connections {
target: UiLogic
function onGoToPage(page, reset, slide) {
console.debug("Connections onGoToPage " + page);
root.gotoPage(page, reset, slide)
console.debug("Qml Connections onGoToPage " + page);
root.gotoPage(PageType.Basic, page, reset, slide)
}
function onGoToProtocolPage(protocol, reset, slide) {
console.debug("Connections onGoToProtocolPage " + protocol);
root.gotoProtocolPage(protocol, reset, slide)
console.debug("Qml Connections onGoToProtocolPage " + protocol);
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() {
root.close_page()
}
@ -253,6 +239,11 @@ Window {
function onHide() {
root.hide()
}
function onRaise() {
root.show()
root.raise()
root.requestActivate()
}
}
MessageDialog {
@ -267,62 +258,6 @@ Window {
}
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 {
id: publicKeyWarning
title: "AmneziaVPN"

View file

@ -69,15 +69,13 @@ using namespace PageEnumNS;
UiLogic::UiLogic(QObject *parent) :
QObject(parent),
m_currentPageValue{0},
m_trayIconUrl{},
m_trayActionDisconnectEnabled{true},
m_trayActionConnectEnabled{true},
m_dialogConnectErrorText{}
{
m_containersModel = new ContainersModel(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_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()
{
qDebug() << "UiLogic::initalizeUiLogic()";
@ -168,86 +190,8 @@ void UiLogic::initalizeUiLogic()
// ui->lineEdit_proto_shadowsocks_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
{
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()
{
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)
{
@ -326,9 +272,7 @@ void UiLogic::keyPressEvent(Qt::Key key)
emit goToPage(Page::ServerSettings);
break;
case Qt::Key_P:
selectedServerIndex = m_settings.defaultServerIndex();
selectedDockerContainer = m_settings.defaultContainer(selectedServerIndex);
emit goToPage(Page::ServerContainers);
onGotoCurrentProtocolsPage();
break;
case Qt::Key_T:
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)
@ -650,12 +601,22 @@ ErrorCode UiLogic::doInstallAction(const std::function<ErrorCode()> &action,
void UiLogic::setupTray()
{
setTrayState(VpnProtocol::Disconnected);
m_tray = new QSystemTrayIcon(qmlRoot());
setTrayState(VpnProtocol::Disconnected);
m_tray->show();
connect(m_tray, &QSystemTrayIcon::activated, this, &UiLogic::onTrayActivated);
}
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) {
@ -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()
{
return static_cast<PageEnumNS::Page>(getCurrentPageValue());
return static_cast<PageEnumNS::Page>(currentPageValue());
}
void UiLogic::setTrayState(VpnProtocol::ConnectionState state)
{
QString resourcesPath = "qrc:/images/tray/%1";
setTrayActionDisconnectEnabled(state == VpnProtocol::Connected);
setTrayActionConnectEnabled(state == VpnProtocol::Disconnected);
QString resourcesPath = ":/images/tray/%1";
switch (state) {
case VpnProtocol::Disconnected:
@ -713,8 +681,40 @@ void UiLogic::setTrayState(VpnProtocol::ConnectionState state)
// resourcesPath = ":/images_mac/tray_icon/%1";
// useIconName = useIconName.replace(".png", darkTaskBar ? "@2x.png" : " dark@2x.png");
//#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 <functional>
#include <QKeyEvent>
#include <QThread>
#include <QSystemTrayIcon>
#include "property_helper.h"
#include "pages.h"
@ -45,15 +47,13 @@ class UiLogic : public QObject
Q_OBJECT
AUTO_PROPERTY(bool, pageEnabled)
AUTO_PROPERTY(int, pagesStackDepth)
AUTO_PROPERTY(int, currentPageValue)
READONLY_PROPERTY(QObject *, containersModel)
READONLY_PROPERTY(QObject *, protocolsModel)
Q_PROPERTY(int currentPageValue READ getCurrentPageValue WRITE setCurrentPageValue NOTIFY currentPageValueChanged)
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)
// TODO: review
Q_PROPERTY(QString dialogConnectErrorText READ getDialogConnectErrorText WRITE setDialogConnectErrorText NOTIFY dialogConnectErrorTextChanged)
public:
@ -82,6 +82,9 @@ public:
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 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 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);
int getCurrentPageValue() const;
void setCurrentPageValue(int currentPageValue);
QString getTrayIconUrl() const;
void setTrayIconUrl(const QString &trayIconUrl);
bool getTrayActionDisconnectEnabled() const;
void setTrayActionDisconnectEnabled(bool trayActionDisconnectEnabled);
bool getTrayActionConnectEnabled() const;
void setTrayActionConnectEnabled(bool trayActionConnectEnabled);
Q_INVOKABLE bool saveTextFile(const QString& desc, const QString& ext, const QString& data);
Q_INVOKABLE bool saveBinaryFile(const QString& desc, const QString& ext, const QString& data);
Q_INVOKABLE void copyToClipboard(const QString& text);
QString getDialogConnectErrorText() const;
void setDialogConnectErrorText(const QString &dialogConnectErrorText);
signals:
void currentPageValueChanged();
void trayIconUrlChanged();
void trayActionDisconnectEnabledChanged();
void trayActionConnectEnabledChanged();
@ -116,18 +115,18 @@ signals:
void goToPage(PageEnumNS::Page page, 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 setStartPage(PageEnumNS::Page page, bool slide = true);
void showPublicKeyWarning();
void showConnectErrorDialog();
void show();
void hide();
void raise();
private:
int m_currentPageValue;
QString m_trayIconUrl;
bool m_trayActionDisconnectEnabled;
bool m_trayActionConnectEnabled;
QSystemTrayIcon *m_tray;
QString m_dialogConnectErrorText;
@ -136,6 +135,7 @@ private slots:
void installServer(QMap<DockerContainer, QJsonObject> &containers);
void setTrayState(VpnProtocol::ConnectionState state);
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
private:
PageEnumNS::Page currentPage();
@ -192,7 +192,12 @@ public:
Q_INVOKABLE PageProtocolLogicBase *protocolLogic(Protocol p);
QObject *qmlRoot() const;
void setQmlRoot(QObject *newQmlRoot);
private:
QObject *m_qmlRoot{nullptr};
AppSettingsLogic *m_appSettingsLogic;
GeneralSettingsLogic *m_generalSettingsLogic;
NetworkSettingsLogic *m_networkSettingsLogic;
@ -210,6 +215,7 @@ private:
QMap<Protocol, PageProtocolLogicBase *> m_protocolLogicMap;
VpnConnection* m_vpnConnection;
QThread m_vpnConnectionThread;
Settings m_settings;

View file

@ -23,12 +23,7 @@
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()
@ -190,10 +185,6 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
for (ProtocolEnumNS::Protocol proto : ContainerProps::protocolsForContainer(container)) {
// QString vpnConfigData =
// createVpnConfigurationForProto(
// serverIndex, credentials, container, containerConfig, proto, &e);
QJsonObject vpnConfigData = QJsonDocument::fromJson(
createVpnConfigurationForProto(
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);
}
Protocol proto = ContainerProps::defaultProtocol(container);
@ -214,11 +204,27 @@ QJsonObject VpnConnection::createVpnConfiguration(int serverIndex,
return vpnConfiguration;
}
ErrorCode VpnConnection::connectToVpn(int serverIndex,
void VpnConnection::connectToVpn(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{
qDebug() << QString("СonnectToVpn, Server index is %1, container is %2, route mode is")
.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;
emit connectionStateChanged(VpnProtocol::Connecting);
@ -233,26 +239,26 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex,
m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig);
if (e) {
emit connectionStateChanged(VpnProtocol::Error);
return e;
return;
}
#ifndef Q_OS_ANDROID
m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration));
if (!m_vpnProtocol) {
return ErrorCode::InternalError;
emit VpnProtocol::Error;
return;
}
m_vpnProtocol->prepare();
#else
Protocol proto = ContainerProps::defaultProtocol(container);
AndroidVpnProtocol *androidVpnProtocol = new AndroidVpnProtocol(proto, m_vpnConfiguration);
if (!androidVpnProtocol->initialize()) {
qDebug() << QString("Init failed") ;
return UnknownError;
emit VpnProtocol::Error;
return;
}
m_vpnProtocol.reset(androidVpnProtocol);
#endif
@ -263,7 +269,8 @@ ErrorCode VpnConnection::connectToVpn(int serverIndex,
ServerController::disconnectFromHost(credentials);
return m_vpnProtocol.data()->start();
e = m_vpnProtocol.data()->start();
if (e) emit VpnProtocol::Error;
}
QString VpnConnection::bytesPerSecToText(quint64 bytes)

View file

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

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)
qtservice-uselib:SUBDIRS=buildlib
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