Compare commits

..

3 Commits

Author SHA1 Message Date
Mykola Baibuz 75d5b73e2f fix: ignore IPv6 setup error for Linux
This error can be cased by system disabled IPv6
2025-04-28 15:38:37 +03:00
Mykola Baibuz 25f7356a1a add check for route prefix type 2025-04-16 12:12:18 +03:00
Mykola Baibuz 764d432453 fix: AWG/WG protocol with system disabled IPv6 2025-04-15 20:34:00 +03:00
20 changed files with 90 additions and 188 deletions
+42 -19
View File
@@ -1,41 +1,64 @@
name: 'Upload a new version' name: 'Upload a new version'
on: on:
workflow_dispatch: push:
inputs: tags:
RELEASE_VERSION: - '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
description: 'Release version (e.g. 1.2.3.4)'
required: true
type: string
jobs: jobs:
Upload-S3: upload:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: upload
steps: steps:
- name: Checkout - name: Checkout CMakeLists.txt
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
ref: ${{ inputs.RELEASE_VERSION }} ref: ${{ github.ref_name }}
sparse-checkout: | sparse-checkout: |
CMakeLists.txt CMakeLists.txt
deploy/deploy_s3.sh
sparse-checkout-cone-mode: false sparse-checkout-cone-mode: false
- name: Verify git tag - name: Verify git tag
run: | run: |
TAG_NAME=${{ inputs.RELEASE_VERSION }} GIT_TAG=${{ github.ref_name }}
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/') CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
if [[ "$TAG_NAME" == "$CMAKE_TAG" ]]; then
echo "Git tag ($TAG_NAME) matches CMakeLists.txt version ($CMAKE_TAG)." if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
else else
echo "::error::Mismatch: Git tag ($TAG_NAME) != CMakeLists.txt version ($CMAKE_TAG). Exiting with error..." echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
exit 1 exit 1
fi fi
- name: Setup Rclone - name: Download artifacts from the "${{ github.ref_name }}" tag
uses: AnimMouse/setup-rclone@v1 uses: robinraju/release-downloader@v1.8
with: with:
rclone_config: ${{ secrets.RCLONE_CONFIG }} tag: ${{ github.ref_name }}
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
out-file-path: ${{ github.ref_name }}
- name: Send dist to S3 - name: Upload beta version
run: bash deploy/deploy_s3.sh ${{ inputs.RELEASE_VERSION }} uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'dev')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: beta/${{ github.ref_name }}
- name: Upload stable version
uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'master')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: stable/${{ github.ref_name }}
+1 -9
View File
@@ -10,8 +10,7 @@ namespace apiDefs
AmneziaFreeV3, AmneziaFreeV3,
AmneziaPremiumV1, AmneziaPremiumV1,
AmneziaPremiumV2, AmneziaPremiumV2,
SelfHosted, SelfHosted
ExternalPremium
}; };
enum ConfigSource { enum ConfigSource {
@@ -44,13 +43,6 @@ namespace apiDefs
constexpr QLatin1String maxDeviceCount("max_device_count"); constexpr QLatin1String maxDeviceCount("max_device_count");
constexpr QLatin1String subscriptionEndDate("subscription_end_date"); constexpr QLatin1String subscriptionEndDate("subscription_end_date");
constexpr QLatin1String issuedConfigs("issued_configs"); constexpr QLatin1String issuedConfigs("issued_configs");
constexpr QLatin1String supportInfo("support_info");
constexpr QLatin1String email("email");
constexpr QLatin1String billingEmail("billing_email");
constexpr QLatin1String website("website");
constexpr QLatin1String websiteName("website_name");
constexpr QLatin1String telegram("telegram");
} }
const int requestTimeoutMsecs = 12 * 1000; // 12 secs const int requestTimeoutMsecs = 12 * 1000; // 12 secs
+3 -12
View File
@@ -32,17 +32,15 @@ apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObjec
constexpr QLatin1String servicePremium("amnezia-premium"); constexpr QLatin1String servicePremium("amnezia-premium");
constexpr QLatin1String serviceFree("amnezia-free"); constexpr QLatin1String serviceFree("amnezia-free");
constexpr QLatin1String serviceExternalPremium("external-premium");
auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject();
auto stackType = apiConfigObject.value(apiDefs::key::stackType).toString();
auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString(); auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString();
if (serviceType == servicePremium) { if (serviceType == servicePremium || stackType == stackPremium) {
return apiDefs::ConfigType::AmneziaPremiumV2; return apiDefs::ConfigType::AmneziaPremiumV2;
} else if (serviceType == serviceFree) { } else if (serviceType == serviceFree || stackType == stackFree) {
return apiDefs::ConfigType::AmneziaFreeV3; return apiDefs::ConfigType::AmneziaFreeV3;
} else if (serviceType == serviceExternalPremium) {
return apiDefs::ConfigType::ExternalPremium;
} }
} }
default: { default: {
@@ -88,10 +86,3 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
qDebug() << "something went wrong"; qDebug() << "something went wrong";
return amnezia::ErrorCode::InternalError; return amnezia::ErrorCode::InternalError;
} }
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
{
static const QSet<apiDefs::ConfigType> premiumTypes = { apiDefs::ConfigType::AmneziaPremiumV1, apiDefs::ConfigType::AmneziaPremiumV2,
apiDefs::ConfigType::ExternalPremium };
return premiumTypes.contains(getConfigType(serverConfigObject));
}
-2
View File
@@ -13,8 +13,6 @@ namespace apiUtils
bool isSubscriptionExpired(const QString &subscriptionEndDate); bool isSubscriptionExpired(const QString &subscriptionEndDate);
bool isPremiumServer(const QJsonObject &serverConfigObject);
apiDefs::ConfigType getConfigType(const QJsonObject &serverConfigObject); apiDefs::ConfigType getConfigType(const QJsonObject &serverConfigObject);
apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject); apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
+9 -23
View File
@@ -138,7 +138,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
if (overwriteMode == libssh::ScpOverwriteMode::ScpOverwriteExisting) { if (overwriteMode == libssh::ScpOverwriteMode::ScpOverwriteExisting) {
e = runScript(credentials, e = runScript(credentials,
replaceVars(QStringLiteral("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName, path), replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), genVarsForScript(credentials, container)),
cbReadStd, cbReadStd); cbReadStd, cbReadStd);
@@ -146,7 +146,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
return e; return e;
} else if (overwriteMode == libssh::ScpOverwriteMode::ScpAppendToExisting) { } else if (overwriteMode == libssh::ScpOverwriteMode::ScpAppendToExisting) {
e = runScript(credentials, e = runScript(credentials,
replaceVars(QStringLiteral("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName, tmpFileName), replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
genVarsForScript(credentials, container)), genVarsForScript(credentials, container)),
cbReadStd, cbReadStd); cbReadStd, cbReadStd);
@@ -154,7 +154,7 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
return e; return e;
e = runScript(credentials, e = runScript(credentials,
replaceVars(QStringLiteral("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName, path), replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), genVarsForScript(credentials, container)),
cbReadStd, cbReadStd); cbReadStd, cbReadStd);
@@ -177,7 +177,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
errorCode = ErrorCode::NoError; errorCode = ErrorCode::NoError;
QString script = QStringLiteral("sudo docker exec -i %1 sh -c \"xxd -p '%2'\"").arg(ContainerProps::containerToString(container), path); QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").arg(ContainerProps::containerToString(container)).arg(path);
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) { auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -383,13 +383,6 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
return true; return true;
} }
if (container == DockerContainer::Xray) {
if (oldProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)) {
return true;
}
}
return false; return false;
} }
@@ -446,22 +439,15 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
stdOut += data + "\n"; stdOut += data + "\n";
return ErrorCode::NoError; return ErrorCode::NoError;
}; };
auto cbReadStdErr = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
ErrorCode error = errorCode =
runScript(credentials, runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)), replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr); cbReadStdOut);
if (errorCode)
return errorCode;
if (stdOut.contains("doesn't work on cgroups v2")) return errorCode;
return ErrorCode::ServerDockerOnCgroupsV2;
if (stdOut.contains("cgroup mountpoint does not exist"))
return ErrorCode::ServerCgroupMountpoint;
return error;
} }
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config) ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
-2
View File
@@ -58,8 +58,6 @@ namespace amnezia
ServerUserDirectoryNotAccessible = 208, ServerUserDirectoryNotAccessible = 208,
ServerUserNotAllowedInSudoers = 209, ServerUserNotAllowedInSudoers = 209,
ServerUserPasswordRequired = 210, ServerUserPasswordRequired = 210,
ServerDockerOnCgroupsV2 = 211,
ServerCgroupMountpoint = 212,
// Ssh connection errors // Ssh connection errors
SshRequestDeniedError = 300, SshRequestDeniedError = 300,
-2
View File
@@ -26,8 +26,6 @@ QString errorString(ErrorCode code) {
case(ErrorCode::ServerUserDirectoryNotAccessible): errorMessage = QObject::tr("The server user's home directory is not accessible"); 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::ServerUserNotAllowedInSudoers): errorMessage = QObject::tr("Action not allowed in sudoers"); break;
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break; case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); 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
View File
@@ -6,7 +6,6 @@
#define INTERFACECONFIG_H #define INTERFACECONFIG_H
#include <QList> #include <QList>
#include <QMap>
#include <QString> #include <QString>
#include "ipaddress.h" #include "ipaddress.h"
@@ -31,7 +31,9 @@ IPUtilsLinux::~IPUtilsLinux() {
} }
bool IPUtilsLinux::addInterfaceIPs(const InterfaceConfig& config) { bool IPUtilsLinux::addInterfaceIPs(const InterfaceConfig& config) {
return addIP4AddressToDevice(config) && addIP6AddressToDevice(config); bool ret = addIP4AddressToDevice(config);
addIP6AddressToDevice(config);
return ret;
} }
bool IPUtilsLinux::setMTUAndUp(const InterfaceConfig& config) { bool IPUtilsLinux::setMTUAndUp(const InterfaceConfig& config) {
@@ -14,8 +14,6 @@
#include "leakdetector.h" #include "leakdetector.h"
#include "logger.h" #include "logger.h"
#include "platforms/windows/windowscommons.h"
#include "windowsdaemon.h"
#include "windowsfirewall.h" #include "windowsfirewall.h"
#pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "iphlpapi.lib")
@@ -269,6 +267,13 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
if (result == ERROR_OBJECT_ALREADY_EXISTS) { if (result == ERROR_OBJECT_ALREADY_EXISTS) {
return true; return true;
} }
// Case for ipv6 route with disabled ipv6
if (prefix.address().protocol() == QAbstractSocket::IPv6Protocol
&& result == ERROR_NOT_FOUND) {
return true;
}
if (result != NO_ERROR) { if (result != NO_ERROR) {
logger.error() << "Failed to create route to" logger.error() << "Failed to create route to"
<< prefix.toString() << prefix.toString()
@@ -310,7 +310,7 @@ bool ApiConfigsController::deactivateDevice()
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
if (!apiUtils::isPremiumServer(serverConfigObject)) { if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV2) {
return true; return true;
} }
@@ -345,7 +345,7 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
if (!apiUtils::isPremiumServer(serverConfigObject)) { if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV2) {
return true; return true;
} }
@@ -62,7 +62,7 @@ bool ApiSettingsController::getAccountInfo(bool reload)
QByteArray responseBody; QByteArray responseBody;
if (apiUtils::isPremiumServer(serverConfig)) { if (apiUtils::getConfigType(serverConfig) == apiDefs::ConfigType::AmneziaPremiumV2) {
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode); emit errorOccurred(errorCode);
+6 -6
View File
@@ -145,7 +145,7 @@ void ExportController::generateOpenVpnConfig(const QString &clientName)
} }
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n"); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -163,7 +163,7 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
} }
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n"); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -183,7 +183,7 @@ void ExportController::generateAwgConfig(const QString &clientName)
} }
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n"); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -211,7 +211,7 @@ void ExportController::generateShadowSocksConfig()
} }
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n"); QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -240,7 +240,7 @@ void ExportController::generateCloakConfig()
nativeConfig.insert("ProxyMethod", "shadowsocks"); nativeConfig.insert("ProxyMethod", "shadowsocks");
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n"); QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -257,7 +257,7 @@ void ExportController::generateXrayConfig(const QString &clientName)
} }
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n"); QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : std::as_const(lines)) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
+8 -29
View File
@@ -48,19 +48,15 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
} }
case ServiceDescriptionRole: { case ServiceDescriptionRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) { if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
return tr("Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online " return tr("Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. "
"resources. "
"Speeds up to 200 Mbps"); "Speeds up to 200 Mbps");
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) { } else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return tr("Free unlimited access to a basic set of websites such as Facebook, Instagram, Twitter (X), Discord, Telegram and " return tr("Free unlimited access to a basic set of websites such as Facebook, Instagram, Twitter (X), Discord, Telegram and "
"more. YouTube is not included in the free plan."); "more. YouTube is not included in the free plan.");
} else {
return "";
} }
} }
case IsComponentVisibleRole: { case IsComponentVisibleRole: {
return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2 return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2;
|| m_accountInfoData.configType == apiDefs::ConfigType::ExternalPremium;
} }
case HasExpiredWorkerRole: { case HasExpiredWorkerRole: {
for (int i = 0; i < m_issuedConfigsInfo.size(); i++) { for (int i = 0; i < m_issuedConfigsInfo.size(); i++) {
@@ -97,8 +93,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
m_accountInfoData = accountInfoData; m_accountInfoData = accountInfoData;
m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
endResetModel(); endResetModel();
} }
@@ -127,27 +121,12 @@ QJsonArray ApiAccountInfoModel::getIssuedConfigsInfo()
QString ApiAccountInfoModel::getTelegramBotLink() QString ApiAccountInfoModel::getTelegramBotLink()
{ {
return m_supportInfo.value(apiDefs::key::telegram).toString(); if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
} return tr("amnezia_free_support_bot");
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
QString ApiAccountInfoModel::getEmailLink() return tr("amnezia_premium_support_bot");
{ }
return m_supportInfo.value(apiDefs::key::email).toString(); return "";
}
QString ApiAccountInfoModel::getBillingEmailLink()
{
return m_supportInfo.value(apiDefs::key::billingEmail).toString();
}
QString ApiAccountInfoModel::getSiteLink()
{
return m_supportInfo.value(apiDefs::key::websiteName).toString();
}
QString ApiAccountInfoModel::getFullSiteLink()
{
return m_supportInfo.value(apiDefs::key::website).toString();
} }
QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
@@ -33,12 +33,7 @@ public slots:
QJsonArray getAvailableCountries(); QJsonArray getAvailableCountries();
QJsonArray getIssuedConfigsInfo(); QJsonArray getIssuedConfigsInfo();
QString getTelegramBotLink(); QString getTelegramBotLink();
QString getEmailLink();
QString getBillingEmailLink();
QString getSiteLink();
QString getFullSiteLink();
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
@@ -56,7 +51,6 @@ private:
AccountInfoData m_accountInfoData; AccountInfoData m_accountInfoData;
QJsonArray m_availableCountries; QJsonArray m_availableCountries;
QJsonArray m_issuedConfigsInfo; QJsonArray m_issuedConfigsInfo;
QJsonObject m_supportInfo;
}; };
#endif // APIACCOUNTINFOMODEL_H #endif // APIACCOUNTINFOMODEL_H
@@ -20,7 +20,6 @@ bool XrayConfigModel::setData(const QModelIndex &index, const QVariant &value, i
switch (role) { switch (role) {
case Roles::SiteRole: m_protocolConfig.insert(config_key::site, value.toString()); break; case Roles::SiteRole: m_protocolConfig.insert(config_key::site, value.toString()); break;
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
} }
emit dataChanged(index, index, QList { role }); emit dataChanged(index, index, QList { role });
@@ -35,7 +34,6 @@ QVariant XrayConfigModel::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case Roles::SiteRole: return m_protocolConfig.value(config_key::site).toString(protocols::xray::defaultSite); case Roles::SiteRole: return m_protocolConfig.value(config_key::site).toString(protocols::xray::defaultSite);
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::xray::defaultPort);
} }
return QVariant(); return QVariant();
@@ -69,7 +67,6 @@ QHash<int, QByteArray> XrayConfigModel::roleNames() const
QHash<int, QByteArray> roles; QHash<int, QByteArray> roles;
roles[SiteRole] = "site"; roles[SiteRole] = "site";
roles[PortRole] = "port";
return roles; return roles;
} }
+1 -2
View File
@@ -12,8 +12,7 @@ class XrayConfigModel : public QAbstractListModel
public: public:
enum Roles { enum Roles {
SiteRole, SiteRole
PortRole
}; };
explicit XrayConfigModel(QObject *parent = nullptr); explicit XrayConfigModel(QObject *parent = nullptr);
@@ -103,29 +103,8 @@ PageType {
} }
} }
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
BasicButtonType { BasicButtonType {
id: saveButton id: basicButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
@@ -28,24 +28,24 @@ PageType {
id: techSupport id: techSupport
readonly property string title: qsTr("Email") readonly property string title: qsTr("Email")
readonly property string description: ApiAccountInfoModel.getEmailLink() readonly property string description: qsTr("support@amnezia.org")
readonly property string link: "mailto:" + ApiAccountInfoModel.getEmailLink() readonly property string link: "mailto:support@amnezia.org"
} }
QtObject { QtObject {
id: paymentSupport id: paymentSupport
readonly property string title: qsTr("Email Billing & Orders") readonly property string title: qsTr("Email Billing & Orders")
readonly property string description: ApiAccountInfoModel.getBillingEmailLink() readonly property string description: qsTr("help@vpnpay.io")
readonly property string link: "mailto:" + ApiAccountInfoModel.getBillingEmailLink() readonly property string link: "mailto:help@vpnpay.io"
} }
QtObject { QtObject {
id: site id: site
readonly property string title: qsTr("Website") readonly property string title: qsTr("Website")
readonly property string description: ApiAccountInfoModel.getSiteLink() readonly property string description: qsTr("amnezia.org")
readonly property string link: ApiAccountInfoModel.getFullSiteLink() readonly property string link: LanguageModel.getCurrentSiteUrl()
} }
property list<QtObject> supportModel: [ property list<QtObject> supportModel: [
-38
View File
@@ -1,38 +0,0 @@
#!/bin/sh
set -e
VERSION=$1
if [[ $VERSION = '' ]]; then
echo '::error::VERSION does not set. Exiting with error...'
exit 1
fi
mkdir -p dist
cd dist
echo $VERSION >> VERSION
curl -s https://api.github.com/repos/amnezia-vpn/amnezia-client/releases/tags/$VERSION | jq -r .body | tr -d '\r' > CHANGELOG
if [[ $(cat CHANGELOG) = null ]]; then
echo '::error::Release does not exists. Exiting with error...'
exit 1
fi
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_arm64-v8a.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_armeabi-v7a.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_x86.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android8+_x86_64.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_arm64-v8a.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_armeabi-v7a.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_android_7_x86_64.apk
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_linux.tar.zip
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos.dmg
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_macos_old.dmg
wget -q https://github.com/amnezia-vpn/amnezia-client/releases/download/${VERSION}/AmneziaVPN_${VERSION}_x64.exe
cd ../
rclone sync ./dist/ r2:/updates/