Compare commits

..

33 Commits

Author SHA1 Message Date
Mykola Baibuz
e0abd3f9dc XRay Linux firewall rules 2024-12-30 13:21:45 +02:00
Mykola Baibuz
c0ea38db61 bugfix: check for Linux firewall install before use it 2024-12-30 12:24:27 +02:00
Andrey Alekseenko
212e9b3a91 fix: adding second new VMess links now works (#1325) 2024-12-30 12:45:26 +07:00
Mikhail Kiselev
2bff37efae fix: segmentation violation due to missing return (#1321) 2024-12-28 12:02:14 +07:00
albexk
b88ab8e432 fix(build): fix aqtinstall (#1312) 2024-12-23 08:27:09 +07:00
Nethius
48f6cf904e chore/minor UI fixes (#1308)
* chore: corrected the translation error

* bugfix: fixed basic button left iamge color
2024-12-19 14:36:20 +07:00
KsZnak
367789bda2 Update README_RU.md (#1300)
* Update README_RU.md
2024-12-14 19:29:33 +07:00
Cyril Anisimov
d06924c59d feature/xray user management (#972)
* feature: implement client management functionality for Xray

---------

Co-authored-by: aiamnezia <ai@amnezia.org>
Co-authored-by: vladimir.kuznetsov <nethiuswork@gmail.com>
2024-12-10 09:17:16 +07:00
Nethius
2db99715b1 feature: added subscription expiration date for premium v2 (#1261)
* feature: added subscription expiration date for premium v2

* feature: added a check for the presence of the “services” field in the response body of the getServicesList() function

* feature: added prohibition to change location when connection is active

* bugfix: renamed public_key->end_date to public_key->expires_at according to the changes on the backend
2024-12-09 13:32:49 +07:00
pokamest
9688a8e52d Merge pull request #1292 from amnezia-vpn/Add-english-option
Update README.md
2024-12-08 10:40:20 +01:00
pokamest
b2c429f74d Merge pull request #1291 from amnezia-vpn/readme_ru_update
Update README_RU.md
2024-12-08 10:39:01 +01:00
Nethius
6ea6ab1bd9 chore: added clang-format config files (#1293) 2024-12-08 12:14:22 +07:00
KsZnak
c5aa070bf4 Update README_RU.md 2024-12-08 05:49:26 +02:00
KsZnak
d67201ede9 Update README.md 2024-12-08 05:34:18 +02:00
pokamest
4323fb2063 Merge pull request #1290 from amnezia-vpn/Readme_ru
Add files via upload
2024-12-07 15:36:56 +01:00
pokamest
6d5452b8ee Merge pull request #1288 from amnezia-vpn/Readme-ru
Update README_RU.md
2024-12-07 15:36:08 +01:00
KsZnak
569d63ef0f Add files via upload 2024-12-07 15:53:40 +02:00
KsZnak
ea910ba300 Update README_RU.md 2024-12-06 22:15:01 +02:00
Pokamest Nikak
1c1e74d06f ru readme 2024-12-06 12:40:04 +00:00
Nethius
5dc16c06f1 chore: increased the api request timeout (#1276) 2024-12-03 12:47:33 +07:00
Nethius
4efaf20a1c chore: fix deploy workflow (#1280) 2024-12-02 14:46:20 +07:00
Pokamest Nikak
9d96b1cd13 Update Readme 2024-11-29 22:10:35 +00:00
Anton Sosnin
1d721ffb9a SteamDeck/OS installation fix (#1270) 2024-11-27 09:55:23 +07:00
Nethius
2130131a9d bugfix: added scroll on page with services list (#1262)
* added scroll on page with services list

* fixed margins on PageSetupWizardApiServicesList
2024-11-26 11:41:17 +07:00
Aftershock669
e0b091b474 Update readme (#1267) 2024-11-25 23:51:46 +07:00
Nethius
8547de82ea bump xcode-version for macos build (#1249) 2024-11-14 10:58:04 +07:00
Nethius
aa871bd1c9 feature: added country selection on home page drawer (#1215) 2024-11-12 13:22:34 +07:00
albexk
23806e1def chore: bump version to 4.8.2.4 (#1240) 2024-11-08 15:22:16 +07:00
Nethius
31867993ce chore: minor fixes (#1235) 2024-11-06 12:57:39 +07:00
pokamest
7b7a922d92 Merge pull request #1226 from amnezia-vpn/fix/android-awg-connection
Fix connection check for AWG/WG
2024-11-05 12:25:49 +01:00
pokamest
09bd958d8d Merge pull request #1231 from amnezia-vpn/fix/android-network-state
Add CHANGE_NETWORK_STATE permission for all Android versions
2024-11-05 12:25:11 +01:00
albexk
576e2226fe fix(android): add CHANGE_NETWORK_STATE permission for all Android versions 2024-11-03 16:11:23 +03:00
albexk
1533270e4e Fix connection check for AWG/WG 2024-11-02 00:54:24 +03:00
106 changed files with 2248 additions and 2502 deletions

39
.clang-format Normal file
View File

@@ -0,0 +1,39 @@
BasedOnStyle: WebKit
AccessModifierOffset: '-4'
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: 'true'
AlignTrailingComments: 'true'
AllowAllArgumentsOnNextLine: 'true'
AllowAllParametersOfDeclarationOnNextLine: 'true'
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortEnumsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: None
AlwaysBreakTemplateDeclarations: 'No'
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakConstructorInitializers: BeforeColon
ColumnLimit: '120'
CommentPragmas: '"^!|^:"'
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
ConstructorInitializerIndentWidth: '4'
ContinuationIndentWidth: '8'
IndentPPDirectives: BeforeHash
NamespaceIndentation: All
PenaltyExcessCharacter: '10'
PointerAlignment: Right
SortIncludes: 'true'
SpaceAfterTemplateKeyword: 'false'
Standard: Auto

20
.clang-format-ignore Normal file
View File

@@ -0,0 +1,20 @@
/client/3rd
/client/3rd-prebuild
/client/android
/client/cmake
/client/core/serialization
/client/daemon
/client/fonts
/client/images
/client/ios
/client/mozilla
/client/platforms/dummy
/client/platforms/linux
/client/platforms/macos
/client/platforms/windows
/client/server_scripts
/client/translations
/deploy
/docs
/metadata
/service/src

View File

@@ -217,7 +217,11 @@ jobs:
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin"
export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
export PATH=$PATH:~/go/bin
sh deploy/build_ios.sh
sh deploy/build_ios.sh | \
sed -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/d' | \
sed -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/d' | \
sed -e '/-DPROD_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DPROD_AGW_PUBLIC_KEY/d' | \
sed -e '/-DDEV_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DDEV_AGW_PUBLIC_KEY/d'
env:
IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
@@ -256,7 +260,7 @@ jobs:
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '14.3.1'
xcode-version: '15.4.0'
- name: 'Install Qt'
uses: jurplel/install-qt-action@v3
@@ -306,70 +310,6 @@ jobs:
path: deploy/build/client/AmneziaVPN.app
retention-days: 7
# ------------------------------------------------------
Build-MacOS-NE:
runs-on: macos-latest
env:
QT_VERSION: 6.4.3
QIF_VERSION: 4.6
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
steps:
- name: 'Setup Xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '14.3.1'
- name: 'Install desktop Qt'
uses: jurplel/install-qt-action@v3
with:
version: ${{ env.QT_VERSION }}
host: 'mac'
target: 'desktop'
modules: 'qtremoteobjects qt5compat qtshadertools qtmultimedia'
arch: 'clang_64'
dir: ${{ runner.temp }}
set-env: 'true'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
run: |
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
- name: 'Install Go'
uses: actions/setup-go@v5
with:
go-version: '1.22.1'
cache: false
- name: 'Get sources'
uses: actions/checkout@v4
with:
submodules: 'true'
fetch-depth: 10
- name: 'Install dependencies'
run: pip install jsonschema jinja2
- name: 'Set execute permissions for deploy script'
run: chmod +x deploy/build_macos_ne.sh
# - name: 'Build and deploy macOS NE'
# run: |
# export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
# export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
# export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
# bash deploy/build_macos_ne.sh
# env:
# APPSTORE_CONNECT_KEY_ID: ${{ secrets.APPSTORE_CONNECT_KEY_ID }}
# APPSTORE_CONNECT_ISSUER_ID: ${{ secrets.APPSTORE_CONNECT_ISSUER_ID }}
# APPSTORE_CONNECT_PRIVATE_KEY: ${{ secrets.APPSTORE_CONNECT_PRIVATE_KEY }}
# MAC_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
# MAC_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
# MAC_SIGNING_CERT_PASSWORD: ${{ secrets.IOS_SIGNING_CERT_PASSWORD }}
# ------------------------------------------------------
Build-Android:
@@ -395,7 +335,8 @@ jobs:
arch: 'linux_gcc_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86_64 Qt'
uses: jurplel/install-qt-action@v4
@@ -406,7 +347,8 @@ jobs:
arch: 'android_x86_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86 Qt'
uses: jurplel/install-qt-action@v4
@@ -417,7 +359,8 @@ jobs:
arch: 'android_x86'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_armv7 Qt'
uses: jurplel/install-qt-action@v4
@@ -428,7 +371,8 @@ jobs:
arch: 'android_armv7'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_arm64_v8a Qt'
uses: jurplel/install-qt-action@v4
@@ -439,7 +383,8 @@ jobs:
arch: 'android_arm64_v8a'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Grant execute permission for qt-cmake'
shell: bash
@@ -540,4 +485,4 @@ jobs:
if: ${{ fromJSON(steps.pull_request.outputs.data)[0].number != '' }}
run: |
echo "Pull request:" >> $GITHUB_STEP_SUMMARY
echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY
echo "[[#${{ fromJSON(steps.pull_request.outputs.data)[0].number }}] ${{ fromJSON(steps.pull_request.outputs.data)[0].title }}](${{ fromJSON(steps.pull_request.outputs.data)[0].html_url }})" >> $GITHUB_STEP_SUMMARY

2
.gitmodules vendored
View File

@@ -1,7 +1,6 @@
[submodule "client/3rd/OpenVPNAdapter"]
path = client/3rd/OpenVPNAdapter
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
branch = macos-dirty-build
[submodule "client/3rd/qtkeychain"]
path = client/3rd/qtkeychain
url = https://github.com/frankosterfeld/qtkeychain.git
@@ -11,7 +10,6 @@
[submodule "client/3rd-prebuilt"]
path = client/3rd-prebuilt
url = https://github.com/amnezia-vpn/3rd-prebuilt
branch = fixbug/mac-network-extension
[submodule "client/3rd/amneziawg-apple"]
path = client/3rd/amneziawg-apple
url = https://github.com/amnezia-vpn/amneziawg-apple

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.8.2.3
project(${PROJECT} VERSION 4.8.2.4
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 2069)
set(APP_ANDROID_VERSION_CODE 2071)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
@@ -31,13 +31,13 @@ set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if((APPLE AND NOT IOS) OR (DEFINED MACOS_NE AND MACOS_NE AND NOT IOS))
if(APPLE AND NOT IOS)
set(CMAKE_OSX_ARCHITECTURES "x86_64")
endif()
add_subdirectory(client)
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
if(NOT IOS AND NOT ANDROID)
add_subdirectory(service)
include(${CMAKE_SOURCE_DIR}/deploy/installer/config.cmake)

View File

@@ -1,24 +1,29 @@
# Amnezia VPN
## _The best client for self-hosted VPN_
### _The best client for self-hosted VPN_
[![Build Status](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml/badge.svg?branch=dev)](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
Amnezia is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)
<br>
[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download.png" width="150" style="max-width: 100%;"></a>
<a href="https://play.google.com/store/search?q=amnezia+vpn&c=apps"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/play.png" width="150" style="max-width: 100%;"></a>
<a href="https://apps.apple.com/us/app/amneziavpn/id1600529900"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/apl.png" width="150" style="max-width: 100%;"></a>
[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
[Alternative download link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org/downloads)
### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/kldscp/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
> [!TIP]
> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/kldscp/amnezia.org).
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
<a href="https://storage.googleapis.com/kldscp/amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
<br>
<br/>
<a href="https://www.testiny.io"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/testiny.png" height="28px"></a>
@@ -33,7 +38,8 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
## Links
- [https://amnezia.org](https://amnezia.org) - project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
- [https://amnezia.org](https://amnezia.org) - Project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
- [https://docs.amnezia.org](https://docs.amnezia.org) - Documentation
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
@@ -182,8 +188,8 @@ Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn
Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3 <br>
TON: UQDpU1CyKRmg7L8mNScKk9FRc2SlESuI7N-Hby4nX-CcVmns
## Acknowledgments
This project is tested with BrowserStack.

181
README_RU.md Normal file
View File

@@ -0,0 +1,181 @@
# Amnezia VPN
### _Лучший клиент для создания VPN на собственном сервере_
[![Build Status](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml/badge.svg?branch=dev)](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
[AmneziaVPN](https://amnezia.org) — это open sourse VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
[![Image](https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/uipic4.png)](https://amnezia.org)
### [Сайт](https://amnezia.org) | [Зеркало на сайт](https://storage.googleapis.com/kldscp/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
> [!TIP]
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/kldscp/amnezia.org).
<a href="https://storage.googleapis.com/kldscp/amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
<br/>
<a href="https://www.testiny.io"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/testiny.png" height="28px"></a>
## Особенности
- Простой в использовании — введите IP-адрес, SSH-логин и пароль, и Amnezia автоматически установит VPN-контейнеры Docker на ваш сервер и подключится к VPN.
- Классические VPN-протоколы: OpenVPN, WireGuard и IKEv2.
- Протоколы с маскировкой трафика (обфускацией): OpenVPN с плагином [Cloak](https://github.com/cbeuw/Cloak), Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
- Поддержка Split Tunneling — добавляйте любые сайты или приложения в список, чтобы включить VPN только для них.
- Поддерживает платформы: Windows, MacOS, Linux, Android, iOS.
- Поддержка конфигурации протокола AmneziaWG на [бета-прошивке Keenetic](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
## Ссылки
- [https://amnezia.org](https://amnezia.org) - Веб-сайт проекта | [Альтернативная ссылка (зеркало)](https://storage.googleapis.com/kldscp/amnezia.org)
- [https://docs.amnezia.org](https://docs.amnezia.org) - Документация
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддржки в Telegram (Английский)
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддржки в Telegram (Фарси)
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддржки в Telegram (Мьянма)
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддржки в Telegram (Русский)
- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium | [Зеркало](https://storage.googleapis.com/kldscp/vpnpay.io/ru/amnezia-premium\)
## Технологии
AmneziaVPN использует несколько проектов с открытым исходным кодом:
- [OpenSSL](https://www.openssl.org/)
- [OpenVPN](https://openvpn.net/)
- [Shadowsocks](https://shadowsocks.org/)
- [Qt](https://www.qt.io/)
- [LibSsh](https://libssh.org)
- и другие...
## Проверка исходного кода
После клонирования репозитория обязательно загрузите все подмодули.
```bash
git submodule update --init --recursive
```
## Разработка
Хотите внести свой вклад? Добро пожаловать!
### Помощь с переводами
Загрузите самые актуальные файлы перевода.
Перейдите на [вкладку "Actions"](https://github.com/amnezia-vpn/amnezia-client/actions?query=is%3Asuccess+branch%3Adev), нажмите на первую строку. Затем прокрутите вниз до раздела "Artifacts" и скачайте "AmneziaVPN_translations".
Распакуйте этот файл. Каждый файл с расширением *.ts содержит строки для соответствующего языка.
Переведите или исправьте строки в одном или нескольких файлах *.ts и загрузите их обратно в этот репозиторий в папку ``client/translations``. Это можно сделать через веб-интерфейс или любым другим знакомым вам способом.
### Сборка исходного кода и деплой
Проверьте папку deploy для скриптов сборки.
### Как собрать iOS-приложение из исходного кода на MacOS
1. Убедитесь, что у вас установлен XCode версии 14 или выше.
2. Для генерации проекта XCode используется QT. Требуется версия QT 6.6.2. Установите QT для MacOS здесь или через QT Online Installer. Необходимые модули:
- MacOS
- iOS
- Модуль совместимости с Qt 5
- Qt Shader Tools
- Дополнительные библиотеки:
- Qt Image Formats
- Qt Multimedia
- Qt Remote Objects
3. Установите CMake, если это необходимо. Рекомендуемая версия — 3.25. Скачать CMake можно здесь.
4. Установите Go версии >= v1.16. Если Go ещё не установлен, скачайте его с [официального сайта](https://golang.org/dl/) или используйте Homebrew. Установите gomobile:
```bash
export PATH=$PATH:~/go/bin
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
```
5. Соберите проект:
```bash
export QT_BIN_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/ios/bin"
export QT_MACOS_ROOT_DIR="<PATH-TO-QT-FOLDER>/Qt/<QT-VERSION>/macos"
export QT_IOS_BIN=$QT_BIN_DIR
export PATH=$PATH:~/go/bin
mkdir build-ios
$QT_IOS_BIN/qt-cmake . -B build-ios -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR
```
Замените <PATH-TO-QT-FOLDER> и <QT-VERSION> на ваши значения.
Если появляется ошибка gomobile: command not found, убедитесь, что PATH настроен на папку bin, где установлен gomobile:
```bash
export PATH=$(PATH):/path/to/GOPATH/bin
```
6. Откройте проект в XCode. Теперь вы можете тестировать, архивировать или публиковать приложение.
Если сборка завершится с ошибкой:
```
make: ***
[$(PROJECTDIR)/client/build/AmneziaVPN.build/Debug-iphoneos/wireguard-go-bridge/goroot/.prepared]
Error 1
```
Добавьте пользовательскую переменную PATH в настройки сборки для целей AmneziaVPN и WireGuardNetworkExtension с ключом `PATH` и значением `${PATH}/path/to/bin/folder/with/go/executable`, e.g. `${PATH}:/usr/local/go/bin`.
Если ошибка повторяется на Mac с M1, установите версию CMake для архитектуры ARM:
```
arch -arm64 brew install cmake
```
При первой попытке сборка может завершиться с ошибкой source files not found. Это происходит из-за параллельной компиляции зависимостей в XCode. Просто перезапустите сборку.
## Как собрать Android-приложение
Сборка тестировалась на MacOS. Требования:
- JDK 11
- Android SDK 33
- CMake 3.25.0
Установите QT, QT Creator и Android Studio.
Настройте QT Creator:
- В меню QT Creator перейдите в `QT Creator` -> `Preferences` -> `Devices` ->`Android`.
- Укажите путь к JDK 11.
- Укажите путь к Android SDK (`$ANDROID_HOME`)
Если вы сталкиваетесь с ошибками, связанными с отсутствием SDK или сообщением «SDK manager not running», их нельзя исправить просто корректировкой путей. Если у вас есть несколько свободных гигабайт на диске, вы можете позволить Qt Creator установить все необходимые компоненты, выбрав пустую папку для расположения Android SDK и нажав кнопку **Set Up SDK**. Учтите: это установит второй Android SDK и NDK на вашем компьютере!
Убедитесь, что настроена правильная версия CMake: перейдите в **Qt Creator -> Preferences** и в боковом меню выберите пункт **Kits**. В центральной части окна, на вкладке **Kits**, найдите запись для инструмента **CMake Tool**. Если выбранная по умолчанию версия CMake ниже 3.25.0, установите на свою систему CMake версии 3.25.0 или выше, а затем выберите опцию **System CMake at <путь>** из выпадающего списка. Если этот пункт отсутствует, это может означать, что вы еще не установили CMake, или Qt Creator не смог найти путь к нему. В таком случае в окне **Preferences** перейдите в боковое меню **CMake**, затем во вкладку **Tools** в центральной части окна и нажмите кнопку **Add**, чтобы указать путь к установленному CMake.
Убедитесь, что для вашего проекта выбрана Android Platform SDK 33: в главном окне на боковой панели выберите пункт **Projects**, и слева вы увидите раздел **Build & Run**, показывающий различные целевые Android-платформы. Вы можете выбрать любую из них, так как настройка проекта Amnezia VPN разработана таким образом, чтобы все Android-цели могли быть собраны. Перейдите в подраздел **Build** и прокрутите центральную часть окна до раздела **Build Steps**. Нажмите **Details** в заголовке **Build Android APK** (кнопка **Details** может быть скрыта, если окно Qt Creator не запущено в полноэкранном режиме!). Вот здесь выберите **android-33** в качестве Android Build Platform SDK.
### Разработка Android-компонентов
После сборки QT Creator копирует проект в отдельную папку, например, `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>`. Для разработки Android-компонентов откройте сгенерированный проект в Android Studio, указав папку `build-amnezia-client-Android_Qt_<version>_Clang_<architecture>-<BuildType>/client/android-build` в качестве корневой.
Изменения в сгенерированном проекте нужно вручную перенести в репозиторий. После этого можно коммитить изменения.
Если возникают проблемы со сборкой в QT Creator после работы в Android Studio, выполните команду `./gradlew clean` в корневой папке сгенерированного проекта (`<path>/client/android-build/.`).
## Лицензия
GPL v3.0
## Донаты
Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn)
Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3 <br>
TON: UQDpU1CyKRmg7L8mNScKk9FRc2SlESuI7N-Hby4nX-CcVmns
## Благодарности
Этот проект тестируется с помощью BrowserStack.
Мы выражаем благодарность [BrowserStack](https://www.browserstack.com) за поддержку нашего проекта.

View File

@@ -31,12 +31,11 @@ add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
if(IOS OR MACOS_NE)
if(IOS)
set(PACKAGES ${PACKAGES} Multimedia)
endif()
#Macos Network Extension doesn't need Widgets
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(PACKAGES ${PACKAGES} Widgets)
endif()
@@ -49,23 +48,18 @@ set(LIBS ${LIBS}
Qt6::Core5Compat Qt6::Concurrent
)
if(IOS OR MACOS_NE)
if(IOS)
set(LIBS ${LIBS} Qt6::Multimedia)
endif()
# message("Client desktop build ", ${MACOS_NE})
#Macos Network Extension doesn't need Widgets
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
message("Run this block when MACOS_NE is not defined or set to FALSE")
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(LIBS ${LIBS} Qt6::Widgets)
endif()
qt_standard_project_setup()
qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
# TODO error in there
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
message("Run this block when MACOS_NE is not defined or set to FALSE")
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
@@ -103,18 +97,10 @@ qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
# -- i18n end
if(IOS)
message("Building for iOS")
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endif()
# Build openvpn adapter for MacOS Network Extension
if(MACOS_NE)
message("Building for MacOS Network Extension")
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/macos/scripts/openvpn.sh args
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endif()
set(IS_CI ${CI})
if(IS_CI)
message("Detected CI env")
@@ -175,24 +161,12 @@ include_directories(mozilla)
include_directories(mozilla/shared)
include_directories(mozilla/models)
if(MACOS_NE)
message("MACOS_NE is ON")
add_definitions(-DQ_OS_IOS)
add_definitions(-DMACOS_NE)
message("Add macros for MacOS Network Extension")
else()
message("MACOS_NE is OFF")
endif()
if(NOT IOS AND NOT MACOS_NE)
message(" Add header for non-IOS and non-MACOS_NE")
if(NOT IOS)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.h
)
endif()
if(NOT ANDROID)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
@@ -237,7 +211,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG")
endif()
if(NOT IOS AND NOT MACOS_NE)
if(NOT IOS)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/platforms/ios/QRCodeReaderBase.cpp
)
@@ -338,7 +312,6 @@ if(APPLE)
set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${BUILD_VPN_DEVELOPMENT_TEAM})
set(CMAKE_XCODE_ATTRIBUTE_GROUP_ID_IOS ${BUILD_IOS_GROUP_IDENTIFIER})
set(MACOSX_DEPLOYMENT_TARGET "12.0")
endif()
if(LINUX AND NOT ANDROID)
@@ -346,9 +319,10 @@ if(LINUX AND NOT ANDROID)
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
endif()
# Macos Network Extension doesn't need
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
message("Client desktop build")
add_compile_definitions(AMNEZIA_DESKTOP)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/ipcclient.h
${CMAKE_CURRENT_LIST_DIR}/core/privileged_process.h
@@ -381,12 +355,9 @@ endif()
if(IOS)
include(cmake/ios.cmake)
include(cmake/ios-arch-fixup.cmake)
elseif(APPLE AND NOT IOS AND NOT DEFINED MACOS_NE)
# include(cmake/osxtools.cmake)
include(cmake/macos.cmake)
elseif(APPLE AND NOT IOS AND MACOS_NE)
elseif(APPLE AND NOT IOS)
include(cmake/osxtools.cmake)
include(cmake/macos_ne.cmake)
include(cmake/macos.cmake)
endif()
target_link_libraries(${PROJECT} PRIVATE ${LIBS})
@@ -405,7 +376,7 @@ elseif(APPLE AND NOT IOS)
set(DEPLOY_PLATFORM_PATH "macos")
endif()
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
if(NOT IOS AND NOT ANDROID)
add_custom_command(
TARGET ${PROJECT} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
@@ -424,36 +395,4 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
endif()
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
if(MACOS_NE)
message("Copy MacOS Network Extension files")
add_custom_command(TARGET ${PROJECT} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks
COMMAND ${CMAKE_COMMAND} -E echo "Copying OpenVPNAdapter.framework..."
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/client/3rd/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework/Versions/A
$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks/OpenVPNAdapter.framework/Versions/A
COMMAND ${CMAKE_COMMAND} -E echo "OpenVPNAdapter.framework copied successfully."
)
# MacOS specific application deployment
add_custom_command(TARGET ${PROJECT} POST_BUILD
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:AmneziaVPN> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR}
)
# MacOS specific code signing for Release
if(CMAKE_BUILD_TYPE STREQUAL "Release")
SET(SIGN_CMD codesign --deep --force --sign 'Apple Distribution: Privacy Technologies OU \(X7UJ388FXK\)' --timestamp --options runtime $<TARGET_BUNDLE_DIR:AmneziaVPN>)
message("Manual signing bundle...")
message(${SIGN_CMD})
add_custom_command(TARGET ${PROJECT} POST_BUILD
COMMAND ${SIGN_CMD}
)
endif()
endif()
qt_finalize_target(${PROJECT})

View File

@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<!-- To request network state -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

View File

@@ -1,11 +1,12 @@
package org.amnezia.vpn.protocol.wireguard
import android.net.VpnService.Builder
import java.io.IOException
import java.util.Locale
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlinx.coroutines.launch
import org.amnezia.awg.GoBackend
import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
@@ -27,6 +28,8 @@ open class Wireguard : Protocol() {
private var tunnelHandle: Int = -1
protected open val ifName: String = "amn0"
private lateinit var scope: CoroutineScope
private var statusJob: Job? = null
override val statistics: Statistics
get() {
@@ -49,46 +52,17 @@ open class Wireguard : Protocol() {
override fun internalInit() {
if (!isInitialized) loadSharedLibrary(context, "wg-go")
if (this::scope.isInitialized) {
scope.cancel()
}
scope = CoroutineScope(Dispatchers.IO)
}
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val wireguardConfig = parseConfig(config)
val startTime = System.currentTimeMillis()
start(wireguardConfig, vpnBuilder, protect)
waitForConnection(startTime)
state.value = CONNECTED
}
private suspend fun waitForConnection(startTime: Long) {
Log.d(TAG, "Waiting for connection")
withContext(Dispatchers.IO) {
val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
try {
delay(1000)
var log = getLogcat(time)
Log.v(TAG, "First waiting log: $log")
// check that there is a connection log,
// to avoid infinite connection
if (!log.contains("Attaching to interface")) {
Log.w(TAG, "Logs do not contain a connection log")
return@withContext
}
while (!log.contains("Received handshake response")) {
delay(1000)
log = getLogcat(time)
}
} catch (e: IOException) {
Log.e(TAG, "Failed to get logcat: $e")
}
}
}
private fun getLogcat(time: String): String =
ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
.redirectErrorStream(true)
.start()
.inputStream.reader().readText()
protected open fun parseConfig(config: JSONObject): WireguardConfig {
val configData = config.getJSONObject("wireguard_config_data")
return WireguardConfig.build {
@@ -178,6 +152,43 @@ open class Wireguard : Protocol() {
tunnelHandle = -1
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
}
launchStatusJob()
}
private fun launchStatusJob() {
Log.d(TAG, "Launch status job")
statusJob = scope.launch {
while (true) {
val lastHandshake = getLastHandshake()
Log.v(TAG, "lastHandshake=$lastHandshake")
if (lastHandshake == 0L) {
delay(1000)
continue
}
if (lastHandshake == -2L || lastHandshake > 0L) state.value = CONNECTED
else if (lastHandshake == -1L) state.value = DISCONNECTED
statusJob = null
break
}
}
}
private fun getLastHandshake(): Long {
if (tunnelHandle == -1) {
Log.e(TAG, "Trying to get config of a non-existent tunnel")
return -1
}
val config = GoBackend.awgGetConfig(tunnelHandle)
if (config == null) {
Log.e(TAG, "Failed to get tunnel config")
return -2
}
val lastHandshake = config.lines().find { it.startsWith("last_handshake_time_sec=") }?.substring(24)?.toLong()
if (lastHandshake == null) {
Log.e(TAG, "Failed to get last_handshake_time_sec")
return -2
}
return lastHandshake
}
override fun stopVpn() {
@@ -185,6 +196,8 @@ open class Wireguard : Protocol() {
Log.w(TAG, "Tunnel already down")
return
}
statusJob?.cancel()
statusJob = null
val handleToClose = tunnelHandle
tunnelHandle = -1
GoBackend.awgTurnOff(handleToClose)

View File

@@ -1,140 +0,0 @@
message("Client ==> MacOS NE build")
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
set(CMAKE_OSX_ARCHITECTURES "x86_64")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
enable_language(OBJC)
enable_language(Swift)
find_package(Qt6 REQUIRED COMPONENTS ShaderTools)
set(LIBS ${LIBS} Qt6::ShaderTools)
find_library(FW_AUTHENTICATIONSERVICES AuthenticationServices)
find_library(FW_AVFOUNDATION AVFoundation)
find_library(FW_FOUNDATION Foundation)
find_library(FW_STOREKIT StoreKit)
find_library(FW_USERNOTIFICATIONS UserNotifications)
find_library(FW_NETWORKEXTENSION NetworkExtension)
set(LIBS ${LIBS}
${FW_AUTHENTICATIONSERVICES}
${FW_AVFOUNDATION}
${FW_FOUNDATION}
${FW_STOREKIT}
${FW_USERNOTIFICATIONS}
${FW_NETWORKEXTENSION}
)
set(HEADERS ${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate-C-Interface.h
)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.h PROPERTIES OBJECTIVE_CPP_HEADER TRUE)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller.mm
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/ios_controller_wrapper.mm
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosnotificationhandler.mm
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosglue.mm
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QRCodeReaderBase.mm
${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/QtAppDelegate.mm
)
target_include_directories(${PROJECT} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
set_target_properties(${PROJECT} PROPERTIES
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Info.plist.in
MACOSX_BUNDLE_ICON_FILE "AppIcon"
MACOSX_BUNDLE_INFO_STRING "AmneziaVPN"
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPN"
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_LONG_VERSION_STRING "${APPLE_PROJECT_VERSION}-${CMAKE_PROJECT_VERSION_TWEAK}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/ios/app/main.entitlements"
XCODE_ATTRIBUTE_MARKETING_VERSION "${APPLE_PROJECT_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPN"
XCODE_ATTRIBUTE_BUNDLE_INFO_STRING "AmneziaVPN"
XCODE_GENERATE_SCHEME TRUE
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "NO"
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY "YES"
XCODE_LINK_BUILD_PHASE_MODE KNOWN_LOCATION
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
XCODE_EMBED_APP_EXTENSIONS networkextension
# XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution: Privacy Technologies OU (X7UJ388FXK)"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "Mac AppStore AmneziaVPN"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "org.amnezia.AmneziaVPNManual"
)
set_target_properties(${PROJECT} PROPERTIES
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "AmneziaVPN-Swift.h"
XCODE_ATTRIBUTE_SWIFT_OBJC_INTEROP_MODE "objcxx"
)
set_target_properties(${PROJECT} PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_compile_options(${PROJECT} PRIVATE
-DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\"
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
)
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources)
target_sources(${PROJECT} PRIVATE
${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c
${CLIENT_ROOT_DIR}/platforms/ios/LogController.swift
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/ScreenProtection.swift
${CLIENT_ROOT_DIR}/platforms/ios/VPNCController.swift
)
target_sources(${PROJECT} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
)
set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
${CMAKE_CURRENT_SOURCE_DIR}/macos/app/Images.xcassets
${CMAKE_CURRENT_SOURCE_DIR}/ios/app/PrivacyInfo.xcprivacy
)
add_subdirectory(macos/networkextension)
add_dependencies(${PROJECT} networkextension)
get_target_property(QtCore_location Qt6::Core LOCATION)
message("QtCore_location")
message(${QtCore_location})
get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE)
set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS
"${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework"
)
set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-macos)
target_link_libraries("networkextension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd/OpenVPNAdapter/build/Release-macos/OpenVPNAdapter.framework")

View File

@@ -76,7 +76,7 @@ function(osx_bundle_assetcatalog TARGET)
)
## Patch the asset catalog into the target bundle.
if(NOT IOS AND NOT MACOS_NE)
if(NOT IOS)
set(XCASSETS_RESOURCE_DIR "Resources")
endif()
add_custom_command(TARGET ${TARGET} POST_BUILD
@@ -141,7 +141,6 @@ function(osx_codesign_target TARGET)
endif()
foreach(FILE ${CODESIGN_FILES})
message(STATUS "Signing ${TARGET}: ${FILE}")
add_custom_command(TARGET ${TARGET} POST_BUILD VERBATIM
COMMAND ${COMMENT_ECHO_COMMAND} "Signing ${TARGET}: ${FILE}"
COMMAND ${CODESIGN_BIN} ${CODESIGN_ARGS} ${FILE}

View File

@@ -102,9 +102,7 @@ QProcessEnvironment SshConfigurator::prepareEnv()
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
#elif defined(Q_OS_MACX)
#if !defined(MACOS_NE)
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
#endif
#endif
env.insert("PATH", pathEnvVar);

View File

@@ -3,38 +3,169 @@
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUuid>
#include "logger.h"
#include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
namespace {
Logger logger("XrayConfigurator");
}
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
: ConfiguratorBase(settings, serverController, parent)
{
}
QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
ErrorCode &errorCode)
QString XrayConfigurator::prepareServerConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode &errorCode)
{
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
m_serverController->genVarsForScript(credentials, container, containerConfig));
QString xrayPublicKey =
m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
xrayPublicKey.replace("\n", "");
QString xrayUuid = m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, errorCode);
xrayUuid.replace("\n", "");
QString xrayShortId =
m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::shortidPath, errorCode);
xrayShortId.replace("\n", "");
// Generate new UUID for client
QString clientId = QUuid::createUuid().toString(QUuid::WithoutBraces);
// Get current server config
QString currentConfig = m_serverController->getTextFileFromContainer(
container, credentials, amnezia::protocols::xray::serverConfigPath, errorCode);
if (errorCode != ErrorCode::NoError) {
logger.error() << "Failed to get server config file";
return "";
}
config.replace("$XRAY_CLIENT_ID", xrayUuid);
// Parse current config as JSON
QJsonDocument doc = QJsonDocument::fromJson(currentConfig.toUtf8());
if (doc.isNull() || !doc.isObject()) {
logger.error() << "Failed to parse server config JSON";
errorCode = ErrorCode::InternalError;
return "";
}
QJsonObject serverConfig = doc.object();
// Validate server config structure
if (!serverConfig.contains("inbounds")) {
logger.error() << "Server config missing 'inbounds' field";
errorCode = ErrorCode::InternalError;
return "";
}
QJsonArray inbounds = serverConfig["inbounds"].toArray();
if (inbounds.isEmpty()) {
logger.error() << "Server config has empty 'inbounds' array";
errorCode = ErrorCode::InternalError;
return "";
}
QJsonObject inbound = inbounds[0].toObject();
if (!inbound.contains("settings")) {
logger.error() << "Inbound missing 'settings' field";
errorCode = ErrorCode::InternalError;
return "";
}
QJsonObject settings = inbound["settings"].toObject();
if (!settings.contains("clients")) {
logger.error() << "Settings missing 'clients' field";
errorCode = ErrorCode::InternalError;
return "";
}
QJsonArray clients = settings["clients"].toArray();
// Create configuration for new client
QJsonObject clientConfig {
{"id", clientId},
{"flow", "xtls-rprx-vision"}
};
clients.append(clientConfig);
// Update config
settings["clients"] = clients;
inbound["settings"] = settings;
inbounds[0] = inbound;
serverConfig["inbounds"] = inbounds;
// Save updated config to server
QString updatedConfig = QJsonDocument(serverConfig).toJson();
errorCode = m_serverController->uploadTextFileToContainer(
container,
credentials,
updatedConfig,
amnezia::protocols::xray::serverConfigPath,
libssh::ScpOverwriteMode::ScpOverwriteExisting
);
if (errorCode != ErrorCode::NoError) {
logger.error() << "Failed to upload updated config";
return "";
}
// Restart container
QString restartScript = QString("sudo docker restart $CONTAINER_NAME");
errorCode = m_serverController->runScript(
credentials,
m_serverController->replaceVars(restartScript, m_serverController->genVarsForScript(credentials, container))
);
if (errorCode != ErrorCode::NoError) {
logger.error() << "Failed to restart container";
return "";
}
return clientId;
}
QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode &errorCode)
{
// Get client ID from prepareServerConfig
QString xrayClientId = prepareServerConfig(credentials, container, containerConfig, errorCode);
if (errorCode != ErrorCode::NoError || xrayClientId.isEmpty()) {
logger.error() << "Failed to prepare server config";
errorCode = ErrorCode::InternalError;
return "";
}
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
m_serverController->genVarsForScript(credentials, container, containerConfig));
if (config.isEmpty()) {
logger.error() << "Failed to get config template";
errorCode = ErrorCode::InternalError;
return "";
}
QString xrayPublicKey =
m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
if (errorCode != ErrorCode::NoError || xrayPublicKey.isEmpty()) {
logger.error() << "Failed to get public key";
errorCode = ErrorCode::InternalError;
return "";
}
xrayPublicKey.replace("\n", "");
QString xrayShortId =
m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::shortidPath, errorCode);
if (errorCode != ErrorCode::NoError || xrayShortId.isEmpty()) {
logger.error() << "Failed to get short ID";
errorCode = ErrorCode::InternalError;
return "";
}
xrayShortId.replace("\n", "");
// Validate all required variables are present
if (!config.contains("$XRAY_CLIENT_ID") || !config.contains("$XRAY_PUBLIC_KEY") || !config.contains("$XRAY_SHORT_ID")) {
logger.error() << "Config template missing required variables:"
<< "XRAY_CLIENT_ID:" << !config.contains("$XRAY_CLIENT_ID")
<< "XRAY_PUBLIC_KEY:" << !config.contains("$XRAY_PUBLIC_KEY")
<< "XRAY_SHORT_ID:" << !config.contains("$XRAY_SHORT_ID");
errorCode = ErrorCode::InternalError;
return "";
}
config.replace("$XRAY_CLIENT_ID", xrayClientId);
config.replace("$XRAY_PUBLIC_KEY", xrayPublicKey);
config.replace("$XRAY_SHORT_ID", xrayShortId);

View File

@@ -14,6 +14,10 @@ public:
QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
ErrorCode &errorCode);
private:
QString prepareServerConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
ErrorCode &errorCode);
};
#endif // XRAY_CONFIGURATOR_H

View File

@@ -50,6 +50,8 @@ namespace
constexpr char authData[] = "auth_data";
}
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
{
if (!sslErrors.empty()) {
@@ -177,7 +179,7 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
QStringList ApiController::getProxyUrls()
{
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QEventLoop wait;
@@ -280,7 +282,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
if (serverConfig.value(config_key::configVersion).toInt()) {
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(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();
@@ -336,7 +338,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
#endif
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
@@ -377,6 +379,13 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
auto errorCode = checkErrors(sslErrors, reply);
reply->deleteLater();
if (errorCode == ErrorCode::NoError) {
if (!responseBody.contains("services")) {
return ErrorCode::ApiServicesMissingError;
}
}
return errorCode;
}
@@ -390,7 +399,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
#endif
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));

View File

@@ -109,6 +109,7 @@ namespace amnezia
ApiConfigSslError = 1104,
ApiMissingAgwPublicKey = 1105,
ApiConfigDecryptionError = 1106,
ApiServicesMissingError = 1107,
// QFile errors
OpenError = 1200,

View File

@@ -63,7 +63,8 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
case (ErrorCode::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
case (ErrorCode::ApiConfigDecryptionError): errorMessage = QObject::tr("Failed to decrypt response payload"); break;
case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
case(ErrorCode::ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break;

View File

@@ -104,7 +104,7 @@ QJsonObject Deserialize(const QString &vmessStr, QString *alias, QString *errMes
server.users.first().security = "auto";
}
const static auto getQueryValue = [&query](const QString &key, const QString &defaultValue) {
const auto getQueryValue = [&query](const QString &key, const QString &defaultValue) {
if (query.hasQueryItem(key))
return query.queryItemValue(key, QUrl::FullyDecoded);
else

View File

@@ -16,7 +16,5 @@
<array>
<string>$(AppIdentifierPrefix)group.org.amnezia.AmneziaVPN</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 B

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,68 +1,68 @@
{
"images": [
"images" : [
{
"idiom": "mac",
"size": "16x16",
"scale": "1x",
"filename": "16.png"
"filename" : "16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"idiom": "mac",
"size": "16x16",
"scale": "2x",
"filename": "16@2x.png"
"filename" : "16@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"idiom": "mac",
"size": "32x32",
"scale": "1x",
"filename": "32.png"
"filename" : "32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"idiom": "mac",
"size": "32x32",
"scale": "2x",
"filename": "32@2x.png"
"filename" : "32@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"idiom": "mac",
"size": "128x128",
"scale": "1x",
"filename": "128.png"
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"idiom": "mac",
"size": "128x128",
"scale": "2x",
"filename": "128@2x.png"
"filename" : "128@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"idiom": "mac",
"size": "256x256",
"scale": "1x",
"filename": "256.png"
"filename" : "256.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"idiom": "mac",
"size": "256x256",
"scale": "2x",
"filename": "256@2x.png"
"filename" : "256@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"idiom": "mac",
"size": "512x512",
"scale": "1x",
"filename": "512.png"
"filename" : "512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"idiom": "mac",
"size": "512x512",
"scale": "2x",
"filename": "512@2x.png"
"filename" : "512@2x.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info": {
"version": 1,
"author": "xcode"
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,68 +1,6 @@
{
"images": [
{
"idiom": "mac",
"size": "16x16",
"scale": "1x",
"filename": "16.png"
},
{
"idiom": "mac",
"size": "16x16",
"scale": "2x",
"filename": "16@2x.png"
},
{
"idiom": "mac",
"size": "32x32",
"scale": "1x",
"filename": "32.png"
},
{
"idiom": "mac",
"size": "32x32",
"scale": "2x",
"filename": "32@2x.png"
},
{
"idiom": "mac",
"size": "128x128",
"scale": "1x",
"filename": "128.png"
},
{
"idiom": "mac",
"size": "128x128",
"scale": "2x",
"filename": "128@2x.png"
},
{
"idiom": "mac",
"size": "256x256",
"scale": "1x",
"filename": "256.png"
},
{
"idiom": "mac",
"size": "256x256",
"scale": "2x",
"filename": "256@2x.png"
},
{
"idiom": "mac",
"size": "512x512",
"scale": "1x",
"filename": "512.png"
},
{
"idiom": "mac",
"size": "512x512",
"scale": "2x",
"filename": "512@2x.png"
}
],
"info": {
"version": 1,
"author": "xcode"
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,184 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${QT_INTERNAL_DOLLAR_VAR}{PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>AmneziaVPNLaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array/>
<key>UIRequiresFullScreen</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array/>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>com.wireguard.ios.app_group_id</key>
<string>group.org.amnezia.AmneziaVPN</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Amnezia VPN needs access to the camera for reading QR-codes.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>Amnezia VPN config</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>vpn</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>WireGuard config</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>conf</string>
<string>cfg</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>OpenVPN config</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ovpn</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>AmneziaVPN backup file</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>org.amnezia.AmneziaVPN.backup-config</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>backup</string>
</array>
<key>public.mime-type</key>
<array>
<string>text/plain</string>
</array>
</dict>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Amnezia VPN config</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>org.amnezia.AmneziaVPN.amnezia-config</string>
<string>org.amnezia.AmneziaVPN.wireguard-config</string>
<string>org.amnezia.AmneziaVPN.openvpn-config</string>
<string>org.amnezia.AmneziaVPN.backup-config</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -3,52 +3,40 @@
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>X7UJ388FXK.org.amnezia.AmneziaVPN.network-extension</string>
<string>$(DEVELOPMENT_TEAM).$(NETEXT_ID_MACOS)</string>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>X7UJ388FXK</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.org.amnezia.AmneziaVPN</string>
</array>
<key>com.apple.security.assets.movies.read-write</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.personal-information.addressbook</key>
<true/>
<key>com.apple.security.personal-information.calendars</key>
<true/>
<key>com.apple.security.personal-information.location</key>
<true/>
<key>com.apple.security.print</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)org.amnezia.AmneziaVPN.network-extension</string>
<string>$(DEVELOPMENT_TEAM).*</string>
</array>
<key>com.apple.developer.team-identifier</key>
<string>$(DEVELOPMENT_TEAM)</string>
<key>com.apple.developer.system-extension.install</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>$(DEVELOPMENT_TEAM).$(GROUP_ID_MACOS)</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.private.network.socket-delegate</key>
<true/>
</dict>
</plist>

View File

@@ -1,139 +0,0 @@
enable_language(Swift)
message("Client message >> macos build >> networkextension")
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
add_executable(networkextension)
if(MACOS_NE)
message("MACOS_NE is ON")
add_definitions(-DQ_OS_IOS)
add_definitions(-DMACOS_NE)
else()
message("MACOS_NE is OFF")
endif()
message("executable_path is: @executable_path/../../Frameworks")
set_target_properties(networkextension PROPERTIES
XCODE_PRODUCT_TYPE com.apple.product-type.app-extension
BUNDLE_EXTENSION appex
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APPLE_PROJECT_VERSION}"
MACOSX_BUNDLE_INFO_STRING "AmneziaVPNNetworkExtension"
MACOSX_BUNDLE_BUNDLE_NAME "AmneziaVPNNetworkExtension"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_NAME "${BUILD_IOS_APP_IDENTIFIER}.network-extension"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/AmneziaVPNNetworkExtension.entitlements
XCODE_ATTRIBUTE_MARKETING_VERSION "${APP_MAJOR_VERSION}"
XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION "${BUILD_ID}"
XCODE_ATTRIBUTE_PRODUCT_NAME "AmneziaVPNNetworkExtension"
XCODE_ATTRIBUTE_APPLICATION_EXTENSION_API_ONLY "YES"
XCODE_ATTRIBUTE_ENABLE_BITCODE "NO"
# XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic
XCODE_ATTRIBUTE_CODE_SIGN_STYLE Manual
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "Mac AppStore AmneziaVPN.network-extension"
XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER[variant=Debug] "amnezia.AmneziaVPN.network-extensionManual"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Distribution: Privacy Technologies OU (X7UJ388FXK)"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY[variant=Debug] "Apple Development"
XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../../../../Frameworks @loader_path/../../../../Frameworks"
)
set_target_properties(networkextension PROPERTIES
XCODE_ATTRIBUTE_SWIFT_VERSION "5.0"
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES "YES"
XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/WireGuardNetworkExtension-Bridging-Header.h"
XCODE_ATTRIBUTE_SWIFT_OPTIMIZATION_LEVEL "-Onone"
XCODE_ATTRIBUTE_SWIFT_PRECOMPILE_BRIDGING_HEADER "NO"
)
set_target_properties("networkextension" PROPERTIES
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "X7UJ388FXK"
)
find_library(FW_ASSETS_LIBRARY AssetsLibrary)
find_library(FW_MOBILE_CORE MobileCoreServices)
find_library(FW_UI_KIT UIKit)
find_library(FW_LIBRESOLV libresolv.9.tbd)
# Set the root directory
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
set(CMAKE_FRAMEWORK_PATH ${CLIENT_ROOT_DIR}/3rd/OpenVPNAdapter/build/Release-macos)
target_link_libraries(networkextension PRIVATE ${FW_LIBRESOLV})
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources)
message("WG_APPLE_SOURCE_DIR is: ${WG_APPLE_SOURCE_DIR}")
message("CLIENT_ROOT_DIR is: ${CLIENT_ROOT_DIR}")
target_sources(networkextension PRIVATE
${WG_APPLE_SOURCE_DIR}/WireGuardKit/WireGuardAdapter.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PacketTunnelSettingsGenerator.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSResolver.swift
${WG_APPLE_SOURCE_DIR}/WireGuardNetworkExtension/ErrorNotifier.swift
${WG_APPLE_SOURCE_DIR}/Shared/Keychain.swift
${WG_APPLE_SOURCE_DIR}/Shared/Model/TunnelConfiguration+WgQuickConfig.swift
${WG_APPLE_SOURCE_DIR}/Shared/Model/NETunnelProviderProtocol+Extension.swift
${WG_APPLE_SOURCE_DIR}/Shared/Model/String+ArrayConversion.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/TunnelConfiguration.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddressRange.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/Endpoint.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/DNSServer.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/InterfaceConfiguration.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PeerConfiguration.swift
${WG_APPLE_SOURCE_DIR}/Shared/FileManager+Extension.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKitC/x25519.c
${WG_APPLE_SOURCE_DIR}/WireGuardKit/Array+ConcurrentMap.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/IPAddress+AddrInfo.swift
${WG_APPLE_SOURCE_DIR}/WireGuardKit/PrivateKey.swift
${CLIENT_ROOT_DIR}/platforms/ios/HevSocksTunnel.swift
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
${CLIENT_ROOT_DIR}/platforms/ios/Log.swift
${CLIENT_ROOT_DIR}/platforms/ios/LogRecord.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+WireGuard.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+OpenVPN.swift
${CLIENT_ROOT_DIR}/platforms/ios/PacketTunnelProvider+Xray.swift
${CLIENT_ROOT_DIR}/platforms/ios/WGConfig.swift
${CLIENT_ROOT_DIR}/platforms/ios/iosglue.mm
${CLIENT_ROOT_DIR}/platforms/ios/XrayConfig.swift
)
target_sources(networkextension PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
set_property(TARGET networkextension APPEND PROPERTY RESOURCE
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
)
## Build wireguard-go-version.h
execute_process(
COMMAND go list -m golang.zx2c4.com/wireguard
WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo
OUTPUT_VARIABLE WG_VERSION_FULL
)
string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
target_sources(networkextension PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR})
target_include_directories(networkextension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/x86_64/libwg-go.a)
message(${CLIENT_ROOT_DIR})
message(${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers)

View File

@@ -3,32 +3,27 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>AmneziaVPNNetworkExtension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.amnezia.AmneziaVPN.network-extension</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>AmneziaVPNNetworkExtension</string>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>${APPLE_PROJECT_VERSION}</string>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>${CMAKE_PROJECT_VERSION_TWEAK}</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSMinimumSystemVersion</key>
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
<key>CFBundleDisplayName</key>
<string>AmneziaVPNNetworkExtension</string>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
@@ -36,11 +31,5 @@
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
</dict>
<key>com.wireguard.ios.app_group_id</key>
<string>group.org.amnezia.AmneziaVPN</string>
<key>com.wireguard.macos.app_group_id</key>
<string>${BUILD_VPN_DEVELOPMENT_TEAM}.group.org.amnezia.AmneziaVPN</string>
</dict>
</plist>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>1C8F.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -1,10 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "macos/gobridge/wireguard.h"
#include "wireguard-go-version.h"
#include "3rd/amneziawg-apple/Sources/WireGuardKitGo/wireguard.h"
#include "3rd/amneziawg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include "3rd/awg-apple/Sources/WireGuardKitC/WireGuardKitC.h"
#include <stdbool.h>
#include <stdint.h>
@@ -23,8 +23,3 @@ bool key_from_hex(uint8_t key[WG_KEY_LEN], const char* hex);
bool key_eq(const uint8_t key1[WG_KEY_LEN], const uint8_t key2[WG_KEY_LEN]);
void write_msg_to_log(const char* tag, const char* msg);
// init function definition in C
void hev_socks5_tunnel_quit(void);
// Updated function definition in C
int hev_socks5_tunnel_main(const char* configFile, int fd);

View File

@@ -1,3 +0,0 @@
#ifndef WIREGUARD_GO_VERSION
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
#endif // WIREGUARD_GO_VERSION

View File

@@ -1,36 +0,0 @@
#!/bin/bash
XCODEBUILD="/usr/bin/xcodebuild"
WORKINGDIR=`pwd`
PATCH="/usr/bin/patch"
echo "Building OpenVPNAdapter for macOS Network Extension (MacNE)..."
# Copy the Project-MacNE.xcconfig settings to amnezia.xcconfig
cat $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/Project-MacNE.xcconfig > $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
# Append macOS-specific build directory configurations to amnezia.xcconfig
cat << EOF >> $WORKINGDIR/3rd/OpenVPNAdapter/Configuration/amnezia.xcconfig
PROJECT_TEMP_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/OpenVPNAdapter.build
CONFIGURATION_BUILD_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Release-macos
BUILT_PRODUCTS_DIR = $WORKINGDIR/3rd/OpenVPNAdapter/build/Release-macos
EOF
# Fetch the current macOS SDK version dynamically
MACOSX_SDK=$(xcrun --sdk macosx --show-sdk-path | sed -E 's/.*MacOSX([0-9]+\.[0-9]+)\.sdk/\1/')
echo "Using macOS SDK version: $MACOSX_SDK"
cd 3rd/OpenVPNAdapter
# Build for macOS using the correct SDK and destination
if $XCODEBUILD -scheme OpenVPNAdapter -configuration Release -xcconfig Configuration/amnezia.xcconfig -sdk macosx$MACOSX_SDK -destination 'generic/platform=macOS' -project OpenVPNAdapter.xcodeproj ; then
echo "OpenVPNAdapter built successfully for macOS Network Extension (MacNE)"
else
echo "OpenVPNAdapter macOS Network Extension (MacNE) build failed..."
fi
# Remove CodeSignature if needed for macOS
rm -rf ./build/Release-macos/OpenVPNAdapter.framework/Versions/A/_CodeSignature
cd ../../

View File

@@ -47,7 +47,7 @@ extension PacketTunnelProvider {
let configuration = OpenVPNConfiguration()
configuration.fileContent = ovpnConfiguration
if str.contains("cloak") {
configuration.setPTCloak()
configuration.setPTCloak()
}
let evaluation: OpenVPNConfigurationEvaluation?

View File

@@ -1,4 +1,3 @@
#if !MACOS_NE
#include "QRCodeReaderBase.h"
#import <UIKit/UIKit.h>
@@ -109,19 +108,3 @@ void QRCodeReader::startReading() {
void QRCodeReader::stopReading() {
[m_qrCodeReader stopReading];
}
#else
#include "QRCodeReaderBase.h"
QRCodeReader::QRCodeReader()
{
}
QRect QRCodeReader::cameraSize() {
return QRect();
}
void QRCodeReader::startReading() {}
void QRCodeReader::stopReading() {}
void QRCodeReader::setCameraSize(QRect) {}
#endif

View File

@@ -1,6 +1,5 @@
#if !MACOS_NE
#import <UIKit/UIKit.h>
#endif
@interface QIOSApplicationDelegate
@end

View File

@@ -5,7 +5,7 @@
@implementation QIOSApplicationDelegate (AmneziaVPNDelegate)
#if !MACOS_NE
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
@@ -57,5 +57,5 @@
}
return NO;
}
#endif
@end

View File

@@ -1,13 +1,3 @@
#if MACOS_NE
public func toggleScreenshots(_ isEnabled: Bool) {
}
class ScreenProtection {
}
#else
import UIKit
public func toggleScreenshots(_ isEnabled: Bool) {
@@ -95,4 +85,3 @@ struct ProtectionPair {
textField.removeFromSuperview()
}
}
#endif

View File

@@ -27,7 +27,6 @@ const char* MessageKey::isOnDemand = "is-on-demand";
const char* MessageKey::SplitTunnelType = "SplitTunnelType";
const char* MessageKey::SplitTunnelSites = "SplitTunnelSites";
#if !MACOS_NE
static UIViewController* getViewController() {
NSArray *windows = [[UIApplication sharedApplication]windows];
for (UIWindow *window in windows) {
@@ -37,7 +36,6 @@ static UIViewController* getViewController() {
}
return nil;
}
#endif
Vpn::ConnectionState iosStatusToState(NEVPNStatus status) {
switch (status) {
@@ -791,14 +789,14 @@ bool IosController::shareText(const QStringList& filesToSend) {
NSURL *logFileUrl = [[NSURL alloc] initFileURLWithPath:filesToSend[i].toNSString()];
[sharingItems addObject:logFileUrl];
}
#if !MACOS_NE
UIViewController *qtController = getViewController();
if (!qtController) return;
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
#endif
__block bool isAccepted = false;
#if !MACOS_NE
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
isAccepted = completed;
emit finished();
@@ -810,7 +808,7 @@ bool IosController::shareText(const QStringList& filesToSend) {
popController.sourceView = qtController.view;
popController.sourceRect = CGRectMake(100, 100, 100, 100);
}
#endif
QEventLoop wait;
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
wait.exec();
@@ -819,7 +817,6 @@ bool IosController::shareText(const QStringList& filesToSend) {
}
QString IosController::openFile() {
#if !MACOS_NE
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeOpen];
DocumentPickerDelegate *documentPickerDelegate = [[DocumentPickerDelegate alloc] init];
@@ -829,9 +826,9 @@ QString IosController::openFile() {
if (!qtController) return;
[qtController presentViewController:documentPicker animated:YES completion:nil];
#endif
__block QString filePath;
#if !MACOS_NE
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
if (path) {
filePath = QString::fromUtf8(path.UTF8String);
@@ -840,7 +837,7 @@ QString IosController::openFile() {
}
emit finished();
};
#endif
QEventLoop wait;
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
wait.exec();
@@ -866,4 +863,3 @@ void IosController::requestInetAccess() {
}];
[task resume];
}

View File

@@ -1,11 +1,7 @@
#import <NetworkExtension/NetworkExtension.h>
#import <NetworkExtension/NETunnelProviderSession.h>
#import <Foundation/Foundation.h>
#if !MACOS_NE
#include <UIKit/UIKit.h>
#endif
#include <Security/Security.h>
class IosController;
@@ -21,10 +17,9 @@ class IosController;
@end
typedef void (^DocumentPickerClosedCallback)(NSString *path);
#if !MACOS_NE
@interface DocumentPickerDelegate : NSObject <UIDocumentPickerDelegate>
@property (nonatomic, copy) DocumentPickerClosedCallback documentPickerClosedCallback;
@end
#endif

View File

@@ -26,8 +26,7 @@
@end
#if !MACOS_NE
@implementation DocumentPickerDelegate
@implementation DocumentPickerDelegate
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
for (NSURL *url in urls) {
@@ -43,5 +42,4 @@
}
}
@end
#endif
@end

View File

@@ -6,8 +6,6 @@
#import <UserNotifications/UserNotifications.h>
#import <Foundation/Foundation.h>
#if !MACOS_NE
#import <UIKit/UIKit.h>
@interface IOSNotificationDelegate
@@ -89,86 +87,3 @@ void IOSNotificationHandler::notify(NotificationHandler::Message type, const QSt
}
}];
}
#else
// Removed the UIResponder and UIApplicationDelegate references as these are not available in macOS
@interface IOSNotificationDelegate
: NSObject <UNUserNotificationCenterDelegate> {
IOSNotificationHandler* m_iosNotificationHandler;
}
@end
@implementation IOSNotificationDelegate
- (id)initWithObject:(IOSNotificationHandler*)notification {
self = [super init]; // Removed `super init` as it refers to UIResponder, which is iOS specific
if (self) {
m_iosNotificationHandler = notification;
}
return self;
}
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
willPresentNotification:(UNNotification*)notification
withCompletionHandler:
(void (^)(UNNotificationPresentationOptions options))completionHandler {
Q_UNUSED(center)
completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
}
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
didReceiveNotificationResponse:(UNNotificationResponse*)response
withCompletionHandler:(void (^)())completionHandler {
Q_UNUSED(center)
Q_UNUSED(response)
completionHandler();
}
@end
IOSNotificationHandler::IOSNotificationHandler(QObject* parent) : NotificationHandler(parent) {
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert |
UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted, NSError* _Nullable error) {
Q_UNUSED(granted);
if (!error) {
m_delegate = [[IOSNotificationDelegate alloc] initWithObject:this];
}
}];
}
IOSNotificationHandler::~IOSNotificationHandler() { }
void IOSNotificationHandler::notify(NotificationHandler::Message type, const QString& title,
const QString& message, int timerMsec) {
Q_UNUSED(type);
if (!m_delegate) {
return;
}
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = title.toNSString();
content.body = message.toNSString();
content.sound = [UNNotificationSound defaultSound];
int timerSec = timerMsec / 1000;
UNTimeIntervalNotificationTrigger* trigger =
[UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timerSec repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"amneziavpn"
content:content
trigger:trigger];
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = (id<UNUserNotificationCenterDelegate>)m_delegate;
[center addNotificationRequest:request
withCompletionHandler:^(NSError* _Nullable error) {
if (error) {
NSLog(@"Local Notification failed");
}
}];
}
#endif

View File

@@ -196,6 +196,8 @@ QStringList LinuxFirewall::getDNSRules(const QStringList& servers)
result << QStringLiteral("-o amn0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun2+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server);
result << QStringLiteral("-o tun2+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server);
}
return result;
}
@@ -277,6 +279,7 @@ void LinuxFirewall::install()
installAnchor(Both, QStringLiteral("200.allowVPN"), {
QStringLiteral("-o amn0+ -j ACCEPT"),
QStringLiteral("-o tun0+ -j ACCEPT"),
QStringLiteral("-o tun2+ -j ACCEPT"),
});
installAnchor(IPv4, QStringLiteral("120.blockNets"), {});

View File

@@ -4,7 +4,7 @@
#include "core/errorstrings.h"
#include "vpnprotocol.h"
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
#include "openvpnovercloakprotocol.h"
#include "openvpnprotocol.h"
#include "shadowsocksvpnprotocol.h"
@@ -109,7 +109,7 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
#if defined(Q_OS_WINDOWS)
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
#endif
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
case DockerContainer::Cloak: return new OpenVpnOverCloakProtocol(configuration);
case DockerContainer::ShadowSocks: return new ShadowSocksVpnProtocol(configuration);

View File

@@ -89,60 +89,60 @@
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>اتصل</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>لم يتم تثبيت بروتوكولات VPN, من فضلك قم بتنزيل حاوية VPN اولاً</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>اتصال...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>تم الاتصال</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>إعادة الاتصال...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>إنهاء الاتصال...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>جاري التحضير...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>تم تحديث الاعدادات بنجاح, جاري إعادة الاتصال...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>تم تحديث الاعدادات بنجاح</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>البروتوكول المحدد غير مدعوم علي المنصة الحالية</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>غير قادر علي إنشاء تكوين</translation>
</message>
@@ -253,20 +253,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">غير قادر علي فتح الملف</translation>
<translation>غير قادر علي فتح الملف</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">ملف تكوين غير صحيح</translation>
<translation>ملف تكوين غير صحيح</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>تم فحص%1 من %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة:</translation>
</message>
@@ -274,24 +277,24 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 تم التثبيت بنجاح. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 بالفعل مٌثبت علي الخادم. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
تمت إضافة الحاويات التي كانت مٌثبتة بالفعل علي الخادم</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
@@ -299,62 +302,62 @@ Already installed containers were found on the server. All installed containers
تمت إضافة جميع الحاويات المٌثبتة إلي التطبيق</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>تم تحديث الاعدادات بنجاح</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation>تمت إعادة تشغيل الخادم%1</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation>تمت إزالة الخادم &apos;%1&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation>قد تم حذفها &apos;%1&apos; جميع الحاويات من الخادم</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 تم حدف &apos;%2&apos; اسم الخادم</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation>تم حذف تكوين Api</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>تم مسح ملف تعريف %1 المخزن مؤقتًا</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation>من فضلك قم بتسجيل الدخول كمستخدم</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>تمت إضافة الخادم بنجاح</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation>تم تحميل %1 بنجاح</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation>تمت إعادة تحميل تكوين API</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation>تم تغيير بلد الاتصال بنجاح إلى %1</translation>
</message>
@@ -398,28 +401,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>تم الاتصال</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>تم إنهاء الاتصال</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>إشعار من AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>تم العثور علي شبكة غير مؤمنة: </translation>
</message>
@@ -2315,107 +2318,97 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSetupWizardConfigSource</name>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation>الاتصال</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">إعدادات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished">علامة الدعم</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation>أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>أدخل مفتاح</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>أدخل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation>اختيارات اتصال اخري</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation>VPN بواسطة Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation>VPN ذاتية الاستضافة</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation>قم بتكوين Amnezia VPN على الخادم الخاص بك</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation>استرجاع من ملف يحتوي علي نسخة احتياطية</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation>افتح ملف نسخ احتياطي</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation>ملفات نٌسخ احتياطية (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>ملف إعدادات اتصال</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>افتح ملف تكوين</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>رمز QR</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>ليس لدي اي شئ</translation>
</message>
@@ -2433,12 +2426,12 @@ Already installed containers were found on the server. All installed containers
<translation>عنوان خادم IP [:منفذ]</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>ستظل جميع البيانات التي تدخلها سرية للغاية ولن تتم مشاركتها أو الكشف عنها ل Amnezia أو أي طرف ثالث</translation>
</message>
@@ -2448,42 +2441,42 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>كلمة مرور او مفتاح SSH خاص</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation>كيف تقوم بتشغيل خادم ال VPN الخاص بك</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>اين تحصل علي بيانات الاتصال, تعليمات خطوة ب خطوة لشراء VPS</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>لا يمكن لعنوان IP ان يكون فارغ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>ادخل العنوان في شكل 255.255.255.255:88</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>تسجيل دخول لا يمكن ان يكون فارغ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>كلمة مرور/مفتاح خاص لأ يمكن ان يكونو فارغين</translation>
</message>
@@ -2778,67 +2771,62 @@ Already installed containers were found on the server. All installed containers
<translation>ابحث</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>تاريخ الإنشاء: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation>اخر تصافح: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation>البيانات المستلمة: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation>البيانات المٌرسلة: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation>إعادة التسمية</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>اسم العميل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation>احفظ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>سحب وإبطال</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>سحب وإبطال للمستخدم - %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>المستخدم لن يكون قادر علي الاتصال بعد الان.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>إلغاء</translation>
</message>
@@ -2951,17 +2939,17 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>تم تعطيل التسجيل بعد 14 يومًا، وتم حذف ملفات السجل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation>تم تحميل الإعدادات من ملف نسخة احتياطية</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3300,22 +3288,22 @@ Already installed containers were found on the server. All installed containers
<translation>انتهت مدة الاتصال بالخادم</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation>خطأ عند استرداد التكوين من API</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation>هذا التكوين بالفعل تمت إضافتة للبرنامج</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation></translation>
</message>
@@ -3390,67 +3378,57 @@ Already installed containers were found on the server. All installed containers
<translation>التكوين لا يحتوي علي اي حاويات و اعتماد للأتصال بالخادم</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation>في الاستجابة من الخادم، تم تلقي تكوين فارغ</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation>حدث خطأ SSL</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation>انتهت مهلة استجابة الخادم عند طلب واجهة برمجة التطبيقات</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation>مفتاح AGW عام مفقود</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation>خطأ QFile: لا يمكن فتح الملف</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation>خطأ QFile: ظهر خطأ اثناء القراءه من الملف</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation>خطأ QFile: لا يمكن الوصول للملف</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation>خطأ QFile: ظهر خطأ غير محدد</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation>خطأ QFile: حدث خطأ فادح</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation>خطأ QFile: تم إحباط العملية</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>خطأ داخلي</translation>
</message>
@@ -4048,7 +4026,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>
@@ -4122,12 +4100,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>عبارة المرور الخاصة بالمفتاح</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation>احفظ</translation>
</message>

View File

@@ -88,63 +88,63 @@
<context>
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>پروتکل ویپیان نصب نشده است
لطفا کانتینر ویپیان را نصب کنید</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>در حال ارتباط...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>متصل</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>در حال آمادهسازی...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>تنظیمات به روز رسانی شد
در حال اتصال دوباره...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>تنظیمات با موفقیت بهروزرسانی شدند</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>پروتکل انتخابشده در پلتفرم فعلی پشتیبانی نمیشود.</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>نمیتوان پیکربندی را ایجاد کرد.</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>اتصال دوباره...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>اتصال</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>قطع ارتباط...</translation>
</message>
@@ -258,20 +258,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">نمیتوان فایل را باز کرد.</translation>
<translation>نمیتوان فایل را باز کرد.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">فایل پیکربندی نامعتبر است.</translation>
<translation>فایل پیکربندی نامعتبر است.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>ارزیابی %1 از %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند:</translation>
</message>
@@ -279,86 +282,86 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 با موفقیت نصب شد. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 در حال حاضر بر روی سرور نصب شده است. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
کانتینرهایی که بر روی سرور موجود بودند اضافه شدند</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
کانتینرهای نصب شده بر روی سرور شناسایی شدند. تمام کانتینترهای نصب شده به نرم افزار اضافه شدند</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>تنظیمات با موفقیت بهروزرسانی شدند</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation>سرور %1 راه اندازی مجدد شد</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation>سرور %1 حذف شد</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation>تمام کانتینترها از سرور %1 حذف شدند</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 از سرور %2 حذف شد</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation>پیکربندی API حذف شد.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>%1 پروفایل ذخیره شده پاک شد.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation>لطفا به عنوان کاربر وارد شوید</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>سرور با موفقیت اضافه شد</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation>%1 با موفقیت نصب شد.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation>پیکربندی API دوباره بارگذاری شد.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation>کشور اتصال با موفقیت به %1 تغییر یافت.</translation>
</message>
@@ -402,28 +405,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>ویپیان وصل شد</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>ویپیان قطع شد</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>اخطار AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>شبکه ناامن شناسایی شد: </translation>
</message>
@@ -2430,7 +2433,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">چی داری؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>فایل شامل تنظیمات اتصال</translation>
</message>
@@ -2439,102 +2442,92 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">فایل شامل تنظیمات اتصال یا بکآپ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation>ارتباط</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">تنظیمات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished">کپی شد</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation>کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>کلید را وارد کنید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>وارد کردن</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>ادامه دهید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation>گزینههای اتصال دیگر</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation>VPN توسط Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>اتصال به سرویسهای VPN کلاسیک پولی و رایگان از Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation>Self-hosted VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation>پیکربندی VPN Amnezia بر روی سرور خودتان</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation>بازیابی از پشتیبان</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation>باز کردن فایل پشتیبان</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation>Backup files (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>باز کردن فایل تنظیمات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-Code</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>من هیچی ندارم</translation>
</message>
@@ -2551,12 +2544,12 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>آدرس آیپی سرور (:پورت)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>ادامه</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>آدرس را با فرمت 255.255.255.255:88 وارد کنید</translation>
</message>
@@ -2571,42 +2564,42 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>رمز عبور یا کلید خصوصی SSH</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>تمام دادههایی که شما وارد میکنید به شدت محرمانه است و با Amnezia یا هر شخص ثالث دیگری به اشتراک گذاشته نمیشود</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation>چگونه سرور VPN خود را اجرا کنید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>دادههای اتصال را از کجا دریافت کنید و دستورالعملهای مرحله به مرحله برای خرید یک VPS</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>آدرس آیپی نمیتواند خالی باشد</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>نامکاربری نمیتواند خالی باشد</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>پسورد یا کلید خصوصی نمیتواند خالی باشد</translation>
</message>
@@ -2946,71 +2939,66 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>جستجو</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>تاریخ ایجاد: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation>آخرین ارتباط: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation>دادههای دریافت شده: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation>دادههای ارسال شده: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="vanished">تاریخ ایجاد: </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation>تغییر نام</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>نام کلاینت</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation>ذخیره</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>ابطال</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>لغو پیکربندی برای یک کاربر - %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>کاربر دیگر نمیتواند به سرور وصل شود.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>ادامه</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>کنسل</translation>
</message>
@@ -3097,17 +3085,17 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>ثبت وقایع پس از ۱۴ روز غیرفعال شد و فایلهای ثبت وقایع حذف شدند</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation>تنظیمات از فایل پشتیبان بازیابی شد</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3491,22 +3479,22 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>تنظیمات شامل هیچ کانتینر یا اعتبارنامهای برای اتصال به سرور نیست</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>خطای اتصال VPN</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation>خطا هنگام بازیابی پیکربندی از API</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation>این پیکربندی قبلاً به برنامه اضافه شده است</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>کد خطا: %1. </translation>
</message>
@@ -3576,67 +3564,57 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>VPN pool error: no available addresses</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation>در پاسخ از سرور، پیکربندی خالی دریافت شد</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation type="unfinished">SSL error occurred</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation>Server response timeout on api request</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>Internal error</translation>
</message>
@@ -4256,7 +4234,7 @@ For more detailed information, you can
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>
@@ -4338,12 +4316,12 @@ For more detailed information, you can
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>عبارت کلید خصوصی</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation>ذخیره</translation>
</message>

View File

@@ -89,61 +89,61 @@
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation> ि .
ि </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>ि ि </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation> ...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>ि ...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation> ...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>ि ...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>ि </translation>
</message>
@@ -254,20 +254,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished"> </translation>
<translation> </translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished"> ि </translation>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>%2 %1 ि .</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -275,86 +278,86 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 ि . </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 ि . </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
ि ि ि ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation> &apos;%1&apos; ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation> &apos;%1&apos; ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation> &apos;%1&apos; ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 &apos;%2&apos; ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>%1 </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -398,28 +401,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation></translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation></translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>AmneziaVPN ि</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>ि : </translation>
</message>
@@ -2379,107 +2382,97 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished"> ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished"> ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished"> (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation> ि</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished"> </translation>
</message>
@@ -2501,12 +2494,12 @@ Already installed containers were found on the server. All installed containers
<translation> [:]</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation> ि ि ि ि </translation>
</message>
@@ -2516,42 +2509,42 @@ Already installed containers were found on the server. All installed containers
<translation>255.255.255.255:22</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>SSH </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation> SSH ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation> 255.255.255.255:88 </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>/ि </translation>
</message>
@@ -2864,71 +2857,66 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>ि ि: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation> ि: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation> : %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation> : %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="vanished">ि िि: </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>ि ि ि ि - %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation> .</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation> </translation>
</message>
@@ -3046,17 +3034,17 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>14 ि ि , </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation type="unfinished"> ि ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3405,52 +3393,42 @@ Already installed containers were found on the server. All installed containers
<translation> </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>VPN ि</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation> ि ि</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation> ि ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>ErrorCode: %1. </translation>
</message>
@@ -3515,37 +3493,37 @@ Already installed containers were found on the server. All installed containers
<translation>ि ि ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation>Qफ़ ि: </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation>Qफ़ ि: ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation>Qफ़ ि: </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation>Qफ़ ि: िि ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation>Qफ़ ि: ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation>Qफ़ ि: ि ि </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>ि ि</translation>
</message>
@@ -4144,7 +4122,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>
@@ -4230,12 +4208,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation></translation>
</message>

View File

@@ -88,62 +88,62 @@
<context>
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>VPN ကက
က VPN ကက </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>က...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>ကက က...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>ကက </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation> ကက ကက က</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>configuration </translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>က...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>က...</translation>
</message>
@@ -254,20 +254,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">က</translation>
<translation>က</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">Configuration က</translation>
<translation>Configuration က</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>%2 %1 က က.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation> configuration က :</translation>
</message>
@@ -275,86 +278,86 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 က . </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 က . </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
ကက </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
ကက ကက က </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>ကက </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation> &apos;%1&apos; က </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation> &apos;%1&apos; က </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation> &apos;%1&apos; ကက က</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 က &apos;%2&apos; က</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation>Api config ကက</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>ကက %1 က </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation> log in က</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>က </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation>%1 က .</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation>API config က က</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation>ကက %1 က</translation>
</message>
@@ -398,28 +401,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>VPN က</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>VPN က</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>AmneziaVPN </translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>ကက က: </translation>
</message>
@@ -2324,107 +2327,97 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSetupWizardConfigSource</name>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished">က tag</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished">က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation>Key က က QR-ကက က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Key က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation>Amnezia VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>Amnezia VPN က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation>က host VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation>Amnezia VPN က က </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation>က </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation> (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>config က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>က</translation>
</message>
@@ -2437,12 +2430,12 @@ Already installed containers were found on the server. All installed containers
<translation> IP [:port]</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>က 255.255.255.255:88 </translation>
</message>
@@ -2457,42 +2450,42 @@ Already installed containers were found on the server. All installed containers
<translation>255.255.255.255:22</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>SSH </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>ကက SSH private key</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>က ကက Amnezia က </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation>က </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>ကက VPS က ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>IP </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>ကက </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>ကက/private key </translation>
</message>
@@ -2812,67 +2805,62 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>က: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation>က handshake : %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation>က: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation>က: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation> %1 က config က ?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation> က.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>က</translation>
</message>
@@ -2959,17 +2947,17 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation> ကက Logging က က ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation>ကက </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3301,17 +3289,17 @@ Already installed containers were found on the server. All installed containers
<translation>Config ကက က က </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation>API က </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation> config က က </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>က: %1. </translation>
</message>
@@ -3381,72 +3369,62 @@ Already installed containers were found on the server. All installed containers
<translation>VPN pool မှု: ရရှိနိုင်သ</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>VPN က</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation> config က က</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation>SSL </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation>Api က</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation>AGW public key က</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation>QFile မှု: ဖိုင်ကို </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation>QFile မှု: ဖိုင်ကိုဖတ်န </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation>QFile မှု: ဖိုင်ကို </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation>QFile မှု: သတ်မှတ်မထ </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation>QFile မှု: က </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation>QFile မှု: လုပ်ငန်က ကက</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>က </translation>
</message>
@@ -4053,7 +4031,7 @@ For more detailed information, you can
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>
@@ -4127,12 +4105,12 @@ For more detailed information, you can
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>က key ကက</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation></translation>
</message>

View File

@@ -88,62 +88,62 @@
<context>
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>VPN-протоколы не установлены.
Пожалуйста, установите протокол</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>Подключение...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>Подключено</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>Подготовка...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>Настройки успешно обновлены, переподключение...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>Настройки успешно обновлены</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>Выбранный протокол не поддерживается на данном устройстве</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>не удалось создать конфигурацию</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>Переподключение...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>Подключиться</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>Отключение...</translation>
</message>
@@ -258,20 +258,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">Невозможно открыть файл</translation>
<translation>Невозможно открыть файл</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">Неверный файл конфигурации</translation>
<translation>Неверный файл конфигурации</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>Отсканировано %1 из %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
</message>
@@ -279,86 +282,86 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 успешно установлен. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 уже установлен на сервер. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
Добавлены сервисы и протоколы, которые были ранее установлены на сервер</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
На сервере обнаружены установленные протоколы и сервисы. Все они были добавлены в приложение</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>Настройки успешно обновлены</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation>Сервер &apos;%1&apos; был перезагружен</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation>Сервер &apos;%1&apos; был удален</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation>Все протоколы и сервисы были удалены с сервера &apos;%1&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 был удален с сервера &apos;%2&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation>Конфигурация API удалена</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>%1 закэшированный профиль очищен</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation>Пожалуйста, войдите в систему от имени пользователя</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>Сервер успешно добавлен</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation>%1 успешно установлен.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation>Конфигурация API перезагружена</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation>Изменение страны подключения на %1</translation>
</message>
@@ -402,28 +405,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>VPN подключен</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>VPN выключен</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>Уведомление AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>Обнаружена незащищенная сеть: </translation>
</message>
@@ -2502,7 +2505,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Что у вас есть?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>Файл с настройками подключения</translation>
</message>
@@ -2511,102 +2514,92 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Файл с настройками подключения или резервной копией</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation>Соединение</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">Настройки</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished">Скопировано</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation>Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Вставьте ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>Вставить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation>Другие варианты подключения</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation>VPN от Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation>Self-hosted VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation>Настроить VPN на собственном сервере</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation>Восстановить из резервной копии</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation>Открыть резервную копию</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation>Файлы резервных копий (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>Открыть файл с конфигурацией</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>У меня ничего нет</translation>
</message>
@@ -2635,7 +2628,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Password / SSH private key</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
@@ -2645,7 +2638,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation type="vanished">Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>Введите адрес в формате 255.255.255.255:88</translation>
</message>
@@ -2664,42 +2657,42 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>255.255.255.255:22</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>Имя пользователя SSH</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>Пароль или закрытый ключ SSH</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation>Как создать VPN на собственном сервере</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>Где взять данные для подключения, пошаговые инстуркции по покупке VPS</translation>
<translation>Где взять данные для подключения, пошаговые инструкции по покупке VPS</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>Поле с IP-адресом не может быть пустым</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>Поле с логином не может быть пустым</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>Поле с паролем/закрытым ключом не может быть пустым</translation>
</message>
@@ -3075,71 +3068,66 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Поиск</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>Дата создания: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation>Последнее рукопожатие: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation>Получено данных: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation>Отправлено данных: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="vanished">Дата создания: </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation>Переименовать</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>Имя клиента</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation>Сохранить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>Отозвать</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>Отозвать конфигурацию для пользователя - %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>Пользователь больше не сможет подключаться к вашему серверу.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>Отменить</translation>
</message>
@@ -3230,17 +3218,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>Логирование было отключено по прошествии 14 дней, файлы логов были удалены.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation>Настройки восстановлены из бэкап файла</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3637,17 +3625,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Конфигурация не содержит каких-либо контейнеров и учетных данных для подключения к серверу</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation>Ошибка при получении конфигурации из API</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation>Данная конфигурация уже была добавлена в приложение</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>Код ошибки: %1. </translation>
</message>
@@ -3706,72 +3694,62 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Ошибка пула VPN: нет доступных адресов</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>Ошибка VPN-соединения</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation>В ответе от сервера была получена пустая конфигурация</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation>Произошла ошибка SSL</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation>Тайм-аут ответа сервера на запрос API</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation>Ошибка QFile: не удалось открыть файл</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation>Ошибка QFile: произошла ошибка при чтении из файла</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation>Ошибка QFile: не удалось получить доступ к файлу</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation>Ошибка QFile: произошла неизвестная ошибка</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation>Ошибка QFile: произошла фатальная ошибка</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation>Ошибка QFile: операция была прервана</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>Внутренняя ошибка</translation>
</message>
@@ -4471,7 +4449,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Мбит/с</translation>
</message>
@@ -4569,12 +4547,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>Парольная фраза для закрытого ключа</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation>Сохранить</translation>
</message>

View File

@@ -111,62 +111,62 @@
<context>
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>VPN протоколи не встановлено.
Будь-ласка, встановіть VPN контейнер</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>Неможливо створити конфігурацію</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>Підключення...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>Підключено</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>Підготовка...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>Налаштування оновлено, підключення...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>Налаштування оновлено</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>Вибраний протокол не підтримується на цьому пристрої</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>Перепідключення...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>Підключитись</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>Відключаємось...</translation>
</message>
@@ -285,20 +285,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">Неможливо відкрити файл</translation>
<translation>Неможливо відкрити файл</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">Недійсний файл конфігурації</translation>
<translation>Недійсний файл конфігурації</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>Відскановано %1 з %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>У імпортованій конфігурації знайдено потенційно небезпечні рядки:</translation>
</message>
@@ -306,85 +309,85 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 встановлено. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 вже встановлено на сервері. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>Додані сервіси і протоколи, які були раніше встановлені на сервері</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
На сервері знайдені сервіси та протоколи, всі вони додані в застосунок</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>Налаштування оновлено</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation>Сервер &apos;%1&apos; перезавантажено</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation>Сервер &apos;%1&apos; був видалений</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation>Всі сервіси та протоколи були видалені з сервера &apos;%1&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 був видалений з сервера &apos;%2&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation>Конфігурацію API видалено</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>Кешований профіль %1 очищено</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation>Буль-ласка, увійдіть в систему від імені користувача</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>Сервер додано</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation>%1 встановлено успішно.</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation>Конфігурацію API перезавантажено</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation>Успішно змінено країну підключення на %1</translation>
</message>
@@ -428,28 +431,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>VPN Підключено</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>VPN Вимкнено</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>Сповіщення AmneziaVPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>Знайдена не захищена мережа: </translation>
</message>
@@ -2588,7 +2591,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Виберіть що у вас є</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>Файл з налаштуваннями підключення</translation>
</message>
@@ -2597,102 +2600,92 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Файл з налаштуваннями підключення або бекап</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation>Підключення</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">Налаштування</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished">Скопійовано</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation>Вставте ключ, додайте файл конфігурації або відскануйте QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Вставити ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>Вставити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation>Інші параметри підключення</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation>VPN від Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation>Self-hosted VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation>Налаштуйте Amnezia VPN на власному сервері</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation>Відновити із бекапа</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation>Відкрити бекап файл</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation>Файли резервної копії (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>Відкрити файл з конфігурацією</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>У мене нічого нема</translation>
</message>
@@ -2721,7 +2714,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Password / SSH private key</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
@@ -2732,7 +2725,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
і не будуть передані чи розголошені Amnezia або будь-яким третім особам</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>Введіть адресу в форматі 255.255.255.255:88</translation>
</message>
@@ -2751,42 +2744,42 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>255.255.255.255:22</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>SSH Username</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>Пароль або SSH ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Усі дані, які ви вводите, залишатимуться суворо конфіденційними та не будуть передані чи розголошені Amnezia або будь-яким третім особам</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation>Як запустити ваш VPN-сервер</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>Де отримати дані для підключення: покрокові інструкції з придбання VPS</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>Поле IP address не може бути пустим</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>Поле Login не може бути пустим</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>Поле Password/Private key не може бути пустим</translation>
</message>
@@ -3170,71 +3163,66 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Пошук</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation>Дата створення: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation>Останнє з&apos;єднання: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation>Отримано даних: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation>Відправлено даних: %1</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="obsolete">Дата створення:</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation>Перейменувати</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>Назва клієнта</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation>Зберегти</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>Відкликати</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>Відкликати доступ для користувача - %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>Користувач більше не зможе підключатись до вашого сервера </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>Відмінити</translation>
</message>
@@ -3324,17 +3312,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>Логування було вимкнене через 14 днів, файли журналів були видалені</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation>Відновлення налаштувань із бекап файлу</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3733,17 +3721,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation type="unfinished">Конфігурація не містить контейнерів і облікових даних для підключення до серверу</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation>Ця конфігурація вже була додана в застосунок</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation type="unfinished"></translation>
</message>
@@ -3802,72 +3790,62 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>VPN pool error: no available addresses</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>Internal error</translation>
</message>
@@ -4548,7 +4526,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>
@@ -4646,12 +4624,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>Пароль для особистого ключа</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation>Зберегти</translation>
</message>

View File

@@ -89,60 +89,60 @@
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation>جوڑنا</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation>منتخب کردہ پروٹوکول موجودہ پلیٹ فارم پر تعاون یافتہ نہیں ہے</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>وی پی این پروٹوکول انسٹال نہیں ہے,براہ کرم پہلےوی پی این کنٹینر انسٹال کریں</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation>تشکیل تیار کرنے میں ناکام</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation>جوڑاجارھاھے....</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation>جوڑاجارھاھے</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation>دوبارہ جوڑنےکی کوشش...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation>منقطع کرنا...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation>تیاری کیا جا رہا ہے...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>ترتیب ک ھوگی،دوبارہ جوڑنےکی کوشش...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation>دوبارہ ترتیب تاذہ کامیاب</translation>
</message>
@@ -252,20 +252,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="vanished">فائل کو کھولنے سے قاصر ہے</translation>
<translation>فائل کو کھولنے سے قاصر ہے</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="vanished">غلط کنفیگریشن فائل</translation>
<translation>غلط کنفیگریشن فائل</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>سکین%1 کی%2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -273,86 +276,86 @@ Can&apos;t be disabled for current server</source>
<context>
<name>InstallController</name>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 کامیابی سےنصب. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation>%1 پہلے ہی سرور پر انسٹال ہے. </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation>
وہ کنٹینرز شامل کیے گئے جو پہلے سے سرور پر نصب تھے</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
سرور پر پہلے سے نصب کنٹینرز پائے گئے۔ تمام نصب کنٹینرز کو ایپلی کیشن میں شامل کر دیا گیا ہے</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation>ترتیب کامیابی کے ساتھ اپ ڈیٹ ہو گئی</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation>سرور %1 دوبارہ چالو کیا گیا تھا</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation>سرور %1 ہٹا دیا گیا تھا</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation>سرور &apos;%1&apos; سے تمام کنٹینرز ہٹا دیے گئے ہیں</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>سرور &apos;%2&apos; سے %1 ہٹا دیا گیا ہے</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation>%1 کیش کردہ پروفائل ختم کر دی گئی</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation>براہ کرم صارف کے طور پر لاگ ان کریں</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation>سرور کامیابی سے شامل کیا گیا</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -396,30 +399,30 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation>The translation of &quot;AmneziaVPN&quot; in Urdu would be:
امنیزیا وی پی ای</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>وی پی این متصل ہوگیا</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>وی پی این منقطع ہوگیا</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>امنیزیا وی پی این کی اطلاعات</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation>غیر محفوظ نیٹ ورک کا پتہ لگایا گیا ہے: </translation>
</message>
@@ -2383,107 +2386,97 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">کنکشن کی ترتیبات یا بیک اپ والی فائل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation type="unfinished">کنکشن</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished">ترتیبات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished">داخل کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished">بیک اپ سے بحال کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished">بیک اپ فائل کو کھولیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished">بیک اپ فائلیں (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>کنکشن کی ترتیبات والی فائل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>کنفیگ فائل کو کھولیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR کوڈ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished">میرے پاس کچھ نہیں ہے</translation>
</message>
@@ -2505,12 +2498,12 @@ Already installed containers were found on the server. All installed containers
<translation>سرور آئی پی پتہ [:پورٹ]</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation>براہ کرم جاری رکھیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>آپ جو ڈیٹا داخل کریں گے وہ بالکل خفیہ رہے گا اور نہ تو امنیزیا یا کسی تیسری شخصیت کے ساتھ اشتراک کیا جائے گا</translation>
</message>
@@ -2520,42 +2513,42 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>ایس ایس ایچ صارف نام</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation>پاس ورڈ یا SSH نجی کلید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>آئی پی پتہ خالی نہیں ہو سکتا</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation>ایڈریس درج کریں فارمیٹ 255.255.255.255:88</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation>لاگ ان نام خالی نہیں ہو سکتا</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation>پاس ورڈ یا نجی کلید خالی نہیں ہو سکتی</translation>
</message>
@@ -2868,71 +2861,66 @@ Already installed containers were found on the server. All installed containers
<translation>تلاش</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="vanished">تخلیق کی تاریخ: </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation>نام تبدیل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation>کلائنٹ کا نام</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation>محفوظ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation>واپس لین</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>کیا آپ مستعمل کے لئے کنفیگ کو واپس لینا چاہتے ہیں - %1؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>صارف آپ کے سرور سے متصل ہونے کا اختیار نہیں رہے گا.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>جاری رکھیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation>منسوخ</translation>
</message>
@@ -3050,17 +3038,17 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation>لاگنگ کو 14 دنوں کے بعد غیر فعال کر دیا گیا، لاگ فائلوں کو حذف کر دیا گیا</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation type="unfinished">ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3399,22 +3387,22 @@ Already installed containers were found on the server. All installed containers
<translation>سرور سے منسلک ہونے کا ٹائم آؤٹ</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>VPN کنکشن کی خرابی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation>آپی سے کنفیگریشن بازیافت کرتے وقت خرابی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation>یہ تشکیل پہلے ہی ایپلی کیشن میں شامل کی جا چکی ہے</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>ایرر کوڈ: %1. </translation>
</message>
@@ -3489,67 +3477,57 @@ Already installed containers were found on the server. All installed containers
<translation>ترتیب میں سرور سے منسلک ہونے کے لیے کوئی کنٹینرز اور اسناد نہیں ہیں</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation>QFile کی خرابی: فائل کو نہیں کھولا جا سکا</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation>کیو فائل کی خرابی: فائل سے پڑھتے وقت ایک خرابی پیش آگئی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation>QFile کی خرابی: فائل تک رسائی نہیں ہو سکی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation>کیو فائل میں خرابی: ایک غیر متعینہ خرابی پیش آگئی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation>کیو فائل میں خرابی: ایک مہلک خرابی پیش آگئی</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation>کیو فائل کی خرابی: آپریشن روک دیا گیا تھا</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation>داخلی خامی</translation>
</message>
@@ -4090,7 +4068,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>ایم بی پی ایس</translation>
</message>
@@ -4176,12 +4154,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation>نجی کلید پاس فریز</translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation>محفوظ کریں</translation>
</message>

View File

@@ -89,60 +89,60 @@
<name>ConnectionController</name>
<message>
<location filename="../ui/controllers/connectionController.h" line="80"/>
<location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="124"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/>
<source>Connect</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="217"/>
<location filename="../ui/controllers/connectionController.cpp" line="214"/>
<source>VPN Protocols is not installed.
Please install VPN container at first</source>
<translation>VPN协议</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="84"/>
<location filename="../ui/controllers/connectionController.cpp" line="81"/>
<source>Connecting...</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="89"/>
<location filename="../ui/controllers/connectionController.cpp" line="86"/>
<source>Connected</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="98"/>
<location filename="../ui/controllers/connectionController.cpp" line="95"/>
<source>Reconnecting...</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="108"/>
<location filename="../ui/controllers/connectionController.cpp" line="105"/>
<source>Disconnecting...</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="113"/>
<location filename="../ui/controllers/connectionController.cpp" line="110"/>
<source>Preparing...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<location filename="../ui/controllers/connectionController.cpp" line="132"/>
<source>Settings updated successfully, reconnnection...</source>
<translation>, ...</translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="138"/>
<location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="212"/>
<location filename="../ui/controllers/connectionController.cpp" line="209"/>
<source>The selected protocol is not supported on the current platform</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/connectionController.cpp" line="236"/>
<location filename="../ui/controllers/connectionController.cpp" line="233"/>
<source>unable to create configuration</source>
<translation type="unfinished"></translation>
</message>
@@ -257,12 +257,23 @@ Can&apos;t be disabled for current server</source>
<context>
<name>ImportController</name>
<message>
<location filename="../ui/controllers/importController.cpp" line="623"/>
<location filename="../ui/controllers/importController.cpp" line="87"/>
<source>Unable to open file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation> %1 of %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="658"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -278,75 +289,75 @@ Can&apos;t be disabled for current server</source>
<translation type="obsolete"> </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="157"/>
<location filename="../ui/controllers/installController.cpp" line="181"/>
<source>%1 installed successfully. </source>
<translation>%1 </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="159"/>
<location filename="../ui/controllers/installController.cpp" line="183"/>
<source>%1 is already installed on the server. </source>
<translation> %1</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="179"/>
<location filename="../ui/controllers/installController.cpp" line="203"/>
<source>
Added containers that were already installed on the server</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="259"/>
<location filename="../ui/controllers/installController.cpp" line="283"/>
<source>
Already installed containers were found on the server. All installed containers have been added to the application</source>
<translation>
</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="517"/>
<location filename="../ui/controllers/installController.cpp" line="541"/>
<source>Settings updated successfully</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="534"/>
<location filename="../ui/controllers/installController.cpp" line="558"/>
<source>Server &apos;%1&apos; was rebooted</source>
<translation> &apos;%1&apos; </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="546"/>
<location filename="../ui/controllers/installController.cpp" line="570"/>
<source>Server &apos;%1&apos; was removed</source>
<translation> &apos;%1&apos;</translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="557"/>
<location filename="../ui/controllers/installController.cpp" line="581"/>
<source>All containers from server &apos;%1&apos; have been removed</source>
<translation> &apos;%1&apos; </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="575"/>
<location filename="../ui/controllers/installController.cpp" line="599"/>
<source>%1 has been removed from the server &apos;%2&apos;</source>
<translation>%1 &apos;%2&apos; </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="584"/>
<location filename="../ui/controllers/installController.cpp" line="608"/>
<source>Api config removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="606"/>
<location filename="../ui/controllers/installController.cpp" line="630"/>
<source>%1 cached profile cleared</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="821"/>
<location filename="../ui/controllers/installController.cpp" line="845"/>
<source>%1 installed successfully.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="855"/>
<location filename="../ui/controllers/installController.cpp" line="877"/>
<source>API config reloaded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="859"/>
<location filename="../ui/controllers/installController.cpp" line="881"/>
<source>Successfully changed the country of connection to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -367,12 +378,12 @@ Already installed containers were found on the server. All installed containers
<translation type="obsolete"> </translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="745"/>
<location filename="../ui/controllers/installController.cpp" line="769"/>
<source>Please login as the user</source>
<translation></translation>
</message>
<message>
<location filename="../ui/controllers/installController.cpp" line="773"/>
<location filename="../ui/controllers/installController.cpp" line="797"/>
<source>Server added successfully</source>
<translation></translation>
</message>
@@ -416,28 +427,28 @@ Already installed containers were found on the server. All installed containers
<context>
<name>NotificationHandler</name>
<message>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<location filename="../ui/notificationhandler.cpp" line="63"/>
<location filename="../ui/notificationhandler.cpp" line="70"/>
<source>AmneziaVPN</source>
<translation></translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="65"/>
<location filename="../ui/notificationhandler.cpp" line="64"/>
<source>VPN Connected</source>
<translation>VPN</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="72"/>
<location filename="../ui/notificationhandler.cpp" line="71"/>
<source>VPN Disconnected</source>
<translation>VPN断开</translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<location filename="../ui/notificationhandler.cpp" line="94"/>
<source>AmneziaVPN notification</source>
<translation>AmneziaVPN </translation>
</message>
<message>
<location filename="../ui/notificationhandler.cpp" line="96"/>
<location filename="../ui/notificationhandler.cpp" line="95"/>
<source>Unsecured network detected: </source>
<translation></translation>
</message>
@@ -2538,107 +2549,97 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="59"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="57"/>
<source>Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="86"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="83"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="91"/>
<source>Enable logs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
<source>Support tag</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Copied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="140"/>
<source>Insert the key, add a configuration file or scan the QR-code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="171"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="200"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="201"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="245"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="251"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="252"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="269"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="296"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="319"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished"></translation>
</message>
@@ -2672,12 +2673,12 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="113"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="116"/>
<source>Continue</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation> Amnezia </translation>
</message>
@@ -2693,42 +2694,42 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="75"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="78"/>
<source>SSH Username</source>
<translation>SSH </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="91"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<source>Password or SSH private key</source>
<translation> SSH </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="150"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="153"/>
<source>How to run your VPN server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="151"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<source>Ip address cannot be empty</source>
<translation>IP不能为空</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="173"/>
<source>Enter the address in the format 255.255.255.255:88</source>
<translation> 255.255.255.255:88</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="177"/>
<source>Login cannot be empty</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="181"/>
<source>Password/private key cannot be empty</source>
<translation></translation>
</message>
@@ -3066,71 +3067,66 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="814"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="817"/>
<source>Creation date: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="822"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="825"/>
<source>Latest handshake: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="830"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="833"/>
<source>Data received: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="838"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="841"/>
<source>Data sent: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="846"/>
<source>Allowed IPs: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Creation date: </source>
<translation type="vanished">: </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="866"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="862"/>
<source>Rename</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="912"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="908"/>
<source>Client name</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="925"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="921"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="955"/>
<source>Revoke</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="964"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="959"/>
<source>Revoke the config for a user - %1?</source>
<translation>- %1?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="965"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="960"/>
<source>The user will no longer be able to connect to your server.</source>
<translation>.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="966"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="967"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="962"/>
<source>Cancel</source>
<translation></translation>
</message>
@@ -3287,17 +3283,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<context>
<name>PageStart</name>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="198"/>
<source>Logging was disabled after 14 days, log files were deleted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="202"/>
<source>Settings restored from backup file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageStart.qml" line="212"/>
<location filename="../ui/qml/Pages2/PageStart.qml" line="208"/>
<source>Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.</source>
<translation type="unfinished"></translation>
</message>
@@ -3650,11 +3646,6 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<source>SCP error: Generic failure</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="53"/>
<source>Unable to open config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Sftp error: End-of-file encountered</source>
<translation type="vanished">Sftp错误: End-of-file encountered</translation>
@@ -3708,77 +3699,72 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation type="vanished">Sftp 错误: 远程驱动器中没有媒介</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="56"/>
<location filename="../core/errorstrings.cpp" line="55"/>
<source>VPN connection error</source>
<translation>VPN </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="59"/>
<location filename="../core/errorstrings.cpp" line="58"/>
<source>Error when retrieving configuration from API</source>
<translation> API </translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="60"/>
<location filename="../core/errorstrings.cpp" line="59"/>
<source>This config has already been added to the application</source>
<translation></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="61"/>
<location filename="../core/errorstrings.cpp" line="60"/>
<source>In the response from the server, an empty config was received</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="62"/>
<location filename="../core/errorstrings.cpp" line="61"/>
<source>SSL error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="63"/>
<location filename="../core/errorstrings.cpp" line="62"/>
<source>Server response timeout on api request</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="64"/>
<location filename="../core/errorstrings.cpp" line="63"/>
<source>Missing AGW public key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="65"/>
<source>Failed to decrypt response payload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="68"/>
<location filename="../core/errorstrings.cpp" line="66"/>
<source>QFile error: The file could not be opened</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="69"/>
<location filename="../core/errorstrings.cpp" line="67"/>
<source>QFile error: An error occurred when reading from the file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="70"/>
<location filename="../core/errorstrings.cpp" line="68"/>
<source>QFile error: The file could not be accessed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="71"/>
<location filename="../core/errorstrings.cpp" line="69"/>
<source>QFile error: An unspecified error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="72"/>
<location filename="../core/errorstrings.cpp" line="70"/>
<source>QFile error: A fatal error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="73"/>
<location filename="../core/errorstrings.cpp" line="71"/>
<source>QFile error: The operation was aborted</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="80"/>
<location filename="../core/errorstrings.cpp" line="78"/>
<source>ErrorCode: %1. </source>
<translation>: %1. </translation>
</message>
@@ -3846,7 +3832,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="77"/>
<location filename="../core/errorstrings.cpp" line="75"/>
<source>Internal error</source>
<translation></translation>
</message>
@@ -4526,7 +4512,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="409"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>
@@ -4624,12 +4610,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>main2</name>
<message>
<location filename="../ui/qml/main2.qml" line="163"/>
<location filename="../ui/qml/main2.qml" line="162"/>
<source>Private key passphrase</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/main2.qml" line="186"/>
<location filename="../ui/qml/main2.qml" line="185"/>
<source>Save</source>
<translation></translation>
</message>

View File

@@ -55,7 +55,7 @@ void ConnectionController::openConnection()
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
emit updateApiConfigFromGateway();
} else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
qDebug() << "attempt to update api config by end_date event";
qDebug() << "attempt to update api config by expires_at event";
if (configVersion == ApiConfigSources::Telegram) {
emit updateApiConfigFromTelegram();
} else {

View File

@@ -121,9 +121,8 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container
jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg) {
auto clientId = jsonNativeConfig.value(config_key::clientId).toString();
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials, serverController);
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
errorCode = m_clientManagementModel->appendClient(jsonNativeConfig, clientName, container, credentials, serverController);
}
return errorCode;
}
@@ -248,10 +247,10 @@ void ExportController::generateCloakConfig()
emit exportConfigChanged();
}
void ExportController::generateXrayConfig()
void ExportController::generateXrayConfig(const QString &clientName)
{
QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, clientName, Proto::Xray, nativeConfig);
if (errorCode) {
emit exportErrorOccurred(errorCode);
return;

View File

@@ -28,7 +28,7 @@ public slots:
void generateAwgConfig(const QString &clientName);
void generateShadowSocksConfig();
void generateCloakConfig();
void generateXrayConfig();
void generateXrayConfig(const QString &clientName);
QString getConfig();
QString getNativeConfigString();

View File

@@ -848,7 +848,6 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
newServerConfig.insert(configKey::apiConfig, newApiConfig);
newServerConfig.insert(configKey::authData, authData);
newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
m_serversModel->editServer(newServerConfig, serverIndex);
if (reloadServiceConfig) {

View File

@@ -24,7 +24,7 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor);
#endif
#if defined Q_OS_MACX and !defined MACOS_NE
#if defined Q_OS_MACX
connect(this, &PageController::raiseMainWindow, []() { setDockIconVisible(true); });
connect(this, &PageController::hideMainWindow, []() { setDockIconVisible(false); });
#endif
@@ -114,7 +114,7 @@ void PageController::showOnStartup()
} else {
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
emit hideMainWindow();
#elif defined Q_OS_MACX and !defined MACOS_NE
#elif defined Q_OS_MACX
setDockIconVisible(false);
#endif
}

View File

@@ -27,6 +27,9 @@ namespace
constexpr char storeEndpoint[] = "store_endpoint";
constexpr char isAvailable[] = "is_available";
constexpr char subscription[] = "subscription";
constexpr char endDate[] = "end_date";
}
namespace serviceType
@@ -51,23 +54,23 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
return QVariant();
QJsonObject service = m_services.at(index.row()).toObject();
QJsonObject serviceInfo = service.value(configKey::serviceInfo).toObject();
auto serviceType = service.value(configKey::serviceType).toString();
auto apiServiceData = m_services.at(index.row());
auto serviceType = apiServiceData.type;
auto isServiceAvailable = apiServiceData.isServiceAvailable;
switch (role) {
case NameRole: {
return serviceInfo.value(configKey::name).toString();
return apiServiceData.serviceInfo.name;
}
case CardDescriptionRole: {
auto speed = serviceInfo.value(configKey::speed).toString();
auto speed = apiServiceData.serviceInfo.speed;
if (serviceType == serviceType::amneziaPremium) {
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
"Works for any sites. Speed up to %1 MBit/s")
.arg(speed);
} else if (serviceType == serviceType::amneziaFree){
QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
if (isServiceAvailable) {
description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a>");
}
return description;
@@ -83,25 +86,24 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
}
case IsServiceAvailableRole: {
if (serviceType == serviceType::amneziaFree) {
if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
if (isServiceAvailable) {
return false;
}
}
return true;
}
case SpeedRole: {
auto speed = serviceInfo.value(configKey::speed).toString();
return tr("%1 MBit/s").arg(speed);
return tr("%1 MBit/s").arg(apiServiceData.serviceInfo.speed);
}
case WorkPeriodRole: {
auto timelimit = serviceInfo.value(configKey::timelimit).toString();
if (timelimit == "0") {
case TimeLimitRole: {
auto timeLimit = apiServiceData.serviceInfo.timeLimit;
if (timeLimit == "0") {
return "";
}
return tr("%1 days").arg(timelimit);
return tr("%1 days").arg(timeLimit);
}
case RegionRole: {
return serviceInfo.value(configKey::region).toString();
return apiServiceData.serviceInfo.region;
}
case FeaturesRole: {
if (serviceType == serviceType::amneziaPremium) {
@@ -113,12 +115,15 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
}
}
case PriceRole: {
auto price = serviceInfo.value(configKey::price).toString();
auto price = apiServiceData.serviceInfo.price;
if (price == "free") {
return tr("Free");
}
return tr("%1 $/month").arg(price);
}
case EndDateRole: {
return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
}
}
return QVariant();
@@ -128,15 +133,18 @@ void ApiServicesModel::updateModel(const QJsonObject &data)
{
beginResetModel();
m_countryCode = data.value(configKey::userCountryCode).toString();
m_services = data.value(configKey::services).toArray();
if (m_services.isEmpty()) {
QJsonObject service;
service.insert(configKey::serviceInfo, data.value(configKey::serviceInfo));
service.insert(configKey::serviceType, data.value(configKey::serviceType));
m_services.clear();
m_services.push_back(service);
m_countryCode = data.value(configKey::userCountryCode).toString();
auto services = data.value(configKey::services).toArray();
if (services.isEmpty()) {
m_services.push_back(getApiServicesData(data));
m_selectedServiceIndex = 0;
} else {
for (const auto &service : services) {
m_services.push_back(getApiServicesData(service.toObject()));
}
}
endResetModel();
@@ -149,32 +157,32 @@ void ApiServicesModel::setServiceIndex(const int index)
QJsonObject ApiServicesModel::getSelectedServiceInfo()
{
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
return service.value(configKey::serviceInfo).toObject();
auto service = m_services.at(m_selectedServiceIndex);
return service.serviceInfo.object;
}
QString ApiServicesModel::getSelectedServiceType()
{
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
return service.value(configKey::serviceType).toString();
auto service = m_services.at(m_selectedServiceIndex);
return service.type;
}
QString ApiServicesModel::getSelectedServiceProtocol()
{
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
return service.value(configKey::serviceProtocol).toString();
auto service = m_services.at(m_selectedServiceIndex);
return service.protocol;
}
QString ApiServicesModel::getSelectedServiceName()
{
auto modelIndex = index(m_selectedServiceIndex, 0);
return data(modelIndex, ApiServicesModel::Roles::NameRole).toString();
auto service = m_services.at(m_selectedServiceIndex);
return service.serviceInfo.name;
}
QJsonArray ApiServicesModel::getSelectedServiceCountries()
{
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
return service.value(configKey::availableCountries).toArray();
auto service = m_services.at(m_selectedServiceIndex);
return service.availableCountries;
}
QString ApiServicesModel::getCountryCode()
@@ -184,8 +192,8 @@ QString ApiServicesModel::getCountryCode()
QString ApiServicesModel::getStoreEndpoint()
{
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
return service.value(configKey::storeEndpoint).toString();
auto service = m_services.at(m_selectedServiceIndex);
return service.storeEndpoint;
}
QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
@@ -209,10 +217,46 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
roles[ServiceDescriptionRole] = "serviceDescription";
roles[IsServiceAvailableRole] = "isServiceAvailable";
roles[SpeedRole] = "speed";
roles[WorkPeriodRole] = "workPeriod";
roles[TimeLimitRole] = "timeLimit";
roles[RegionRole] = "region";
roles[FeaturesRole] = "features";
roles[PriceRole] = "price";
roles[EndDateRole] = "endDate";
return roles;
}
ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJsonObject &data)
{
auto serviceInfo = data.value(configKey::serviceInfo).toObject();
auto serviceType = data.value(configKey::serviceType).toString();
auto serviceProtocol = data.value(configKey::serviceProtocol).toString();
auto availableCountries = data.value(configKey::availableCountries).toArray();
auto subscriptionObject = data.value(configKey::subscription).toObject();
ApiServicesData serviceData;
serviceData.serviceInfo.name = serviceInfo.value(configKey::name).toString();
serviceData.serviceInfo.price = serviceInfo.value(configKey::price).toString();
serviceData.serviceInfo.region = serviceInfo.value(configKey::region).toString();
serviceData.serviceInfo.speed = serviceInfo.value(configKey::speed).toString();
serviceData.serviceInfo.timeLimit = serviceInfo.value(configKey::timelimit).toString();
serviceData.type = serviceType;
serviceData.protocol = serviceProtocol;
serviceData.storeEndpoint = serviceInfo.value(configKey::storeEndpoint).toString();
if (serviceInfo.value(configKey::isAvailable).isBool()) {
serviceData.isServiceAvailable = data.value(configKey::isAvailable).toBool();
} else {
serviceData.isServiceAvailable = true;
}
serviceData.serviceInfo.object = serviceInfo;
serviceData.availableCountries = availableCountries;
serviceData.subscription.endDate = subscriptionObject.value(configKey::endDate).toString();
return serviceData;
}

View File

@@ -3,6 +3,7 @@
#include <QAbstractListModel>
#include <QJsonArray>
#include <QJsonObject>
class ApiServicesModel : public QAbstractListModel
{
@@ -15,10 +16,11 @@ public:
ServiceDescriptionRole,
IsServiceAvailableRole,
SpeedRole,
WorkPeriodRole,
TimeLimitRole,
RegionRole,
FeaturesRole,
PriceRole
PriceRole,
EndDateRole
};
explicit ApiServicesModel(QObject *parent = nullptr);
@@ -48,8 +50,40 @@ protected:
QHash<int, QByteArray> roleNames() const override;
private:
struct ServiceInfo
{
QString name;
QString speed;
QString timeLimit;
QString region;
QString price;
QJsonObject object;
};
struct Subscription
{
QString endDate;
};
struct ApiServicesData
{
bool isServiceAvailable;
QString type;
QString protocol;
QString storeEndpoint;
ServiceInfo serviceInfo;
Subscription subscription;
QJsonArray availableCountries;
};
ApiServicesData getApiServicesData(const QJsonObject &data);
QString m_countryCode;
QJsonArray m_services;
QVector<ApiServicesData> m_services;
int m_selectedServiceIndex;
};

View File

@@ -106,6 +106,8 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
error = getOpenVpnClients(container, credentials, serverController, count);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(container, credentials, serverController, count);
} else if (container == DockerContainer::Xray) {
error = getXrayClients(container, credentials, serverController, count);
}
if (error != ErrorCode::NoError) {
endResetModel();
@@ -239,6 +241,68 @@ ErrorCode ClientManagementModel::getWireGuardClients(const DockerContainer conta
}
return error;
}
ErrorCode ClientManagementModel::getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
const QSharedPointer<ServerController> &serverController, int &count)
{
ErrorCode error = ErrorCode::NoError;
const QString serverConfigPath = amnezia::protocols::xray::serverConfigPath;
const QString configString = serverController->getTextFileFromContainer(container, credentials, serverConfigPath, error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the xray server config file from the server";
return error;
}
QJsonDocument serverConfig = QJsonDocument::fromJson(configString.toUtf8());
if (serverConfig.isNull()) {
logger.error() << "Failed to parse xray server config JSON";
return ErrorCode::InternalError;
}
if (!serverConfig.object().contains("inbounds") || serverConfig.object()["inbounds"].toArray().isEmpty()) {
logger.error() << "Invalid xray server config structure";
return ErrorCode::InternalError;
}
const QJsonObject inbound = serverConfig.object()["inbounds"].toArray()[0].toObject();
if (!inbound.contains("settings")) {
logger.error() << "Missing settings in xray inbound config";
return ErrorCode::InternalError;
}
const QJsonObject settings = inbound["settings"].toObject();
if (!settings.contains("clients")) {
logger.error() << "Missing clients in xray settings config";
return ErrorCode::InternalError;
}
const QJsonArray clients = settings["clients"].toArray();
for (const auto &clientValue : clients) {
const QJsonObject clientObj = clientValue.toObject();
if (!clientObj.contains("id")) {
logger.error() << "Missing id in xray client config";
continue;
}
QString clientId = clientObj["id"].toString();
QString xrayDefaultUuid = serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, error);
xrayDefaultUuid.replace("\n", "");
if (!isClientExists(clientId) && clientId != xrayDefaultUuid) {
QJsonObject client;
client[configKey::clientId] = clientId;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
count++;
}
}
return error;
}
ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
@@ -326,17 +390,67 @@ ErrorCode ClientManagementModel::appendClient(const DockerContainer container, c
const QSharedPointer<ServerController> &serverController)
{
Proto protocol;
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
protocol = Proto::OpenVpn;
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
protocol = ContainerProps::defaultProtocol(container);
} else {
return ErrorCode::NoError;
switch (container) {
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak:
protocol = Proto::OpenVpn;
break;
case DockerContainer::OpenVpn:
case DockerContainer::WireGuard:
case DockerContainer::Awg:
case DockerContainer::Xray:
protocol = ContainerProps::defaultProtocol(container);
break;
default:
return ErrorCode::NoError;
}
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
return appendClient(protocolConfig, clientName, container, credentials, serverController);
}
return appendClient(protocolConfig.value(config_key::clientId).toString(), clientName, container, credentials, serverController);
ErrorCode ClientManagementModel::appendClient(QJsonObject &protocolConfig, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController)
{
QString clientId;
if (container == DockerContainer::Xray) {
if (!protocolConfig.contains("outbounds")) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
if (outbounds.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject outbound = outbounds[0].toObject();
if (!outbound.contains("settings")) {
return ErrorCode::InternalError;
}
QJsonObject settings = outbound["settings"].toObject();
if (!settings.contains("vnext")) {
return ErrorCode::InternalError;
}
QJsonArray vnext = settings["vnext"].toArray();
if (vnext.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject vnextObj = vnext[0].toObject();
if (!vnextObj.contains("users")) {
return ErrorCode::InternalError;
}
QJsonArray users = vnextObj["users"].toArray();
if (users.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject user = users[0].toObject();
if (!user.contains("id")) {
return ErrorCode::InternalError;
}
clientId = user["id"].toString();
} else {
clientId = protocolConfig.value(config_key::clientId).toString();
}
return appendClient(clientId, clientName, container, credentials, serverController);
}
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
@@ -422,10 +536,27 @@ ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContain
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
errorCode = revokeWireGuard(row, container, credentials, serverController);
switch(container)
{
case DockerContainer::OpenVpn:
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak: {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
break;
}
case DockerContainer::WireGuard:
case DockerContainer::Awg: {
errorCode = revokeWireGuard(row, container, credentials, serverController);
break;
}
case DockerContainer::Xray: {
errorCode = revokeXray(row, container, credentials, serverController);
break;
}
default: {
logger.error() << "Internal error: received unexpected container type";
return ErrorCode::InternalError;
}
}
if (errorCode == ErrorCode::NoError) {
@@ -463,19 +594,69 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
}
Proto protocol;
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
protocol = Proto::OpenVpn;
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
protocol = ContainerProps::defaultProtocol(container);
} else {
return ErrorCode::NoError;
switch(container)
{
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak: {
protocol = Proto::OpenVpn;
break;
}
case DockerContainer::OpenVpn:
case DockerContainer::WireGuard:
case DockerContainer::Awg:
case DockerContainer::Xray: {
protocol = ContainerProps::defaultProtocol(container);
break;
}
default: {
logger.error() << "Internal error: received unexpected container type";
return ErrorCode::InternalError;
}
}
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
QString clientId;
if (container == DockerContainer::Xray) {
if (!protocolConfig.contains("outbounds")) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
if (outbounds.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject outbound = outbounds[0].toObject();
if (!outbound.contains("settings")) {
return ErrorCode::InternalError;
}
QJsonObject settings = outbound["settings"].toObject();
if (!settings.contains("vnext")) {
return ErrorCode::InternalError;
}
QJsonArray vnext = settings["vnext"].toArray();
if (vnext.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject vnextObj = vnext[0].toObject();
if (!vnextObj.contains("users")) {
return ErrorCode::InternalError;
}
QJsonArray users = vnextObj["users"].toArray();
if (users.isEmpty()) {
return ErrorCode::InternalError;
}
QJsonObject user = users[0].toObject();
if (!user.contains("id")) {
return ErrorCode::InternalError;
}
clientId = user["id"].toString();
} else {
clientId = protocolConfig.value(config_key::clientId).toString();
}
int row;
bool clientExists = false;
QString clientId = protocolConfig.value(config_key::clientId).toString();
for (row = 0; row < rowCount(); row++) {
auto client = m_clientsTable.at(row).toObject();
if (clientId == client.value(configKey::clientId).toString()) {
@@ -487,11 +668,28 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
return errorCode;
}
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
switch (container)
{
case DockerContainer::OpenVpn:
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak: {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
errorCode = revokeWireGuard(row, container, credentials, serverController);
break;
}
case DockerContainer::WireGuard:
case DockerContainer::Awg: {
errorCode = revokeWireGuard(row, container, credentials, serverController);
break;
}
case DockerContainer::Xray: {
errorCode = revokeXray(row, container, credentials, serverController);
break;
}
default:
logger.error() << "Internal error: received unexpected container type";
return ErrorCode::InternalError;
}
return errorCode;
}
@@ -594,6 +792,117 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeXray(const int row,
const DockerContainer container,
const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController)
{
ErrorCode error = ErrorCode::NoError;
// Get server config
const QString serverConfigPath = amnezia::protocols::xray::serverConfigPath;
const QString configString = serverController->getTextFileFromContainer(container, credentials, serverConfigPath, error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the xray server config file";
return error;
}
QJsonDocument serverConfig = QJsonDocument::fromJson(configString.toUtf8());
if (serverConfig.isNull()) {
logger.error() << "Failed to parse xray server config JSON";
return ErrorCode::InternalError;
}
// Get client ID to remove
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
// Remove client from server config
QJsonObject configObj = serverConfig.object();
if (!configObj.contains("inbounds")) {
logger.error() << "Missing inbounds in xray config";
return ErrorCode::InternalError;
}
QJsonArray inbounds = configObj["inbounds"].toArray();
if (inbounds.isEmpty()) {
logger.error() << "Empty inbounds array in xray config";
return ErrorCode::InternalError;
}
QJsonObject inbound = inbounds[0].toObject();
if (!inbound.contains("settings")) {
logger.error() << "Missing settings in xray inbound config";
return ErrorCode::InternalError;
}
QJsonObject settings = inbound["settings"].toObject();
if (!settings.contains("clients")) {
logger.error() << "Missing clients in xray settings";
return ErrorCode::InternalError;
}
QJsonArray clients = settings["clients"].toArray();
if (clients.isEmpty()) {
logger.error() << "Empty clients array in xray config";
return ErrorCode::InternalError;
}
for (int i = 0; i < clients.size(); ++i) {
QJsonObject clientObj = clients[i].toObject();
if (clientObj.contains("id") && clientObj["id"].toString() == clientId) {
clients.removeAt(i);
break;
}
}
// Update server config
settings["clients"] = clients;
inbound["settings"] = settings;
inbounds[0] = inbound;
configObj["inbounds"] = inbounds;
// Upload updated config
error = serverController->uploadTextFileToContainer(
container,
credentials,
QJsonDocument(configObj).toJson(),
serverConfigPath
);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload updated xray config";
return error;
}
// Remove from local table
beginRemoveRows(QModelIndex(), row, row);
m_clientsTable.removeAt(row);
endRemoveRows();
// Update clients table file on server
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable")
.arg(ContainerProps::containerTypeToString(container));
error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file";
}
// Restart container
QString restartScript = QString("sudo docker restart $CONTAINER_NAME");
error = serverController->runScript(
credentials,
serverController->replaceVars(restartScript, serverController->genVarsForScript(credentials, container))
);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to restart xray container";
return error;
}
return error;
}
QHash<int, QByteArray> ClientManagementModel::roleNames() const
{
QHash<int, QByteArray> roles;
@@ -604,4 +913,4 @@ QHash<int, QByteArray> ClientManagementModel::roleNames() const
roles[DataSentRole] = "dataSent";
roles[AllowedIpsRole] = "allowedIps";
return roles;
}
}

View File

@@ -40,6 +40,8 @@ public slots:
const QSharedPointer<ServerController> &serverController);
ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials, const QJsonObject &containerConfig,
const QString &clientName, const QSharedPointer<ServerController> &serverController);
ErrorCode appendClient(QJsonObject &protocolConfig, const QString &clientName,const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, const ServerCredentials &credentials,
@@ -64,11 +66,15 @@ private:
const QSharedPointer<ServerController> &serverController);
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController);
ErrorCode revokeXray(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController);
ErrorCode getOpenVpnClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count);
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count);
ErrorCode getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
const QSharedPointer<ServerController> &serverController, int &count);
ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data);

View File

@@ -22,7 +22,7 @@ namespace
constexpr char serviceProtocol[] = "service_protocol";
constexpr char publicKeyInfo[] = "public_key";
constexpr char endDate[] = "end_date";
constexpr char expiresAt[] = "expires_at";
}
}
@@ -39,6 +39,9 @@ ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
emit ServersModel::defaultServerNameChanged();
updateDefaultServerContainersModel();
});
connect(this, &ServersModel::processedServerIndexChanged, this, &ServersModel::processedServerChanged);
connect(this, &ServersModel::dataChanged, this, &ServersModel::processedServerChanged);
}
int ServersModel::rowCount(const QModelIndex &parent) const
@@ -79,6 +82,12 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int
return true;
}
bool ServersModel::setData(const int index, const QVariant &value, int role)
{
QModelIndex modelIndex = this->index(index);
return setData(modelIndex, value, role);
}
QVariant ServersModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_servers.size())) {
@@ -679,6 +688,18 @@ QVariant ServersModel::getProcessedServerData(const QString roleString)
return {};
}
bool ServersModel::setProcessedServerData(const QString &roleString, const QVariant &value)
{
const auto roles = roleNames();
for (auto it = roles.begin(); it != roles.end(); it++) {
if (QString(it.value()) == roleString) {
return setData(m_processedServerIndex, value, it.key());
}
}
return false;
}
bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
{
auto server = m_servers.at(m_defaultServerIndex).toObject();
@@ -718,9 +739,9 @@ bool ServersModel::isApiKeyExpired(const int serverIndex)
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
auto publicKeyInfo = apiConfig.value(configKey::publicKeyInfo).toObject();
const QString endDate = publicKeyInfo.value(configKey::endDate).toString();
if (endDate.isEmpty()) {
publicKeyInfo.insert(configKey::endDate, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate));
const QString expiresAt = publicKeyInfo.value(configKey::expiresAt).toString();
if (expiresAt.isEmpty()) {
publicKeyInfo.insert(configKey::expiresAt, QDateTime::currentDateTimeUtc().addDays(1).toString(Qt::ISODate));
apiConfig.insert(configKey::publicKeyInfo, publicKeyInfo);
serverConfig.insert(configKey::apiConfig, apiConfig);
editServer(serverConfig, serverIndex);
@@ -728,8 +749,8 @@ bool ServersModel::isApiKeyExpired(const int serverIndex)
return false;
}
auto endDateDateTime = QDateTime::fromString(endDate, Qt::ISODate).toUTC();
if (endDateDateTime < QDateTime::currentDateTimeUtc()) {
auto expiresAtDateTime = QDateTime::fromString(expiresAt, Qt::ISODate).toUTC();
if (expiresAtDateTime < QDateTime::currentDateTimeUtc()) {
return true;
}
return false;

View File

@@ -46,6 +46,7 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool setData(const int index, const QVariant &value, int role = Qt::EditRole);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant data(const int index, int role = Qt::DisplayRole) const;
@@ -115,6 +116,7 @@ public slots:
QVariant getDefaultServerData(const QString roleString);
QVariant getProcessedServerData(const QString roleString);
bool setProcessedServerData(const QString &roleString, const QVariant &value);
bool isDefaultServerDefaultContainerHasSplitTunneling();
@@ -127,6 +129,9 @@ protected:
signals:
void processedServerIndexChanged(const int index);
// emitted when the processed server index or processed server data is changed
void processedServerChanged();
void defaultServerIndexChanged(const int index);
void defaultServerNameChanged();
void defaultServerDescriptionChanged();

View File

@@ -5,13 +5,12 @@
#include <QDebug>
#include "notificationhandler.h"
#if defined(Q_OS_IOS) || defined(MACOS_NE)
#if defined(Q_OS_IOS)
# include "platforms/ios/iosnotificationhandler.h"
#else
# include "systemtray_notificationhandler.h"
#endif
// static
NotificationHandler* NotificationHandler::create(QObject* parent) {
#if defined(Q_OS_IOS)

View File

@@ -84,7 +84,7 @@ DrawerType2 {
Layout.topMargin: 16
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
leftImageSource: "qrc:/images/controls/share-2.svg"
KeyNavigation.tab: copyConfigTextButton
@@ -120,7 +120,7 @@ DrawerType2 {
borderWidth: 1
text: qsTr("Copy")
imageSource: "qrc:/images/controls/copy.svg"
leftImageSource: "qrc:/images/controls/copy.svg"
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
@@ -143,7 +143,7 @@ DrawerType2 {
borderWidth: 1
text: qsTr("Copy config string")
imageSource: "qrc:/images/controls/copy.svg"
leftImageSource: "qrc:/images/controls/copy.svg"
KeyNavigation.tab: showSettingsButton
}

View File

@@ -22,9 +22,10 @@ Button {
property int borderWidth: 0
property int borderFocusedWidth: 1
property string imageSource
property string leftImageSource
property string rightImageSource
property string leftImageColor: textColor
property bool changeLeftImageSize: true
property bool squareLeftSide: false
@@ -127,18 +128,23 @@ Button {
anchors.centerIn: parent
Image {
Layout.preferredHeight: 20
Layout.preferredWidth: 20
source: root.imageSource
visible: root.imageSource === "" ? false : true
id: leftImage
source: root.leftImageSource
visible: root.leftImageSource === "" ? false : true
layer {
enabled: true
enabled: leftImageColor !== "" ? true : false
effect: ColorOverlay {
color: leftImageColor
}
}
Component.onCompleted: {
if (root.changeLeftImageSize) {
leftImage.Layout.preferredHeight = 20
leftImage.Layout.preferredWidth = 20
}
}
}
ButtonTextType {

View File

@@ -14,7 +14,7 @@ Popup {
visible: false
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
color: AmneziaStyle.color.translucentMidnightBlack
}
background: Rectangle {

View File

@@ -19,7 +19,7 @@ RadioButton {
property string textColor: AmneziaStyle.color.midnightBlack
property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3)
property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
property string defaultBodredColor: AmneziaStyle.color.transparent
property int borderWidth: 0

View File

@@ -145,6 +145,7 @@ Button {
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
enabled: root.enabled
onEntered: {
backgroundRect.color = root.hoveredColor

View File

@@ -92,7 +92,7 @@ Item {
id: background
anchors.fill: parent
color: root.isCollapsed ? AmneziaStyle.color.transparent : Qt.rgba(14/255, 14/255, 17/255, 0.8)
color: root.isCollapsed ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
Behavior on color {
PropertyAnimation { duration: 200 }

View File

@@ -24,7 +24,7 @@ Popup {
Overlay.modal: Rectangle {
visible: root.closeButtonVisible
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
color: AmneziaStyle.color.translucentMidnightBlack
}
onOpened: {

View File

@@ -183,7 +183,7 @@ Item {
focusPolicy: Qt.NoFocus
text: root.buttonText
imageSource: root.buttonImageSource
leftImageSource: root.buttonImageSource
anchors.top: content.top
anchors.bottom: content.bottom

View File

@@ -14,7 +14,7 @@ Popup {
visible: false
Overlay.modal: Rectangle {
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
color: AmneziaStyle.color.translucentMidnightBlack
}
background: Rectangle {

View File

@@ -22,5 +22,9 @@ QtObject {
readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
readonly property color translucentMidnightBlack: Qt.rgba(14/255, 14/255, 17/255, 0.8)
readonly property color softGoldenApricot: Qt.rgba(251/255, 178/255, 106/255, 0.3)
readonly property color mistyGray: Qt.rgba(215/255, 216/255, 219/255, 0.8)
readonly property color cloudyGray: Qt.rgba(215/255, 216/255, 219/255, 0.65)
}
}

View File

@@ -98,7 +98,6 @@ PageType {
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.mutedGray
leftImageColor: AmneziaStyle.color.transparent
borderWidth: 0
buttonTextLabel.lineHeight: 20
@@ -110,7 +109,8 @@ PageType {
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
imageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
leftImageSource: isSplitTunnelingEnabled ? "qrc:/images/controls/split-tunneling.svg" : ""
leftImageColor: ""
rightImageSource: "qrc:/images/controls/chevron-down.svg"
Keys.onEnterPressed: splitTunnelingButton.clicked()
@@ -166,6 +166,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Component.onCompleted: {
drawer.collapsedHeight = collapsed.implicitHeight
@@ -267,18 +268,39 @@ PageType {
RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
Layout.topMargin: 8
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
spacing: 0
Image {
Layout.rightMargin: 8
visible: source !== ""
source: ServersModel.defaultServerImagePathCollapsed
}
BasicButtonType {
enabled: (ServersModel.defaultServerImagePathCollapsed !== "") && drawer.isCollapsed
hoverEnabled: enabled
implicitHeight: 36
leftPadding: 16
rightPadding: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.transparent
textColor: AmneziaStyle.color.mutedGray
buttonTextLabel.lineHeight: 16
buttonTextLabel.font.pixelSize: 13
buttonTextLabel.font.weight: 400
LabelTextType {
id: collapsedServerMenuDescription
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
leftImageSource: ServersModel.defaultServerImagePathCollapsed
changeLeftImageSize: false
rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
onClicked: {
ServersModel.processedIndex = ServersModel.defaultIndex
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
}
}
}
@@ -316,8 +338,8 @@ PageType {
rootButtonImageColor: AmneziaStyle.color.midnightBlack
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
rootButtonBackgroundHoveredColor: AmneziaStyle.color.mistyGray
rootButtonBackgroundPressedColor: AmneziaStyle.color.cloudyGray
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
rootButtonTextTopMargin: 8

View File

@@ -54,8 +54,14 @@ PageType {
imageSource: "qrc:/images/controls/download.svg"
checked: index === ApiCountryModel.currentIndex
checkable: !ConnectionController.isConnected
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
return
}
if (index !== ApiCountryModel.currentIndex) {
PageController.showBusyIndicator(true)
var prevIndex = ApiCountryModel.currentIndex

View File

@@ -56,12 +56,15 @@ PageType {
}
LabelWithImageType {
property bool showSubscriptionEndDate: ServersModel.getProcessedServerData("isCountrySelectionAvailable")
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/history.svg"
leftText: qsTr("Work period")
rightText: ApiServicesModel.getSelectedServiceData("workPeriod")
leftText: showSubscriptionEndDate ? qsTr("Valid until") : qsTr("Work period")
rightText: showSubscriptionEndDate ? ApiServicesModel.getSelectedServiceData("endDate")
: ApiServicesModel.getSelectedServiceData("workPeriod")
visible: rightText !== ""
}
@@ -132,8 +135,8 @@ PageType {
implicitHeight: 32
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Reload API config")
@@ -172,8 +175,8 @@ PageType {
implicitHeight: 32
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Remove from application")

View File

@@ -25,6 +25,8 @@ PageType {
property int pageSettingsApiServerInfo: 3
property int pageSettingsApiLanguageList: 4
property var processedServer
defaultActiveFocusItem: focusItem
Connections {
@@ -35,8 +37,18 @@ PageType {
}
}
Connections {
target: ServersModel
function onProcessedServerChanged() {
root.processedServer = proxyServersModel.get(0)
}
}
SortFilterProxyModel {
id: proxyServersModel
objectName: "proxyServersModel"
sourceModel: ServersModel
filters: [
ValueFilter {
@@ -44,147 +56,139 @@ PageType {
value: true
}
]
Component.onCompleted: {
root.processedServer = proxyServersModel.get(0)
}
}
Item {
id: focusItem
KeyNavigation.tab: header
//KeyNavigation.tab: header
}
ColumnLayout {
anchors.fill: parent
spacing: 16
spacing: 4
Repeater {
id: header
model: proxyServersModel
BackButtonType {
id: backButton
activeFocusOnTab: true
onFocusChanged: {
header.itemAt(0).focusItem.forceActiveFocus()
Layout.topMargin: 20
KeyNavigation.tab: headerContent.actionButton
backButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
root.processedServer.isCountrySelectionAvailable) {
nestedStackView.currentIndex = root.pageSettingsApiLanguageList
} else {
PageController.closePage()
}
}
}
HeaderType {
id: headerContent
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg"
: "qrc:/images/controls/edit-3.svg"
headerText: root.processedServer.name
descriptionText: {
if (root.processedServer.isServerFromGatewayApi) {
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
return qsTr("Subscription is valid until ") + ApiServicesModel.getSelectedServiceData("endDate")
} else {
return ApiServicesModel.getSelectedServiceData("serviceDescription")
}
} else if (root.processedServer.isServerFromTelegramApi) {
return root.processedServer.serverDescription
} else if (root.processedServer.hasWriteAccess) {
return root.processedServer.credentialsLogin + " · " + root.processedServer.hostName
} else {
return root.processedServer.hostName
}
}
delegate: ColumnLayout {
KeyNavigation.tab: tabBar
property alias focusItem: backButton
actionButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
} else {
serverNameEditDrawer.open()
}
}
}
id: content
DrawerType2 {
id: serverNameEditDrawer
Layout.topMargin: 20
parent: root
BackButtonType {
id: backButton
KeyNavigation.tab: headerContent.actionButton
anchors.fill: parent
expandedHeight: root.height * 0.35
backButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
ServersModel.getProcessedServerData("isCountrySelectionAvailable")) {
nestedStackView.currentIndex = root.pageSettingsApiLanguageList
} else {
PageController.closePage()
}
onClosed: {
if (!GC.isMobile()) {
headerContent.actionButton.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
enabled: !GC.isMobile()
function onOpened() {
serverName.textField.forceActiveFocus()
}
}
HeaderType {
id: headerContent
Item {
id: focusItem1
KeyNavigation.tab: serverName.textField
}
TextFieldWithHeaderType {
id: serverName
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Server name")
textFieldText: root.processedServer.name
textField.maximumLength: 30
checkEmptyText: true
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg" : "qrc:/images/controls/edit-3.svg"
headerText: name
descriptionText: {
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
return ApiServicesModel.getSelectedServiceData("serviceDescription")
} else if (ServersModel.getProcessedServerData("isServerFromTelegramApi")) {
return serverDescription
} else if (ServersModel.isProcessedServerHasWriteAccess()) {
return credentialsLogin + " · " + hostName
} else {
return hostName
}
}
KeyNavigation.tab: tabBar
actionButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
} else {
serverNameEditDrawer.open()
}
}
KeyNavigation.tab: saveButton
}
DrawerType2 {
id: serverNameEditDrawer
BasicButtonType {
id: saveButton
parent: root
Layout.fillWidth: true
anchors.fill: parent
expandedHeight: root.height * 0.35
text: qsTr("Save")
KeyNavigation.tab: focusItem1
onClosed: {
if (!GC.isMobile()) {
headerContent.actionButton.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
enabled: !GC.isMobile()
function onOpened() {
serverName.textField.forceActiveFocus()
}
clickedFunc: function() {
if (serverName.textFieldText === "") {
return
}
Item {
id: focusItem1
KeyNavigation.tab: serverName.textField
}
TextFieldWithHeaderType {
id: serverName
Layout.fillWidth: true
headerText: qsTr("Server name")
textFieldText: name
textField.maximumLength: 30
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
text: qsTr("Save")
KeyNavigation.tab: focusItem1
clickedFunc: function() {
if (serverName.textFieldText === "") {
return
}
if (serverName.textFieldText !== name) {
name = serverName.textFieldText
}
serverNameEditDrawer.close()
}
if (serverName.textFieldText !== root.processedServer.name) {
ServersModel.setProcessedServerData("name", serverName.textFieldText);
}
serverNameEditDrawer.close()
}
}
}
@@ -257,8 +261,7 @@ PageType {
StackLayout {
id: nestedStackView
Layout.preferredWidth: root.width
Layout.preferredHeight: root.height - tabBar.implicitHeight - header.implicitHeight
Layout.fillWidth: true
currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ?
(ServersModel.getProcessedServerData("isCountrySelectionAvailable") ?

View File

@@ -16,83 +16,82 @@ PageType {
defaultActiveFocusItem: focusItem
FlickableType {
id: fl
ColumnLayout {
id: header
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.left: parent.left
anchors.right: parent.right
ColumnLayout {
id: content
spacing: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Item {
id: focusItem
KeyNavigation.tab: backButton
}
spacing: 0
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
Layout.topMargin: 20
BackButtonType {
id: backButton
Layout.topMargin: 20
// KeyNavigation.tab: fileButton.rightButton
}
}
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 32
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("VPN by Amnezia")
descriptionText: qsTr("Choose a VPN service that suits your needs.")
}
headerText: qsTr("VPN by Amnezia")
descriptionText: qsTr("Choose a VPN service that suits your needs.")
}
}
ListView {
id: containers
width: parent.width
height: containers.contentItem.height
spacing: 16
ListView {
id: servicesListView
anchors.top: header.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
spacing: 0
currentIndex: 1
interactive: false
model: ApiServicesModel
currentIndex: 1
clip: true
model: ApiServicesModel
delegate: Item {
implicitWidth: containers.width
implicitHeight: delegateContent.implicitHeight
ScrollBar.vertical: ScrollBar {}
ColumnLayout {
id: delegateContent
delegate: Item {
implicitWidth: servicesListView.width
implicitHeight: delegateContent.implicitHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ColumnLayout {
id: delegateContent
CardWithIconsType {
id: card
anchors.fill: parent
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
CardWithIconsType {
id: card
headerText: name
bodyText: cardDescription
footerText: price
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
rightImageSource: "qrc:/images/controls/chevron-right.svg"
headerText: name
bodyText: cardDescription
footerText: price
onClicked: {
if (isServiceAvailable) {
ApiServicesModel.setServiceIndex(index)
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
}
}
rightImageSource: "qrc:/images/controls/chevron-right.svg"
enabled: isServiceAvailable
onClicked: {
if (isServiceAvailable) {
ApiServicesModel.setServiceIndex(index)
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
}
}
}

View File

@@ -47,7 +47,6 @@ PageType {
KeyNavigation.tab: textKey.textField
}
HeaderType {
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()

View File

@@ -92,7 +92,7 @@ PageType {
break
}
case PageShare.ConfigType.Xray: {
ExportController.generateXrayConfig()
ExportController.generateXrayConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save XRay config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_xray"
@@ -573,7 +573,7 @@ PageType {
visible: accessTypeSelector.currentIndex === 0
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)

View File

@@ -135,7 +135,7 @@ PageType {
Layout.topMargin: 40
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)

View File

@@ -248,7 +248,7 @@ bool Utils::killProcessByName(const QString &name)
#elif defined Q_OS_IOS || defined(Q_OS_ANDROID)
return false;
#else
QProcess::execute(QString("pkill %1").arg(name));
return QProcess::execute(QString("pkill %1").arg(name)) == 0;
#endif
}

View File

@@ -1,134 +0,0 @@
#!/bin/bash
echo "Build script for macOS Network Extension started ..."
set -o errexit -o nounset
while getopts n flag
do
case "${flag}" in
n) NOTARIZE_APP=1;;
esac
done
# Hold on to current directory
PROJECT_DIR=$(pwd)
DEPLOY_DIR=$PROJECT_DIR/deploy
mkdir -p $DEPLOY_DIR/build
BUILD_DIR=$DEPLOY_DIR/build
echo "Project dir: ${PROJECT_DIR}"
echo "Build dir: ${BUILD_DIR}"
APP_NAME=AmneziaVPN
APP_FILENAME=$APP_NAME.app
APP_DOMAIN=org.amneziavpn.package
PLIST_NAME=$APP_NAME.plist
OUT_APP_DIR=$BUILD_DIR/client
BUNDLE_DIR=$OUT_APP_DIR/$APP_FILENAME
PREBUILT_DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/deploy-prebuilt/macos
DEPLOY_DATA_DIR=$PROJECT_DIR/deploy/data/macos
INSTALLER_DATA_DIR=$BUILD_DIR/installer/packages/$APP_DOMAIN/data
INSTALLER_BUNDLE_DIR=$BUILD_DIR/installer/$APP_FILENAME
DMG_FILENAME=$PROJECT_DIR/${APP_NAME}.dmg
# Setup provisioning profiles for main app and NE
echo "Setting up provisioning profiles..."
# Tạo thư mục Provisioning Profiles nếu chưa tồn tại
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
# Setup provisioning profile cho main app
echo "Setting up provisioning profile for main app (AmneziaVPN)"
cp $PROJECT_DIR/deploy/AnhTVMacOSMain.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/
macos_main_uuid=$(grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/AnhTVMacOSMain.provisionprofile | grep -io "[-A-F0-9]\{36\}")
mv ~/Library/MobileDevice/Provisioning\ Profiles/AnhTVMacOSMain.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$macos_main_uuid.mobileprovision
# Setup provisioning profile cho Network Extension (NE)
echo "Setting up provisioning profile for Network Extension"
cp $PROJECT_DIR/deploy/AnhTVMacOSNE.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/macos_ne.mobileprovision
macos_ne_uuid=$(grep UUID -A1 -a ~/Library/MobileDevice/Provisioning\ Profiles/macos_ne.mobileprovision | grep -io "[-A-F0-9]\{36\}")
mv ~/Library/MobileDevice/Provisioning\ Profiles/macos_ne.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$macos_ne_uuid.mobileprovision
# Decode and install signing certificates
echo "Installing signing certificates..."
echo $MAC_TRUST_CERT_BASE64 | base64 --decode > mac_trust_cert.pem
echo $MAC_SIGNING_CERT_BASE64 | base64 --decode > mac_signing_cert.p12
# Install certificates into keychain
security create-keychain -p password build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p password build.keychain
security import mac_trust_cert.pem -k build.keychain -A
security import mac_signing_cert.p12 -k build.keychain -P $MAC_SIGNING_CERT_PASSWORD -A
# Establish the keychain settings for the signing process
security set-key-partition-list -S apple-tool:,apple: -s -k password build.keychain
# Check if QIF_VERSION is properly set, otherwise set a default
if [ -z "${QIF_VERSION+x}" ]; then
echo "QIF_VERSION is not set, using default 4.6"
QIF_VERSION=4.6
fi
QIF_BIN_DIR="$QT_BIN_DIR/../../../Tools/QtInstallerFramework/$QIF_VERSION/bin"
# Checking environment
$QT_BIN_DIR/qt-cmake --version || { echo "Error: qt-cmake not found in $QT_BIN_DIR"; exit 1; }
cmake --version || { echo "Error: cmake not found"; exit 1; }
clang -v || { echo "Error: clang not found"; exit 1; }
# Build the Network Extension app
echo "Building Network Extension App..."
mkdir -p build-macos-ne
cd build-macos-ne
$QT_BIN_DIR/qt-cmake .. -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR -DMACOS_NE=TRUE
cmake --build . --config release --target AmneziaVPN -- -allowProvisioningUpdates # Thay đổi target phù hợp cho Network Extension
# Build and run tests here
echo "____________________________________"
echo "............Deploy.................."
echo "____________________________________"
# Package Network Extension
echo "Packaging Network Extension ..."
# Copy necessary data
cp -Rv $PREBUILT_DEPLOY_DATA_DIR/* $BUNDLE_DIR/Contents/macOS
$QT_BIN_DIR/macdeployqt $OUT_APP_DIR/$APP_FILENAME -always-overwrite -qmldir=$PROJECT_DIR
cp -av $BUILD_DIR/service/server/$APP_NAME-service $BUNDLE_DIR/Contents/macOS
cp -Rv $PROJECT_DIR/deploy/data/macos/* $BUNDLE_DIR/Contents/macOS
# Signing and notarizing the Network Extension
if [ "${MAC_CERT_PW+x}" ]; then
CERTIFICATE_P12=$DEPLOY_DIR/PrivacyTechAppleCertDeveloperId.p12
WWDRCA=$DEPLOY_DIR/WWDRCA.cer
KEYCHAIN=amnezia.build.macos.keychain
TEMP_PASS=tmp_pass
security create-keychain -p $TEMP_PASS $KEYCHAIN || true
security default-keychain -s $KEYCHAIN
security unlock-keychain -p $TEMP_PASS $KEYCHAIN
security import $WWDRCA -k $KEYCHAIN -T /usr/bin/codesign || true
security import $CERTIFICATE_P12 -k $KEYCHAIN -P $MAC_CERT_PW -T /usr/bin/codesign || true
echo "Signing Network Extension..."
/usr/bin/codesign --deep --force --verbose --timestamp -o runtime --sign "$MAC_SIGNER_ID" $BUNDLE_DIR
spctl -a -vvvv $BUNDLE_DIR || true
if [ "${NOTARIZE_APP+x}" ]; then
echo "Notarizing Network Extension bundle..."
/usr/bin/ditto -c -k --keepParent $BUNDLE_DIR $PROJECT_DIR/NE_Bundle_to_notarize.zip
xcrun notarytool submit $PROJECT_DIR/NE_Bundle_to_notarize.zip --apple-id $APPLE_DEV_EMAIL --team-id $MAC_TEAM_ID --password $APPLE_DEV_PASSWORD
rm $PROJECT_DIR/NE_Bundle_to_notarize.zip
sleep 300
xcrun stapler staple $BUNDLE_DIR
spctl -a -vvvv $BUNDLE_DIR || true
fi
fi

View File

@@ -19,6 +19,11 @@ date > $LOG_FILE
echo "Script started" >> $LOG_FILE
sudo killall -9 $APP_NAME 2>> $LOG_FILE
if command -v steamos-readonly &> /dev/null; then
sudo steamos-readonly disable >> $LOG_FILE
echo "steamos-readonly disabled" >> $LOG_FILE
fi
if sudo systemctl is-active --quiet $APP_NAME; then
sudo systemctl stop $APP_NAME >> $LOG_FILE
sudo systemctl disable $APP_NAME >> $LOG_FILE
@@ -42,6 +47,11 @@ sudo chmod 555 /usr/share/applications/$APP_NAME.desktop >> $LOG_FILE
echo "user desktop creation loop ended" >> $LOG_FILE
if command -v steamos-readonly &> /dev/null; then
sudo steamos-readonly enable >> $LOG_FILE
echo "steamos-readonly enabled" >> $LOG_FILE
fi
date >> $LOG_FILE
echo "Service status:" >> $LOG_FILE
sudo systemctl status $APP_NAME >> $LOG_FILE

View File

@@ -13,6 +13,11 @@ date >> $LOG_FILE
echo "Uninstall Script started" >> $LOG_FILE
sudo killall -9 $APP_NAME 2>> $LOG_FILE
if command -v steamos-readonly &> /dev/null; then
sudo steamos-readonly disable >> $LOG_FILE
echo "steamos-readonly disabled" >> $LOG_FILE
fi
ls /opt/AmneziaVPN/client/lib/* | while IFS=: read -r dir; do
sudo unlink $dir >> $LOG_FILE
done
@@ -59,6 +64,11 @@ if test -f /usr/share/pixmaps/$APP_NAME.png; then
fi
if command -v steamos-readonly &> /dev/null; then
sudo steamos-readonly enable >> $LOG_FILE
echo "steamos-readonly enabled" >> $LOG_FILE
fi
date >> $LOG_FILE
echo "Service after uninstall status:" >> $LOG_FILE
sudo systemctl status $APP_NAME >> $LOG_FILE

View File

@@ -4,7 +4,7 @@ if(WIN32)
${CMAKE_CURRENT_LIST_DIR}/config/windows.xml.in
${CMAKE_BINARY_DIR}/installer/config/windows.xml
)
elseif(APPLE AND NOT IOS AND NOT MACOS_NE)
elseif(APPLE AND NOT IOS)
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/macos.xml.in
${CMAKE_BINARY_DIR}/installer/config/macos.xml

View File

@@ -228,6 +228,8 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
#ifdef Q_OS_LINUX
// double-check + ensure our firewall is installed and enabled
if (!LinuxFirewall::isInstalled())
LinuxFirewall::install();
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true);
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), blockAll);
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("110.allowNets"), allowNets);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Some files were not shown because too many files have changed in this diff Show More