amnezia-client/client/ui/controllers/apiController.cpp
2024-03-07 09:18:25 +03:00

170 lines
6.6 KiB
C++

#include "apiController.h"
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QtConcurrent>
#include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h"
namespace
{
namespace configKey
{
constexpr char cloak[] = "cloak";
constexpr char awg[] = "awg";
constexpr char apiEdnpoint[] = "api_endpoint";
constexpr char accessToken[] = "api_key";
constexpr char certificate[] = "certificate";
constexpr char publicKey[] = "public_key";
constexpr char protocol[] = "protocol";
}
}
ApiController::ApiController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel)
{
}
void ApiController::processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData,
QString &config)
{
if (protocol == configKey::cloak) {
config.replace("<key>", "<key>\n");
config.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
return;
} else if (protocol == configKey::awg) {
config.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
}
return;
}
ApiController::ApiPayloadData ApiController::generateApiPayloadData(const QString &protocol)
{
ApiController::ApiPayloadData apiPayload;
if (protocol == configKey::cloak) {
apiPayload.certRequest = OpenVpnConfigurator::createCertRequest();
} else if (protocol == configKey::awg) {
auto connData = WireguardConfigurator::genClientKeys();
apiPayload.wireGuardClientPubKey = connData.clientPubKey;
apiPayload.wireGuardClientPrivKey = connData.clientPrivKey;
}
return apiPayload;
}
QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData)
{
QJsonObject obj;
if (protocol == configKey::cloak) {
obj[configKey::certificate] = apiPayloadData.certRequest.request;
} else if (protocol == configKey::awg) {
obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey;
}
return obj;
}
void ApiController::updateServerConfigFromApi()
{
QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
QNetworkAccessManager manager;
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization",
"Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
request.setUrl(endpoint);
QString protocol = serverConfig.value(configKey::protocol).toString();
auto apiPayloadData = generateApiPayloadData(protocol);
QByteArray requestBody = QJsonDocument(fillApiPayload(protocol, apiPayloadData)).toJson();
QScopedPointer<QNetworkReply> reply;
reply.reset(manager.post(request, requestBody));
QEventLoop wait;
QObject::connect(reply.get(), &QNetworkReply::finished, &wait, &QEventLoop::quit);
wait.exec();
if (reply->error() == QNetworkReply::NoError) {
QString contents = QString::fromUtf8(reply->readAll());
auto data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
processApiConfig(protocol, apiPayloadData, configStr);
QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig.insert(config_key::dns1, apiConfig.value(config_key::dns1));
serverConfig.insert(config_key::dns2, apiConfig.value(config_key::dns2));
serverConfig.insert(config_key::containers, apiConfig.value(config_key::containers));
serverConfig.insert(config_key::hostName, apiConfig.value(config_key::hostName));
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
}
}
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
return;
});
}
void ApiController::clearApiConfig()
{
auto serverConfig = m_serversModel->getDefaultServerConfig();
serverConfig.remove(config_key::dns1);
serverConfig.remove(config_key::dns2);
serverConfig.remove(config_key::containers);
serverConfig.remove(config_key::hostName);
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
}