Add clickable docs url on error (#806)

This commit is contained in:
Vladyslav Miachkov 2024-05-25 13:00:51 +03:00 committed by GitHub
parent a0c06048cd
commit b027fff103
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 173 additions and 104 deletions

View file

@ -363,10 +363,16 @@ void AmneziaApplication::initControllers()
new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings)); new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get()); m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
connect(m_connectionController.get(), &ConnectionController::connectionErrorOccurred, this, [this](const QString &errorMessage) { connect(m_connectionController.get(), qOverload<const QString &>(&ConnectionController::connectionErrorOccurred), this, [this](const QString &errorMessage) {
emit m_pageController->showErrorMessage(errorMessage); emit m_pageController->showErrorMessage(errorMessage);
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
}); });
connect(m_connectionController.get(), qOverload<ErrorCode>(&ConnectionController::connectionErrorOccurred), this, [this](ErrorCode errorCode) {
emit m_pageController->showErrorMessage(errorCode);
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_connectionController.get(), &ConnectionController::connectButtonClicked, m_connectionController.get(), connect(m_connectionController.get(), &ConnectionController::connectButtonClicked, m_connectionController.get(),
&ConnectionController::toggleConnection, Qt::QueuedConnection); &ConnectionController::toggleConnection, Qt::QueuedConnection);

View file

@ -8,7 +8,6 @@
#include "amnezia_application.h" #include "amnezia_application.h"
#include "configurators/wireguard_configurator.h" #include "configurators/wireguard_configurator.h"
#include "version.h" #include "version.h"
#include "core/errorstrings.h"
namespace namespace
{ {
@ -110,7 +109,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) { if (ba.isEmpty()) {
emit errorOccurred(errorString(ErrorCode::ApiConfigEmptyError)); emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return; return;
} }
@ -135,14 +134,14 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
} else { } else {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) { || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
emit errorOccurred(errorString(ErrorCode::ApiConfigTimeoutError)); emit errorOccurred(ErrorCode::ApiConfigTimeoutError);
} else { } else {
QString err = reply->errorString(); QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll()); qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error(); qDebug() << reply->error();
qDebug() << err; qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ErrorCode::ApiConfigDownloadError)); emit errorOccurred(ErrorCode::ApiConfigDownloadError);
} }
} }
@ -153,7 +152,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
[this, reply](QNetworkReply::NetworkError error) { qDebug() << reply->errorString() << error; }); [this, reply](QNetworkReply::NetworkError error) { qDebug() << reply->errorString() << error; });
connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) { connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) {
qDebug().noquote() << errors; qDebug().noquote() << errors;
emit errorOccurred(errorString(ErrorCode::ApiConfigSslError)); emit errorOccurred(ErrorCode::ApiConfigSslError);
}); });
} }
} }

View file

@ -20,7 +20,7 @@ public slots:
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig); void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
signals: signals:
void errorOccurred(const QString &errorMessage); void errorOccurred(ErrorCode errorCode);
void configUpdated(const bool updateConfig, const QJsonObject &config, const int serverIndex); void configUpdated(const bool updateConfig, const QJsonObject &config, const int serverIndex);
private: private:

View file

@ -36,6 +36,10 @@ namespace amnezia
} }
}; };
namespace error_code_ns
{
Q_NAMESPACE
// TODO: change to enum class
enum ErrorCode { enum ErrorCode {
// General error codes // General error codes
NoError = 0, NoError = 0,
@ -111,6 +115,10 @@ namespace amnezia
FatalError = 1204, FatalError = 1204,
AbortError = 1205 AbortError = 1205
}; };
Q_ENUM_NS(ErrorCode)
}
using ErrorCode = error_code_ns::ErrorCode;
} // namespace amnezia } // namespace amnezia

View file

@ -8,68 +8,68 @@ QString errorString(ErrorCode code) {
switch (code) { switch (code) {
// General error codes // General error codes
case(NoError): errorMessage = QObject::tr("No error"); break; case(ErrorCode::NoError): errorMessage = QObject::tr("No error"); break;
case(UnknownError): errorMessage = QObject::tr("Unknown Error"); break; case(ErrorCode::UnknownError): errorMessage = QObject::tr("Unknown Error"); break;
case(NotImplementedError): errorMessage = QObject::tr("Function not implemented"); break; case(ErrorCode::NotImplementedError): errorMessage = QObject::tr("Function not implemented"); break;
case(AmneziaServiceNotRunning): errorMessage = QObject::tr("Background service is not running"); break; case(ErrorCode::AmneziaServiceNotRunning): errorMessage = QObject::tr("Background service is not running"); break;
// Server errors // Server errors
case(ServerCheckFailed): errorMessage = QObject::tr("Server check failed"); break; case(ErrorCode::ServerCheckFailed): errorMessage = QObject::tr("Server check failed"); break;
case(ServerPortAlreadyAllocatedError): errorMessage = QObject::tr("Server port already used. Check for another software"); break; case(ErrorCode::ServerPortAlreadyAllocatedError): errorMessage = QObject::tr("Server port already used. Check for another software"); break;
case(ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break; case(ErrorCode::ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break;
case(ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break; case(ErrorCode::ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break;
case(ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break; case(ErrorCode::ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break;
case(ServerUserNotInSudo): errorMessage = QObject::tr("The user does not have permission to use sudo"); break; case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user does not have permission to use sudo"); break;
case(ServerPacketManagerError): errorMessage = QObject::tr("Server error: Packet manager error"); break; case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Packet manager error"); break;
// Libssh errors // Libssh errors
case(SshRequestDeniedError): errorMessage = QObject::tr("Ssh request was denied"); break; case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("Ssh request was denied"); break;
case(SshInterruptedError): errorMessage = QObject::tr("Ssh request was interrupted"); break; case(ErrorCode::SshInterruptedError): errorMessage = QObject::tr("Ssh request was interrupted"); break;
case(SshInternalError): errorMessage = QObject::tr("Ssh internal error"); break; case(ErrorCode::SshInternalError): errorMessage = QObject::tr("Ssh internal error"); break;
case(SshPrivateKeyError): errorMessage = QObject::tr("Invalid private key or invalid passphrase entered"); break; case(ErrorCode::SshPrivateKeyError): errorMessage = QObject::tr("Invalid private key or invalid passphrase entered"); break;
case(SshPrivateKeyFormatError): errorMessage = QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types"); break; case(ErrorCode::SshPrivateKeyFormatError): errorMessage = QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types"); break;
case(SshTimeoutError): errorMessage = QObject::tr("Timeout connecting to server"); break; case(ErrorCode::SshTimeoutError): errorMessage = QObject::tr("Timeout connecting to server"); break;
// Ssh scp errors // Ssh scp errors
case(SshScpFailureError): errorMessage = QObject::tr("Scp error: Generic failure"); break; case(ErrorCode::SshScpFailureError): errorMessage = QObject::tr("Scp error: Generic failure"); break;
// Local errors // Local errors
case (OpenVpnConfigMissing): errorMessage = QObject::tr("OpenVPN config missing"); break; case (ErrorCode::OpenVpnConfigMissing): errorMessage = QObject::tr("OpenVPN config missing"); break;
case (OpenVpnManagementServerError): errorMessage = QObject::tr("OpenVPN management server error"); break; case (ErrorCode::OpenVpnManagementServerError): errorMessage = QObject::tr("OpenVPN management server error"); break;
// Distro errors // Distro errors
case (OpenVpnExecutableMissing): errorMessage = QObject::tr("OpenVPN executable missing"); break; case (ErrorCode::OpenVpnExecutableMissing): errorMessage = QObject::tr("OpenVPN executable missing"); break;
case (ShadowSocksExecutableMissing): errorMessage = QObject::tr("ShadowSocks (ss-local) executable missing"); break; case (ErrorCode::ShadowSocksExecutableMissing): errorMessage = QObject::tr("ShadowSocks (ss-local) executable missing"); break;
case (CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break; case (ErrorCode::CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break;
case (AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break; case (ErrorCode::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break;
case (OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break; case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
// VPN errors // VPN errors
case (OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break; case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
case (OpenVpnTapAdapterError): errorMessage = QObject::tr("Can't setup OpenVPN TAP network adapter"); break; case (ErrorCode::OpenVpnTapAdapterError): errorMessage = QObject::tr("Can't setup OpenVPN TAP network adapter"); break;
case (AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break; case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
case (ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break; case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
// Android errors // Android errors
case (AndroidError): errorMessage = QObject::tr("VPN connection error"); break; case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
// Api errors // Api errors
case (ApiConfigDownloadError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break; case (ErrorCode::ApiConfigDownloadError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
case (ApiConfigAlreadyAdded): errorMessage = QObject::tr("This config has already been added to the application"); break; case (ErrorCode::ApiConfigAlreadyAdded): errorMessage = QObject::tr("This config has already been added to the application"); break;
case (ApiConfigEmptyError): errorMessage = QObject::tr("In the response from the server, an empty config was received"); break; case (ErrorCode::ApiConfigEmptyError): errorMessage = QObject::tr("In the response from the server, an empty config was received"); break;
case (ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break; case (ErrorCode::ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break;
case (ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break; case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
// QFile errors // QFile errors
case(OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break; case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
case(ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break; case(ErrorCode::ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break;
case(PermissionsError): errorMessage = QObject::tr("QFile error: The file could not be accessed"); break; case(ErrorCode::PermissionsError): errorMessage = QObject::tr("QFile error: The file could not be accessed"); break;
case(UnspecifiedError): errorMessage = QObject::tr("QFile error: An unspecified error occurred"); break; case(ErrorCode::UnspecifiedError): errorMessage = QObject::tr("QFile error: An unspecified error occurred"); break;
case(FatalError): errorMessage = QObject::tr("QFile error: A fatal error occurred"); break; case(ErrorCode::FatalError): errorMessage = QObject::tr("QFile error: A fatal error occurred"); break;
case(AbortError): errorMessage = QObject::tr("QFile error: The operation was aborted"); break; case(ErrorCode::AbortError): errorMessage = QObject::tr("QFile error: The operation was aborted"); break;
case(InternalError): case(ErrorCode::InternalError):
default: default:
errorMessage = QObject::tr("Internal error"); break; errorMessage = QObject::tr("Internal error"); break;
} }

View file

@ -136,7 +136,7 @@ ErrorCode AndroidController::start(const QJsonObject &vpnConfig)
callActivityMethod("start", "(Ljava/lang/String;)V", callActivityMethod("start", "(Ljava/lang/String;)V",
QJniObject::fromString(config).object<jstring>()); QJniObject::fromString(config).object<jstring>());
return NoError; return ErrorCode::NoError;
} }
void AndroidController::stop() void AndroidController::stop()

View file

@ -8,7 +8,6 @@
#include <QtConcurrent> #include <QtConcurrent>
#include "core/controllers/vpnConfigurationController.h" #include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "version.h" #include "version.h"
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel, ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
@ -30,7 +29,7 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
connect(&m_apiController, &ApiController::configUpdated, this, connect(&m_apiController, &ApiController::configUpdated, this,
static_cast<void (ConnectionController::*)(const bool, const QJsonObject &, const int)>(&ConnectionController::openConnection)); static_cast<void (ConnectionController::*)(const bool, const QJsonObject &, const int)>(&ConnectionController::openConnection));
connect(&m_apiController, &ApiController::errorOccurred, this, &ConnectionController::connectionErrorOccurred); connect(&m_apiController, qOverload<ErrorCode>(&ApiController::errorOccurred), this, qOverload<ErrorCode>(&ConnectionController::connectionErrorOccurred));
m_state = Vpn::ConnectionState::Disconnected; m_state = Vpn::ConnectionState::Disconnected;
} }
@ -40,7 +39,7 @@ void ConnectionController::openConnection()
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
{ {
emit connectionErrorOccurred(errorString(ErrorCode::AmneziaServiceNotRunning)); emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
return; return;
} }
#endif #endif
@ -63,9 +62,9 @@ void ConnectionController::closeConnection()
emit disconnectFromVpn(); emit disconnectFromVpn();
} }
QString ConnectionController::getLastConnectionError() ErrorCode ConnectionController::getLastConnectionError()
{ {
return errorString(m_vpnConnection->lastError()); return m_vpnConnection->lastError();
} }
void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state) void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
@ -218,7 +217,7 @@ void ConnectionController::openConnection(const bool updateConfig, const QJsonOb
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
ErrorCode errorCode = updateProtocolConfig(container, credentials, containerConfig, serverController); ErrorCode errorCode = updateProtocolConfig(container, credentials, containerConfig, serverController);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit connectionErrorOccurred(errorString(errorCode)); emit connectionErrorOccurred(errorCode);
return; return;
} }

View file

@ -34,7 +34,7 @@ public slots:
void openConnection(); void openConnection();
void closeConnection(); void closeConnection();
QString getLastConnectionError(); ErrorCode getLastConnectionError();
void onConnectionStateChanged(Vpn::ConnectionState state); void onConnectionStateChanged(Vpn::ConnectionState state);
void onCurrentContainerUpdated(); void onCurrentContainerUpdated();
@ -50,6 +50,7 @@ signals:
void connectionStateChanged(); void connectionStateChanged();
void connectionErrorOccurred(const QString &errorMessage); void connectionErrorOccurred(const QString &errorMessage);
void connectionErrorOccurred(ErrorCode errorCode);
void reconnectWithUpdatedContainer(const QString &message); void reconnectWithUpdatedContainer(const QString &message);
void noInstalledContainers(); void noInstalledContainers();

View file

@ -9,7 +9,6 @@
#include <QStandardPaths> #include <QStandardPaths>
#include "core/controllers/vpnConfigurationController.h" #include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "systemController.h" #include "systemController.h"
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "platforms/android/android_utils.h" #include "platforms/android/android_utils.h"
@ -101,7 +100,7 @@ void ExportController::generateConnectionConfig(const QString &clientName)
errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig, clientName, serverController); errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig, clientName, serverController);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -171,7 +170,7 @@ void ExportController::generateOpenVpnConfig(const QString &clientName)
} }
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -189,7 +188,7 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
QJsonObject nativeConfig; QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::WireGuard, clientName, Proto::WireGuard, nativeConfig); ErrorCode errorCode = generateNativeConfig(DockerContainer::WireGuard, clientName, Proto::WireGuard, nativeConfig);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -209,7 +208,7 @@ void ExportController::generateAwgConfig(const QString &clientName)
QJsonObject nativeConfig; QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Awg, clientName, Proto::Awg, nativeConfig); ErrorCode errorCode = generateNativeConfig(DockerContainer::Awg, clientName, Proto::Awg, nativeConfig);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -237,7 +236,7 @@ void ExportController::generateShadowSocksConfig()
} }
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -263,7 +262,7 @@ void ExportController::generateCloakConfig()
QJsonObject nativeConfig; QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Cloak, "", Proto::Cloak, nativeConfig); ErrorCode errorCode = generateNativeConfig(DockerContainer::Cloak, "", Proto::Cloak, nativeConfig);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -283,7 +282,7 @@ void ExportController::generateXrayConfig()
QJsonObject nativeConfig; QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig); ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
return; return;
} }
@ -320,7 +319,7 @@ void ExportController::updateClientManagementModel(const DockerContainer contain
QSharedPointer<ServerController> serverController(new ServerController(m_settings)); QSharedPointer<ServerController> serverController(new ServerController(m_settings));
ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials, serverController); ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials, serverController);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
} }
} }
@ -330,7 +329,7 @@ void ExportController::revokeConfig(const int row, const DockerContainer contain
ErrorCode errorCode = ErrorCode errorCode =
m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex(), serverController); m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex(), serverController);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
} }
} }
@ -339,7 +338,7 @@ void ExportController::renameClient(const int row, const QString &clientName, co
QSharedPointer<ServerController> serverController(new ServerController(m_settings)); QSharedPointer<ServerController> serverController(new ServerController(m_settings));
ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials, serverController); ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials, serverController);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorCode);
} }
} }

View file

@ -49,6 +49,7 @@ public slots:
signals: signals:
void generateConfig(int type); void generateConfig(int type);
void exportErrorOccurred(const QString &errorMessage); void exportErrorOccurred(const QString &errorMessage);
void exportErrorOccurred(ErrorCode errorCode);
void exportConfigChanged(); void exportConfigChanged();

View file

@ -6,7 +6,6 @@
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QStandardPaths> #include <QStandardPaths>
#include "core/errorstrings.h"
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h" #include "platforms/android/android_controller.h"
#endif #endif
@ -221,7 +220,7 @@ void ImportController::importConfig()
} else if (m_config.contains(config_key::configVersion)) { } else if (m_config.contains(config_key::configVersion)) {
quint16 crc = qChecksum(QJsonDocument(m_config).toJson()); quint16 crc = qChecksum(QJsonDocument(m_config).toJson());
if (m_serversModel->isServerFromApiAlreadyExists(crc)) { if (m_serversModel->isServerFromApiAlreadyExists(crc)) {
emit importErrorOccurred(errorString(ErrorCode::ApiConfigAlreadyAdded), true); emit importErrorOccurred(ErrorCode::ApiConfigAlreadyAdded, true);
} else { } else {
m_config.insert(config_key::crc, crc); m_config.insert(config_key::crc, crc);
@ -231,7 +230,7 @@ void ImportController::importConfig()
} else { } else {
qDebug() << "Failed to import profile"; qDebug() << "Failed to import profile";
qDebug().noquote() << QJsonDocument(m_config).toJson(); qDebug().noquote() << QJsonDocument(m_config).toJson();
emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError), false); emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
} }
m_config = {}; m_config = {};
@ -308,7 +307,7 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
hostName = hostNameAndPortMatch.captured(1); hostName = hostNameAndPortMatch.captured(1);
} else { } else {
qDebug() << "Key parameter 'Endpoint' is missing"; qDebug() << "Key parameter 'Endpoint' is missing";
emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError), false); emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return QJsonObject(); return QJsonObject();
} }
@ -334,7 +333,7 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
lastConfig[config_key::server_pub_key] = configMap.value("PublicKey"); lastConfig[config_key::server_pub_key] = configMap.value("PublicKey");
} else { } else {
qDebug() << "One of the key parameters is missing (PrivateKey, Address, PublicKey)"; qDebug() << "One of the key parameters is missing (PrivateKey, Address, PublicKey)";
emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError), false); emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return QJsonObject(); return QJsonObject();
} }

View file

@ -54,6 +54,7 @@ public slots:
signals: signals:
void importFinished(); void importFinished();
void importErrorOccurred(const QString &errorMessage, bool goToPageHome); void importErrorOccurred(const QString &errorMessage, bool goToPageHome);
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
void qrDecodingFinished(); void qrDecodingFinished();

View file

@ -9,7 +9,6 @@
#include "core/controllers/serverController.h" #include "core/controllers/serverController.h"
#include "core/controllers/vpnConfigurationController.h" #include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
#include "logger.h" #include "logger.h"
#include "ui/models/protocols/awgConfigModel.h" #include "ui/models/protocols/awgConfigModel.h"
@ -149,7 +148,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
QMap<DockerContainer, QJsonObject> installedContainers; QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, serverController, installedContainers); ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, serverController, installedContainers);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
@ -158,7 +157,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
if (!installedContainers.contains(container)) { if (!installedContainers.contains(container)) {
errorCode = serverController->setupContainer(serverCredentials, container, config); errorCode = serverController->setupContainer(serverCredentials, container, config);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
@ -169,7 +168,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
} }
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
@ -204,7 +203,7 @@ void InstallController::installServer(const DockerContainer container, const QMa
auto errorCode = vpnConfigurationController.createProtocolConfigForContainer(m_processedServerCredentials, iterator.key(), auto errorCode = vpnConfigurationController.createProtocolConfigForContainer(m_processedServerCredentials, iterator.key(),
containerConfig); containerConfig);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
containerConfigs.append(containerConfig); containerConfigs.append(containerConfig);
@ -212,7 +211,7 @@ void InstallController::installServer(const DockerContainer container, const QMa
errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig, errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController); QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
} else { } else {
@ -244,7 +243,7 @@ void InstallController::installContainer(const DockerContainer container, const
auto errorCode = auto errorCode =
vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, iterator.key(), containerConfig); vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, iterator.key(), containerConfig);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
m_serversModel->addContainerConfig(iterator.key(), containerConfig); m_serversModel->addContainerConfig(iterator.key(), containerConfig);
@ -252,7 +251,7 @@ void InstallController::installContainer(const DockerContainer container, const
errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig, errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController); QString("Admin [%1]").arg(QSysInfo::prettyProductName()), serverController);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
} else { } else {
@ -310,7 +309,7 @@ void InstallController::scanServerForInstalledContainers()
auto errorCode = auto errorCode =
vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, container, containerConfig); vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, container, containerConfig);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
m_serversModel->addContainerConfig(container, containerConfig); m_serversModel->addContainerConfig(container, containerConfig);
@ -319,7 +318,7 @@ void InstallController::scanServerForInstalledContainers()
QString("Admin [%1]").arg(QSysInfo::prettyProductName()), QString("Admin [%1]").arg(QSysInfo::prettyProductName()),
serverController); serverController);
if (errorCode) { if (errorCode) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return; return;
} }
} else { } else {
@ -334,7 +333,7 @@ void InstallController::scanServerForInstalledContainers()
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
} }
ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentials &credentials, ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
@ -515,7 +514,7 @@ void InstallController::updateContainer(QJsonObject config)
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
} }
void InstallController::rebootProcessedServer() void InstallController::rebootProcessedServer()
@ -528,7 +527,7 @@ void InstallController::rebootProcessedServer()
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
emit rebootProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName)); emit rebootProcessedServerFinished(tr("Server '%1' was rebooted").arg(serverName));
} else { } else {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
} }
} }
@ -552,7 +551,7 @@ void InstallController::removeAllContainers()
emit removeAllContainersFinished(tr("All containers from server '%1' have been removed").arg(serverName)); emit removeAllContainersFinished(tr("All containers from server '%1' have been removed").arg(serverName));
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
} }
void InstallController::removeProcessedContainer() void InstallController::removeProcessedContainer()
@ -570,7 +569,7 @@ void InstallController::removeProcessedContainer()
emit removeProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName)); emit removeProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName));
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
} }
void InstallController::removeApiConfig(const int serverIndex) void InstallController::removeApiConfig(const int serverIndex)
@ -738,7 +737,7 @@ bool InstallController::checkSshConnection(QSharedPointer<ServerController> serv
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
m_processedServerCredentials.secretData = decryptedPrivateKey; m_processedServerCredentials.secretData = decryptedPrivateKey;
} else { } else {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return false; return false;
} }
} }
@ -747,7 +746,7 @@ bool InstallController::checkSshConnection(QSharedPointer<ServerController> serv
output = serverController->checkSshConnection(m_processedServerCredentials, errorCode); output = serverController->checkSshConnection(m_processedServerCredentials, errorCode);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorCode);
return false; return false;
} else { } else {
if (output.contains(tr("Please login as the user"))) { if (output.contains(tr("Please login as the user"))) {

View file

@ -64,6 +64,7 @@ signals:
void removeProcessedContainerFinished(const QString &finishedMessage); void removeProcessedContainerFinished(const QString &finishedMessage);
void installationErrorOccurred(const QString &errorMessage); void installationErrorOccurred(const QString &errorMessage);
void installationErrorOccurred(ErrorCode errorCode);
void serverAlreadyExists(int serverIndex); void serverAlreadyExists(int serverIndex);

View file

@ -1,4 +1,6 @@
#include "pageController.h" #include "pageController.h"
#include "utils/converter.h"
#include "core/errorstrings.h"
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include <QGuiApplication> #include <QGuiApplication>
@ -39,6 +41,8 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); }); connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); });
#endif #endif
connect(this, qOverload<ErrorCode>(&PageController::showErrorMessage), this, &PageController::onShowErrorMessage);
m_isTriggeredByConnectButton = false; m_isTriggeredByConnectButton = false;
} }
@ -161,3 +165,13 @@ int PageController::getDrawerDepth()
{ {
return m_drawerDepth; return m_drawerDepth;
} }
void PageController::onShowErrorMessage(ErrorCode errorCode)
{
const auto fullErrorMessage = errorString(errorCode);
const auto errorMessage = fullErrorMessage.mid(fullErrorMessage.indexOf(". ") + 1); // remove ErrorCode %1.
const auto errorUrl = QStringLiteral("https://docs.amnezia.org/troubleshooting/error-codes/#error-%1-%2").arg(static_cast<int>(errorCode)).arg(utils::enumToString(errorCode).toLower());
const auto fullMessage = QStringLiteral("<a href=\"%1\" style=\"color: #FBB26A;\">ErrorCode: %2</a>. %3").arg(errorUrl).arg(static_cast<int>(errorCode)).arg(errorMessage);
emit showErrorMessage(fullMessage);
}

View file

@ -4,6 +4,7 @@
#include <QObject> #include <QObject>
#include <QQmlEngine> #include <QQmlEngine>
#include "core/defs.h"
#include "ui/models/servers_model.h" #include "ui/models/servers_model.h"
namespace PageLoader namespace PageLoader
@ -93,6 +94,9 @@ public slots:
void setDrawerDepth(const int depth); void setDrawerDepth(const int depth);
int getDrawerDepth(); int getDrawerDepth();
private slots:
void onShowErrorMessage(amnezia::ErrorCode errorCode);
signals: signals:
void goToPage(PageLoader::PageEnum page, bool slide = true); void goToPage(PageLoader::PageEnum page, bool slide = true);
void goToStartPage(); void goToStartPage();
@ -107,6 +111,7 @@ signals:
void restorePageHomeState(bool isContainerInstalled = false); void restorePageHomeState(bool isContainerInstalled = false);
void replaceStartPage(); void replaceStartPage();
void showErrorMessage(amnezia::ErrorCode);
void showErrorMessage(const QString &errorMessage); void showErrorMessage(const QString &errorMessage);
void showNotificationMessage(const QString &message); void showNotificationMessage(const QString &message);

View file

@ -57,7 +57,17 @@ Popup {
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
text: root.text text: root.text
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
} }
Item { Item {

View file

@ -76,9 +76,9 @@ PageType {
Connections { Connections {
target: InstallController target: InstallController
function onInstallationErrorOccurred(errorMessage) { function onInstallationErrorOccurred(error) {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
PageController.showErrorMessage(errorMessage) PageController.showErrorMessage(error)
var currentPageName = stackView.currentItem.objectName var currentPageName = stackView.currentItem.objectName
@ -97,8 +97,8 @@ PageType {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
function onImportErrorOccurred(errorMessage, goToPageHome) { function onImportErrorOccurred(error, goToPageHome) {
PageController.showErrorMessage(errorMessage) PageController.showErrorMessage(error)
} }
} }

View file

@ -102,9 +102,10 @@ PageType {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
function onExportErrorOccurred(errorMessage) { function onExportErrorOccurred(error) {
shareConnectionDrawer.close() shareConnectionDrawer.close()
PageController.showErrorMessage(errorMessage)
PageController.showErrorMessage(error)
} }
} }

View file

@ -99,9 +99,10 @@ PageType {
Connections { Connections {
target: InstallController target: InstallController
function onInstallationErrorOccurred(errorMessage) { function onInstallationErrorOccurred(error) {
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
PageController.showErrorMessage(errorMessage)
PageController.showErrorMessage(error)
var needCloseCurrentPage = false var needCloseCurrentPage = false
var currentPageName = tabBarStackView.currentItem.objectName var currentPageName = tabBarStackView.currentItem.objectName
@ -146,8 +147,8 @@ PageType {
Connections { Connections {
target: ImportController target: ImportController
function onImportErrorOccurred(errorMessage, goToPageHome) { function onImportErrorOccurred(error, goToPageHome) {
PageController.showErrorMessage(errorMessage) PageController.showErrorMessage(error)
} }
} }

25
client/utils/converter.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include <QMetaEnum>
namespace utils
{
template<typename Enum>
QString enumToString(Enum value)
{
auto metaEnum = QMetaEnum::fromType<Enum>();
return metaEnum.valueToKey(static_cast<int>(value));
}
template<typename Enum>
Enum enumFromString(const QString &str, Enum defaultValue = {})
{
auto metaEnum = QMetaEnum::fromType<Enum>();
bool isOk;
auto value = metaEnum.keyToValue(str.toLatin1(), &isOk);
if (isOk) {
return static_cast<Enum>(value);
}
return defaultValue;
}
}