added button 'Reset settings and remove all data from the application'

This commit is contained in:
vladimir.kuznetsov 2023-07-14 22:59:49 +09:00
parent 3aaa7b62ef
commit 75489c00c2
18 changed files with 585 additions and 432 deletions

View file

@ -1,23 +1,23 @@
#include "servercontroller.h"
#include <QApplication>
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
#include <QEventLoop>
#include <QFile>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
#include <QPointer>
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
#include <QApplication>
#include <QTemporaryFile>
#include <QFileInfo>
#include <QThread>
#include <QTimer>
#include <QtConcurrent>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <chrono>
@ -25,15 +25,14 @@
#include "containers/containers_defs.h"
#include "logger.h"
#include "scripts_registry.h"
#include "server_defs.h"
#include "settings.h"
#include "scripts_registry.h"
#include "utilities.h"
#include <configurators/vpn_configurator.h>
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) :
m_settings(settings)
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings)
{
}
@ -42,10 +41,10 @@ ServerController::~ServerController()
m_sshClient.disconnectFromHost();
}
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr) {
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
{
auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) {
@ -82,7 +81,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
qDebug().noquote() << "EXEC" << lineToExec;
Logger::appendSshLog("Run command:" + lineToExec);
error = m_sshClient.executeCommand(lineToExec, cbReadStdOut, cbReadStdErr);
if (error != ErrorCode::NoError) {
return error;
@ -93,36 +91,36 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
return ErrorCode::NoError;
}
ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials,
DockerContainer container, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr)
ErrorCode
ServerController::runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
{
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
if (e) return e;
if (e)
return e;
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
e = runScript(credentials,
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
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)), cbReadStdOut, cbReadStdErr);
runScript(credentials, replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
return e;
}
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
const ServerCredentials &credentials, const QString &file, const QString &path,
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode)
{
ErrorCode e = ErrorCode::NoError;
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
if (e) return e;
if (e)
return e;
QString stdOut;
auto cbReadStd = [&](const QString &data, libssh::Client &) {
@ -131,61 +129,63 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
};
// mkdir
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"")
.arg(path);
e = runScript(credentials,
replaceVars(mkdir, genVarsForScript(credentials, container)));
if (e) return e;
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"").arg(path);
e = runScript(credentials, replaceVars(mkdir, genVarsForScript(credentials, container)));
if (e)
return e;
if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) {
e = runScript(credentials,
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e) return e;
}
else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
if (e)
return e;
} else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
e = runScript(credentials,
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e) return e;
if (e)
return e;
e = runScript(credentials,
replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
if (e) return e;
}
else return ErrorCode::NotImplementedError;
e = runScript(
credentials,
replaceVars(
QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e)
return e;
} else
return ErrorCode::NotImplementedError;
if (stdOut.contains("Error: No such container:")) {
return ErrorCode::ServerContainerMissingError;
}
runScript(credentials,
replaceVars(QString("sudo shred %1").arg(tmpFileName),
genVarsForScript(credentials, container)));
replaceVars(QString("sudo shred %1").arg(tmpFileName), genVarsForScript(credentials, container)));
runScript(credentials,
replaceVars(QString("sudo rm %1").arg(tmpFileName),
genVarsForScript(credentials, container)));
runScript(credentials, replaceVars(QString("sudo rm %1").arg(tmpFileName), genVarsForScript(credentials, container)));
return e;
}
QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode)
QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode)
{
if (errorCode) *errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").
arg(ContainerProps::containerToString(container)).arg(path);
if (errorCode)
*errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"")
.arg(ContainerProps::containerToString(container))
.arg(path);
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@ -197,14 +197,13 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
qDebug().noquote() << "Copy file from container stdout : \n" << stdOut;
qDebug().noquote() << "Copy file from container END : \n" ;
qDebug().noquote() << "Copy file from container END : \n";
return QByteArray::fromHex(stdOut.toUtf8());
}
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::SftpOverwriteMode overwriteMode)
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode)
{
auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) {
@ -218,7 +217,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
qDebug() << "remotePath" << remotePath;
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(), "non_desc");
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
"non_desc");
if (error != ErrorCode::NoError) {
return error;
}
@ -227,8 +227,7 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
ErrorCode ServerController::removeAllContainers(const ServerCredentials &credentials)
{
return runScript(credentials,
amnezia::scriptData(SharedScriptType::remove_all_containers));
return runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
}
ErrorCode ServerController::removeContainer(const ServerCredentials &credentials, DockerContainer container)
@ -242,26 +241,31 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
QJsonObject &config, bool isUpdate)
{
qDebug().noquote() << "ServerController::setupContainer" << ContainerProps::containerToString(container);
//qDebug().noquote() << QJsonDocument(config).toJson();
// qDebug().noquote() << QJsonDocument(config).toJson();
ErrorCode e = ErrorCode::NoError;
e = isUserInSudo(credentials, container);
if (e) return e;
if (e)
return e;
if (!isUpdate) {
e = isServerPortBusy(credentials, container, config);
if (e) return e;
if (e)
return e;
}
e = isServerDpkgBusy(credentials, container);
if (e) return e;
if (e)
return e;
e = installDockerWorker(credentials, container);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer installDockerWorker finished";
e = prepareHostWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer prepareHostWorker finished";
removeContainer(credentials, container);
@ -269,15 +273,18 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
qDebug().noquote() << "buildContainerWorker start";
e = buildContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer buildContainerWorker finished";
e = runContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer runContainerWorker finished";
e = configureContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer configureContainerWorker finished";
setupServerFirewall(credentials);
@ -290,43 +297,22 @@ ErrorCode ServerController::updateContainer(const ServerCredentials &credentials
const QJsonObject &oldConfig, QJsonObject &newConfig)
{
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is"
<< reinstallRequired;
if (reinstallRequired) {
return setupContainer(credentials, container, newConfig, true);
}
else {
} else {
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
if (e) return e;
if (e)
return e;
return startupContainerWorker(credentials, container, newConfig);
}
}
QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject config {
{ config_key::container, ContainerProps::containerToString(container) }
};
QJsonObject protoConfig;
protoConfig.insert(config_key::port, QString::number(port));
protoConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(tp, mainProto));
if (container == DockerContainer::Sftp) {
protoConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
protoConfig.insert(config_key::password, Utils::getRandomString(10));
}
config.insert(ProtocolProps::protoToString(mainProto), protoConfig);
return config;
}
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
const QJsonObject &newConfig)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
@ -334,24 +320,24 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
if (container == DockerContainer::OpenVpn) {
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto)
!= newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
return true;
}
if (container == DockerContainer::Cloak) {
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
return true;
}
if (container == DockerContainer::ShadowSocks) {
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
return true;
}
@ -374,48 +360,56 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
return ErrorCode::NoError;
};
ErrorCode error = runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
ErrorCode error =
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::install_docker), genVarsForScript(credentials)),
cbReadStdOut, cbReadStdErr);
if (stdOut.contains("command not found")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("command not found"))
return ErrorCode::ServerDockerFailedError;
return error;
}
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
// create folder on host
return runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
genVarsForScript(credentials, container)));
return runScript(
credentials,
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host), genVarsForScript(credentials, container)));
}
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
if (e) return e;
if (e)
return e;
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
e = runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
genVarsForScript(credentials, container, config)), cbReadStdOut);
if (e) return e;
genVarsForScript(credentials, container, config)),
cbReadStdOut);
if (e)
return e;
return e;
}
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@ -428,21 +422,26 @@ ErrorCode ServerController::runContainerWorker(const ServerCredentials &credenti
ErrorCode e = runScript(credentials,
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
genVarsForScript(credentials, container, config)), cbReadStdOut);
genVarsForScript(credentials, container, config)),
cbReadStdOut);
qDebug() << "cbReadStdOut: " << stdOut;
if (stdOut.contains("docker: Error response from daemon"))
return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("docker: Error response from daemon")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("address already in use")) return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("is already in use by container")) return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("invalid publish")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("address already in use"))
return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("is already in use by container"))
return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("invalid publish"))
return ErrorCode::ServerDockerFailedError;
return e;
}
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@ -454,19 +453,18 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
return ErrorCode::NoError;
};
ErrorCode e = runContainerScript(credentials, container,
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr);
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
return e;
}
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
@ -477,14 +475,17 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
ErrorCode e = uploadTextFileToContainer(container, credentials,
replaceVars(script, genVarsForScript(credentials, container, config)),
"/opt/amnezia/start.sh");
if (e) return e;
if (e)
return e;
return runScript(credentials,
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && "
"/opt/amnezia/start.sh\"",
genVarsForScript(credentials, container, config)));
}
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &config)
{
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
@ -495,85 +496,102 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
Vars vars;
vars.append({{"$REMOTE_HOST", credentials.hostName}});
vars.append({ { "$REMOTE_HOST", credentials.hostName } });
// OpenVPN vars
vars.append({{"$OPENVPN_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) }});
vars.append({{"$OPENVPN_SUBNET_CIDR", openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) }});
vars.append({{"$OPENVPN_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) }});
vars.append(
{ { "$OPENVPN_SUBNET_IP",
openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) } });
vars.append({ { "$OPENVPN_SUBNET_CIDR",
openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) } });
vars.append({ { "$OPENVPN_SUBNET_MASK",
openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) } });
vars.append({{"$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) }});
vars.append({{"$OPENVPN_TRANSPORT_PROTO", openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) }});
vars.append({ { "$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) } });
vars.append(
{ { "$OPENVPN_TRANSPORT_PROTO",
openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) } });
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
vars.append({{"$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" }});
vars.append({ { "$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" } });
vars.append({{"$OPENVPN_CIPHER", openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) }});
vars.append({{"$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) }});
vars.append({ { "$OPENVPN_CIPHER",
openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) } });
vars.append({ { "$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) } });
bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
vars.append({{"$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" }});
vars.append({ { "$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" } });
if (!isTlsAuth) {
// erase $OPENVPN_TA_KEY, so it will not set in OpenVpnConfigurator::genOpenVpnConfig
vars.append({{"$OPENVPN_TA_KEY", "" }});
vars.append({ { "$OPENVPN_TA_KEY", "" } });
}
vars.append({{"$OPENVPN_ADDITIONAL_CLIENT_CONFIG", openvpnConfig.value(config_key::additional_client_config).
toString(protocols::openvpn::defaultAdditionalClientConfig) }});
vars.append({{"$OPENVPN_ADDITIONAL_SERVER_CONFIG", openvpnConfig.value(config_key::additional_server_config).
toString(protocols::openvpn::defaultAdditionalServerConfig) }});
vars.append({ { "$OPENVPN_ADDITIONAL_CLIENT_CONFIG",
openvpnConfig.value(config_key::additional_client_config)
.toString(protocols::openvpn::defaultAdditionalClientConfig) } });
vars.append({ { "$OPENVPN_ADDITIONAL_SERVER_CONFIG",
openvpnConfig.value(config_key::additional_server_config)
.toString(protocols::openvpn::defaultAdditionalServerConfig) } });
// ShadowSocks vars
vars.append({{"$SHADOWSOCKS_SERVER_PORT", ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) }});
vars.append({{"$SHADOWSOCKS_LOCAL_PORT", ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) }});
vars.append({{"$SHADOWSOCKS_CIPHER", ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) }});
vars.append({ { "$SHADOWSOCKS_SERVER_PORT",
ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) } });
vars.append({ { "$SHADOWSOCKS_LOCAL_PORT",
ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) } });
vars.append({ { "$SHADOWSOCKS_CIPHER",
ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) } });
vars.append({{"$CONTAINER_NAME", ContainerProps::containerToString(container)}});
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container)}});
vars.append({ { "$CONTAINER_NAME", ContainerProps::containerToString(container) } });
vars.append({ { "$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container) } });
// Cloak vars
vars.append({{"$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) }});
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
vars.append({ { "$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) } });
vars.append({ { "$FAKE_WEB_SITE_ADDRESS",
cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) } });
// Wireguard vars
vars.append({{"$WIREGUARD_SUBNET_IP", wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
vars.append({{"$WIREGUARD_SUBNET_CIDR", wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
vars.append({{"$WIREGUARD_SUBNET_MASK", wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
vars.append(
{ { "$WIREGUARD_SUBNET_IP",
wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
vars.append({ { "$WIREGUARD_SUBNET_CIDR",
wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) } });
vars.append({ { "$WIREGUARD_SUBNET_MASK",
wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) } });
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
vars.append({ { "$WIREGUARD_SERVER_PORT",
wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) } });
// IPsec vars
vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}});
vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}});
vars.append({{"$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1"}});
vars.append({ { "$IPSEC_VPN_L2TP_NET", "192.168.42.0/24" } });
vars.append({ { "$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250" } });
vars.append({ { "$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1" } });
vars.append({{"$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24"}});
vars.append({{"$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250"}});
vars.append({ { "$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24" } });
vars.append({ { "$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250" } });
vars.append({{"$IPSEC_VPN_SHA2_TRUNCBUG", "yes"}});
vars.append({ { "$IPSEC_VPN_SHA2_TRUNCBUG", "yes" } });
vars.append({{"$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes"}});
vars.append({{"$IPSEC_VPN_DISABLE_IKEV2", "no"}});
vars.append({{"$IPSEC_VPN_DISABLE_L2TP", "no"}});
vars.append({{"$IPSEC_VPN_DISABLE_XAUTH", "no"}});
vars.append({ { "$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes" } });
vars.append({ { "$IPSEC_VPN_DISABLE_IKEV2", "no" } });
vars.append({ { "$IPSEC_VPN_DISABLE_L2TP", "no" } });
vars.append({ { "$IPSEC_VPN_DISABLE_XAUTH", "no" } });
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}});
vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}});
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
vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) }});
vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }});
vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }});
vars.append(
{ { "$SFTP_PORT",
sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) } });
vars.append({ { "$SFTP_USER", sftpConfig.value(config_key::userName).toString() } });
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
QString serverIp = Utils::getIPAddress(credentials.hostName);
if (!serverIp.isEmpty()) {
vars.append({{"$SERVER_IP_ADDRESS", serverIp}});
}
else {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
} else {
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
}
@ -592,10 +610,11 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
return ErrorCode::NoError;
};
ErrorCode e = runScript(credentials,
amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
ErrorCode e =
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return stdOut;
}
@ -607,23 +626,24 @@ void ServerController::setCancelInstallation(const bool cancel)
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
{
return runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall),
genVarsForScript(credentials)));
return runScript(
credentials,
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall), genVarsForScript(credentials)));
}
QString ServerController::replaceVars(const QString &script, const Vars &vars)
{
QString s = script;
for (const QPair<QString, QString> &var : vars) {
//qDebug() << "Replacing" << var.first << var.second;
// qDebug() << "Replacing" << var.first << var.second;
s.replace(var.first, var.second);
}
//qDebug().noquote() << script;
// qDebug().noquote() << script;
return s;
}
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
if (container == DockerContainer::Dns) {
return ErrorCode::NoError;
@ -646,8 +666,10 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
QString defaultPort("%1");
QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
QString port =
containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
QString defaultTransportProto =
ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
QString script = QString("sudo lsof -i -P -n | grep -E ':%1 ").arg(port);
@ -660,8 +682,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
script = script.append(" | grep LISTEN");
}
ErrorCode errorCode = runScript(credentials,
replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
ErrorCode errorCode = runScript(credentials, replaceVars(script, genVarsForScript(credentials, container)),
cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
@ -689,9 +711,11 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
};
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
ErrorCode error =
runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
if (!stdOut.contains("sudo")) return ErrorCode::ServerUserNotInSudo;
if (!stdOut.contains("sudo"))
return ErrorCode::ServerUserNotInSudo;
return error;
}
@ -718,7 +742,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
stdOut.clear();
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::check_server_is_busy),
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
genVarsForScript(credentials)),
cbReadStdOut, cbReadStdErr);
if (!stdOut.isEmpty() || stdOut.contains("Unable to acquire the dpkg frontend lock")) {
emit serverIsBusy(true);
QThread::msleep(1000);
@ -738,7 +763,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
return future.result();
}
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers)
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@ -770,13 +796,10 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
QString transportProto = containerAndPortMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject config {
{ config_key::container, name },
{ ProtocolProps::protoToString(mainProto), QJsonObject {
{ config_key::port, port },
{ config_key::transport_proto, transportProto }}
}
};
QJsonObject config { { config_key::container, name },
{ ProtocolProps::protoToString(mainProto),
QJsonObject { { config_key::port, port },
{ config_key::transport_proto, transportProto } } } };
installedContainers.insert(container, config);
}
}
@ -784,7 +807,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
return ErrorCode::NoError;
}
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback)
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
const std::function<QString()> &callback)
{
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
return error;

View file

@ -4,8 +4,8 @@
#include <QJsonObject>
#include <QObject>
#include "defs.h"
#include "containers/containers_defs.h"
#include "defs.h"
#include "sshclient.h"
class Settings;
@ -24,52 +24,61 @@ public:
ErrorCode removeAllContainers(const ServerCredentials &credentials);
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config, bool isUpdate = false);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config,
bool isUpdate = false);
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, QJsonObject &newConfig);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers);
// create initial config - generate passwords, etc
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &file, const QString &path,
ErrorCode uploadTextFileToContainer(
DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode = nullptr);
QString replaceVars(const QString &script, const Vars &vars);
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None,
const QJsonObject &config = QJsonObject());
ErrorCode runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
ErrorCode
runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
void setCancelInstallation(const bool cancel);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
const std::function<QString()> &callback);
private:
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config);
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
const QJsonObject &newConfig);
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
ErrorCode setupServerFirewall(const ServerCredentials &credentials);

View file

@ -274,5 +274,6 @@
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
</qresource>
</RCC>

View file

@ -1,30 +1,28 @@
#include "secure_qsettings.h"
#include "platforms/ios/MobileUtils.h"
#include "QAead.h"
#include "QBlockCipher.h"
#include "utilities.h"
#include <QDataStream>
#include <QDebug>
#include <QEventLoop>
#include <QIODevice>
#include <QJsonDocument>
#include <QJsonObject>
#include <QRandomGenerator>
#include <QSharedPointer>
#include <QTimer>
#include "utilities.h"
#include <QRandomGenerator>
#include "QAead.h"
#include "QBlockCipher.h"
using namespace QKeychain;
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
: QObject{parent},
m_settings(organization, application, parent),
encryptedKeys({"Servers/serversList"})
: QObject { parent }, m_settings(organization, application, parent), encryptedKeys({ "Servers/serversList" })
{
bool encrypted = m_settings.value("Conf/encrypted").toBool();
// convert settings to encrypted for if updated to >= 2.1.0
if (encryptionRequired() && ! encrypted) {
if (encryptionRequired() && !encrypted) {
for (const QString &key : m_settings.allKeys()) {
if (encryptedKeys.contains(key)) {
const QVariant &val = value(key);
@ -44,15 +42,15 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
return m_cache.value(key);
}
if (!m_settings.contains(key)) return defaultValue;
if (!m_settings.contains(key))
return defaultValue;
QVariant retVal;
// check if value is not encrypted, v. < 2.0.x
retVal = m_settings.value(key);
if (retVal.isValid()) {
if (retVal.userType() == QVariant::ByteArray &&
retVal.toByteArray().mid(0, magicString.size()) == magicString) {
if (retVal.userType() == QVariant::ByteArray && retVal.toByteArray().mid(0, magicString.size()) == magicString) {
if (getEncKey().isEmpty() || getEncIv().isEmpty()) {
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
@ -71,8 +69,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
retVal = QVariant();
}
}
}
else {
} else {
qWarning() << "SecureQSettings::value invalid QVariant value";
retVal = QVariant();
}
@ -95,14 +92,12 @@ void SecureQSettings::setValue(const QString &key, const QVariant &value)
QByteArray encryptedValue = encryptText(decryptedValue);
m_settings.setValue(key, magicString + encryptedValue);
}
else {
} else {
qCritical() << "SecureQSettings::setValue Encryption required, but key is empty";
return;
}
}
else {
} else {
m_settings.setValue(key, value);
}
@ -139,7 +134,8 @@ QByteArray SecureQSettings::backupAppConfig() const
bool SecureQSettings::restoreAppConfig(const QByteArray &json)
{
QJsonObject cfg = QJsonDocument::fromJson(json).object();
if (cfg.isEmpty()) return false;
if (cfg.isEmpty())
return false;
for (const QString &key : cfg.keys()) {
setValue(key, cfg.value(key).toVariant());
@ -149,14 +145,13 @@ bool SecureQSettings::restoreAppConfig(const QByteArray &json)
return true;
}
QByteArray SecureQSettings::encryptText(const QByteArray& value) const
QByteArray SecureQSettings::encryptText(const QByteArray &value) const
{
QSimpleCrypto::QBlockCipher cipher;
return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
}
QByteArray SecureQSettings::decryptText(const QByteArray& ba) const
QByteArray SecureQSettings::decryptText(const QByteArray &ba) const
{
QSimpleCrypto::QBlockCipher cipher;
return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
@ -228,13 +223,11 @@ QByteArray SecureQSettings::getSecTag(const QString &tag)
job->setAutoDelete(false);
job->setKey(tag);
QEventLoop loop;
job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop](){
loop.quit();
});
job->connect(job.data(), &ReadPasswordJob::finished, job.data(), [&loop]() { loop.quit(); });
job->start();
loop.exec();
if ( job->error() ) {
if (job->error()) {
qCritical() << "SecureQSettings::getSecTag Error:" << job->errorString();
}
@ -249,9 +242,7 @@ void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
job->setBinaryData(data);
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop](){
loop.quit();
});
job->connect(job.data(), &WritePasswordJob::finished, job.data(), [&loop]() { loop.quit(); });
job->start();
loop.exec();
@ -260,4 +251,10 @@ void SecureQSettings::setSecTag(const QString &tag, const QByteArray &data)
}
}
void SecureQSettings::clearSettings()
{
QMutexLocker locker(&mutex);
m_settings.clear();
m_cache.clear();
sync();
}

View file

@ -1,23 +1,22 @@
#ifndef SECUREQSETTINGS_H
#define SECUREQSETTINGS_H
#include <QSettings>
#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QObject>
#include <QSettings>
#include "keychain.h"
constexpr const char* settingsKeyTag = "settingsKeyTag";
constexpr const char* settingsIvTag = "settingsIvTag";
constexpr const char* keyChainName = "AmneziaVPN-Keychain";
constexpr const char *settingsKeyTag = "settingsKeyTag";
constexpr const char *settingsIvTag = "settingsIvTag";
constexpr const char *keyChainName = "AmneziaVPN-Keychain";
class SecureQSettings : public QObject
{
public:
explicit SecureQSettings(const QString &organization, const QString &application = QString(), QObject *parent = nullptr);
explicit SecureQSettings(const QString &organization, const QString &application = QString(),
QObject *parent = nullptr);
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const;
void setValue(const QString &key, const QVariant &value);
@ -28,7 +27,7 @@ public:
bool restoreAppConfig(const QByteArray &json);
QByteArray encryptText(const QByteArray &value) const;
QByteArray decryptText(const QByteArray& ba) const;
QByteArray decryptText(const QByteArray &ba) const;
bool encryptionRequired() const;
@ -38,6 +37,8 @@ public:
static QByteArray getSecTag(const QString &tag);
static void setSecTag(const QString &tag, const QByteArray &data);
void clearSettings();
private:
QSettings m_settings;

View file

@ -1,6 +1,6 @@
#include "version.h"
#include "settings.h"
#include "utilities.h"
#include "version.h"
#include "containers/containers_defs.h"
#include "logger.h"
@ -8,10 +8,7 @@
const char Settings::cloudFlareNs1[] = "1.1.1.1";
const char Settings::cloudFlareNs2[] = "1.0.0.1";
Settings::Settings(QObject* parent) :
QObject(parent),
m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
Settings::Settings(QObject *parent) : QObject(parent), m_settings(ORGANIZATION_NAME, APPLICATION_NAME, this)
{
// Import old settings
if (serversCount() == 0) {
@ -20,7 +17,7 @@ Settings::Settings(QObject* parent) :
QString serverName = m_settings.value("Server/serverName").toString();
int port = m_settings.value("Server/serverPort").toInt();
if (!user.isEmpty() && !password.isEmpty() && !serverName.isEmpty()){
if (!user.isEmpty() && !password.isEmpty() && !serverName.isEmpty()) {
QJsonObject server;
server.insert(config_key::userName, user);
server.insert(config_key::password, password);
@ -46,7 +43,8 @@ int Settings::serversCount() const
QJsonObject Settings::server(int index) const
{
const QJsonArray &servers = serversArray();
if (index >= servers.size()) return QJsonObject();
if (index >= servers.size())
return QJsonObject();
return servers.at(index).toObject();
}
@ -61,7 +59,8 @@ void Settings::addServer(const QJsonObject &server)
void Settings::removeServer(int index)
{
QJsonArray servers = serversArray();
if (index >= servers.size()) return;
if (index >= servers.size())
return;
servers.removeAt(index);
setServersArray(servers);
@ -70,7 +69,8 @@ void Settings::removeServer(int index)
bool Settings::editServer(int index, const QJsonObject &server)
{
QJsonArray servers = serversArray();
if (index >= servers.size()) return false;
if (index >= servers.size())
return false;
servers.replace(index, server);
setServersArray(servers);
@ -94,8 +94,8 @@ QString Settings::defaultContainerName(int serverIndex) const
QString name = server(serverIndex).value(config_key::defaultContainer).toString();
if (name.isEmpty()) {
return ContainerProps::containerToString(DockerContainer::None);
}
else return name;
} else
return name;
}
QMap<DockerContainer, QJsonObject> Settings::containers(int serverIndex) const
@ -104,7 +104,8 @@ QMap<DockerContainer, QJsonObject> Settings::containers(int serverIndex) const
QMap<DockerContainer, QJsonObject> containersMap;
for (const QJsonValue &val : containers) {
containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()), val.toObject());
containersMap.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()),
val.toObject());
}
return containersMap;
@ -114,17 +115,17 @@ void Settings::setContainers(int serverIndex, const QMap<DockerContainer, QJsonO
{
QJsonObject s = server(serverIndex);
QJsonArray c;
for (const QJsonObject &o: containers) {
for (const QJsonObject &o : containers) {
c.append(o);
}
s.insert(config_key::containers, c);
editServer(serverIndex, s);
}
QJsonObject Settings::containerConfig(int serverIndex, DockerContainer container)
{
if (container == DockerContainer::None) return QJsonObject();
if (container == DockerContainer::None)
return QJsonObject();
return containers(serverIndex).value(container);
}
@ -170,7 +171,7 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai
{
// recursively remove
if (proto == Proto::Any) {
for (Proto p: ContainerProps::protocolsForContainer(container)) {
for (Proto p : ContainerProps::protocolsForContainer(container)) {
clearLastConnectionConfig(serverIndex, container, p);
}
return;
@ -183,7 +184,8 @@ void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer contai
bool Settings::haveAuthData(int serverIndex) const
{
if (serverIndex < 0) return false;
if (serverIndex < 0)
return false;
ServerCredentials cred = serverCredentials(serverIndex);
return (!cred.hostName.isEmpty() && !cred.userName.isEmpty() && !cred.secretData.isEmpty());
}
@ -196,7 +198,7 @@ QString Settings::nextAvailableServerName() const
do {
i++;
nameExist = false;
for (const QJsonValue &server: serversArray()) {
for (const QJsonValue &server : serversArray()) {
if (server.toObject().value(config_key::description).toString() == tr("Server") + " " + QString::number(i)) {
nameExist = true;
break;
@ -223,19 +225,17 @@ void Settings::setSaveLogs(bool enabled)
QString Settings::routeModeString(RouteMode mode) const
{
switch (mode) {
case VpnAllSites:
return "AllSites";
case VpnOnlyForwardSites:
return "ForwardSites";
case VpnAllExceptSites:
return "ExceptSites";
case VpnAllSites: return "AllSites";
case VpnOnlyForwardSites: return "ForwardSites";
case VpnAllExceptSites: return "ExceptSites";
}
}
void Settings::addVpnSite(RouteMode mode, const QString &site, const QString &ip)
{
QVariantMap sites = vpnSites(mode);
if (sites.contains(site) && ip.isEmpty()) return;
if (sites.contains(site) && ip.isEmpty())
return;
sites.insert(site, ip);
setVpnSites(mode, sites);
@ -248,7 +248,8 @@ void Settings::addVpnSites(RouteMode mode, const QMap<QString, QString> &sites)
const QString &site = i.key();
const QString &ip = i.value();
if (allSites.contains(site) && allSites.value(site) == ip) continue;
if (allSites.contains(site) && allSites.value(site) == ip)
continue;
allSites.insert(site, ip);
}
@ -263,8 +264,7 @@ QStringList Settings::getVpnIps(RouteMode mode) const
for (auto i = m.constBegin(); i != m.constEnd(); ++i) {
if (Utils::checkIpSubnetFormat(i.key())) {
ips.append(i.key());
}
else if (Utils::checkIpSubnetFormat(i.value().toString())) {
} else if (Utils::checkIpSubnetFormat(i.value().toString())) {
ips.append(i.value().toString());
}
}
@ -275,7 +275,8 @@ QStringList Settings::getVpnIps(RouteMode mode) const
void Settings::removeVpnSite(RouteMode mode, const QString &site)
{
QVariantMap sites = vpnSites(mode);
if (!sites.contains(site)) return;
if (!sites.contains(site))
return;
sites.remove(site);
setVpnSites(mode, sites);
@ -285,7 +286,8 @@ void Settings::addVpnIps(RouteMode mode, const QStringList &ips)
{
QVariantMap sites = vpnSites(mode);
for (const QString &ip : ips) {
if (ip.isEmpty()) continue;
if (ip.isEmpty())
continue;
sites.insert(ip, "");
}
@ -297,7 +299,8 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
{
QVariantMap sitesMap = vpnSites(mode);
for (const QString &site : sites) {
if (site.isEmpty()) continue;
if (site.isEmpty())
continue;
sitesMap.remove(site);
}
@ -305,9 +308,20 @@ void Settings::removeVpnSites(RouteMode mode, const QStringList &sites)
setVpnSites(mode, sitesMap);
}
QString Settings::primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString(); }
QString Settings::primaryDns() const
{
return m_settings.value("Conf/primaryDns", cloudFlareNs1).toString();
}
QString Settings::secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString(); }
QString Settings::secondaryDns() const
{
return m_settings.value("Conf/secondaryDns", cloudFlareNs2).toString();
}
void Settings::clearSettings()
{
m_settings.clearSettings();
}
ServerCredentials Settings::defaultServerCredentials() const
{

View file

@ -183,6 +183,8 @@ public:
m_settings.setValue("Conf/appLanguage", locale);
};
void clearSettings();
signals:
void saveLogsChanged();

View file

@ -16,12 +16,19 @@ InstallController::InstallController(const QSharedPointer<ServersModel> &servers
void InstallController::install(DockerContainer container, int port, TransportProto transportProto)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject containerConfig;
QJsonObject containerConfig { { config_key::port, QString::number(port) },
{ config_key::transport_proto,
ProtocolProps::transportProtoToString(transportProto, mainProto) } };
QJsonObject config { { config_key::container, ContainerProps::containerToString(container) },
{ ProtocolProps::protoToString(mainProto), containerConfig } };
containerConfig.insert(config_key::port, QString::number(port));
containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, mainProto));
if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(10));
}
QJsonObject config;
config.insert(config_key::container, ContainerProps::containerToString(container));
config.insert(ProtocolProps::protoToString(mainProto), containerConfig);
if (m_shouldCreateServer) {
if (isServerAlreadyExists()) {

View file

@ -27,6 +27,7 @@ namespace PageLoader
PageSettingsApplication,
PageSettingsBackup,
PageSettingsAbout,
PageSettingsLogging,
PageSetupWizardStart,
PageSetupWizardCredentials,

View file

@ -46,14 +46,15 @@ void SettingsController::setSecondaryDns(const QString &dns)
emit secondaryDnsChanged();
}
bool SettingsController::isSaveLogsEnabled()
bool SettingsController::isLoggingEnable()
{
return m_settings->isSaveLogs();
}
void SettingsController::setSaveLogs(bool enable)
void SettingsController::toggleLogging(bool enable)
{
m_settings->setSaveLogs(enable);
emit loggingStateChanged();
}
void SettingsController::openLogsFolder()
@ -101,3 +102,8 @@ QString SettingsController::getAppVersion()
{
return m_appVersion;
}
void SettingsController::clearSettings()
{
m_settings->clearSettings();
}

View file

@ -16,6 +16,7 @@ public:
Q_PROPERTY(QString primaryDns READ getPrimaryDns WRITE setPrimaryDns NOTIFY primaryDnsChanged)
Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged)
Q_PROPERTY(bool isLoggingEnable READ isLoggingEnable WRITE toggleLogging NOTIFY loggingStateChanged)
public slots:
void setAmneziaDns(bool enable);
@ -27,8 +28,8 @@ public slots:
QString getSecondaryDns();
void setSecondaryDns(const QString &dns);
bool isSaveLogsEnabled();
void setSaveLogs(bool enable);
bool isLoggingEnable();
void toggleLogging(bool enable);
void openLogsFolder();
void exportLogsFile();
@ -39,9 +40,12 @@ public slots:
QString getAppVersion();
void clearSettings();
signals:
void primaryDnsChanged();
void secondaryDnsChanged();
void loggingStateChanged();
private:
QSharedPointer<ServersModel> m_serversModel;

View file

@ -54,3 +54,8 @@ int LanguageModel::getCurrentLanguageIndex()
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}
QString LanguageModel::getCurrentLanuageName()
{
return m_availableLanguages[getCurrentLanguageIndex()].name;
}

View file

@ -46,6 +46,7 @@ public:
public slots:
void changeLanguage(const LanguageSettings::AvailableLanguageEnum language);
int getCurrentLanguageIndex();
QString getCurrentLanuageName();
signals:
void updateTranslations(const QLocale &locale);

View file

@ -89,7 +89,7 @@ void ServerContainersLogic::onPushButtonRemoveClicked(DockerContainer container)
void ServerContainersLogic::onPushButtonContinueClicked(DockerContainer c, int port, TransportProto tp)
{
ServerController serverController(m_settings);
QJsonObject config = serverController.createContainerInitialConfig(c, port, tp);
QJsonObject config; // = serverController.createContainerInitialConfig(c, port, tp);
emit uiLogic()->goToPage(Page::ServerConfiguringProgress);
qApp->processEvents();

View file

@ -17,14 +17,16 @@ Item {
property string textColor: "#d7d8db"
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
RowLayout {
id: content
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.topMargin: 16
anchors.bottomMargin: 16
Rectangle {
id: leftImageBackground
@ -56,8 +58,6 @@ Item {
color: root.textColor
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: description.visible ? 0 : 16
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
@ -72,7 +72,6 @@ Item {
visible: root.descriptionText !== ""
Layout.fillWidth: true
Layout.bottomMargin: 16
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter

View file

@ -48,6 +48,7 @@ PageType {
Layout.topMargin: 16
text: qsTr("Language")
descriptionText: LanguageModel.getCurrentLanuageName()
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
@ -60,6 +61,22 @@ PageType {
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Logging")
descriptionText: SettingsController.isLoggingEnable ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
goToPage(PageEnum.PageSettingsLogging)
}
}
DividerType {}
LabelWithButtonType {
Layout.fillWidth: true
@ -67,10 +84,27 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Reset settings and remove all data from the application?")
questionDrawer.descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
SettingsController.clearSettings()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {}
QuestionDrawer {
id: questionDrawer
}
}
}
}

View file

@ -44,96 +44,6 @@ PageType {
headerText: qsTr("Backup")
}
SwitcherType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Save logs")
checked: SettingsController.isSaveLogsEnabled()
onCheckedChanged: {
if (checked !== SettingsController.isSaveLogsEnabled()) {
SettingsController.setSaveLogs(checked)
}
}
}
RowLayout {
Layout.fillWidth: true
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/folder-open.svg"
onClicked: SettingsController.openLogsFolder()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Open folder with logs")
color: "#D7D8DB"
}
}
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/save.svg"
onClicked: SettingsController.exportLogsFile()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Save logs to file")
color: "#D7D8DB"
}
}
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/delete.svg"
onClicked: SettingsController.clearLogs()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Clear logs")
color: "#D7D8DB"
}
}
}
ListItemTitleType {
Layout.fillWidth: true
Layout.topMargin: 10

View file

@ -0,0 +1,138 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Config"
import "../Controls2/TextTypes"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
HeaderType {
Layout.fillWidth: true
headerText: qsTr("Logging")
}
SwitcherType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Save logs")
checked: SettingsController.isLoggingEnable
onCheckedChanged: {
if (checked !== SettingsController.isLoggingEnable) {
SettingsController.isLoggingEnable = checked
}
}
}
RowLayout {
Layout.fillWidth: true
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/folder-open.svg"
onClicked: SettingsController.openLogsFolder()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Open folder with logs")
color: "#D7D8DB"
}
}
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/save.svg"
onClicked: SettingsController.exportLogsFile()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Save logs to file")
color: "#D7D8DB"
}
}
ColumnLayout {
Layout.alignment: Qt.AlignBaseline
Layout.preferredWidth: root.width / 3
ImageButtonType {
Layout.alignment: Qt.AlignHCenter
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/delete.svg"
onClicked: SettingsController.clearLogs()
}
CaptionTextType {
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
text: qsTr("Clear logs")
color: "#D7D8DB"
}
}
}
}
}
}