Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD
This commit is contained in:
commit
325b84197e
17 changed files with 93 additions and 75 deletions
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
|
|
@ -190,7 +190,7 @@ jobs:
|
||||||
- name: 'Install go'
|
- name: 'Install go'
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22.1'
|
go-version: '1.24'
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: 'Setup gomobile'
|
- name: 'Setup gomobile'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT DefaultVPN)
|
set(PROJECT DefaultVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.8.4.4
|
project(${PROJECT} VERSION 1.0.0.0
|
||||||
DESCRIPTION "DefaultVPN"
|
DESCRIPTION "DefaultVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
|
|
@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 2081)
|
set(APP_ANDROID_VERSION_CODE 2082)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,6 @@ add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
|
||||||
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
|
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
|
||||||
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
|
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
|
||||||
|
|
||||||
if(IOS)
|
|
||||||
set(PACKAGES ${PACKAGES} Multimedia)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
set(PACKAGES ${PACKAGES} Widgets)
|
set(PACKAGES ${PACKAGES} Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -48,10 +44,6 @@ set(LIBS ${LIBS}
|
||||||
Qt6::Core5Compat Qt6::Concurrent
|
Qt6::Core5Compat Qt6::Concurrent
|
||||||
)
|
)
|
||||||
|
|
||||||
if(IOS)
|
|
||||||
set(LIBS ${LIBS} Qt6::Multimedia)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||||
set(LIBS ${LIBS} Qt6::Widgets)
|
set(LIBS ${LIBS} Qt6::Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "coreController.h"
|
#include "coreController.h"
|
||||||
|
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID)
|
#if defined(Q_OS_ANDROID)
|
||||||
|
|
@ -238,7 +239,23 @@ void CoreController::updateTranslator(const QLocale &locale)
|
||||||
QCoreApplication::removeTranslator(m_translator.get());
|
QCoreApplication::removeTranslator(m_translator.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString strFileName = QString(":/translations/defaultvpn") + QLatin1String("_") + locale.name() + ".qm";
|
QStringList availableTranslations;
|
||||||
|
QDirIterator it(":/translations", QStringList("defaultvpn_*.qm"), QDir::Files);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
availableTranslations << it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This code allow to load translation for the language only, without country code
|
||||||
|
const QString lang = locale.name().split("_").first();
|
||||||
|
const QString translationFilePrefix = QString(":/translations/defaultvpn_") + lang;
|
||||||
|
QString strFileName = QString(":/translations/defaultvpn_%1.qm").arg(locale.name());
|
||||||
|
for (const QString &translation : availableTranslations) {
|
||||||
|
if (translation.contains(translationFilePrefix)) {
|
||||||
|
strFileName = translation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_translator->load(strFileName)) {
|
if (m_translator->load(strFileName)) {
|
||||||
if (QCoreApplication::installTranslator(m_translator.get())) {
|
if (QCoreApplication::installTranslator(m_translator.get())) {
|
||||||
m_settings->setAppLanguage(locale);
|
m_settings->setAppLanguage(locale);
|
||||||
|
|
|
||||||
|
|
@ -757,10 +757,6 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
||||||
|
|
||||||
ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, DockerContainer container)
|
ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, DockerContainer container)
|
||||||
{
|
{
|
||||||
if (credentials.userName == "root") {
|
|
||||||
return ErrorCode::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString stdOut;
|
QString stdOut;
|
||||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||||
stdOut += data + "\n";
|
stdOut += data + "\n";
|
||||||
|
|
@ -774,8 +770,16 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
|
||||||
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
|
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"))
|
if (credentials.userName != "root" && stdOut.contains("sudo:") && !stdOut.contains("uname:") && stdOut.contains("not found"))
|
||||||
|
return ErrorCode::ServerSudoPackageIsNotPreinstalled;
|
||||||
|
if (credentials.userName != "root" && !stdOut.contains("sudo") && !stdOut.contains("wheel"))
|
||||||
return ErrorCode::ServerUserNotInSudo;
|
return ErrorCode::ServerUserNotInSudo;
|
||||||
|
if (stdOut.contains("can't cd to") || stdOut.contains("Permission denied") || stdOut.contains("No such file or directory"))
|
||||||
|
return ErrorCode::ServerUserDirectoryNotAccessible;
|
||||||
|
if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
|
||||||
|
return ErrorCode::ServerUserNotAllowedInSudoers;
|
||||||
|
if (stdOut.contains("password is required"))
|
||||||
|
return ErrorCode::ServerUserPasswordRequired;
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,10 @@ namespace amnezia
|
||||||
ServerCancelInstallation = 204,
|
ServerCancelInstallation = 204,
|
||||||
ServerUserNotInSudo = 205,
|
ServerUserNotInSudo = 205,
|
||||||
ServerPacketManagerError = 206,
|
ServerPacketManagerError = 206,
|
||||||
|
ServerSudoPackageIsNotPreinstalled = 207,
|
||||||
|
ServerUserDirectoryNotAccessible = 208,
|
||||||
|
ServerUserNotAllowedInSudoers = 209,
|
||||||
|
ServerUserPasswordRequired = 210,
|
||||||
|
|
||||||
// Ssh connection errors
|
// Ssh connection errors
|
||||||
SshRequestDeniedError = 300,
|
SshRequestDeniedError = 300,
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,12 @@ QString errorString(ErrorCode code) {
|
||||||
case(ErrorCode::ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break;
|
case(ErrorCode::ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break;
|
||||||
case(ErrorCode::ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break;
|
case(ErrorCode::ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break;
|
||||||
case(ErrorCode::ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break;
|
case(ErrorCode::ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break;
|
||||||
case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user does not have permission to use sudo"); break;
|
case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user is not a member of the sudo group"); break;
|
||||||
case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Packet manager error"); break;
|
case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Package manager error"); break;
|
||||||
|
case(ErrorCode::ServerSudoPackageIsNotPreinstalled): errorMessage = QObject::tr("The sudo package is not pre-installed on the server"); break;
|
||||||
|
case(ErrorCode::ServerUserDirectoryNotAccessible): errorMessage = QObject::tr("The server user's home directory is not accessible"); break;
|
||||||
|
case(ErrorCode::ServerUserNotAllowedInSudoers): errorMessage = QObject::tr("Action not allowed in sudoers"); break;
|
||||||
|
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
|
||||||
|
|
||||||
// Libssh errors
|
// Libssh errors
|
||||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,13 @@
|
||||||
CUR_USER=$(whoami);\
|
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
||||||
groups $CUR_USER
|
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
||||||
|
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
||||||
|
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
||||||
|
else pm="uname"; opt="-a";\
|
||||||
|
fi;\
|
||||||
|
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
||||||
|
echo $LANG | grep -qE '^(en_US.UTF-8|C.UTF-8|C)$' || export LC_ALL=C;\
|
||||||
|
sudo -K;\
|
||||||
|
cd ~;\
|
||||||
|
if [ "$CUR_USER" = "root" ] || ( groups "$CUR_USER" | grep -E '\<(sudo|wheel)\>' ); then \
|
||||||
|
sudo -nu $CUR_USER $pm $opt > /dev/null; sudo -n $pm $opt > /dev/null;\
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
CUR_USER=$(whoami);\
|
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
||||||
sudo mkdir -p $DOCKERFILE_FOLDER;\
|
sudo mkdir -p $DOCKERFILE_FOLDER;\
|
||||||
sudo chown $CUR_USER $DOCKERFILE_FOLDER;\
|
sudo chown $CUR_USER $DOCKERFILE_FOLDER;\
|
||||||
if ! sudo docker network ls | grep -q amnezia-dns-net; then sudo docker network create \
|
if ! sudo docker network ls | grep -q amnezia-dns-net; then sudo docker network create \
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace
|
||||||
constexpr char cloak[] = "cloak";
|
constexpr char cloak[] = "cloak";
|
||||||
constexpr char awg[] = "awg";
|
constexpr char awg[] = "awg";
|
||||||
|
|
||||||
constexpr char apiEdnpoint[] = "api_endpoint";
|
constexpr char apiEndpoint[] = "api_endpoint";
|
||||||
constexpr char accessToken[] = "api_key";
|
constexpr char accessToken[] = "api_key";
|
||||||
constexpr char certificate[] = "certificate";
|
constexpr char certificate[] = "certificate";
|
||||||
constexpr char publicKey[] = "public_key";
|
constexpr char publicKey[] = "public_key";
|
||||||
|
|
@ -251,7 +251,6 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||||
|
|
||||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||||
newServerConfig.insert(configKey::authData, authData);
|
newServerConfig.insert(configKey::authData, authData);
|
||||||
// newServerConfig.insert(
|
|
||||||
|
|
||||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||||
if (reloadServiceConfig) {
|
if (reloadServiceConfig) {
|
||||||
|
|
@ -270,54 +269,37 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||||
|
|
||||||
bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||||
{
|
{
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
|
||||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
|
||||||
|
|
||||||
#ifdef Q_OS_IOS
|
#ifdef Q_OS_IOS
|
||||||
IosController::Instance()->requestInetAccess();
|
IosController::Instance()->requestInetAccess();
|
||||||
QThread::msleep(10);
|
QThread::msleep(10);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (serverConfig.value(config_key::configVersion).toInt()) {
|
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
|
||||||
QNetworkRequest request;
|
|
||||||
request.setTransferTimeout(apiDefs::requestTimeoutMsecs);
|
|
||||||
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 serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
|
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||||
|
|
||||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
|
||||||
|
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||||
|
|
||||||
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||||
apiPayload[configKey::uuid] = installationUuid;
|
apiPayload[configKey::uuid] = installationUuid;
|
||||||
|
apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString();
|
||||||
|
apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
|
||||||
|
|
||||||
QByteArray requestBody = QJsonDocument(apiPayload).toJson();
|
QByteArray responseBody;
|
||||||
|
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
||||||
|
|
||||||
QNetworkReply *reply = amnApp->networkManager()->post(request, requestBody);
|
if (errorCode == ErrorCode::NoError) {
|
||||||
|
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||||
|
|
||||||
QEventLoop wait;
|
|
||||||
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
|
||||||
|
|
||||||
QList<QSslError> sslErrors;
|
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
|
||||||
wait.exec();
|
|
||||||
|
|
||||||
auto errorCode = apiUtils::checkNetworkReplyErrors(sslErrors, reply);
|
|
||||||
if (errorCode != ErrorCode::NoError) {
|
|
||||||
reply->deleteLater();
|
|
||||||
emit errorOccurred(errorCode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto apiResponseBody = reply->readAll();
|
|
||||||
reply->deleteLater();
|
|
||||||
fillServerConfig(protocol, apiPayloadData, apiResponseBody, serverConfig);
|
|
||||||
m_serversModel->editServer(serverConfig, serverIndex);
|
m_serversModel->editServer(serverConfig, serverIndex);
|
||||||
emit updateServerFromApiFinished();
|
emit updateServerFromApiFinished();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
emit errorOccurred(errorCode);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApiConfigsController::deactivateDevice()
|
bool ApiConfigsController::deactivateDevice()
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace
|
||||||
} else if ((config.contains(xrayConfigPatternInbound)) && (config.contains(xrayConfigPatternOutbound))) {
|
} else if ((config.contains(xrayConfigPatternInbound)) && (config.contains(xrayConfigPatternOutbound))) {
|
||||||
return ConfigTypes::Xray;
|
return ConfigTypes::Xray;
|
||||||
} else if (config.contains(openVpnConfigPatternCli)
|
} else if (config.contains(openVpnConfigPatternCli)
|
||||||
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||||
return ConfigTypes::OpenVpn;
|
return ConfigTypes::OpenVpn;
|
||||||
}
|
}
|
||||||
return ConfigTypes::Invalid;
|
return ConfigTypes::Invalid;
|
||||||
|
|
@ -94,6 +94,8 @@ bool ImportController::extractConfigFromFile(const QString &fileName)
|
||||||
|
|
||||||
bool ImportController::extractConfigFromData(QString data)
|
bool ImportController::extractConfigFromData(QString data)
|
||||||
{
|
{
|
||||||
|
m_maliciousWarningText.clear();
|
||||||
|
|
||||||
QString config = data;
|
QString config = data;
|
||||||
QString prefix;
|
QString prefix;
|
||||||
QString errormsg;
|
QString errormsg;
|
||||||
|
|
@ -658,6 +660,7 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||||
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|
||||||
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|
||||||
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
|
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
|
||||||
|
|
||||||
QString protocolConfig =
|
QString protocolConfig =
|
||||||
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
|
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
|
||||||
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
|
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
|
||||||
|
|
@ -679,8 +682,11 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_maliciousWarningText = tr("This configuration contains an OpenVPN setup. OpenVPN configurations can include malicious "
|
||||||
|
"scripts, so only add it if you fully trust the provider of this config. ");
|
||||||
|
|
||||||
if (maliciousStrings.size() >= dangerousTagsMaxCount) {
|
if (maliciousStrings.size() >= dangerousTagsMaxCount) {
|
||||||
m_maliciousWarningText = tr("In the imported configuration, potentially dangerous lines were found:");
|
m_maliciousWarningText.push_back(tr("<br>In the imported configuration, potentially dangerous lines were found:"));
|
||||||
for (const auto &string : maliciousStrings) {
|
for (const auto &string : maliciousStrings) {
|
||||||
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
|
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
#include "languageModel.h"
|
#include "languageModel.h"
|
||||||
|
|
||||||
LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent)
|
LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent)
|
||||||
: m_settings(settings), QAbstractListModel(parent)
|
|
||||||
{
|
{
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<LanguageSettings::AvailableLanguageEnum>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<LanguageSettings::AvailableLanguageEnum>();
|
||||||
for (int i = 0; i < metaEnum.keyCount(); i++) {
|
for (int i = 0; i < metaEnum.keyCount(); i++) {
|
||||||
m_availableLanguages.push_back(
|
m_availableLanguages.push_back(LanguageModelData { getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(i)),
|
||||||
LanguageModelData {getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(i)),
|
static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
|
||||||
static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,8 +48,7 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
|
||||||
case LanguageSettings::AvailableLanguageEnum::Burmese: strLanguage = "မြန်မာဘာသာ"; break;
|
case LanguageSettings::AvailableLanguageEnum::Burmese: strLanguage = "မြန်မာဘာသာ"; break;
|
||||||
case LanguageSettings::AvailableLanguageEnum::Urdu: strLanguage = "اُرْدُوْ"; break;
|
case LanguageSettings::AvailableLanguageEnum::Urdu: strLanguage = "اُرْدُوْ"; break;
|
||||||
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return strLanguage;
|
return strLanguage;
|
||||||
|
|
@ -104,11 +101,12 @@ QString LanguageModel::getCurrentLanguageName()
|
||||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LanguageModel::getCurrentSiteUrl()
|
QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||||
{
|
{
|
||||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||||
switch (language) {
|
switch (language) {
|
||||||
case LanguageSettings::AvailableLanguageEnum::Russian: return "https://storage.googleapis.com/amnezia/amnezia.org";
|
case LanguageSettings::AvailableLanguageEnum::Russian:
|
||||||
default: return "https://amnezia.org";
|
return "https://storage.googleapis.com/amnezia/amnezia.org" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path)));
|
||||||
|
default: return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public slots:
|
||||||
int getCurrentLanguageIndex();
|
int getCurrentLanguageIndex();
|
||||||
int getLineHeightAppend();
|
int getLineHeightAppend();
|
||||||
QString getCurrentLanguageName();
|
QString getCurrentLanguageName();
|
||||||
QString getCurrentSiteUrl();
|
QString getCurrentSiteUrl(const QString &path = "");
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateTranslations(const QLocale &locale);
|
void updateTranslations(const QLocale &locale);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ Rectangle {
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
onClicked: function() {
|
onClicked: function() {
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/premium")
|
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("premium"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ PageType {
|
||||||
text: qsTr("Privacy Policy")
|
text: qsTr("Privacy Policy")
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("policy"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ PageType {
|
||||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/starter-guide")
|
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ PageType {
|
||||||
height: containers.contentItem.height
|
height: containers.contentItem.height
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
currentIndex: 1
|
currentIndex: 0
|
||||||
clip: true
|
clip: true
|
||||||
interactive: false
|
interactive: false
|
||||||
model: proxyContainersModel
|
model: proxyContainersModel
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue