Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/linux-ipsec
This commit is contained in:
commit
afd2542a11
158 changed files with 6069 additions and 3480 deletions
39
.clang-format
Normal file
39
.clang-format
Normal 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
20
.clang-format-ignore
Normal 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
|
||||||
32
.github/workflows/deploy.yml
vendored
32
.github/workflows/deploy.yml
vendored
|
|
@ -16,6 +16,10 @@ jobs:
|
||||||
QT_VERSION: 6.6.2
|
QT_VERSION: 6.6.2
|
||||||
QIF_VERSION: 4.7
|
QIF_VERSION: 4.7
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install Qt'
|
- name: 'Install Qt'
|
||||||
|
|
@ -82,6 +86,10 @@ jobs:
|
||||||
QIF_VERSION: 4.7
|
QIF_VERSION: 4.7
|
||||||
BUILD_ARCH: 64
|
BUILD_ARCH: 64
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Get sources'
|
- name: 'Get sources'
|
||||||
|
|
@ -144,6 +152,10 @@ jobs:
|
||||||
CC: cc
|
CC: cc
|
||||||
CXX: c++
|
CXX: c++
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Setup xcode'
|
- name: 'Setup xcode'
|
||||||
|
|
@ -178,7 +190,7 @@ jobs:
|
||||||
- name: 'Install go'
|
- name: 'Install go'
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22.1'
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- name: 'Setup gomobile'
|
- name: 'Setup gomobile'
|
||||||
|
|
@ -205,7 +217,11 @@ jobs:
|
||||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin"
|
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 QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
|
||||||
export PATH=$PATH:~/go/bin
|
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:
|
env:
|
||||||
IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
|
IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
|
||||||
IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
|
IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
|
||||||
|
|
@ -235,12 +251,16 @@ jobs:
|
||||||
QT_VERSION: 6.4.3
|
QT_VERSION: 6.4.3
|
||||||
QIF_VERSION: 4.6
|
QIF_VERSION: 4.6
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Setup xcode'
|
- name: 'Setup xcode'
|
||||||
uses: maxim-lobanov/setup-xcode@v1
|
uses: maxim-lobanov/setup-xcode@v1
|
||||||
with:
|
with:
|
||||||
xcode-version: '14.3.1'
|
xcode-version: '15.4.0'
|
||||||
|
|
||||||
- name: 'Install Qt'
|
- name: 'Install Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
|
|
@ -297,9 +317,13 @@ jobs:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
ANDROID_BUILD_PLATFORM: android-34
|
ANDROID_BUILD_PLATFORM: android-34
|
||||||
QT_VERSION: 6.7.2
|
QT_VERSION: 6.7.3
|
||||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install desktop Qt'
|
- name: 'Install desktop Qt'
|
||||||
|
|
|
||||||
4
.github/workflows/tag-deploy.yml
vendored
4
.github/workflows/tag-deploy.yml
vendored
|
|
@ -16,6 +16,10 @@ jobs:
|
||||||
QT_VERSION: 6.4.1
|
QT_VERSION: 6.4.1
|
||||||
QIF_VERSION: 4.5
|
QIF_VERSION: 4.5
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||||
|
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||||
|
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
|
||||||
|
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install desktop Qt'
|
- name: 'Install desktop Qt'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.7.0.0
|
project(${PROJECT} VERSION 4.8.2.4
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
|
|
@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 57)
|
set(APP_ANDROID_VERSION_CODE 2071)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|
|
||||||
32
README.md
32
README.md
|
|
@ -1,30 +1,31 @@
|
||||||
# Amnezia VPN
|
# Amnezia VPN
|
||||||
## _The best client for self-hosted VPN_
|
|
||||||
|
### _The best client for self-hosted VPN_
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
|
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
|
||||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
[](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)
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
<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://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_4.7.0.0_x64.exe"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/win.png" width="150" style="max-width: 100%;"></a>
|
[](https://amnezia.org)
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_4.7.0.0.dmg"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/mac.png" width="150" style="max-width: 100%;"></a>
|
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_Linux_4.7.0.0.tar.zip"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/lin.png" width="150" style="max-width: 100%;"></a>
|
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/tag/4.7.0.0"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/andr.png" width="150" style="max-width: 100%;"></a>
|
|
||||||
|
|
||||||
<br>
|
### [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)
|
||||||
|
|
||||||
<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>
|
> [!TIP]
|
||||||
<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>
|
> 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)
|
[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>
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
|
@ -37,7 +38,8 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- [https://amnezia.org](https://amnezia.org) - project website
|
- [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://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_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)
|
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
|
||||||
|
|
@ -186,8 +188,8 @@ Patreon: [https://www.patreon.com/amneziavpn](https://www.patreon.com/amneziavpn
|
||||||
Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
|
Bitcoin: bc1q26eevjcg9j0wuyywd2e3uc9cs2w58lpkpjxq6p <br>
|
||||||
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
|
USDT BEP20: 0x6abD576765a826f87D1D95183438f9408C901bE4 <br>
|
||||||
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
|
USDT TRC20: TELAitazF1MZGmiNjTcnxDjEiH5oe7LC9d <br>
|
||||||
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3
|
XMR: 48spms39jt1L2L5vyw2RQW6CXD6odUd4jFu19GZcDyKKQV9U88wsJVjSbL4CfRys37jVMdoaWVPSvezCQPhHXUW5UKLqUp3 <br>
|
||||||
|
TON: UQDpU1CyKRmg7L8mNScKk9FRc2SlESuI7N-Hby4nX-CcVmns
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
This project is tested with BrowserStack.
|
This project is tested with BrowserStack.
|
||||||
|
|
|
||||||
181
README_RU.md
Normal file
181
README_RU.md
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
# Amnezia VPN
|
||||||
|
|
||||||
|
### _Лучший клиент для создания VPN на собственном сервере_
|
||||||
|
|
||||||
|
[](https://github.com/amnezia-vpn/amnezia-client/actions/workflows/deploy.yml?query=branch:dev)
|
||||||
|
[](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 на вашем сервере.
|
||||||
|
|
||||||
|
[](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) за поддержку нашего проекта.
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c38a587fcda89bab4009560d36239fa8de74705e
|
Subproject commit ba580dc5bd7784f7b1e110ff0365f3286e549a61
|
||||||
2
client/3rd/OpenVPNAdapter
vendored
2
client/3rd/OpenVPNAdapter
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit dea6040996298e947d63fb172709e6abfec2ba93
|
Subproject commit 7c821a8d5c1ad5ad94e0763b4f25a875b5a6fe1b
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS
|
|
||||||
Core Network
|
|
||||||
)
|
|
||||||
set(LIBS ${LIBS} Qt6::Core Qt6::Network)
|
|
||||||
|
|
||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/singleapplication.h
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/singleapplication_p.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/singleapplication.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/singleapplication_p.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
if(MSVC)
|
|
||||||
set(LIBS ${LIBS} Advapi32.lib)
|
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
|
||||||
set(LIBS ${LIBS} advapi32)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) Itay Grudev 2015 - 2020
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
#include <QtCore/QElapsedTimer>
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include <QtCore/QSharedMemory>
|
|
||||||
|
|
||||||
#include "singleapplication.h"
|
|
||||||
#include "singleapplication_p.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Constructor. Checks and fires up LocalServer or closes the program
|
|
||||||
* if another instance already exists
|
|
||||||
* @param argc
|
|
||||||
* @param argv
|
|
||||||
* @param allowSecondary Whether to enable secondary instance support
|
|
||||||
* @param options Optional flags to toggle specific behaviour
|
|
||||||
* @param timeout Maximum time blocking functions are allowed during app load
|
|
||||||
*/
|
|
||||||
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout, const QString &userData )
|
|
||||||
: app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
|
|
||||||
{
|
|
||||||
Q_D( SingleApplication );
|
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
|
||||||
// On Android and iOS since the library is not supported fallback to
|
|
||||||
// standard QApplication behaviour by simply returning at this point.
|
|
||||||
qWarning() << "SingleApplication is not supported on Android and iOS systems.";
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Store the current mode of the program
|
|
||||||
d->options = options;
|
|
||||||
|
|
||||||
// Add any unique user data
|
|
||||||
if ( ! userData.isEmpty() )
|
|
||||||
d->addAppData( userData );
|
|
||||||
|
|
||||||
// Generating an application ID used for identifying the shared memory
|
|
||||||
// block and QLocalServer
|
|
||||||
d->genBlockServerName();
|
|
||||||
|
|
||||||
// To mitigate QSharedMemory issues with large amount of processes
|
|
||||||
// attempting to attach at the same time
|
|
||||||
SingleApplicationPrivate::randomSleep();
|
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
|
||||||
// By explicitly attaching it and then deleting it we make sure that the
|
|
||||||
// memory is deleted even after the process has crashed on Unix.
|
|
||||||
d->memory = new QSharedMemory( d->blockServerName );
|
|
||||||
d->memory->attach();
|
|
||||||
delete d->memory;
|
|
||||||
#endif
|
|
||||||
// Guarantee thread safe behaviour with a shared memory block.
|
|
||||||
d->memory = new QSharedMemory( d->blockServerName );
|
|
||||||
|
|
||||||
// Create a shared memory block
|
|
||||||
if( d->memory->create( sizeof( InstancesInfo ) )){
|
|
||||||
// Initialize the shared memory block
|
|
||||||
if( ! d->memory->lock() ){
|
|
||||||
qCritical() << "SingleApplication: Unable to lock memory block after create.";
|
|
||||||
abortSafely();
|
|
||||||
}
|
|
||||||
d->initializeMemoryBlock();
|
|
||||||
} else {
|
|
||||||
if( d->memory->error() == QSharedMemory::AlreadyExists ){
|
|
||||||
// Attempt to attach to the memory segment
|
|
||||||
if( ! d->memory->attach() ){
|
|
||||||
qCritical() << "SingleApplication: Unable to attach to shared memory block.";
|
|
||||||
abortSafely();
|
|
||||||
}
|
|
||||||
if( ! d->memory->lock() ){
|
|
||||||
qCritical() << "SingleApplication: Unable to lock memory block after attach.";
|
|
||||||
abortSafely();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qCritical() << "SingleApplication: Unable to create block.";
|
|
||||||
abortSafely();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *inst = static_cast<InstancesInfo*>( d->memory->data() );
|
|
||||||
QElapsedTimer time;
|
|
||||||
time.start();
|
|
||||||
|
|
||||||
// Make sure the shared memory block is initialised and in consistent state
|
|
||||||
while( true ){
|
|
||||||
// If the shared memory block's checksum is valid continue
|
|
||||||
if( d->blockChecksum() == inst->checksum ) break;
|
|
||||||
|
|
||||||
// If more than 5s have elapsed, assume the primary instance crashed and
|
|
||||||
// assume it's position
|
|
||||||
if( time.elapsed() > 5000 ){
|
|
||||||
qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
|
|
||||||
d->initializeMemoryBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise wait for a random period and try again. The random sleep here
|
|
||||||
// limits the probability of a collision between two racing apps and
|
|
||||||
// allows the app to initialise faster
|
|
||||||
if( ! d->memory->unlock() ){
|
|
||||||
qDebug() << "SingleApplication: Unable to unlock memory for random wait.";
|
|
||||||
qDebug() << d->memory->errorString();
|
|
||||||
}
|
|
||||||
SingleApplicationPrivate::randomSleep();
|
|
||||||
if( ! d->memory->lock() ){
|
|
||||||
qCritical() << "SingleApplication: Unable to lock memory after random wait.";
|
|
||||||
abortSafely();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( inst->primary == false ){
|
|
||||||
d->startPrimary();
|
|
||||||
if( ! d->memory->unlock() ){
|
|
||||||
qDebug() << "SingleApplication: Unable to unlock memory after primary start.";
|
|
||||||
qDebug() << d->memory->errorString();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if another instance can be started
|
|
||||||
if( allowSecondary ){
|
|
||||||
d->startSecondary();
|
|
||||||
if( d->options & Mode::SecondaryNotification ){
|
|
||||||
d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
|
|
||||||
}
|
|
||||||
if( ! d->memory->unlock() ){
|
|
||||||
qDebug() << "SingleApplication: Unable to unlock memory after secondary start.";
|
|
||||||
qDebug() << d->memory->errorString();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! d->memory->unlock() ){
|
|
||||||
qDebug() << "SingleApplication: Unable to unlock memory at end of execution.";
|
|
||||||
qDebug() << d->memory->errorString();
|
|
||||||
}
|
|
||||||
|
|
||||||
d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
|
|
||||||
|
|
||||||
delete d;
|
|
||||||
|
|
||||||
::exit( EXIT_SUCCESS );
|
|
||||||
}
|
|
||||||
|
|
||||||
SingleApplication::~SingleApplication()
|
|
||||||
{
|
|
||||||
Q_D( SingleApplication );
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the current application instance is primary.
|
|
||||||
* @return Returns true if the instance is primary, false otherwise.
|
|
||||||
*/
|
|
||||||
bool SingleApplication::isPrimary() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->server != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the current application instance is secondary.
|
|
||||||
* @return Returns true if the instance is secondary, false otherwise.
|
|
||||||
*/
|
|
||||||
bool SingleApplication::isSecondary() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->server == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows you to identify an instance by returning unique consecutive instance
|
|
||||||
* ids. It is reset when the first (primary) instance of your app starts and
|
|
||||||
* only incremented afterwards.
|
|
||||||
* @return Returns a unique instance id.
|
|
||||||
*/
|
|
||||||
quint32 SingleApplication::instanceId() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->instanceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the OS PID (Process Identifier) of the process running the primary
|
|
||||||
* instance. Especially useful when SingleApplication is coupled with OS.
|
|
||||||
* specific APIs.
|
|
||||||
* @return Returns the primary instance PID.
|
|
||||||
*/
|
|
||||||
qint64 SingleApplication::primaryPid() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->primaryPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the username the primary instance is running as.
|
|
||||||
* @return Returns the username the primary instance is running as.
|
|
||||||
*/
|
|
||||||
QString SingleApplication::primaryUser() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->primaryUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the username the current instance is running as.
|
|
||||||
* @return Returns the username the current instance is running as.
|
|
||||||
*/
|
|
||||||
QString SingleApplication::currentUser() const
|
|
||||||
{
|
|
||||||
return SingleApplicationPrivate::getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends message to the Primary Instance.
|
|
||||||
* @param message The message to send.
|
|
||||||
* @param timeout the maximum timeout in milliseconds for blocking functions.
|
|
||||||
* @return true if the message was sent successfuly, false otherwise.
|
|
||||||
*/
|
|
||||||
bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
|
|
||||||
{
|
|
||||||
Q_D( SingleApplication );
|
|
||||||
|
|
||||||
// Nobody to connect to
|
|
||||||
if( isPrimary() ) return false;
|
|
||||||
|
|
||||||
// Make sure the socket is connected
|
|
||||||
if( ! d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
d->socket->write( message );
|
|
||||||
bool dataWritten = d->socket->waitForBytesWritten( timeout );
|
|
||||||
d->socket->flush();
|
|
||||||
return dataWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans up the shared memory block and exits with a failure.
|
|
||||||
* This function halts program execution.
|
|
||||||
*/
|
|
||||||
void SingleApplication::abortSafely()
|
|
||||||
{
|
|
||||||
Q_D( SingleApplication );
|
|
||||||
|
|
||||||
qCritical() << "SingleApplication: " << d->memory->error() << d->memory->errorString();
|
|
||||||
delete d;
|
|
||||||
::exit( EXIT_FAILURE );
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList SingleApplication::userData() const
|
|
||||||
{
|
|
||||||
Q_D( const SingleApplication );
|
|
||||||
return d->appData();
|
|
||||||
}
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) Itay Grudev 2015 - 2018
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
#ifndef SINGLE_APPLICATION_H
|
|
||||||
#define SINGLE_APPLICATION_H
|
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
|
||||||
#include <QtNetwork/QLocalSocket>
|
|
||||||
|
|
||||||
#ifndef QAPPLICATION_CLASS
|
|
||||||
#define QAPPLICATION_CLASS QApplication
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include QT_STRINGIFY(QAPPLICATION_CLASS)
|
|
||||||
|
|
||||||
class SingleApplicationPrivate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The SingleApplication class handles multiple instances of the same
|
|
||||||
* Application
|
|
||||||
* @see QCoreApplication
|
|
||||||
*/
|
|
||||||
class SingleApplication : public QAPPLICATION_CLASS
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
using app_t = QAPPLICATION_CLASS;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Mode of operation of SingleApplication.
|
|
||||||
* Whether the block should be user-wide or system-wide and whether the
|
|
||||||
* primary instance should be notified when a secondary instance had been
|
|
||||||
* started.
|
|
||||||
* @note Operating system can restrict the shared memory blocks to the same
|
|
||||||
* user, in which case the User/System modes will have no effect and the
|
|
||||||
* block will be user wide.
|
|
||||||
* @enum
|
|
||||||
*/
|
|
||||||
enum Mode {
|
|
||||||
User = 1 << 0,
|
|
||||||
System = 1 << 1,
|
|
||||||
SecondaryNotification = 1 << 2,
|
|
||||||
ExcludeAppVersion = 1 << 3,
|
|
||||||
ExcludeAppPath = 1 << 4
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(Options, Mode)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Intitializes a SingleApplication instance with argc command line
|
|
||||||
* arguments in argv
|
|
||||||
* @arg {int &} argc - Number of arguments in argv
|
|
||||||
* @arg {const char *[]} argv - Supplied command line arguments
|
|
||||||
* @arg {bool} allowSecondary - Whether to start the instance as secondary
|
|
||||||
* if there is already a primary instance.
|
|
||||||
* @arg {Mode} mode - Whether for the SingleApplication block to be applied
|
|
||||||
* User wide or System wide.
|
|
||||||
* @arg {int} timeout - Timeout to wait in milliseconds.
|
|
||||||
* @note argc and argv may be changed as Qt removes arguments that it
|
|
||||||
* recognizes
|
|
||||||
* @note Mode::SecondaryNotification only works if set on both the primary
|
|
||||||
* instance and the secondary instance.
|
|
||||||
* @note The timeout is just a hint for the maximum time of blocking
|
|
||||||
* operations. It does not guarantee that the SingleApplication
|
|
||||||
* initialisation will be completed in given time, though is a good hint.
|
|
||||||
* Usually 4*timeout would be the worst case (fail) scenario.
|
|
||||||
* @see See the corresponding QAPPLICATION_CLASS constructor for reference
|
|
||||||
*/
|
|
||||||
explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, const QString &userData = {} );
|
|
||||||
~SingleApplication() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns if the instance is the primary instance
|
|
||||||
* @returns {bool}
|
|
||||||
*/
|
|
||||||
bool isPrimary() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns if the instance is a secondary instance
|
|
||||||
* @returns {bool}
|
|
||||||
*/
|
|
||||||
bool isSecondary() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns a unique identifier for the current instance
|
|
||||||
* @returns {qint32}
|
|
||||||
*/
|
|
||||||
quint32 instanceId() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the process ID (PID) of the primary instance
|
|
||||||
* @returns {qint64}
|
|
||||||
*/
|
|
||||||
qint64 primaryPid() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the username of the user running the primary instance
|
|
||||||
* @returns {QString}
|
|
||||||
*/
|
|
||||||
QString primaryUser() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns the username of the current user
|
|
||||||
* @returns {QString}
|
|
||||||
*/
|
|
||||||
QString currentUser() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sends a message to the primary instance. Returns true on success.
|
|
||||||
* @param {int} timeout - Timeout for connecting
|
|
||||||
* @returns {bool}
|
|
||||||
* @note sendMessage() will return false if invoked from the primary
|
|
||||||
* instance.
|
|
||||||
*/
|
|
||||||
bool sendMessage( const QByteArray &message, int timeout = 100 );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the set user data.
|
|
||||||
* @returns {QStringList}
|
|
||||||
*/
|
|
||||||
QStringList userData() const;
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void instanceStarted();
|
|
||||||
void receivedMessage( quint32 instanceId, QByteArray message );
|
|
||||||
|
|
||||||
private:
|
|
||||||
SingleApplicationPrivate *d_ptr;
|
|
||||||
Q_DECLARE_PRIVATE(SingleApplication)
|
|
||||||
void abortSafely();
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
|
|
||||||
|
|
||||||
#endif // SINGLE_APPLICATION_H
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
QT += core network
|
|
||||||
CONFIG += c++11
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
$$PWD/singleapplication.h \
|
|
||||||
$$PWD/singleapplication_p.h
|
|
||||||
SOURCES += $$PWD/singleapplication.cpp \
|
|
||||||
$$PWD/singleapplication_p.cpp
|
|
||||||
|
|
||||||
INCLUDEPATH += $$PWD
|
|
||||||
|
|
||||||
win32 {
|
|
||||||
msvc:LIBS += Advapi32.lib
|
|
||||||
gcc:LIBS += -ladvapi32
|
|
||||||
}
|
|
||||||
|
|
@ -1,486 +0,0 @@
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) Itay Grudev 2015 - 2020
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
//
|
|
||||||
// W A R N I N G !!!
|
|
||||||
// -----------------
|
|
||||||
//
|
|
||||||
// This file is not part of the SingleApplication API. It is used purely as an
|
|
||||||
// implementation detail. This header file may change from version to
|
|
||||||
// version without notice, or may even be removed.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
#include <QtCore/QThread>
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include <QtCore/QDataStream>
|
|
||||||
#include <QtCore/QElapsedTimer>
|
|
||||||
#include <QtCore/QCryptographicHash>
|
|
||||||
#include <QtNetwork/QLocalServer>
|
|
||||||
#include <QtNetwork/QLocalSocket>
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
#include <QtCore/QRandomGenerator>
|
|
||||||
#else
|
|
||||||
#include <QtCore/QDateTime>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "singleapplication.h"
|
|
||||||
#include "singleapplication_p.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#ifndef NOMINMAX
|
|
||||||
#define NOMINMAX 1
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#include <lmcons.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
|
|
||||||
: q_ptr( q_ptr )
|
|
||||||
{
|
|
||||||
server = nullptr;
|
|
||||||
socket = nullptr;
|
|
||||||
memory = nullptr;
|
|
||||||
instanceNumber = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SingleApplicationPrivate::~SingleApplicationPrivate()
|
|
||||||
{
|
|
||||||
if( socket != nullptr ){
|
|
||||||
socket->close();
|
|
||||||
delete socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( memory != nullptr ){
|
|
||||||
memory->lock();
|
|
||||||
auto *inst = static_cast<InstancesInfo*>(memory->data());
|
|
||||||
if( server != nullptr ){
|
|
||||||
server->close();
|
|
||||||
delete server;
|
|
||||||
inst->primary = false;
|
|
||||||
inst->primaryPid = -1;
|
|
||||||
inst->primaryUser[0] = '\0';
|
|
||||||
inst->checksum = blockChecksum();
|
|
||||||
}
|
|
||||||
memory->unlock();
|
|
||||||
|
|
||||||
delete memory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SingleApplicationPrivate::getUsername()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
wchar_t username[UNLEN + 1];
|
|
||||||
// Specifies size of the buffer on input
|
|
||||||
DWORD usernameLength = UNLEN + 1;
|
|
||||||
if( GetUserNameW( username, &usernameLength ) )
|
|
||||||
return QString::fromWCharArray( username );
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
return QString::fromLocal8Bit( qgetenv( "USERNAME" ) );
|
|
||||||
#else
|
|
||||||
return qEnvironmentVariable( "USERNAME" );
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_UNIX
|
|
||||||
QString username;
|
|
||||||
uid_t uid = geteuid();
|
|
||||||
struct passwd *pw = getpwuid( uid );
|
|
||||||
if( pw )
|
|
||||||
username = QString::fromLocal8Bit( pw->pw_name );
|
|
||||||
if ( username.isEmpty() ){
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
|
||||||
username = QString::fromLocal8Bit( qgetenv( "USER" ) );
|
|
||||||
#else
|
|
||||||
username = qEnvironmentVariable( "USER" );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return username;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::genBlockServerName()
|
|
||||||
{
|
|
||||||
QCryptographicHash appData( QCryptographicHash::Sha256 );
|
|
||||||
appData.addData( "SingleApplication", 17 );
|
|
||||||
appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
|
|
||||||
appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
|
|
||||||
appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
|
|
||||||
|
|
||||||
if ( ! appDataList.isEmpty() )
|
|
||||||
appData.addData( appDataList.join( "" ).toUtf8() );
|
|
||||||
|
|
||||||
if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ){
|
|
||||||
appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! (options & SingleApplication::Mode::ExcludeAppPath) ){
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
|
|
||||||
#else
|
|
||||||
appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// User level block requires a user specific data in the hash
|
|
||||||
if( options & SingleApplication::Mode::User ){
|
|
||||||
appData.addData( getUsername().toUtf8() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
|
|
||||||
// server naming requirements.
|
|
||||||
blockServerName = appData.result().toBase64().replace("/", "_");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::initializeMemoryBlock() const
|
|
||||||
{
|
|
||||||
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
|
||||||
inst->primary = false;
|
|
||||||
inst->secondary = 0;
|
|
||||||
inst->primaryPid = -1;
|
|
||||||
inst->primaryUser[0] = '\0';
|
|
||||||
inst->checksum = blockChecksum();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::startPrimary()
|
|
||||||
{
|
|
||||||
// Reset the number of connections
|
|
||||||
auto *inst = static_cast <InstancesInfo*>( memory->data() );
|
|
||||||
|
|
||||||
inst->primary = true;
|
|
||||||
inst->primaryPid = QCoreApplication::applicationPid();
|
|
||||||
qstrncpy( inst->primaryUser, getUsername().toUtf8().data(), sizeof(inst->primaryUser) );
|
|
||||||
inst->checksum = blockChecksum();
|
|
||||||
instanceNumber = 0;
|
|
||||||
// Successful creation means that no main process exists
|
|
||||||
// So we start a QLocalServer to listen for connections
|
|
||||||
QLocalServer::removeServer( blockServerName );
|
|
||||||
server = new QLocalServer();
|
|
||||||
|
|
||||||
// Restrict access to the socket according to the
|
|
||||||
// SingleApplication::Mode::User flag on User level or no restrictions
|
|
||||||
if( options & SingleApplication::Mode::User ){
|
|
||||||
server->setSocketOptions( QLocalServer::UserAccessOption );
|
|
||||||
} else {
|
|
||||||
server->setSocketOptions( QLocalServer::WorldAccessOption );
|
|
||||||
}
|
|
||||||
|
|
||||||
server->listen( blockServerName );
|
|
||||||
QObject::connect(
|
|
||||||
server,
|
|
||||||
&QLocalServer::newConnection,
|
|
||||||
this,
|
|
||||||
&SingleApplicationPrivate::slotConnectionEstablished
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::startSecondary()
|
|
||||||
{
|
|
||||||
auto *inst = static_cast <InstancesInfo*>( memory->data() );
|
|
||||||
|
|
||||||
inst->secondary += 1;
|
|
||||||
inst->checksum = blockChecksum();
|
|
||||||
instanceNumber = inst->secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
|
|
||||||
{
|
|
||||||
QElapsedTimer time;
|
|
||||||
time.start();
|
|
||||||
|
|
||||||
// Connect to the Local Server of the Primary Instance if not already
|
|
||||||
// connected.
|
|
||||||
if( socket == nullptr ){
|
|
||||||
socket = new QLocalSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( socket->state() == QLocalSocket::ConnectedState ) return true;
|
|
||||||
|
|
||||||
if( socket->state() != QLocalSocket::ConnectedState ){
|
|
||||||
|
|
||||||
while( true ){
|
|
||||||
randomSleep();
|
|
||||||
|
|
||||||
if( socket->state() != QLocalSocket::ConnectingState )
|
|
||||||
socket->connectToServer( blockServerName );
|
|
||||||
|
|
||||||
if( socket->state() == QLocalSocket::ConnectingState ){
|
|
||||||
socket->waitForConnected( static_cast<int>(msecs - time.elapsed()) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// If connected break out of the loop
|
|
||||||
if( socket->state() == QLocalSocket::ConnectedState ) break;
|
|
||||||
|
|
||||||
// If elapsed time since start is longer than the method timeout return
|
|
||||||
if( time.elapsed() >= msecs ) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialisation message according to the SingleApplication protocol
|
|
||||||
QByteArray initMsg;
|
|
||||||
QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
||||||
writeStream.setVersion(QDataStream::Qt_5_6);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
writeStream << blockServerName.toLatin1();
|
|
||||||
writeStream << static_cast<quint8>(connectionType);
|
|
||||||
writeStream << instanceNumber;
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
quint16 checksum = qChecksum(QByteArray(initMsg, static_cast<quint32>(initMsg.length())));
|
|
||||||
#else
|
|
||||||
quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
|
|
||||||
#endif
|
|
||||||
writeStream << checksum;
|
|
||||||
|
|
||||||
// The header indicates the message length that follows
|
|
||||||
QByteArray header;
|
|
||||||
QDataStream headerStream(&header, QIODevice::WriteOnly);
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
||||||
headerStream.setVersion(QDataStream::Qt_5_6);
|
|
||||||
#endif
|
|
||||||
headerStream << static_cast <quint64>( initMsg.length() );
|
|
||||||
|
|
||||||
socket->write( header );
|
|
||||||
socket->write( initMsg );
|
|
||||||
bool result = socket->waitForBytesWritten( static_cast<int>(msecs - time.elapsed()) );
|
|
||||||
socket->flush();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint16 SingleApplicationPrivate::blockChecksum() const
|
|
||||||
{
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
quint16 checksum = qChecksum(QByteArray(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum)));
|
|
||||||
#else
|
|
||||||
quint16 checksum = qChecksum(static_cast<const char*>(memory->constData()), offsetof(InstancesInfo, checksum));
|
|
||||||
#endif
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 SingleApplicationPrivate::primaryPid() const
|
|
||||||
{
|
|
||||||
qint64 pid;
|
|
||||||
|
|
||||||
memory->lock();
|
|
||||||
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
|
||||||
pid = inst->primaryPid;
|
|
||||||
memory->unlock();
|
|
||||||
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SingleApplicationPrivate::primaryUser() const
|
|
||||||
{
|
|
||||||
QByteArray username;
|
|
||||||
|
|
||||||
memory->lock();
|
|
||||||
auto *inst = static_cast<InstancesInfo*>( memory->data() );
|
|
||||||
username = inst->primaryUser;
|
|
||||||
memory->unlock();
|
|
||||||
|
|
||||||
return QString::fromUtf8( username );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Executed when a connection has been made to the LocalServer
|
|
||||||
*/
|
|
||||||
void SingleApplicationPrivate::slotConnectionEstablished()
|
|
||||||
{
|
|
||||||
QLocalSocket *nextConnSocket = server->nextPendingConnection();
|
|
||||||
connectionMap.insert(nextConnSocket, ConnectionInfo());
|
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
|
|
||||||
[nextConnSocket, this](){
|
|
||||||
auto &info = connectionMap[nextConnSocket];
|
|
||||||
Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
|
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::destroyed,
|
|
||||||
[nextConnSocket, this](){
|
|
||||||
connectionMap.remove(nextConnSocket);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
|
|
||||||
[nextConnSocket, this](){
|
|
||||||
auto &info = connectionMap[nextConnSocket];
|
|
||||||
switch(info.stage){
|
|
||||||
case StageHeader:
|
|
||||||
readInitMessageHeader(nextConnSocket);
|
|
||||||
break;
|
|
||||||
case StageBody:
|
|
||||||
readInitMessageBody(nextConnSocket);
|
|
||||||
break;
|
|
||||||
case StageConnected:
|
|
||||||
Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
|
|
||||||
{
|
|
||||||
if (!connectionMap.contains( sock )){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDataStream headerStream( sock );
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
||||||
headerStream.setVersion( QDataStream::Qt_5_6 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Read the header to know the message length
|
|
||||||
quint64 msgLen = 0;
|
|
||||||
headerStream >> msgLen;
|
|
||||||
ConnectionInfo &info = connectionMap[sock];
|
|
||||||
info.stage = StageBody;
|
|
||||||
info.msgLen = msgLen;
|
|
||||||
|
|
||||||
if ( sock->bytesAvailable() >= (qint64) msgLen ){
|
|
||||||
readInitMessageBody( sock );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
|
|
||||||
{
|
|
||||||
Q_Q(SingleApplication);
|
|
||||||
|
|
||||||
if (!connectionMap.contains( sock )){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionInfo &info = connectionMap[sock];
|
|
||||||
if( sock->bytesAvailable() < ( qint64 )info.msgLen ){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the message body
|
|
||||||
QByteArray msgBytes = sock->read(info.msgLen);
|
|
||||||
QDataStream readStream(msgBytes);
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
|
||||||
readStream.setVersion( QDataStream::Qt_5_6 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// server name
|
|
||||||
QByteArray latin1Name;
|
|
||||||
readStream >> latin1Name;
|
|
||||||
|
|
||||||
// connection type
|
|
||||||
ConnectionType connectionType = InvalidConnection;
|
|
||||||
quint8 connTypeVal = InvalidConnection;
|
|
||||||
readStream >> connTypeVal;
|
|
||||||
connectionType = static_cast <ConnectionType>( connTypeVal );
|
|
||||||
|
|
||||||
// instance id
|
|
||||||
quint32 instanceId = 0;
|
|
||||||
readStream >> instanceId;
|
|
||||||
|
|
||||||
// checksum
|
|
||||||
quint16 msgChecksum = 0;
|
|
||||||
readStream >> msgChecksum;
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
const quint16 actualChecksum = qChecksum(QByteArray(msgBytes, static_cast<quint32>(msgBytes.length() - sizeof(quint16))));
|
|
||||||
#else
|
|
||||||
const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool isValid = readStream.status() == QDataStream::Ok &&
|
|
||||||
QLatin1String(latin1Name) == blockServerName &&
|
|
||||||
msgChecksum == actualChecksum;
|
|
||||||
|
|
||||||
if( !isValid ){
|
|
||||||
sock->close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.instanceId = instanceId;
|
|
||||||
info.stage = StageConnected;
|
|
||||||
|
|
||||||
if( connectionType == NewInstance ||
|
|
||||||
( connectionType == SecondaryInstance &&
|
|
||||||
options & SingleApplication::Mode::SecondaryNotification ) )
|
|
||||||
{
|
|
||||||
Q_EMIT q->instanceStarted();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sock->bytesAvailable() > 0){
|
|
||||||
Q_EMIT this->slotDataAvailable( sock, instanceId );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
|
|
||||||
{
|
|
||||||
Q_Q(SingleApplication);
|
|
||||||
Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
|
|
||||||
{
|
|
||||||
if( closedSocket->bytesAvailable() > 0 )
|
|
||||||
Q_EMIT slotDataAvailable( closedSocket, instanceId );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::randomSleep()
|
|
||||||
{
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
|
|
||||||
QThread::msleep( QRandomGenerator::global()->bounded( 8u, 18u ));
|
|
||||||
#else
|
|
||||||
qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
|
|
||||||
QThread::msleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void SingleApplicationPrivate::addAppData(const QString &data)
|
|
||||||
{
|
|
||||||
appDataList.push_back(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList SingleApplicationPrivate::appData() const
|
|
||||||
{
|
|
||||||
return appDataList;
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) Itay Grudev 2015 - 2020
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
//
|
|
||||||
// W A R N I N G !!!
|
|
||||||
// -----------------
|
|
||||||
//
|
|
||||||
// This file is not part of the SingleApplication API. It is used purely as an
|
|
||||||
// implementation detail. This header file may change from version to
|
|
||||||
// version without notice, or may even be removed.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SINGLEAPPLICATION_P_H
|
|
||||||
#define SINGLEAPPLICATION_P_H
|
|
||||||
|
|
||||||
#include <QtCore/QSharedMemory>
|
|
||||||
#include <QtNetwork/QLocalServer>
|
|
||||||
#include <QtNetwork/QLocalSocket>
|
|
||||||
#include "singleapplication.h"
|
|
||||||
|
|
||||||
struct InstancesInfo {
|
|
||||||
bool primary;
|
|
||||||
quint32 secondary;
|
|
||||||
qint64 primaryPid;
|
|
||||||
char primaryUser[128];
|
|
||||||
quint16 checksum; // Must be the last field
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ConnectionInfo {
|
|
||||||
qint64 msgLen = 0;
|
|
||||||
quint32 instanceId = 0;
|
|
||||||
quint8 stage = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SingleApplicationPrivate : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum ConnectionType : quint8 {
|
|
||||||
InvalidConnection = 0,
|
|
||||||
NewInstance = 1,
|
|
||||||
SecondaryInstance = 2,
|
|
||||||
Reconnect = 3
|
|
||||||
};
|
|
||||||
enum ConnectionStage : quint8 {
|
|
||||||
StageHeader = 0,
|
|
||||||
StageBody = 1,
|
|
||||||
StageConnected = 2,
|
|
||||||
};
|
|
||||||
Q_DECLARE_PUBLIC(SingleApplication)
|
|
||||||
|
|
||||||
SingleApplicationPrivate( SingleApplication *q_ptr );
|
|
||||||
~SingleApplicationPrivate() override;
|
|
||||||
|
|
||||||
static QString getUsername();
|
|
||||||
void genBlockServerName();
|
|
||||||
void initializeMemoryBlock() const;
|
|
||||||
void startPrimary();
|
|
||||||
void startSecondary();
|
|
||||||
bool connectToPrimary( int msecs, ConnectionType connectionType );
|
|
||||||
quint16 blockChecksum() const;
|
|
||||||
qint64 primaryPid() const;
|
|
||||||
QString primaryUser() const;
|
|
||||||
void readInitMessageHeader(QLocalSocket *socket);
|
|
||||||
void readInitMessageBody(QLocalSocket *socket);
|
|
||||||
static void randomSleep();
|
|
||||||
void addAppData(const QString &data);
|
|
||||||
QStringList appData() const;
|
|
||||||
|
|
||||||
SingleApplication *q_ptr;
|
|
||||||
QSharedMemory *memory;
|
|
||||||
QLocalSocket *socket;
|
|
||||||
QLocalServer *server;
|
|
||||||
quint32 instanceNumber;
|
|
||||||
QString blockServerName;
|
|
||||||
SingleApplication::Options options;
|
|
||||||
QMap<QLocalSocket*, ConnectionInfo> connectionMap;
|
|
||||||
QStringList appDataList;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void slotConnectionEstablished();
|
|
||||||
void slotDataAvailable( QLocalSocket*, quint32 );
|
|
||||||
void slotClientConnectionClosed( QLocalSocket*, quint32 );
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SINGLEAPPLICATION_P_H
|
|
||||||
|
|
@ -25,10 +25,11 @@ execute_process(
|
||||||
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
||||||
|
|
||||||
add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
|
add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
|
||||||
add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}")
|
add_definitions(-DPROD_S3_ENDPOINT="$ENV{PROD_S3_ENDPOINT}")
|
||||||
|
|
||||||
add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
|
add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
|
||||||
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
|
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
|
||||||
|
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(PACKAGES ${PACKAGES} Multimedia)
|
set(PACKAGES ${PACKAGES} Multimedia)
|
||||||
|
|
@ -61,6 +62,7 @@ qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
||||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
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_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_interface.rep)
|
||||||
|
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QLocalServer>
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "ui/models/installedAppsModel.h"
|
#include "ui/models/installedAppsModel.h"
|
||||||
|
|
@ -28,13 +30,7 @@
|
||||||
#include <AmneziaVPN-Swift.h>
|
#include <AmneziaVPN-Swift.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
|
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
|
||||||
#else
|
|
||||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary, SingleApplication::Options options, int timeout,
|
|
||||||
const QString &userData)
|
|
||||||
: SingleApplication(argc, argv, allowSecondary, options, timeout, userData)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
|
|
@ -115,10 +111,11 @@ void AmneziaApplication::init()
|
||||||
qFatal("Android controller initialization failed");
|
qFatal("Android controller initialization failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) {
|
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
|
||||||
m_pageController->goToPageHome();
|
emit m_pageController->goToPageHome();
|
||||||
m_importController->extractConfigFromData(data);
|
m_importController->extractConfigFromData(data);
|
||||||
m_pageController->goToPageViewConfig();
|
data.clear();
|
||||||
|
emit m_pageController->goToPageViewConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
|
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
|
||||||
|
|
@ -126,16 +123,16 @@ void AmneziaApplication::init()
|
||||||
|
|
||||||
#ifdef Q_OS_IOS
|
#ifdef Q_OS_IOS
|
||||||
IosController::Instance()->initialize();
|
IosController::Instance()->initialize();
|
||||||
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
|
connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
|
||||||
m_pageController->goToPageHome();
|
emit m_pageController->goToPageHome();
|
||||||
m_importController->extractConfigFromData(data);
|
m_importController->extractConfigFromData(data);
|
||||||
m_pageController->goToPageViewConfig();
|
emit m_pageController->goToPageViewConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
|
connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
|
||||||
m_pageController->goToPageHome();
|
emit m_pageController->goToPageHome();
|
||||||
m_pageController->goToPageSettingsBackup();
|
m_pageController->goToPageSettingsBackup();
|
||||||
m_settingsController->importBackupFromOutside(filePath);
|
emit m_settingsController->importBackupFromOutside(filePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
|
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
|
||||||
|
|
@ -180,16 +177,6 @@ void AmneziaApplication::init()
|
||||||
m_pageController->showOnStartup();
|
m_pageController->showOnStartup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO - fix
|
|
||||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
|
||||||
if (isPrimary()) {
|
|
||||||
QObject::connect(this, &SingleApplication::instanceStarted, m_pageController.get(), [this]() {
|
|
||||||
qDebug() << "Secondary instance started, showing this window instead";
|
|
||||||
emit m_pageController->raiseMainWindow();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Android TextArea clipboard workaround
|
// Android TextArea clipboard workaround
|
||||||
// Text from TextArea always has "text/html" mime-type:
|
// Text from TextArea always has "text/html" mime-type:
|
||||||
// /qt/6.6.1/Src/qtdeclarative/src/quick/items/qquicktextcontrol.cpp:1865
|
// /qt/6.6.1/Src/qtdeclarative/src/quick/items/qquicktextcontrol.cpp:1865
|
||||||
|
|
@ -294,6 +281,24 @@ bool AmneziaApplication::parseCommands()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
|
void AmneziaApplication::startLocalServer() {
|
||||||
|
const QString serverName("AmneziaVPNInstance");
|
||||||
|
QLocalServer::removeServer(serverName);
|
||||||
|
|
||||||
|
QLocalServer* server = new QLocalServer(this);
|
||||||
|
server->listen(serverName);
|
||||||
|
|
||||||
|
QObject::connect(server, &QLocalServer::newConnection, this, [server, this]() {
|
||||||
|
if (server) {
|
||||||
|
QLocalSocket* clientConnection = server->nextPendingConnection();
|
||||||
|
clientConnection->deleteLater();
|
||||||
|
}
|
||||||
|
emit m_pageController->raiseMainWindow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
|
||||||
{
|
{
|
||||||
return m_engine;
|
return m_engine;
|
||||||
|
|
|
||||||
|
|
@ -53,22 +53,14 @@
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||||
#define AMNEZIA_BASE_CLASS QGuiApplication
|
#define AMNEZIA_BASE_CLASS QGuiApplication
|
||||||
#else
|
#else
|
||||||
#define AMNEZIA_BASE_CLASS SingleApplication
|
#define AMNEZIA_BASE_CLASS QApplication
|
||||||
#define QAPPLICATION_CLASS QApplication
|
|
||||||
#include "singleapplication.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
class AmneziaApplication : public AMNEZIA_BASE_CLASS
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
|
||||||
AmneziaApplication(int &argc, char *argv[]);
|
AmneziaApplication(int &argc, char *argv[]);
|
||||||
#else
|
|
||||||
AmneziaApplication(int &argc, char *argv[], bool allowSecondary = false,
|
|
||||||
SingleApplication::Options options = SingleApplication::User, int timeout = 1000,
|
|
||||||
const QString &userData = {});
|
|
||||||
#endif
|
|
||||||
virtual ~AmneziaApplication();
|
virtual ~AmneziaApplication();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
@ -78,6 +70,10 @@ public:
|
||||||
void updateTranslator(const QLocale &locale);
|
void updateTranslator(const QLocale &locale);
|
||||||
bool parseCommands();
|
bool parseCommands();
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
|
void startLocalServer();
|
||||||
|
#endif
|
||||||
|
|
||||||
QQmlApplicationEngine *qmlEngine() const;
|
QQmlApplicationEngine *qmlEngine() const;
|
||||||
QNetworkAccessManager *manager() { return m_nam; }
|
QNetworkAccessManager *manager() { return m_nam; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<!-- To request network state -->
|
<!-- 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.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,21 @@
|
||||||
package org.amnezia.vpn.protocol.awg
|
package org.amnezia.vpn.protocol.awg
|
||||||
|
|
||||||
import org.amnezia.vpn.protocol.wireguard.Wireguard
|
import org.amnezia.vpn.protocol.wireguard.Wireguard
|
||||||
|
import org.amnezia.vpn.protocol.wireguard.WireguardConfig
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "protocol": "awg",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "awg_config_data": {
|
|
||||||
* "H1": "969537490",
|
|
||||||
* "H2": "481688153",
|
|
||||||
* "H3": "2049399200",
|
|
||||||
* "H4": "52029755",
|
|
||||||
* "Jc": "3",
|
|
||||||
* "Jmax": "1000",
|
|
||||||
* "Jmin": "50",
|
|
||||||
* "S1": "49",
|
|
||||||
* "S2": "60",
|
|
||||||
* "client_ip": "10.8.1.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "port": 12345,
|
|
||||||
* "client_pub_key": "clientPublicKeyBase64",
|
|
||||||
* "client_priv_key": "privateKeyBase64",
|
|
||||||
* "psk_key": "presharedKeyBase64",
|
|
||||||
* "server_pub_key": "publicKeyBase64",
|
|
||||||
* "config": "[Interface]
|
|
||||||
* Address = 10.8.1.1/32
|
|
||||||
* DNS = 1.1.1.1, 1.0.0.1
|
|
||||||
* PrivateKey = privateKeyBase64
|
|
||||||
* Jc = 3
|
|
||||||
* Jmin = 50
|
|
||||||
* Jmax = 1000
|
|
||||||
* S1 = 49
|
|
||||||
* S2 = 60
|
|
||||||
* H1 = 969537490
|
|
||||||
* H2 = 481688153
|
|
||||||
* H3 = 2049399200
|
|
||||||
* H4 = 52029755
|
|
||||||
*
|
|
||||||
* [Peer]
|
|
||||||
* PublicKey = publicKeyBase64
|
|
||||||
* PresharedKey = presharedKeyBase64
|
|
||||||
* AllowedIPs = 0.0.0.0/0, ::/0
|
|
||||||
* Endpoint = 100.100.100.0:12345
|
|
||||||
* PersistentKeepalive = 25
|
|
||||||
* "
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Awg : Wireguard() {
|
class Awg : Wireguard() {
|
||||||
|
|
||||||
override val ifName: String = "awg0"
|
override val ifName: String = "awg0"
|
||||||
|
|
||||||
override fun parseConfig(config: JSONObject): AwgConfig {
|
override fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configDataJson = config.getJSONObject("awg_config_data")
|
val configData = config.getJSONObject("awg_config_data")
|
||||||
val configData = parseConfigData(configDataJson.getString("config"))
|
return WireguardConfig.build {
|
||||||
return AwgConfig.build {
|
setUseProtocolExtension(true)
|
||||||
configWireguard(configData, configDataJson)
|
configExtensionParameters(configData)
|
||||||
|
configWireguard(config, configData)
|
||||||
configSplitTunneling(config)
|
configSplitTunneling(config)
|
||||||
configAppSplitTunneling(config)
|
configAppSplitTunneling(config)
|
||||||
configData["Jc"]?.let { setJc(it.toInt()) }
|
|
||||||
configData["Jmin"]?.let { setJmin(it.toInt()) }
|
|
||||||
configData["Jmax"]?.let { setJmax(it.toInt()) }
|
|
||||||
configData["S1"]?.let { setS1(it.toInt()) }
|
|
||||||
configData["S2"]?.let { setS2(it.toInt()) }
|
|
||||||
configData["H1"]?.let { setH1(it.toLong()) }
|
|
||||||
configData["H2"]?.let { setH2(it.toLong()) }
|
|
||||||
configData["H3"]?.let { setH3(it.toLong()) }
|
|
||||||
configData["H4"]?.let { setH4(it.toLong()) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
package org.amnezia.vpn.protocol.awg
|
|
||||||
|
|
||||||
import org.amnezia.vpn.protocol.BadConfigException
|
|
||||||
import org.amnezia.vpn.protocol.wireguard.WireguardConfig
|
|
||||||
|
|
||||||
class AwgConfig private constructor(
|
|
||||||
wireguardConfigBuilder: WireguardConfig.Builder,
|
|
||||||
val jc: Int,
|
|
||||||
val jmin: Int,
|
|
||||||
val jmax: Int,
|
|
||||||
val s1: Int,
|
|
||||||
val s2: Int,
|
|
||||||
val h1: Long,
|
|
||||||
val h2: Long,
|
|
||||||
val h3: Long,
|
|
||||||
val h4: Long
|
|
||||||
) : WireguardConfig(wireguardConfigBuilder) {
|
|
||||||
|
|
||||||
private constructor(builder: Builder) : this(
|
|
||||||
builder,
|
|
||||||
builder.jc,
|
|
||||||
builder.jmin,
|
|
||||||
builder.jmax,
|
|
||||||
builder.s1,
|
|
||||||
builder.s2,
|
|
||||||
builder.h1,
|
|
||||||
builder.h2,
|
|
||||||
builder.h3,
|
|
||||||
builder.h4
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
|
||||||
super.appendDeviceLine(this)
|
|
||||||
appendLine("jc=$jc")
|
|
||||||
appendLine("jmin=$jmin")
|
|
||||||
appendLine("jmax=$jmax")
|
|
||||||
appendLine("s1=$s1")
|
|
||||||
appendLine("s2=$s2")
|
|
||||||
appendLine("h1=$h1")
|
|
||||||
appendLine("h2=$h2")
|
|
||||||
appendLine("h3=$h3")
|
|
||||||
appendLine("h4=$h4")
|
|
||||||
}
|
|
||||||
|
|
||||||
class Builder : WireguardConfig.Builder() {
|
|
||||||
|
|
||||||
private var _jc: Int? = null
|
|
||||||
internal var jc: Int
|
|
||||||
get() = _jc ?: throw BadConfigException("AWG: parameter jc is undefined")
|
|
||||||
private set(value) { _jc = value }
|
|
||||||
|
|
||||||
private var _jmin: Int? = null
|
|
||||||
internal var jmin: Int
|
|
||||||
get() = _jmin ?: throw BadConfigException("AWG: parameter jmin is undefined")
|
|
||||||
private set(value) { _jmin = value }
|
|
||||||
|
|
||||||
private var _jmax: Int? = null
|
|
||||||
internal var jmax: Int
|
|
||||||
get() = _jmax ?: throw BadConfigException("AWG: parameter jmax is undefined")
|
|
||||||
private set(value) { _jmax = value }
|
|
||||||
|
|
||||||
private var _s1: Int? = null
|
|
||||||
internal var s1: Int
|
|
||||||
get() = _s1 ?: throw BadConfigException("AWG: parameter s1 is undefined")
|
|
||||||
private set(value) { _s1 = value }
|
|
||||||
|
|
||||||
private var _s2: Int? = null
|
|
||||||
internal var s2: Int
|
|
||||||
get() = _s2 ?: throw BadConfigException("AWG: parameter s2 is undefined")
|
|
||||||
private set(value) { _s2 = value }
|
|
||||||
|
|
||||||
private var _h1: Long? = null
|
|
||||||
internal var h1: Long
|
|
||||||
get() = _h1 ?: throw BadConfigException("AWG: parameter h1 is undefined")
|
|
||||||
private set(value) { _h1 = value }
|
|
||||||
|
|
||||||
private var _h2: Long? = null
|
|
||||||
internal var h2: Long
|
|
||||||
get() = _h2 ?: throw BadConfigException("AWG: parameter h2 is undefined")
|
|
||||||
private set(value) { _h2 = value }
|
|
||||||
|
|
||||||
private var _h3: Long? = null
|
|
||||||
internal var h3: Long
|
|
||||||
get() = _h3 ?: throw BadConfigException("AWG: parameter h3 is undefined")
|
|
||||||
private set(value) { _h3 = value }
|
|
||||||
|
|
||||||
private var _h4: Long? = null
|
|
||||||
internal var h4: Long
|
|
||||||
get() = _h4 ?: throw BadConfigException("AWG: parameter h4 is undefined")
|
|
||||||
private set(value) { _h4 = value }
|
|
||||||
|
|
||||||
fun setJc(jc: Int) = apply { this.jc = jc }
|
|
||||||
fun setJmin(jmin: Int) = apply { this.jmin = jmin }
|
|
||||||
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
|
||||||
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
|
||||||
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
|
||||||
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
|
||||||
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
|
||||||
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
|
||||||
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
|
||||||
|
|
||||||
override fun build(): AwgConfig = configBuild().run { AwgConfig(this@Builder) }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
inline fun build(block: Builder.() -> Unit): AwgConfig = Builder().apply(block).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,40 +3,16 @@ package org.amnezia.vpn.protocol.cloak
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import net.openvpn.ovpn3.ClientAPI_Config
|
import net.openvpn.ovpn3.ClientAPI_Config
|
||||||
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
import org.amnezia.vpn.protocol.openvpn.OpenVpn
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config Example:
|
|
||||||
* {
|
|
||||||
* "protocol": "cloak",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "openvpn_config_data": {
|
|
||||||
* "config": "openVpnConfig"
|
|
||||||
* }
|
|
||||||
* "cloak_config_data": {
|
|
||||||
* "BrowserSig": "chrome",
|
|
||||||
* "EncryptionMethod": "aes-gcm",
|
|
||||||
* "NumConn": 1,
|
|
||||||
* "ProxyMethod": "openvpn",
|
|
||||||
* "PublicKey": "PublicKey=",
|
|
||||||
* "RemoteHost": "100.100.100.0",
|
|
||||||
* "RemotePort": "443",
|
|
||||||
* "ServerName": "servername",
|
|
||||||
* "StreamTimeout": 300,
|
|
||||||
* "Transport": "direct",
|
|
||||||
* "UID": "UID="
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Cloak : OpenVpn() {
|
class Cloak : OpenVpn() {
|
||||||
|
|
||||||
|
override fun internalInit() {
|
||||||
|
super.internalInit()
|
||||||
|
if (!isInitialized) loadSharedLibrary(context, "ck-ovpn-plugin")
|
||||||
|
}
|
||||||
|
|
||||||
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
override fun parseConfig(config: JSONObject): ClientAPI_Config {
|
||||||
val openVpnConfig = ClientAPI_Config()
|
val openVpnConfig = ClientAPI_Config()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ android.library.defaults.buildfeatures.androidresources=false
|
||||||
# For development copy and set local values for these parameters in local.properties
|
# For development copy and set local values for these parameters in local.properties
|
||||||
#androidCompileSdkVersion=android-34
|
#androidCompileSdkVersion=android-34
|
||||||
#androidBuildToolsVersion=34.0.0
|
#androidBuildToolsVersion=34.0.0
|
||||||
#qtMinSdkVersion=24
|
#qtMinSdkVersion=26
|
||||||
#qtTargetSdkVersion=34
|
#qtTargetSdkVersion=34
|
||||||
#androidNdkVersion=26.1.10909125
|
#androidNdkVersion=26.1.10909125
|
||||||
#qtTargetAbiList=x86_64
|
#qtTargetAbiList=x86_64
|
||||||
|
|
|
||||||
|
|
@ -11,28 +11,12 @@ import org.amnezia.vpn.protocol.Protocol
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
||||||
import org.amnezia.vpn.protocol.Statistics
|
import org.amnezia.vpn.protocol.Statistics
|
||||||
import org.amnezia.vpn.protocol.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
import org.amnezia.vpn.util.net.getLocalNetworks
|
import org.amnezia.vpn.util.net.getLocalNetworks
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config Example:
|
|
||||||
* {
|
|
||||||
* "protocol": "openvpn",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "openvpn_config_data": {
|
|
||||||
* "config": "openVpnConfig"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
open class OpenVpn : Protocol() {
|
open class OpenVpn : Protocol() {
|
||||||
|
|
||||||
private var openVpnClient: OpenVpnClient? = null
|
private var openVpnClient: OpenVpnClient? = null
|
||||||
|
|
@ -51,14 +35,17 @@ open class OpenVpn : Protocol() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun internalInit() {
|
override fun internalInit() {
|
||||||
if (!isInitialized) loadSharedLibrary(context, "ovpn3")
|
if (!isInitialized) {
|
||||||
|
loadSharedLibrary(context, "ovpn3")
|
||||||
|
loadSharedLibrary(context, "ovpnutil")
|
||||||
|
}
|
||||||
if (this::scope.isInitialized) {
|
if (this::scope.isInitialized) {
|
||||||
scope.cancel()
|
scope.cancel()
|
||||||
}
|
}
|
||||||
scope = CoroutineScope(Dispatchers.IO)
|
scope = CoroutineScope(Dispatchers.IO)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
val configBuilder = OpenVpnConfig.Builder()
|
val configBuilder = OpenVpnConfig.Builder()
|
||||||
|
|
||||||
openVpnClient = OpenVpnClient(
|
openVpnClient = OpenVpnClient(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package org.amnezia.vpn.protocol
|
||||||
|
|
||||||
sealed class ProtocolException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
sealed class ProtocolException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
||||||
class LoadLibraryException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
|
||||||
class BadConfigException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
class BadConfigException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
||||||
|
|
||||||
class VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
class VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package org.amnezia.vpn.protocol
|
package org.amnezia.vpn.protocol
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.IpPrefix
|
import android.net.IpPrefix
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
|
|
@ -8,9 +7,6 @@ import android.net.VpnService.Builder
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.system.OsConstants
|
import android.system.OsConstants
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import java.io.File
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.util.zip.ZipFile
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
|
|
@ -42,7 +38,7 @@ abstract class Protocol {
|
||||||
|
|
||||||
protected abstract fun internalInit()
|
protected abstract fun internalInit()
|
||||||
|
|
||||||
abstract fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
|
abstract suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
|
||||||
|
|
||||||
abstract fun stopVpn()
|
abstract fun stopVpn()
|
||||||
|
|
||||||
|
|
@ -158,60 +154,6 @@ abstract class Protocol {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
vpnBuilder.setMetered(false)
|
vpnBuilder.setMetered(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean {
|
|
||||||
Log.d(TAG, "Extracting library: $libraryName")
|
|
||||||
val apks = hashSetOf<String>()
|
|
||||||
context.applicationInfo.run {
|
|
||||||
sourceDir?.let { apks += it }
|
|
||||||
splitSourceDirs?.let { apks += it }
|
|
||||||
}
|
|
||||||
for (abi in Build.SUPPORTED_ABIS) {
|
|
||||||
for (apk in apks) {
|
|
||||||
ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
|
|
||||||
val mappedName = System.mapLibraryName(libraryName)
|
|
||||||
val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
|
|
||||||
val zipEntry = zipFile.getEntry(libraryZipPath)
|
|
||||||
zipEntry?.let {
|
|
||||||
Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
|
|
||||||
FileOutputStream(destination).use { outStream ->
|
|
||||||
zipFile.getInputStream(zipEntry).use { inStream ->
|
|
||||||
inStream.copyTo(outStream, 32 * 1024)
|
|
||||||
outStream.fd.sync()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
|
||||||
fun loadSharedLibrary(context: Context, libraryName: String) {
|
|
||||||
Log.d(TAG, "Loading library: $libraryName")
|
|
||||||
try {
|
|
||||||
System.loadLibrary(libraryName)
|
|
||||||
return
|
|
||||||
} catch (_: UnsatisfiedLinkError) {
|
|
||||||
Log.d(TAG, "Failed to load library, try to extract it from apk")
|
|
||||||
}
|
|
||||||
var tempFile: File? = null
|
|
||||||
try {
|
|
||||||
tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
|
|
||||||
if (extractLibrary(context, libraryName, tempFile)) {
|
|
||||||
System.load(tempFile.absolutePath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw LoadLibraryException("Failed to load library apk: $libraryName", e)
|
|
||||||
} finally {
|
|
||||||
tempFile?.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
|
private fun VpnService.Builder.addAddress(addr: InetNetwork) = addAddress(addr.address, addr.mask)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
|
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
|
||||||
|
|
||||||
<array name="bundled_libs">
|
<array name="bundled_libs">
|
||||||
<!-- %%INSERT_EXTRA_LIBS%% -->
|
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<array name="qt_libs">
|
<array name="qt_libs">
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import android.os.Looper
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
import android.os.Messenger
|
import android.os.Messenger
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.WindowManager.LayoutParams
|
import android.view.WindowManager.LayoutParams
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
@ -43,6 +44,7 @@ import kotlinx.coroutines.withContext
|
||||||
import org.amnezia.vpn.protocol.getStatistics
|
import org.amnezia.vpn.protocol.getStatistics
|
||||||
import org.amnezia.vpn.protocol.getStatus
|
import org.amnezia.vpn.protocol.getStatus
|
||||||
import org.amnezia.vpn.qt.QtAndroidController
|
import org.amnezia.vpn.qt.QtAndroidController
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.Prefs
|
import org.amnezia.vpn.util.Prefs
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
|
|
@ -157,7 +159,8 @@ class AmneziaActivity : QtActivity() {
|
||||||
*/
|
*/
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d(TAG, "Create Amnezia activity: $intent")
|
Log.d(TAG, "Create Amnezia activity")
|
||||||
|
loadLibs()
|
||||||
window.apply {
|
window.apply {
|
||||||
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
statusBarColor = getColor(R.color.black)
|
statusBarColor = getColor(R.color.black)
|
||||||
|
|
@ -179,6 +182,17 @@ class AmneziaActivity : QtActivity() {
|
||||||
runBlocking { vpnProto = proto.await() }
|
runBlocking { vpnProto = proto.await() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadLibs() {
|
||||||
|
listOf(
|
||||||
|
"rsapss",
|
||||||
|
"crypto_3",
|
||||||
|
"ssl_3",
|
||||||
|
"ssh"
|
||||||
|
).forEach {
|
||||||
|
loadSharedLibrary(this.applicationContext, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun registerBroadcastReceivers() {
|
private fun registerBroadcastReceivers() {
|
||||||
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
registerBroadcastReceiver(
|
registerBroadcastReceiver(
|
||||||
|
|
@ -187,7 +201,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
|
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Log.d(
|
Log.v(
|
||||||
TAG, "Notification state changed: ${it?.action}, blocked = " +
|
TAG, "Notification state changed: ${it?.action}, blocked = " +
|
||||||
"${it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)}"
|
"${it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)}"
|
||||||
)
|
)
|
||||||
|
|
@ -201,7 +215,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent?) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
Log.d(TAG, "onNewIntent: $intent")
|
Log.v(TAG, "onNewIntent: $intent")
|
||||||
intent?.let(::processIntent)
|
intent?.let(::processIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,7 +404,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
@MainThread
|
@MainThread
|
||||||
private fun startVpn(vpnConfig: String) {
|
private fun startVpn(vpnConfig: String) {
|
||||||
getVpnProto(vpnConfig)?.let { proto ->
|
getVpnProto(vpnConfig)?.let { proto ->
|
||||||
Log.d(TAG, "Proto from config: $proto, current proto: $vpnProto")
|
Log.v(TAG, "Proto from config: $proto, current proto: $vpnProto")
|
||||||
if (isServiceConnected) {
|
if (isServiceConnected) {
|
||||||
if (proto.serviceClass == vpnProto?.serviceClass) {
|
if (proto.serviceClass == vpnProto?.serviceClass) {
|
||||||
vpnProto = proto
|
vpnProto = proto
|
||||||
|
|
@ -503,7 +517,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
|
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
it?.data?.let { uri ->
|
it?.data?.let { uri ->
|
||||||
Log.d(TAG, "Save file to $uri")
|
Log.v(TAG, "Save file to $uri")
|
||||||
try {
|
try {
|
||||||
contentResolver.openOutputStream(uri)?.use { os ->
|
contentResolver.openOutputStream(uri)?.use { os ->
|
||||||
os.bufferedWriter().use { it.write(data) }
|
os.bufferedWriter().use { it.write(data) }
|
||||||
|
|
@ -552,7 +566,7 @@ class AmneziaActivity : QtActivity() {
|
||||||
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
|
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
|
||||||
onAny = {
|
onAny = {
|
||||||
val uri = it?.data?.toString() ?: ""
|
val uri = it?.data?.toString() ?: ""
|
||||||
Log.d(TAG, "Open file: $uri")
|
Log.v(TAG, "Open file: $uri")
|
||||||
mainScope.launch {
|
mainScope.launch {
|
||||||
qtInitialized.await()
|
qtInitialized.await()
|
||||||
QtAndroidController.onFileOpened(uri)
|
QtAndroidController.onFileOpened(uri)
|
||||||
|
|
@ -707,6 +721,66 @@ class AmneziaActivity : QtActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// workaround for a bug in Qt that causes the mouse click event not to be handled
|
||||||
|
// also disable right-click, as it causes the application to crash
|
||||||
|
private var lastButtonState = 0
|
||||||
|
private fun MotionEvent.fixCopy(): MotionEvent = MotionEvent.obtain(
|
||||||
|
downTime,
|
||||||
|
eventTime,
|
||||||
|
action,
|
||||||
|
pointerCount,
|
||||||
|
(0 until pointerCount).map { i ->
|
||||||
|
MotionEvent.PointerProperties().apply {
|
||||||
|
getPointerProperties(i, this)
|
||||||
|
}
|
||||||
|
}.toTypedArray(),
|
||||||
|
(0 until pointerCount).map { i ->
|
||||||
|
MotionEvent.PointerCoords().apply {
|
||||||
|
getPointerCoords(i, this)
|
||||||
|
}
|
||||||
|
}.toTypedArray(),
|
||||||
|
metaState,
|
||||||
|
MotionEvent.BUTTON_PRIMARY,
|
||||||
|
xPrecision,
|
||||||
|
yPrecision,
|
||||||
|
deviceId,
|
||||||
|
edgeFlags,
|
||||||
|
source,
|
||||||
|
flags
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun handleMouseEvent(ev: MotionEvent, superDispatch: (MotionEvent?) -> Boolean): Boolean {
|
||||||
|
when (ev.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
lastButtonState = ev.buttonState
|
||||||
|
if (ev.buttonState == MotionEvent.BUTTON_SECONDARY) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
when (lastButtonState) {
|
||||||
|
MotionEvent.BUTTON_SECONDARY -> return true
|
||||||
|
MotionEvent.BUTTON_PRIMARY -> {
|
||||||
|
val modEvent = ev.fixCopy()
|
||||||
|
return superDispatch(modEvent).apply { modEvent.recycle() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return superDispatch(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
|
if (ev != null && ev.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
|
||||||
|
return handleMouseEvent(ev) { super.dispatchTouchEvent(it) }
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean {
|
||||||
|
ev?.let { return handleMouseEvent(ev) { super.dispatchTrackballEvent(it) }}
|
||||||
|
return super.dispatchTrackballEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils methods
|
* Utils methods
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import androidx.annotation.MainThread
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
import java.net.UnknownHostException
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.LazyThreadSafetyMode.NONE
|
import kotlin.LazyThreadSafetyMode.NONE
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
|
|
@ -31,6 +32,7 @@ import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
|
|
@ -39,7 +41,6 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.amnezia.vpn.protocol.BadConfigException
|
import org.amnezia.vpn.protocol.BadConfigException
|
||||||
import org.amnezia.vpn.protocol.LoadLibraryException
|
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTING
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTING
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
||||||
|
|
@ -49,6 +50,7 @@ import org.amnezia.vpn.protocol.ProtocolState.UNKNOWN
|
||||||
import org.amnezia.vpn.protocol.VpnException
|
import org.amnezia.vpn.protocol.VpnException
|
||||||
import org.amnezia.vpn.protocol.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
import org.amnezia.vpn.protocol.putStatus
|
import org.amnezia.vpn.protocol.putStatus
|
||||||
|
import org.amnezia.vpn.util.LoadLibraryException
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.Prefs
|
import org.amnezia.vpn.util.Prefs
|
||||||
import org.amnezia.vpn.util.net.NetworkState
|
import org.amnezia.vpn.util.net.NetworkState
|
||||||
|
|
@ -111,6 +113,10 @@ open class AmneziaVpnService : VpnService() {
|
||||||
get() = clientMessengers.any { it.value.name == ACTIVITY_MESSENGER_NAME }
|
get() = clientMessengers.any { it.value.name == ACTIVITY_MESSENGER_NAME }
|
||||||
|
|
||||||
private val connectionExceptionHandler = CoroutineExceptionHandler { _, e ->
|
private val connectionExceptionHandler = CoroutineExceptionHandler { _, e ->
|
||||||
|
connectionJob?.cancel()
|
||||||
|
connectionJob = null
|
||||||
|
disconnectionJob?.cancel()
|
||||||
|
disconnectionJob = null
|
||||||
protocolState.value = DISCONNECTED
|
protocolState.value = DISCONNECTED
|
||||||
when (e) {
|
when (e) {
|
||||||
is IllegalArgumentException,
|
is IllegalArgumentException,
|
||||||
|
|
@ -122,6 +128,8 @@ open class AmneziaVpnService : VpnService() {
|
||||||
|
|
||||||
is LoadLibraryException -> onError("${e.message}. Caused: ${e.cause?.message}")
|
is LoadLibraryException -> onError("${e.message}. Caused: ${e.cause?.message}")
|
||||||
|
|
||||||
|
is UnknownHostException -> onError("Unknown host")
|
||||||
|
|
||||||
else -> throw e
|
else -> throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +300,7 @@ open class AmneziaVpnService : VpnService() {
|
||||||
arrayOf(ACTION_CONNECT, ACTION_DISCONNECT), ContextCompat.RECEIVER_NOT_EXPORTED
|
arrayOf(ACTION_CONNECT, ACTION_DISCONNECT), ContextCompat.RECEIVER_NOT_EXPORTED
|
||||||
) {
|
) {
|
||||||
it?.action?.let { action ->
|
it?.action?.let { action ->
|
||||||
Log.d(TAG, "Broadcast request received: $action")
|
Log.v(TAG, "Broadcast request received: $action")
|
||||||
when (action) {
|
when (action) {
|
||||||
ACTION_CONNECT -> connect()
|
ACTION_CONNECT -> connect()
|
||||||
ACTION_DISCONNECT -> disconnect()
|
ACTION_DISCONNECT -> disconnect()
|
||||||
|
|
@ -309,7 +317,7 @@ open class AmneziaVpnService : VpnService() {
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
val state = it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)
|
val state = it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)
|
||||||
Log.d(TAG, "Notification state changed: ${it?.action}, blocked = $state")
|
Log.v(TAG, "Notification state changed: ${it?.action}, blocked = $state")
|
||||||
if (state == false) {
|
if (state == false) {
|
||||||
enableNotification()
|
enableNotification()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -442,7 +450,7 @@ open class AmneziaVpnService : VpnService() {
|
||||||
serviceNotification.isNotificationEnabled() &&
|
serviceNotification.isNotificationEnabled() &&
|
||||||
getSystemService<PowerManager>()?.isInteractive != false
|
getSystemService<PowerManager>()?.isInteractive != false
|
||||||
) {
|
) {
|
||||||
Log.d(TAG, "Launch traffic stats update")
|
Log.v(TAG, "Launch traffic stats update")
|
||||||
trafficStats.reset()
|
trafficStats.reset()
|
||||||
startTrafficStatsUpdateJob()
|
startTrafficStatsUpdateJob()
|
||||||
}
|
}
|
||||||
|
|
@ -531,7 +539,7 @@ open class AmneziaVpnService : VpnService() {
|
||||||
protocolState.value = DISCONNECTING
|
protocolState.value = DISCONNECTING
|
||||||
|
|
||||||
disconnectionJob = connectionScope.launch {
|
disconnectionJob = connectionScope.launch {
|
||||||
connectionJob?.join()
|
connectionJob?.cancelAndJoin()
|
||||||
connectionJob = null
|
connectionJob = null
|
||||||
|
|
||||||
vpnProto?.protocol?.stopVpn()
|
vpnProto?.protocol?.stopVpn()
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ class AuthActivity : FragmentActivity() {
|
||||||
object : BiometricPrompt.AuthenticationCallback() {
|
object : BiometricPrompt.AuthenticationCallback() {
|
||||||
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
|
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
|
||||||
super.onAuthenticationSucceeded(result)
|
super.onAuthenticationSucceeded(result)
|
||||||
Log.d(TAG, "Authentication succeeded")
|
Log.v(TAG, "Authentication succeeded")
|
||||||
QtAndroidController.onAuthResult(true)
|
QtAndroidController.onAuthResult(true)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,20 +29,20 @@ class ImportConfigActivity : ComponentActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d(TAG, "Create Import Config Activity: $intent")
|
Log.v(TAG, "Create Import Config Activity: $intent")
|
||||||
intent?.let(::readConfig)
|
intent?.let(::readConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
Log.d(TAG, "onNewIntent: $intent")
|
Log.v(TAG, "onNewIntent: $intent")
|
||||||
intent.let(::readConfig)
|
intent.let(::readConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readConfig(intent: Intent) {
|
private fun readConfig(intent: Intent) {
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
ACTION_SEND -> {
|
ACTION_SEND -> {
|
||||||
Log.d(TAG, "Process SEND action, type: ${intent.type}")
|
Log.v(TAG, "Process SEND action, type: ${intent.type}")
|
||||||
when (intent.type) {
|
when (intent.type) {
|
||||||
"application/octet-stream" -> {
|
"application/octet-stream" -> {
|
||||||
intent.getUriCompat()?.let { uri ->
|
intent.getUriCompat()?.let { uri ->
|
||||||
|
|
@ -60,7 +60,7 @@ class ImportConfigActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_VIEW -> {
|
ACTION_VIEW -> {
|
||||||
Log.d(TAG, "Process VIEW action, scheme: ${intent.scheme}")
|
Log.v(TAG, "Process VIEW action, scheme: ${intent.scheme}")
|
||||||
when (intent.scheme) {
|
when (intent.scheme) {
|
||||||
"file", "content" -> {
|
"file", "content" -> {
|
||||||
intent.data?.let { uri ->
|
intent.data?.let { uri ->
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ class ServiceNotification(private val context: Context) {
|
||||||
fun buildNotification(serverName: String?, protocol: String?, state: ProtocolState): Notification {
|
fun buildNotification(serverName: String?, protocol: String?, state: ProtocolState): Notification {
|
||||||
val speedString = if (state == CONNECTED) zeroSpeed else null
|
val speedString = if (state == CONNECTED) zeroSpeed else null
|
||||||
|
|
||||||
Log.d(TAG, "Build notification: $serverName, $state")
|
Log.v(TAG, "Build notification: $serverName, $state")
|
||||||
|
|
||||||
return notificationBuilder
|
return notificationBuilder
|
||||||
.setSmallIcon(R.drawable.ic_amnezia_round)
|
.setSmallIcon(R.drawable.ic_amnezia_round)
|
||||||
|
|
@ -88,17 +88,15 @@ class ServiceNotification(private val context: Context) {
|
||||||
fun isNotificationEnabled(): Boolean {
|
fun isNotificationEnabled(): Boolean {
|
||||||
if (!context.isNotificationPermissionGranted()) return false
|
if (!context.isNotificationPermissionGranted()) return false
|
||||||
if (!notificationManager.areNotificationsEnabled()) return false
|
if (!notificationManager.areNotificationsEnabled()) return false
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)?.let {
|
||||||
return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
|
it.importance != NotificationManager.IMPORTANCE_NONE
|
||||||
?.let { it.importance != NotificationManager.IMPORTANCE_NONE } ?: true
|
} ?: true
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) {
|
fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) {
|
||||||
if (context.isNotificationPermissionGranted()) {
|
if (context.isNotificationPermissionGranted()) {
|
||||||
Log.d(TAG, "Update notification: $serverName, $state")
|
Log.v(TAG, "Update notification: $serverName, $state")
|
||||||
notificationManager.notify(NOTIFICATION_ID, buildNotification(serverName, protocol, state))
|
notificationManager.notify(NOTIFICATION_ID, buildNotification(serverName, protocol, state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
client/android/utils/src/main/kotlin/JsonExt.kt
Normal file
9
client/android/utils/src/main/kotlin/JsonExt.kt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.amnezia.vpn.util
|
||||||
|
|
||||||
|
import org.json.JSONArray
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
inline fun <reified T> JSONArray.asSequence(): Sequence<T> =
|
||||||
|
(0..<length()).asSequence().map { get(it) as T }
|
||||||
|
|
||||||
|
fun JSONObject.optStringOrNull(name: String) = optString(name).ifEmpty { null }
|
||||||
66
client/android/utils/src/main/kotlin/LibraryLoader.kt
Normal file
66
client/android/utils/src/main/kotlin/LibraryLoader.kt
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.amnezia.vpn.util
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
|
private const val TAG = "LibraryLoader"
|
||||||
|
|
||||||
|
object LibraryLoader {
|
||||||
|
private fun extractLibrary(context: Context, libraryName: String, destination: File): Boolean {
|
||||||
|
Log.d(TAG, "Extracting library: $libraryName")
|
||||||
|
val apks = hashSetOf<String>()
|
||||||
|
context.applicationInfo.run {
|
||||||
|
sourceDir?.let { apks += it }
|
||||||
|
splitSourceDirs?.let { apks += it }
|
||||||
|
}
|
||||||
|
for (abi in Build.SUPPORTED_ABIS) {
|
||||||
|
for (apk in apks) {
|
||||||
|
ZipFile(File(apk), ZipFile.OPEN_READ).use { zipFile ->
|
||||||
|
val mappedName = System.mapLibraryName(libraryName)
|
||||||
|
val libraryZipPath = listOf("lib", abi, mappedName).joinToString(File.separator)
|
||||||
|
val zipEntry = zipFile.getEntry(libraryZipPath)
|
||||||
|
zipEntry?.let {
|
||||||
|
Log.d(TAG, "Extracting apk:/$libraryZipPath to ${destination.absolutePath}")
|
||||||
|
FileOutputStream(destination).use { outStream ->
|
||||||
|
zipFile.getInputStream(zipEntry).use { inStream ->
|
||||||
|
inStream.copyTo(outStream, 32 * 1024)
|
||||||
|
outStream.fd.sync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
|
fun loadSharedLibrary(context: Context, libraryName: String) {
|
||||||
|
Log.d(TAG, "Loading library: $libraryName")
|
||||||
|
try {
|
||||||
|
System.loadLibrary(libraryName)
|
||||||
|
return
|
||||||
|
} catch (_: UnsatisfiedLinkError) {
|
||||||
|
Log.w(TAG, "Failed to load library, try to extract it from apk")
|
||||||
|
}
|
||||||
|
var tempFile: File? = null
|
||||||
|
try {
|
||||||
|
tempFile = File.createTempFile("lib", ".so", context.codeCacheDir)
|
||||||
|
if (extractLibrary(context, libraryName, tempFile)) {
|
||||||
|
System.load(tempFile.absolutePath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw LoadLibraryException("Failed to load library apk: $libraryName", e)
|
||||||
|
} finally {
|
||||||
|
tempFile?.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoadLibraryException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package org.amnezia.vpn.util
|
package org.amnezia.vpn.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.icu.text.DateFormat
|
|
||||||
import android.icu.text.SimpleDateFormat
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -12,8 +10,6 @@ import java.nio.channels.FileChannel
|
||||||
import java.nio.channels.FileLock
|
import java.nio.channels.FileLock
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import org.amnezia.vpn.util.Log.Priority.D
|
import org.amnezia.vpn.util.Log.Priority.D
|
||||||
import org.amnezia.vpn.util.Log.Priority.E
|
import org.amnezia.vpn.util.Log.Priority.E
|
||||||
|
|
@ -41,11 +37,7 @@ private const val LOG_MAX_FILE_SIZE = 1024 * 1024
|
||||||
* | | | create a report and/or terminate the process |
|
* | | | create a report and/or terminate the process |
|
||||||
*/
|
*/
|
||||||
object Log {
|
object Log {
|
||||||
private val dateTimeFormat: Any =
|
private val dateTimeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
|
|
||||||
else object : ThreadLocal<DateFormat>() {
|
|
||||||
override fun initialValue(): DateFormat = SimpleDateFormat(DATE_TIME_PATTERN, Locale.US)
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var logDir: File
|
private lateinit var logDir: File
|
||||||
private val logFile: File by lazy { File(logDir, LOG_FILE_NAME) }
|
private val logFile: File by lazy { File(logDir, LOG_FILE_NAME) }
|
||||||
|
|
@ -143,12 +135,7 @@ object Log {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
||||||
val date = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val date = LocalDateTime.now().format(dateTimeFormat)
|
||||||
LocalDateTime.now().format(dateTimeFormat as DateTimeFormatter)
|
|
||||||
} else {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
(dateTimeFormat as ThreadLocal<DateFormat>).get()?.format(Date())
|
|
||||||
}
|
|
||||||
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
||||||
"$tag: $msg\n"
|
"$tag: $msg\n"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,18 +42,12 @@ class NetworkState(
|
||||||
private val networkCallback: NetworkCallback by lazy(NONE) {
|
private val networkCallback: NetworkCallback by lazy(NONE) {
|
||||||
object : NetworkCallback() {
|
object : NetworkCallback() {
|
||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
Log.d(TAG, "onAvailable: $network")
|
Log.v(TAG, "onAvailable: $network")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||||
Log.d(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
|
Log.v(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
checkNetworkState(network, networkCapabilities)
|
checkNetworkState(network, networkCapabilities)
|
||||||
} else {
|
|
||||||
handler.post {
|
|
||||||
checkNetworkState(network, networkCapabilities)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) {
|
private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||||
|
|
@ -73,11 +67,11 @@ class NetworkState(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
|
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
|
||||||
Log.d(TAG, "onBlockedStatusChanged: $network, $blocked")
|
Log.v(TAG, "onBlockedStatusChanged: $network, $blocked")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLost(network: Network) {
|
override fun onLost(network: Network) {
|
||||||
Log.d(TAG, "onLost: $network")
|
Log.v(TAG, "onLost: $network")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +81,7 @@ class NetworkState(
|
||||||
Log.d(TAG, "Bind network listener")
|
Log.d(TAG, "Bind network listener")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
|
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
} else {
|
||||||
val numberAttempts = 300
|
val numberAttempts = 300
|
||||||
var attemptCount = 0
|
var attemptCount = 0
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
@ -108,8 +102,6 @@ class NetworkState(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
connectivityManager.requestNetwork(networkRequest, networkCallback)
|
|
||||||
}
|
}
|
||||||
isListenerBound = true
|
isListenerBound = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ fun getLocalNetworks(context: Context, ipv6: Boolean): List<InetNetwork> {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseInetAddress(address: String): InetAddress = parseNumericAddressCompat(address)
|
fun parseInetAddress(address: String): InetAddress = InetAddress.getByName(address)
|
||||||
|
|
||||||
private val parseNumericAddressCompat: (String) -> InetAddress =
|
private val parseNumericAddressCompat: (String) -> InetAddress =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
|
@ -60,7 +60,7 @@ private val parseNumericAddressCompat: (String) -> InetAddress =
|
||||||
internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6
|
internal fun convertIpv6ToCanonicalForm(ipv6: String): String = ipv6
|
||||||
.replace("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)".toRegex(), "::$2")
|
.replace("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)".toRegex(), "::$2")
|
||||||
|
|
||||||
internal val InetAddress.ip: String
|
val InetAddress.ip: String
|
||||||
get() = if (this is Inet4Address) {
|
get() = if (this is Inet4Address) {
|
||||||
hostAddress!!
|
hostAddress!!
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,35 @@
|
||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.net.VpnService.Builder
|
import android.net.VpnService.Builder
|
||||||
import java.util.TreeMap
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.amnezia.awg.GoBackend
|
import org.amnezia.awg.GoBackend
|
||||||
import org.amnezia.vpn.protocol.Protocol
|
import org.amnezia.vpn.protocol.Protocol
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
|
||||||
import org.amnezia.vpn.protocol.Statistics
|
import org.amnezia.vpn.protocol.Statistics
|
||||||
import org.amnezia.vpn.protocol.VpnStartException
|
import org.amnezia.vpn.protocol.VpnStartException
|
||||||
|
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
|
import org.amnezia.vpn.util.asSequence
|
||||||
import org.amnezia.vpn.util.net.InetEndpoint
|
import org.amnezia.vpn.util.net.InetEndpoint
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
|
import org.amnezia.vpn.util.optStringOrNull
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "protocol": "wireguard",
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "splitTunnelSites": [
|
|
||||||
* ],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "wireguard_config_data": {
|
|
||||||
* "client_ip": "10.8.1.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "port": 12345,
|
|
||||||
* "client_pub_key": "clientPublicKeyBase64",
|
|
||||||
* "client_priv_key": "privateKeyBase64",
|
|
||||||
* "psk_key": "presharedKeyBase64",
|
|
||||||
* "server_pub_key": "publicKeyBase64",
|
|
||||||
* "config": "[Interface]
|
|
||||||
* Address = 10.8.1.1/32
|
|
||||||
* DNS = 1.1.1.1, 1.0.0.1
|
|
||||||
* PrivateKey = privateKeyBase64
|
|
||||||
*
|
|
||||||
* [Peer]
|
|
||||||
* PublicKey = publicKeyBase64
|
|
||||||
* PresharedKey = presharedKeyBase64
|
|
||||||
* AllowedIPs = 0.0.0.0/0, ::/0
|
|
||||||
* Endpoint = 100.100.100.0:12345
|
|
||||||
* PersistentKeepalive = 25
|
|
||||||
* "
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
private const val TAG = "Wireguard"
|
private const val TAG = "Wireguard"
|
||||||
|
|
||||||
open class Wireguard : Protocol() {
|
open class Wireguard : Protocol() {
|
||||||
|
|
||||||
private var tunnelHandle: Int = -1
|
private var tunnelHandle: Int = -1
|
||||||
protected open val ifName: String = "amn0"
|
protected open val ifName: String = "amn0"
|
||||||
|
private lateinit var scope: CoroutineScope
|
||||||
|
private var statusJob: Job? = null
|
||||||
|
|
||||||
override val statistics: Statistics
|
override val statistics: Statistics
|
||||||
get() {
|
get() {
|
||||||
|
|
@ -77,69 +52,78 @@ open class Wireguard : Protocol() {
|
||||||
|
|
||||||
override fun internalInit() {
|
override fun internalInit() {
|
||||||
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
||||||
|
if (this::scope.isInitialized) {
|
||||||
|
scope.cancel()
|
||||||
|
}
|
||||||
|
scope = CoroutineScope(Dispatchers.IO)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
val wireguardConfig = parseConfig(config)
|
val wireguardConfig = parseConfig(config)
|
||||||
start(wireguardConfig, vpnBuilder, protect)
|
start(wireguardConfig, vpnBuilder, protect)
|
||||||
state.value = CONNECTED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configDataJson = config.getJSONObject("wireguard_config_data")
|
val configData = config.getJSONObject("wireguard_config_data")
|
||||||
val configData = parseConfigData(configDataJson.getString("config"))
|
|
||||||
return WireguardConfig.build {
|
return WireguardConfig.build {
|
||||||
configWireguard(configData, configDataJson)
|
configWireguard(config, configData)
|
||||||
configSplitTunneling(config)
|
configSplitTunneling(config)
|
||||||
configAppSplitTunneling(config)
|
configAppSplitTunneling(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun WireguardConfig.Builder.configWireguard(configData: Map<String, String>, configDataJson: JSONObject) {
|
protected fun WireguardConfig.Builder.configWireguard(config: JSONObject, configData: JSONObject) {
|
||||||
configData["Address"]?.split(",")?.map { address ->
|
configData.getString("client_ip").split(",").map { address ->
|
||||||
InetNetwork.parse(address.trim())
|
InetNetwork.parse(address.trim())
|
||||||
}?.forEach(::addAddress)
|
}.forEach(::addAddress)
|
||||||
|
|
||||||
configData["DNS"]?.split(",")?.map { dns ->
|
config.optStringOrNull("dns1")?.let { dns ->
|
||||||
parseInetAddress(dns.trim())
|
addDnsServer(parseInetAddress(dns.trim()))
|
||||||
}?.forEach(::addDnsServer)
|
}
|
||||||
|
|
||||||
|
config.optStringOrNull("dns2")?.let { dns ->
|
||||||
|
addDnsServer(parseInetAddress(dns.trim()))
|
||||||
|
}
|
||||||
|
|
||||||
val defRoutes = hashSetOf(
|
val defRoutes = hashSetOf(
|
||||||
InetNetwork("0.0.0.0", 0),
|
InetNetwork("0.0.0.0", 0),
|
||||||
InetNetwork("::", 0)
|
InetNetwork("::", 0)
|
||||||
)
|
)
|
||||||
val routes = hashSetOf<InetNetwork>()
|
val routes = hashSetOf<InetNetwork>()
|
||||||
configData["AllowedIPs"]?.split(",")?.map { route ->
|
configData.getJSONArray("allowed_ips").asSequence<String>().map { route ->
|
||||||
InetNetwork.parse(route.trim())
|
InetNetwork.parse(route.trim())
|
||||||
}?.forEach(routes::add)
|
}.forEach(routes::add)
|
||||||
// if the allowed IPs list contains at least one non-default route, disable global split tunneling
|
// if the allowed IPs list contains at least one non-default route, disable global split tunneling
|
||||||
if (routes.any { it !in defRoutes }) disableSplitTunneling()
|
if (routes.any { it !in defRoutes }) disableSplitTunneling()
|
||||||
addRoutes(routes)
|
addRoutes(routes)
|
||||||
|
|
||||||
configDataJson.optString("mtu").let { mtu ->
|
configData.optStringOrNull("mtu")?.let { setMtu(it.toInt()) }
|
||||||
if (mtu.isNotEmpty()) {
|
|
||||||
setMtu(mtu.toInt())
|
val host = configData.getString("hostName").let { parseInetAddress(it.trim()) }
|
||||||
} else {
|
val port = configData.getInt("port")
|
||||||
configData["MTU"]?.let { setMtu(it.toInt()) }
|
setEndpoint(InetEndpoint(host, port))
|
||||||
}
|
|
||||||
|
if (configData.optBoolean("isObfuscationEnabled")) {
|
||||||
|
setUseProtocolExtension(true)
|
||||||
|
configExtensionParameters(configData)
|
||||||
}
|
}
|
||||||
|
|
||||||
configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) }
|
configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
|
||||||
configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) }
|
configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
|
||||||
configData["PrivateKey"]?.let { setPrivateKeyHex(it.base64ToHex()) }
|
configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
|
||||||
configData["PublicKey"]?.let { setPublicKeyHex(it.base64ToHex()) }
|
configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
||||||
configData["PresharedKey"]?.let { setPreSharedKeyHex(it.base64ToHex()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun parseConfigData(data: String): Map<String, String> {
|
protected fun WireguardConfig.Builder.configExtensionParameters(configData: JSONObject) {
|
||||||
val parsedData = TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER)
|
configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
|
||||||
data.lineSequence()
|
configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
|
||||||
.filter { it.isNotEmpty() && !it.startsWith('[') }
|
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
||||||
.forEach { line ->
|
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
|
||||||
val attr = line.split("=", limit = 2)
|
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
|
||||||
parsedData[attr.first().trim()] = attr.last().trim()
|
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
|
||||||
}
|
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
|
||||||
return parsedData
|
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
||||||
|
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
|
|
@ -168,6 +152,43 @@ open class Wireguard : Protocol() {
|
||||||
tunnelHandle = -1
|
tunnelHandle = -1
|
||||||
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
|
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() {
|
override fun stopVpn() {
|
||||||
|
|
@ -175,6 +196,8 @@ open class Wireguard : Protocol() {
|
||||||
Log.w(TAG, "Tunnel already down")
|
Log.w(TAG, "Tunnel already down")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
statusJob?.cancel()
|
||||||
|
statusJob = null
|
||||||
val handleToClose = tunnelHandle
|
val handleToClose = tunnelHandle
|
||||||
tunnelHandle = -1
|
tunnelHandle = -1
|
||||||
GoBackend.awgTurnOff(handleToClose)
|
GoBackend.awgTurnOff(handleToClose)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import org.amnezia.vpn.protocol.BadConfigException
|
||||||
import org.amnezia.vpn.protocol.ProtocolConfig
|
import org.amnezia.vpn.protocol.ProtocolConfig
|
||||||
import org.amnezia.vpn.util.net.InetEndpoint
|
import org.amnezia.vpn.util.net.InetEndpoint
|
||||||
|
|
||||||
|
|
@ -12,7 +13,17 @@ open class WireguardConfig protected constructor(
|
||||||
val persistentKeepalive: Int,
|
val persistentKeepalive: Int,
|
||||||
val publicKeyHex: String,
|
val publicKeyHex: String,
|
||||||
val preSharedKeyHex: String?,
|
val preSharedKeyHex: String?,
|
||||||
val privateKeyHex: String
|
val privateKeyHex: String,
|
||||||
|
val useProtocolExtension: Boolean,
|
||||||
|
val jc: Int?,
|
||||||
|
val jmin: Int?,
|
||||||
|
val jmax: Int?,
|
||||||
|
val s1: Int?,
|
||||||
|
val s2: Int?,
|
||||||
|
val h1: Long?,
|
||||||
|
val h2: Long?,
|
||||||
|
val h3: Long?,
|
||||||
|
val h4: Long?
|
||||||
) : ProtocolConfig(protocolConfigBuilder) {
|
) : ProtocolConfig(protocolConfigBuilder) {
|
||||||
|
|
||||||
protected constructor(builder: Builder) : this(
|
protected constructor(builder: Builder) : this(
|
||||||
|
|
@ -21,7 +32,17 @@ open class WireguardConfig protected constructor(
|
||||||
builder.persistentKeepalive,
|
builder.persistentKeepalive,
|
||||||
builder.publicKeyHex,
|
builder.publicKeyHex,
|
||||||
builder.preSharedKeyHex,
|
builder.preSharedKeyHex,
|
||||||
builder.privateKeyHex
|
builder.privateKeyHex,
|
||||||
|
builder.useProtocolExtension,
|
||||||
|
builder.jc,
|
||||||
|
builder.jmin,
|
||||||
|
builder.jmax,
|
||||||
|
builder.s1,
|
||||||
|
builder.s2,
|
||||||
|
builder.h1,
|
||||||
|
builder.h2,
|
||||||
|
builder.h3,
|
||||||
|
builder.h4
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
fun toWgUserspaceString(): String = with(StringBuilder()) {
|
||||||
|
|
@ -33,6 +54,30 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
|
||||||
appendLine("private_key=$privateKeyHex")
|
appendLine("private_key=$privateKeyHex")
|
||||||
|
if (useProtocolExtension) {
|
||||||
|
validateProtocolExtensionParameters()
|
||||||
|
appendLine("jc=$jc")
|
||||||
|
appendLine("jmin=$jmin")
|
||||||
|
appendLine("jmax=$jmax")
|
||||||
|
appendLine("s1=$s1")
|
||||||
|
appendLine("s2=$s2")
|
||||||
|
appendLine("h1=$h1")
|
||||||
|
appendLine("h2=$h2")
|
||||||
|
appendLine("h3=$h3")
|
||||||
|
appendLine("h4=$h4")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateProtocolExtensionParameters() {
|
||||||
|
if (jc == null) throw BadConfigException("Parameter jc is undefined")
|
||||||
|
if (jmin == null) throw BadConfigException("Parameter jmin is undefined")
|
||||||
|
if (jmax == null) throw BadConfigException("Parameter jmax is undefined")
|
||||||
|
if (s1 == null) throw BadConfigException("Parameter s1 is undefined")
|
||||||
|
if (s2 == null) throw BadConfigException("Parameter s2 is undefined")
|
||||||
|
if (h1 == null) throw BadConfigException("Parameter h1 is undefined")
|
||||||
|
if (h2 == null) throw BadConfigException("Parameter h2 is undefined")
|
||||||
|
if (h3 == null) throw BadConfigException("Parameter h3 is undefined")
|
||||||
|
if (h4 == null) throw BadConfigException("Parameter h4 is undefined")
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun appendPeerLine(sb: StringBuilder) = with(sb) {
|
open fun appendPeerLine(sb: StringBuilder) = with(sb) {
|
||||||
|
|
@ -65,6 +110,18 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
override var mtu: Int = WIREGUARD_DEFAULT_MTU
|
override var mtu: Int = WIREGUARD_DEFAULT_MTU
|
||||||
|
|
||||||
|
internal var useProtocolExtension: Boolean = false
|
||||||
|
|
||||||
|
internal var jc: Int? = null
|
||||||
|
internal var jmin: Int? = null
|
||||||
|
internal var jmax: Int? = null
|
||||||
|
internal var s1: Int? = null
|
||||||
|
internal var s2: Int? = null
|
||||||
|
internal var h1: Long? = null
|
||||||
|
internal var h2: Long? = null
|
||||||
|
internal var h3: Long? = null
|
||||||
|
internal var h4: Long? = null
|
||||||
|
|
||||||
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
|
||||||
|
|
||||||
fun setPersistentKeepalive(persistentKeepalive: Int) = apply { this.persistentKeepalive = persistentKeepalive }
|
fun setPersistentKeepalive(persistentKeepalive: Int) = apply { this.persistentKeepalive = persistentKeepalive }
|
||||||
|
|
@ -75,6 +132,18 @@ open class WireguardConfig protected constructor(
|
||||||
|
|
||||||
fun setPrivateKeyHex(privateKeyHex: String) = apply { this.privateKeyHex = privateKeyHex }
|
fun setPrivateKeyHex(privateKeyHex: String) = apply { this.privateKeyHex = privateKeyHex }
|
||||||
|
|
||||||
|
fun setUseProtocolExtension(useProtocolExtension: Boolean) = apply { this.useProtocolExtension = useProtocolExtension }
|
||||||
|
|
||||||
|
fun setJc(jc: Int) = apply { this.jc = jc }
|
||||||
|
fun setJmin(jmin: Int) = apply { this.jmin = jmin }
|
||||||
|
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
||||||
|
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
||||||
|
fun setS2(s2: Int) = apply { this.s2 = s2 }
|
||||||
|
fun setH1(h1: Long) = apply { this.h1 = h1 }
|
||||||
|
fun setH2(h2: Long) = apply { this.h2 = h2 }
|
||||||
|
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
||||||
|
fun setH4(h4: Long) = apply { this.h4 = h4 }
|
||||||
|
|
||||||
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,72 +17,10 @@ import org.amnezia.vpn.protocol.xray.libXray.Logger
|
||||||
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
|
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
|
||||||
import org.amnezia.vpn.util.Log
|
import org.amnezia.vpn.util.Log
|
||||||
import org.amnezia.vpn.util.net.InetNetwork
|
import org.amnezia.vpn.util.net.InetNetwork
|
||||||
|
import org.amnezia.vpn.util.net.ip
|
||||||
import org.amnezia.vpn.util.net.parseInetAddress
|
import org.amnezia.vpn.util.net.parseInetAddress
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
/**
|
|
||||||
* Config example:
|
|
||||||
* {
|
|
||||||
* "appSplitTunnelType": 0,
|
|
||||||
* "config_version": 0,
|
|
||||||
* "description": "Server 1",
|
|
||||||
* "dns1": "1.1.1.1",
|
|
||||||
* "dns2": "1.0.0.1",
|
|
||||||
* "hostName": "100.100.100.0",
|
|
||||||
* "protocol": "xray",
|
|
||||||
* "splitTunnelApps": [],
|
|
||||||
* "splitTunnelSites": [],
|
|
||||||
* "splitTunnelType": 0,
|
|
||||||
* "xray_config_data": {
|
|
||||||
* "inbounds": [
|
|
||||||
* {
|
|
||||||
* "listen": "127.0.0.1",
|
|
||||||
* "port": 8080,
|
|
||||||
* "protocol": "socks",
|
|
||||||
* "settings": {
|
|
||||||
* "udp": true
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ],
|
|
||||||
* "log": {
|
|
||||||
* "loglevel": "error"
|
|
||||||
* },
|
|
||||||
* "outbounds": [
|
|
||||||
* {
|
|
||||||
* "protocol": "vless",
|
|
||||||
* "settings": {
|
|
||||||
* "vnext": [
|
|
||||||
* {
|
|
||||||
* "address": "100.100.100.0",
|
|
||||||
* "port": 443,
|
|
||||||
* "users": [
|
|
||||||
* {
|
|
||||||
* "encryption": "none",
|
|
||||||
* "flow": "xtls-rprx-vision",
|
|
||||||
* "id": "id"
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* },
|
|
||||||
* "streamSettings": {
|
|
||||||
* "network": "tcp",
|
|
||||||
* "realitySettings": {
|
|
||||||
* "fingerprint": "chrome",
|
|
||||||
* "publicKey": "publicKey",
|
|
||||||
* "serverName": "google.com",
|
|
||||||
* "shortId": "id",
|
|
||||||
* "spiderX": ""
|
|
||||||
* },
|
|
||||||
* "security": "reality"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
private const val TAG = "Xray"
|
private const val TAG = "Xray"
|
||||||
private const val LIBXRAY_TAG = "libXray"
|
private const val LIBXRAY_TAG = "libXray"
|
||||||
|
|
||||||
|
|
@ -109,7 +47,7 @@ class Xray : Protocol() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
Log.w(TAG, "XRay already running")
|
Log.w(TAG, "XRay already running")
|
||||||
return
|
return
|
||||||
|
|
@ -124,7 +62,15 @@ class Xray : Protocol() {
|
||||||
.put("loglevel", "warning")
|
.put("loglevel", "warning")
|
||||||
.put("access", "none") // disable access log
|
.put("access", "none") // disable access log
|
||||||
|
|
||||||
start(xrayConfig, xrayJsonConfig.toString(), vpnBuilder, protect)
|
var xrayJsonConfigString = xrayJsonConfig.toString()
|
||||||
|
config.getString("hostName").let { hostName ->
|
||||||
|
val ipAddress = parseInetAddress(hostName).ip
|
||||||
|
if (hostName != ipAddress) {
|
||||||
|
xrayJsonConfigString = xrayJsonConfigString.replace(hostName, ipAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start(xrayConfig, xrayJsonConfigString, vpnBuilder, protect)
|
||||||
state.value = CONNECTED
|
state.value = CONNECTED
|
||||||
isRunning = true
|
isRunning = true
|
||||||
}
|
}
|
||||||
|
|
@ -184,8 +130,8 @@ class Xray : Protocol() {
|
||||||
LibXray.initXray(assetsPath)
|
LibXray.initXray(assetsPath)
|
||||||
val geoDir = File(assetsPath, "geo").absolutePath
|
val geoDir = File(assetsPath, "geo").absolutePath
|
||||||
val configPath = File(context.cacheDir, "config.json")
|
val configPath = File(context.cacheDir, "config.json")
|
||||||
Log.d(TAG, "xray.location.asset: $geoDir")
|
Log.v(TAG, "xray.location.asset: $geoDir")
|
||||||
Log.d(TAG, "config: $configPath")
|
Log.v(TAG, "config: $configPath")
|
||||||
try {
|
try {
|
||||||
configPath.writeText(configJson)
|
configPath.writeText(configJson)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,6 @@ set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
|
||||||
|
|
||||||
if(NOT IOS AND NOT ANDROID)
|
|
||||||
include(${CLIENT_ROOT_DIR}/3rd/SingleApplication/singleapplication.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/SortFilterProxyModel)
|
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/SortFilterProxyModel)
|
||||||
set(LIBS ${LIBS} SortFilterProxyModel)
|
set(LIBS ${LIBS} SortFilterProxyModel)
|
||||||
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
message("Client android ${CMAKE_ANDROID_ARCH_ABI} build")
|
message("Client android ${CMAKE_ANDROID_ARCH_ABI} build")
|
||||||
|
|
||||||
set(APP_ANDROID_MIN_SDK 24)
|
set(APP_ANDROID_MIN_SDK 26)
|
||||||
set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING
|
set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING
|
||||||
"The minimum API level supported by the application or library" FORCE)
|
"The minimum API level supported by the application or library" FORCE)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||||
stdOut.replace("/32", "");
|
stdOut.replace("/32", "");
|
||||||
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
|
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts);
|
||||||
|
|
||||||
|
// remove extra IPs from each line for case when user manually edited the wg0.conf
|
||||||
|
// and added there more IPs for route his itnernal networks, like:
|
||||||
|
// ...
|
||||||
|
// AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ...
|
||||||
|
// ...
|
||||||
|
// without this code - next IP would be 1 if last item in 'ips' has format above
|
||||||
|
QStringList vpnIps;
|
||||||
|
for (const auto &ip : ips) {
|
||||||
|
vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed());
|
||||||
|
}
|
||||||
|
ips = vpnIps;
|
||||||
|
|
||||||
// Calc next IP address
|
// Calc next IP address
|
||||||
if (ips.isEmpty()) {
|
if (ips.isEmpty()) {
|
||||||
nextIpNumber = "2";
|
nextIpNumber = "2";
|
||||||
|
|
@ -187,6 +199,10 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
|
||||||
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
||||||
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
|
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
|
||||||
|
|
||||||
|
jConfig[config_key::persistent_keep_alive] = "25";
|
||||||
|
QJsonArray allowedIps { "0.0.0.0/0", "::/0" };
|
||||||
|
jConfig[config_key::allowed_ips] = allowedIps;
|
||||||
|
|
||||||
jConfig[config_key::clientId] = connData.clientPubKey;
|
jConfig[config_key::clientId] = connData.clientPubKey;
|
||||||
|
|
||||||
return QJsonDocument(jConfig).toJson();
|
return QJsonDocument(jConfig).toJson();
|
||||||
|
|
|
||||||
|
|
@ -3,38 +3,169 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QUuid>
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "containers/containers_defs.h"
|
#include "containers/containers_defs.h"
|
||||||
#include "core/controllers/serverController.h"
|
#include "core/controllers/serverController.h"
|
||||||
#include "core/scripts_registry.h"
|
#include "core/scripts_registry.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Logger logger("XrayConfigurator");
|
||||||
|
}
|
||||||
|
|
||||||
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
|
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
|
||||||
: ConfiguratorBase(settings, serverController, parent)
|
: ConfiguratorBase(settings, serverController, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
|
QString XrayConfigurator::prepareServerConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||||
ErrorCode &errorCode)
|
const QJsonObject &containerConfig, ErrorCode &errorCode)
|
||||||
{
|
{
|
||||||
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
|
// Generate new UUID for client
|
||||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
QString clientId = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
|
|
||||||
QString xrayPublicKey =
|
// Get current server config
|
||||||
m_serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
|
QString currentConfig = m_serverController->getTextFileFromContainer(
|
||||||
xrayPublicKey.replace("\n", "");
|
container, credentials, amnezia::protocols::xray::serverConfigPath, errorCode);
|
||||||
|
|
||||||
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", "");
|
|
||||||
|
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
|
logger.error() << "Failed to get server config file";
|
||||||
return "";
|
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_PUBLIC_KEY", xrayPublicKey);
|
||||||
config.replace("$XRAY_SHORT_ID", xrayShortId);
|
config.replace("$XRAY_SHORT_ID", xrayShortId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ public:
|
||||||
|
|
||||||
QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
|
QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
|
||||||
ErrorCode &errorCode);
|
ErrorCode &errorCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString prepareServerConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
|
||||||
|
ErrorCode &errorCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // XRAY_CONFIGURATOR_H
|
#endif // XRAY_CONFIGURATOR_H
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#include "apiController.h"
|
#include "apiController.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
|
@ -11,6 +14,7 @@
|
||||||
#include "amnezia_application.h"
|
#include "amnezia_application.h"
|
||||||
#include "configurators/wireguard_configurator.h"
|
#include "configurators/wireguard_configurator.h"
|
||||||
#include "core/enums/apiEnums.h"
|
#include "core/enums/apiEnums.h"
|
||||||
|
#include "utilities.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
@ -33,6 +37,7 @@ namespace
|
||||||
constexpr char userCountryCode[] = "user_country_code";
|
constexpr char userCountryCode[] = "user_country_code";
|
||||||
constexpr char serverCountryCode[] = "server_country_code";
|
constexpr char serverCountryCode[] = "server_country_code";
|
||||||
constexpr char serviceType[] = "service_type";
|
constexpr char serviceType[] = "service_type";
|
||||||
|
constexpr char serviceInfo[] = "service_info";
|
||||||
|
|
||||||
constexpr char aesKey[] = "aes_key";
|
constexpr char aesKey[] = "aes_key";
|
||||||
constexpr char aesIv[] = "aes_iv";
|
constexpr char aesIv[] = "aes_iv";
|
||||||
|
|
@ -40,9 +45,12 @@ namespace
|
||||||
|
|
||||||
constexpr char apiPayload[] = "api_payload";
|
constexpr char apiPayload[] = "api_payload";
|
||||||
constexpr char keyPayload[] = "key_payload";
|
constexpr char keyPayload[] = "key_payload";
|
||||||
|
|
||||||
|
constexpr char apiConfig[] = "api_config";
|
||||||
|
constexpr char authData[] = "auth_data";
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList proxyStorageUrl = { "" };
|
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
|
||||||
|
|
||||||
ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
|
ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
|
|
@ -63,6 +71,28 @@ namespace
|
||||||
return ErrorCode::ApiConfigDownloadError;
|
return ErrorCode::ApiConfigDownloadError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key = "",
|
||||||
|
const QByteArray &iv = "", const QByteArray &salt = "")
|
||||||
|
{
|
||||||
|
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|
||||||
|
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
|
||||||
|
qDebug() << "Timeout occurred";
|
||||||
|
return true;
|
||||||
|
} else if (responseBody.contains("html")) {
|
||||||
|
qDebug() << "The response contains an html tag";
|
||||||
|
return true;
|
||||||
|
} else if (checkEncryption) {
|
||||||
|
try {
|
||||||
|
QSimpleCrypto::QBlockCipher blockCipher;
|
||||||
|
static_cast<void>(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
|
||||||
|
} catch (...) {
|
||||||
|
qDebug() << "Failed to decrypt the data";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
|
ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
|
||||||
|
|
@ -94,8 +124,8 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
|
||||||
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
|
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
|
||||||
} else if (protocol == configKey::awg) {
|
} else if (protocol == configKey::awg) {
|
||||||
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
||||||
auto serverConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
||||||
auto containers = serverConfig.value(config_key::containers).toArray();
|
auto containers = newServerConfig.value(config_key::containers).toArray();
|
||||||
if (containers.isEmpty()) {
|
if (containers.isEmpty()) {
|
||||||
return; // todo process error
|
return; // todo process error
|
||||||
}
|
}
|
||||||
|
|
@ -114,38 +144,57 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
|
||||||
containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
|
containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
|
||||||
container[containerName] = containerConfig;
|
container[containerName] = containerConfig;
|
||||||
containers.replace(0, container);
|
containers.replace(0, container);
|
||||||
serverConfig[config_key::containers] = containers;
|
newServerConfig[config_key::containers] = containers;
|
||||||
configStr = QString(QJsonDocument(serverConfig).toJson());
|
configStr = QString(QJsonDocument(newServerConfig).toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
|
||||||
serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
|
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
|
||||||
serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
|
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
|
||||||
serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
|
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
|
||||||
serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
|
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
|
||||||
|
|
||||||
if (apiConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
|
if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
|
||||||
serverConfig[config_key::configVersion] = apiConfig.value(config_key::configVersion);
|
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
|
||||||
serverConfig[config_key::description] = apiConfig.value(config_key::description);
|
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
|
||||||
serverConfig[config_key::name] = apiConfig.value(config_key::name);
|
serverConfig[config_key::name] = newServerConfig.value(config_key::name);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
|
auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
|
||||||
serverConfig[config_key::defaultContainer] = defaultContainer;
|
serverConfig[config_key::defaultContainer] = defaultContainer;
|
||||||
|
|
||||||
|
QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
|
||||||
|
map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
|
||||||
|
auto apiConfig = QJsonObject::fromVariantMap(map);
|
||||||
|
|
||||||
|
if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
|
||||||
|
apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConfig[configKey::apiConfig] = apiConfig;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ApiController::getProxyUrls()
|
QStringList ApiController::getProxyUrls()
|
||||||
{
|
{
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(7000);
|
request.setTransferTimeout(requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QList<QSslError> sslErrors;
|
QList<QSslError> sslErrors;
|
||||||
QNetworkReply *reply;
|
QNetworkReply *reply;
|
||||||
|
|
||||||
|
QStringList proxyStorageUrl;
|
||||||
|
if (m_isDevEnvironment) {
|
||||||
|
proxyStorageUrl = QStringList { DEV_S3_ENDPOINT };
|
||||||
|
} else {
|
||||||
|
proxyStorageUrl = QStringList { PROD_S3_ENDPOINT };
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
||||||
|
|
||||||
for (const auto &proxyStorageUrl : proxyStorageUrl) {
|
for (const auto &proxyStorageUrl : proxyStorageUrl) {
|
||||||
request.setUrl(proxyStorageUrl);
|
request.setUrl(proxyStorageUrl);
|
||||||
reply = amnApp->manager()->get(request);
|
reply = amnApp->manager()->get(request);
|
||||||
|
|
@ -166,11 +215,23 @@ QStringList ApiController::getProxyUrls()
|
||||||
EVP_PKEY *privateKey = nullptr;
|
EVP_PKEY *privateKey = nullptr;
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
try {
|
try {
|
||||||
QByteArray key = PROD_PROXY_STORAGE_KEY;
|
if (!m_isDevEnvironment) {
|
||||||
QSimpleCrypto::QRsa rsa;
|
QCryptographicHash hash(QCryptographicHash::Sha512);
|
||||||
privateKey = rsa.getPrivateKeyFromByteArray(key, "");
|
hash.addData(key);
|
||||||
responseBody = rsa.decrypt(encryptedResponseBody, privateKey, RSA_PKCS1_PADDING);
|
QByteArray hashResult = hash.result().toHex();
|
||||||
|
|
||||||
|
QByteArray key = QByteArray::fromHex(hashResult.left(64));
|
||||||
|
QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
|
||||||
|
|
||||||
|
QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
|
||||||
|
|
||||||
|
QSimpleCrypto::QBlockCipher blockCipher;
|
||||||
|
responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
|
||||||
|
} else {
|
||||||
|
responseBody = encryptedResponseBody;
|
||||||
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
Utils::logException();
|
||||||
qCritical() << "error loading private key from environment variables or decrypting payload";
|
qCritical() << "error loading private key from environment variables or decrypting payload";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -221,7 +282,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
|
||||||
|
|
||||||
if (serverConfig.value(config_key::configVersion).toInt()) {
|
if (serverConfig.value(config_key::configVersion).toInt()) {
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(7000);
|
request.setTransferTimeout(requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
|
request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
|
||||||
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
|
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
|
||||||
|
|
@ -277,7 +338,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(7000);
|
request.setTransferTimeout(requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
|
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
|
||||||
|
|
@ -292,40 +353,53 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
|
responseBody = reply->readAll();
|
||||||
|
|
||||||
|
if (sslErrors.isEmpty() && shouldBypassProxy(reply, responseBody, false)) {
|
||||||
m_proxyUrls = getProxyUrls();
|
m_proxyUrls = getProxyUrls();
|
||||||
|
std::random_device randomDevice;
|
||||||
|
std::mt19937 generator(randomDevice());
|
||||||
|
std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
|
||||||
for (const QString &proxyUrl : m_proxyUrls) {
|
for (const QString &proxyUrl : m_proxyUrls) {
|
||||||
|
qDebug() << "Go to the next endpoint";
|
||||||
request.setUrl(QString("%1v1/services").arg(proxyUrl));
|
request.setUrl(QString("%1v1/services").arg(proxyUrl));
|
||||||
|
reply->deleteLater(); // delete the previous reply
|
||||||
reply = amnApp->manager()->get(request);
|
reply = amnApp->manager()->get(request);
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
|
||||||
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
responseBody = reply->readAll();
|
||||||
|
if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBody = reply->readAll();
|
|
||||||
auto errorCode = checkErrors(sslErrors, reply);
|
auto errorCode = checkErrors(sslErrors, reply);
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
|
if (errorCode == ErrorCode::NoError) {
|
||||||
|
if (!responseBody.contains("services")) {
|
||||||
|
return ErrorCode::ApiServicesMissingError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode ApiController::getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
|
ErrorCode ApiController::getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig)
|
const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData,
|
||||||
|
QJsonObject &serverConfig)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_IOS
|
#ifdef Q_OS_IOS
|
||||||
IosController::Instance()->requestInetAccess();
|
IosController::Instance()->requestInetAccess();
|
||||||
QThread::msleep(10);
|
QThread::msleep(10);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QNetworkAccessManager manager;
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
request.setTransferTimeout(7000);
|
request.setTransferTimeout(requestTimeoutMsecs);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));
|
request.setUrl(QString("%1v1/config").arg(m_gatewayEndpoint));
|
||||||
|
|
@ -339,6 +413,9 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
||||||
}
|
}
|
||||||
apiPayload[configKey::serviceType] = serviceType;
|
apiPayload[configKey::serviceType] = serviceType;
|
||||||
apiPayload[configKey::uuid] = installationUuid;
|
apiPayload[configKey::uuid] = installationUuid;
|
||||||
|
if (!authData.isEmpty()) {
|
||||||
|
apiPayload[configKey::authData] = authData;
|
||||||
|
}
|
||||||
|
|
||||||
QSimpleCrypto::QBlockCipher blockCipher;
|
QSimpleCrypto::QBlockCipher blockCipher;
|
||||||
QByteArray key = blockCipher.generatePrivateSalt(32);
|
QByteArray key = blockCipher.generatePrivateSalt(32);
|
||||||
|
|
@ -357,10 +434,11 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
||||||
|
|
||||||
EVP_PKEY *publicKey = nullptr;
|
EVP_PKEY *publicKey = nullptr;
|
||||||
try {
|
try {
|
||||||
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
QByteArray rsaKey = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
||||||
QSimpleCrypto::QRsa rsa;
|
QSimpleCrypto::QRsa rsa;
|
||||||
publicKey = rsa.getPublicKeyFromByteArray(key);
|
publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
Utils::logException();
|
||||||
qCritical() << "error loading public key from environment variables";
|
qCritical() << "error loading public key from environment variables";
|
||||||
return ErrorCode::ApiMissingAgwPublicKey;
|
return ErrorCode::ApiMissingAgwPublicKey;
|
||||||
}
|
}
|
||||||
|
|
@ -370,14 +448,16 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
||||||
|
|
||||||
encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
|
encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
|
||||||
} catch (...) { // todo change error handling in QSimpleCrypto?
|
} catch (...) { // todo change error handling in QSimpleCrypto?
|
||||||
|
Utils::logException();
|
||||||
qCritical() << "error when encrypting the request body";
|
qCritical() << "error when encrypting the request body";
|
||||||
|
return ErrorCode::ApiConfigDecryptionError;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject requestBody;
|
QJsonObject requestBody;
|
||||||
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
|
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
|
||||||
requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
|
requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
|
||||||
|
|
||||||
QNetworkReply *reply = manager.post(request, QJsonDocument(requestBody).toJson());
|
QNetworkReply *reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
|
||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
|
|
@ -386,37 +466,43 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
|
auto encryptedResponseBody = reply->readAll();
|
||||||
if (m_proxyUrls.isEmpty()) {
|
|
||||||
|
if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
|
||||||
m_proxyUrls = getProxyUrls();
|
m_proxyUrls = getProxyUrls();
|
||||||
}
|
std::random_device randomDevice;
|
||||||
|
std::mt19937 generator(randomDevice());
|
||||||
|
std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
|
||||||
for (const QString &proxyUrl : m_proxyUrls) {
|
for (const QString &proxyUrl : m_proxyUrls) {
|
||||||
|
qDebug() << "Go to the next endpoint";
|
||||||
request.setUrl(QString("%1v1/config").arg(proxyUrl));
|
request.setUrl(QString("%1v1/config").arg(proxyUrl));
|
||||||
reply = manager.post(request, QJsonDocument(requestBody).toJson());
|
reply->deleteLater(); // delete the previous reply
|
||||||
|
reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
|
||||||
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
encryptedResponseBody = reply->readAll();
|
||||||
|
if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto errorCode = checkErrors(sslErrors, reply);
|
auto errorCode = checkErrors(sslErrors, reply);
|
||||||
|
reply->deleteLater();
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto encryptedResponseBody = reply->readAll();
|
|
||||||
reply->deleteLater();
|
|
||||||
try {
|
try {
|
||||||
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
|
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
|
||||||
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
|
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
|
||||||
} catch (...) { // todo change error handling in QSimpleCrypto?
|
} catch (...) { // todo change error handling in QSimpleCrypto?
|
||||||
|
Utils::logException();
|
||||||
qCritical() << "error when decrypting the request body";
|
qCritical() << "error when decrypting the request body";
|
||||||
|
return ErrorCode::ApiConfigDecryptionError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorCode;
|
return errorCode;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public slots:
|
||||||
|
|
||||||
ErrorCode getServicesList(QByteArray &responseBody);
|
ErrorCode getServicesList(QByteArray &responseBody);
|
||||||
ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
|
ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
|
||||||
const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig);
|
const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData, QJsonObject &serverConfig);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccurred(ErrorCode errorCode);
|
void errorOccurred(ErrorCode errorCode);
|
||||||
|
|
@ -44,7 +44,7 @@ private:
|
||||||
|
|
||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
QStringList m_proxyUrls;
|
QStringList m_proxyUrls;
|
||||||
bool m_isDevEnvironment;
|
bool m_isDevEnvironment = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APICONTROLLER_H
|
#endif // APICONTROLLER_H
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,8 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
|
||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
QString runner = QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash"));
|
QString runner =
|
||||||
|
QString("sudo docker exec -i $CONTAINER_NAME %2 %1 ").arg(fileName, (container == DockerContainer::Socks5Proxy ? "sh" : "bash"));
|
||||||
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||||
|
|
||||||
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
|
||||||
|
|
@ -435,7 +436,8 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
errorCode = runScript(credentials,
|
errorCode =
|
||||||
|
runScript(credentials,
|
||||||
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
|
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
|
||||||
cbReadStdOut);
|
cbReadStdOut);
|
||||||
if (errorCode)
|
if (errorCode)
|
||||||
|
|
@ -625,7 +627,9 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
||||||
vars.append({ { "$SOCKS5_USER", socks5user } });
|
vars.append({ { "$SOCKS5_USER", socks5user } });
|
||||||
vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
|
vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
|
||||||
|
|
||||||
QString serverIp = NetworkUtilities::getIPAddress(credentials.hostName);
|
QString serverIp = (container != DockerContainer::Awg && container != DockerContainer::WireGuard && container != DockerContainer::Xray)
|
||||||
|
? NetworkUtilities::getIPAddress(credentials.hostName)
|
||||||
|
: credentials.hostName;
|
||||||
if (!serverIp.isEmpty()) {
|
if (!serverIp.isEmpty()) {
|
||||||
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
|
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -711,7 +715,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
||||||
udpProtoScript.append("' | grep -i udp");
|
udpProtoScript.append("' | grep -i udp");
|
||||||
tcpProtoScript.append(" | grep LISTEN");
|
tcpProtoScript.append(" | grep LISTEN");
|
||||||
|
|
||||||
ErrorCode errorCode = runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
ErrorCode errorCode =
|
||||||
|
runScript(credentials, replaceVars(tcpProtoScript, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,13 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QStr
|
||||||
protocolConfigString = configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
|
protocolConfigString = configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
|
||||||
|
|
||||||
QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
||||||
vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
if (container == DockerContainer::Awg || container == DockerContainer::WireGuard) {
|
||||||
|
// add mtu for old configs
|
||||||
|
if (vpnConfigData[config_key::mtu].toString().isEmpty()) {
|
||||||
|
vpnConfigData[config_key::mtu] = container == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData);
|
vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ namespace amnezia
|
||||||
|
|
||||||
// import and install errors
|
// import and install errors
|
||||||
ImportInvalidConfigError = 900,
|
ImportInvalidConfigError = 900,
|
||||||
|
ImportOpenConfigError = 901,
|
||||||
|
|
||||||
// Android errors
|
// Android errors
|
||||||
AndroidError = 1000,
|
AndroidError = 1000,
|
||||||
|
|
@ -107,6 +108,8 @@ namespace amnezia
|
||||||
ApiConfigTimeoutError = 1103,
|
ApiConfigTimeoutError = 1103,
|
||||||
ApiConfigSslError = 1104,
|
ApiConfigSslError = 1104,
|
||||||
ApiMissingAgwPublicKey = 1105,
|
ApiMissingAgwPublicKey = 1105,
|
||||||
|
ApiConfigDecryptionError = 1106,
|
||||||
|
ApiServicesMissingError = 1107,
|
||||||
|
|
||||||
// QFile errors
|
// QFile errors
|
||||||
OpenError = 1200,
|
OpenError = 1200,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ QString errorString(ErrorCode code) {
|
||||||
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
|
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
|
||||||
|
|
||||||
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
|
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
|
||||||
|
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
|
||||||
|
|
||||||
// Android errors
|
// Android errors
|
||||||
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
|
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
|
||||||
|
|
@ -61,6 +62,8 @@ QString errorString(ErrorCode code) {
|
||||||
case (ErrorCode::ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break;
|
case (ErrorCode::ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break;
|
||||||
case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
|
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::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
|
// QFile errors
|
||||||
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
|
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,12 @@ QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
|
||||||
return Instance()->m_ipcClient;
|
return Instance()->m_ipcClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
|
||||||
|
{
|
||||||
|
if (!Instance()) return nullptr;
|
||||||
|
return Instance()->m_Tun2SocksClient;
|
||||||
|
}
|
||||||
|
|
||||||
bool IpcClient::init(IpcClient *instance)
|
bool IpcClient::init(IpcClient *instance)
|
||||||
{
|
{
|
||||||
m_instance = instance;
|
m_instance = instance;
|
||||||
|
|
@ -44,6 +50,12 @@ bool IpcClient::init(IpcClient *instance)
|
||||||
qWarning() << "IpcClient replica is not connected!";
|
qWarning() << "IpcClient replica is not connected!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instance()->m_Tun2SocksClient.reset(Instance()->m_ClientNode.acquire<IpcProcessTun2SocksReplica>());
|
||||||
|
Instance()->m_Tun2SocksClient->waitForSource(1000);
|
||||||
|
|
||||||
|
if (!Instance()->m_Tun2SocksClient->isReplicaValid()) {
|
||||||
|
qWarning() << "IpcClient::m_Tun2SocksClient replica is not connected!";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
|
connect(Instance()->m_localSocket, &QLocalSocket::disconnected, [instance](){
|
||||||
|
|
@ -51,16 +63,16 @@ bool IpcClient::init(IpcClient *instance)
|
||||||
});
|
});
|
||||||
|
|
||||||
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
|
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
|
||||||
|
|
||||||
Instance()->m_localSocket->waitForConnected();
|
Instance()->m_localSocket->waitForConnected();
|
||||||
|
|
||||||
if (!Instance()->m_ipcClient) {
|
if (!Instance()->m_ipcClient) {
|
||||||
qDebug() << "IpcClient::init failed";
|
qDebug() << "IpcClient::init failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "IpcClient::init succeed";
|
qDebug() << "IpcClient::init succeed";
|
||||||
|
|
||||||
return Instance()->m_ipcClient->isReplicaValid();
|
return (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "rep_ipc_interface_replica.h"
|
#include "rep_ipc_interface_replica.h"
|
||||||
|
#include "rep_ipc_process_tun2socks_replica.h"
|
||||||
|
|
||||||
#include "privileged_process.h"
|
#include "privileged_process.h"
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ public:
|
||||||
static IpcClient *Instance();
|
static IpcClient *Instance();
|
||||||
static bool init(IpcClient *instance);
|
static bool init(IpcClient *instance);
|
||||||
static QSharedPointer<IpcInterfaceReplica> Interface();
|
static QSharedPointer<IpcInterfaceReplica> Interface();
|
||||||
|
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
|
||||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||||
|
|
||||||
bool isSocketConnected() const;
|
bool isSocketConnected() const;
|
||||||
|
|
@ -28,8 +30,11 @@ private:
|
||||||
~IpcClient() override;
|
~IpcClient() override;
|
||||||
|
|
||||||
QRemoteObjectNode m_ClientNode;
|
QRemoteObjectNode m_ClientNode;
|
||||||
|
QRemoteObjectNode m_Tun2SocksNode;
|
||||||
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
|
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
|
||||||
QPointer<QLocalSocket> m_localSocket;
|
QPointer<QLocalSocket> m_localSocket;
|
||||||
|
QPointer<QLocalSocket> m_tun2socksSocket;
|
||||||
|
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;
|
||||||
|
|
||||||
struct ProcessDescriptor {
|
struct ProcessDescriptor {
|
||||||
ProcessDescriptor () {
|
ProcessDescriptor () {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,10 @@ QStringList NetworkUtilities::summarizeRoutes(const QStringList &ips, const QStr
|
||||||
|
|
||||||
QString NetworkUtilities::getIPAddress(const QString &host)
|
QString NetworkUtilities::getIPAddress(const QString &host)
|
||||||
{
|
{
|
||||||
if (ipAddressRegExp().match(host).hasMatch()) {
|
QHostAddress address(host);
|
||||||
|
if (QAbstractSocket::IPv4Protocol == address.protocol()) {
|
||||||
|
return host;
|
||||||
|
} else if (QAbstractSocket::IPv6Protocol == address.protocol()) {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
|
if (!dnsutils()->restoreResolvers()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,10 +165,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
|
bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
|
||||||
if (!supportDnsUtils()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
|
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
|
||||||
(config.m_hopType == InterfaceConfig::SingleHop)) {
|
(config.m_hopType == InterfaceConfig::SingleHop)) {
|
||||||
QList<QHostAddress> resolvers;
|
QList<QHostAddress> resolvers;
|
||||||
|
|
@ -423,13 +419,8 @@ bool Daemon::deactivate(bool emitSignals) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup DNS
|
// Cleanup DNS
|
||||||
if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
|
if (!dnsutils()->restoreResolvers()) {
|
||||||
return false;
|
logger.warning() << "Failed to restore DNS resolvers.";
|
||||||
}
|
|
||||||
|
|
||||||
if (!wgutils()->interfaceExists()) {
|
|
||||||
logger.warning() << "Wireguard interface does not exist.";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup peers and routing
|
// Cleanup peers and routing
|
||||||
|
|
@ -449,13 +440,9 @@ bool Daemon::deactivate(bool emitSignals) {
|
||||||
}
|
}
|
||||||
m_excludedAddrSet.clear();
|
m_excludedAddrSet.clear();
|
||||||
|
|
||||||
// Delete the interface
|
|
||||||
if (!wgutils()->deleteInterface()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_connections.clear();
|
m_connections.clear();
|
||||||
return true;
|
// Delete the interface
|
||||||
|
return wgutils()->deleteInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Daemon::logs() {
|
QString Daemon::logs() {
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ class Daemon : public QObject {
|
||||||
virtual WireguardUtils* wgutils() const = 0;
|
virtual WireguardUtils* wgutils() const = 0;
|
||||||
virtual bool supportIPUtils() const { return false; }
|
virtual bool supportIPUtils() const { return false; }
|
||||||
virtual IPUtils* iputils() { return nullptr; }
|
virtual IPUtils* iputils() { return nullptr; }
|
||||||
virtual bool supportDnsUtils() const { return false; }
|
|
||||||
virtual DnsUtils* dnsutils() { return nullptr; }
|
virtual DnsUtils* dnsutils() { return nullptr; }
|
||||||
|
|
||||||
static bool parseStringList(const QJsonObject& obj, const QString& name,
|
static bool parseStringList(const QJsonObject& obj, const QString& name,
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,17 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
|
||||||
|
|
||||||
logger.debug() << "Command received:" << type;
|
logger.debug() << "Command received:" << type;
|
||||||
|
|
||||||
|
// It is expected that sometimes the client will request backend logs
|
||||||
|
// before the first authentication. In these cases we just return empty
|
||||||
|
// logs.
|
||||||
|
if (type == "logs") {
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert("type", "logs");
|
||||||
|
obj.insert("logs", "");
|
||||||
|
write(obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == "activate") {
|
if (type == "activate") {
|
||||||
InterfaceConfig config;
|
InterfaceConfig config;
|
||||||
if (!Daemon::parseConfig(obj, config)) {
|
if (!Daemon::parseConfig(obj, config)) {
|
||||||
|
|
@ -115,8 +126,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
|
||||||
if (type == "status") {
|
if (type == "status") {
|
||||||
QJsonObject obj = Daemon::instance()->getStatus();
|
QJsonObject obj = Daemon::instance()->getStatus();
|
||||||
obj.insert("type", "status");
|
obj.insert("type", "status");
|
||||||
m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
write(obj);
|
||||||
m_socket->write("\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,8 +134,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj.insert("type", "logs");
|
obj.insert("type", "logs");
|
||||||
obj.insert("logs", Daemon::instance()->logs().replace("\n", "|"));
|
obj.insert("logs", Daemon::instance()->logs().replace("\n", "|"));
|
||||||
m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
|
write(obj);
|
||||||
m_socket->write("\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,24 @@
|
||||||
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
#include "platforms/ios/QtAppDelegate-C-Interface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
|
bool isAnotherInstanceRunning()
|
||||||
|
{
|
||||||
|
QLocalSocket socket;
|
||||||
|
socket.connectToServer("AmneziaVPNInstance");
|
||||||
|
if (socket.waitForConnected(500)) {
|
||||||
|
qWarning() << "AmneziaVPN is already running";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Migrations migrationsManager;
|
Migrations migrationsManager;
|
||||||
migrationsManager.doMigrations();
|
migrationsManager.doMigrations();
|
||||||
|
|
||||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
AllowSetForegroundWindow(ASFW_ANY);
|
AllowSetForegroundWindow(ASFW_ANY);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -32,16 +43,14 @@ int main(int argc, char *argv[])
|
||||||
qputenv("ANDROID_OPENSSL_SUFFIX", "_3");
|
qputenv("ANDROID_OPENSSL_SUFFIX", "_3");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
|
||||||
AmneziaApplication app(argc, argv);
|
AmneziaApplication app(argc, argv);
|
||||||
#else
|
|
||||||
AmneziaApplication app(argc, argv, true,
|
|
||||||
SingleApplication::Mode::User | SingleApplication::Mode::SecondaryNotification);
|
|
||||||
|
|
||||||
if (!app.isPrimary()) {
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
|
if (isAnotherInstanceRunning()) {
|
||||||
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
QTimer::singleShot(1000, &app, [&]() { app.quit(); });
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
app.startLocalServer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allow to raise app window if secondary instance launched
|
// Allow to raise app window if secondary instance launched
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ LocalSocketController::LocalSocketController() {
|
||||||
connect(m_socket, &QLocalSocket::connected, this,
|
connect(m_socket, &QLocalSocket::connected, this,
|
||||||
&LocalSocketController::daemonConnected);
|
&LocalSocketController::daemonConnected);
|
||||||
connect(m_socket, &QLocalSocket::disconnected, this,
|
connect(m_socket, &QLocalSocket::disconnected, this,
|
||||||
&LocalSocketController::disconnected);
|
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
|
||||||
connect(m_socket, &QLocalSocket::errorOccurred, this,
|
connect(m_socket, &QLocalSocket::errorOccurred, this,
|
||||||
&LocalSocketController::errorOccurred);
|
&LocalSocketController::errorOccurred);
|
||||||
connect(m_socket, &QLocalSocket::readyRead, this,
|
connect(m_socket, &QLocalSocket::readyRead, this,
|
||||||
|
|
@ -149,7 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||||
QJsonArray jsAllowedIPAddesses;
|
QJsonArray jsAllowedIPAddesses;
|
||||||
|
|
||||||
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
|
QJsonArray plainAllowedIP = wgConfig.value(amnezia::config_key::allowed_ips).toArray();
|
||||||
QJsonArray defaultAllowedIP = QJsonArray::fromStringList(QString("0.0.0.0/0, ::/0").split(","));
|
QJsonArray defaultAllowedIP = { "0.0.0.0/0", "::/0" };
|
||||||
|
|
||||||
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
|
if (plainAllowedIP != defaultAllowedIP && !plainAllowedIP.isEmpty()) {
|
||||||
// Use AllowedIP list from WG config because of higher priority
|
// Use AllowedIP list from WG config because of higher priority
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,6 @@ void IosController::vpnStatusDidChange(void *pNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
qDebug() << "Disconnect error is absent";
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -501,6 +499,20 @@ bool IosController::setupWireGuard()
|
||||||
wgConfig.insert(config_key::persistent_keep_alive, "25");
|
wgConfig.insert(config_key::persistent_keep_alive, "25");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.contains(config_key::isObfuscationEnabled) && config.value(config_key::isObfuscationEnabled).toBool()) {
|
||||||
|
wgConfig.insert(config_key::initPacketMagicHeader, config[config_key::initPacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::responsePacketMagicHeader, config[config_key::responsePacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::underloadPacketMagicHeader, config[config_key::underloadPacketMagicHeader]);
|
||||||
|
wgConfig.insert(config_key::transportPacketMagicHeader, config[config_key::transportPacketMagicHeader]);
|
||||||
|
|
||||||
|
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||||
|
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
|
||||||
|
|
||||||
|
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
|
||||||
|
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||||
|
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
|
||||||
|
}
|
||||||
|
|
||||||
QJsonDocument wgConfigDoc(wgConfig);
|
QJsonDocument wgConfigDoc(wgConfig);
|
||||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||||
|
|
||||||
|
|
@ -835,7 +847,7 @@ QString IosController::openFile() {
|
||||||
|
|
||||||
void IosController::requestInetAccess() {
|
void IosController::requestInetAccess() {
|
||||||
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
|
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
|
||||||
if (url) {
|
if (!url) {
|
||||||
qDebug() << "IosController::requestInetAccess URL error";
|
qDebug() << "IosController::requestInetAccess URL error";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -847,7 +859,6 @@ void IosController::requestInetAccess() {
|
||||||
} else {
|
} else {
|
||||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||||
QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length);
|
QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length);
|
||||||
qDebug() << "IosController::requestInetAccess server response:" << httpResponse.statusCode << "\n\n" <<responseBody;
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
[task resume];
|
[task resume];
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ class LinuxDaemon final : public Daemon {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
WireguardUtils* wgutils() const override { return m_wgutils; }
|
WireguardUtils* wgutils() const override { return m_wgutils; }
|
||||||
bool supportDnsUtils() const override { return true; }
|
|
||||||
DnsUtils* dnsutils() override { return m_dnsutils; }
|
DnsUtils* dnsutils() override { return m_dnsutils; }
|
||||||
bool supportIPUtils() const override { return true; }
|
bool supportIPUtils() const override { return true; }
|
||||||
IPUtils* iputils() override { return m_iputils; }
|
IPUtils* iputils() override { return m_iputils; }
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ class MacOSDaemon final : public Daemon {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
WireguardUtils* wgutils() const override { return m_wgutils; }
|
WireguardUtils* wgutils() const override { return m_wgutils; }
|
||||||
bool supportDnsUtils() const override { return true; }
|
|
||||||
DnsUtils* dnsutils() override { return m_dnsutils; }
|
DnsUtils* dnsutils() override { return m_dnsutils; }
|
||||||
bool supportIPUtils() const override { return true; }
|
bool supportIPUtils() const override { return true; }
|
||||||
IPUtils* iputils() override { return m_iputils; }
|
IPUtils* iputils() override { return m_iputils; }
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ class WindowsDaemon final : public Daemon {
|
||||||
protected:
|
protected:
|
||||||
bool run(Op op, const InterfaceConfig& config) override;
|
bool run(Op op, const InterfaceConfig& config) override;
|
||||||
WireguardUtils* wgutils() const override { return m_wgutils; }
|
WireguardUtils* wgutils() const override { return m_wgutils; }
|
||||||
bool supportDnsUtils() const override { return true; }
|
|
||||||
DnsUtils* dnsutils() override { return m_dnsutils; }
|
DnsUtils* dnsutils() override { return m_dnsutils; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -502,7 +502,7 @@ QString WindowsSplitTunnel::convertPath(const QString& path) {
|
||||||
// device should contain : for e.g C:
|
// device should contain : for e.g C:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
QByteArray buffer(2048, 0xFF);
|
QByteArray buffer(2048, 0xFFu);
|
||||||
auto ok = QueryDosDeviceW(qUtf16Printable(driveLetter),
|
auto ok = QueryDosDeviceW(qUtf16Printable(driveLetter),
|
||||||
(wchar_t*)buffer.data(), buffer.size() / 2);
|
(wchar_t*)buffer.data(), buffer.size() / 2);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
|
||||||
}
|
}
|
||||||
if (result != NO_ERROR) {
|
if (result != NO_ERROR) {
|
||||||
logger.error() << "Failed to create route to"
|
logger.error() << "Failed to create route to"
|
||||||
<< logger.sensitive(prefix.toString())
|
<< prefix.toString()
|
||||||
<< "result:" << result;
|
<< "result:" << result;
|
||||||
}
|
}
|
||||||
return result == NO_ERROR;
|
return result == NO_ERROR;
|
||||||
|
|
@ -265,7 +265,7 @@ bool WireguardUtilsWindows::deleteRoutePrefix(const IPAddress& prefix) {
|
||||||
}
|
}
|
||||||
if (result != NO_ERROR) {
|
if (result != NO_ERROR) {
|
||||||
logger.error() << "Failed to delete route to"
|
logger.error() << "Failed to delete route to"
|
||||||
<< logger.sensitive(prefix.toString())
|
<< prefix.toString()
|
||||||
<< "result:" << result;
|
<< "result:" << result;
|
||||||
}
|
}
|
||||||
return result == NO_ERROR;
|
return result == NO_ERROR;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#include "platforms/windows/windowsutils.h"
|
#include "platforms/windows/windowsutils.h"
|
||||||
|
|
||||||
constexpr const char* VPN_NAME = "AmneziaVPN";
|
constexpr const char* VPN_NAME = "AmneziaVPN";
|
||||||
constexpr const char* WIREGUARD_DIR = "WireGuard";
|
constexpr const char* WIREGUARD_DIR = "AmneziaWG";
|
||||||
constexpr const char* DATA_DIR = "Data";
|
constexpr const char* DATA_DIR = "Data";
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
|
||||||
|
#include "core/networkUtilities.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "openvpnprotocol.h"
|
#include "openvpnprotocol.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
@ -127,7 +128,6 @@ void OpenVpnProtocol::sendManagementCommand(const QString &command)
|
||||||
|
|
||||||
uint OpenVpnProtocol::selectMgmtPort()
|
uint OpenVpnProtocol::selectMgmtPort()
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
quint32 port = QRandomGenerator::global()->generate();
|
quint32 port = QRandomGenerator::global()->generate();
|
||||||
port = (double)(65000 - 15001) * port / UINT32_MAX + 15001;
|
port = (double)(65000 - 15001) * port / UINT32_MAX + 15001;
|
||||||
|
|
@ -137,7 +137,6 @@ uint OpenVpnProtocol::selectMgmtPort()
|
||||||
if (ok)
|
if (ok)
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_managementPort;
|
return m_managementPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,7 +342,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||||
}
|
}
|
||||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||||
m_configData.insert("vpnServer", m_configData.value(amnezia::config_key::hostName).toString());
|
m_configData.insert("vpnServer",
|
||||||
|
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
|
||||||
IpcClient::Interface()->enablePeerTraffic(m_configData);
|
IpcClient::Interface()->enablePeerTraffic(m_configData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,6 +352,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
m_configData.insert("vpnServer",
|
||||||
|
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ namespace amnezia
|
||||||
constexpr char last_config[] = "last_config";
|
constexpr char last_config[] = "last_config";
|
||||||
|
|
||||||
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
|
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
|
||||||
|
constexpr char isObfuscationEnabled[] = "isObfuscationEnabled";
|
||||||
|
|
||||||
constexpr char junkPacketCount[] = "Jc";
|
constexpr char junkPacketCount[] = "Jc";
|
||||||
constexpr char junkPacketMinSize[] = "Jmin";
|
constexpr char junkPacketMinSize[] = "Jmin";
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
#include "logger.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
#include "wireguardprotocol.h"
|
#include "wireguardprotocol.h"
|
||||||
|
#include "core/networkUtilities.h"
|
||||||
|
|
||||||
#include "mozilla/localsocketcontroller.h"
|
#include "mozilla/localsocketcontroller.h"
|
||||||
|
|
||||||
|
|
@ -37,6 +36,12 @@ void WireguardProtocol::stop()
|
||||||
|
|
||||||
ErrorCode WireguardProtocol::startMzImpl()
|
ErrorCode WireguardProtocol::startMzImpl()
|
||||||
{
|
{
|
||||||
|
QString protocolName = m_rawConfig.value("protocol").toString();
|
||||||
|
QJsonObject vpnConfigData = m_rawConfig.value(protocolName + "_config_data").toObject();
|
||||||
|
vpnConfigData[config_key::hostName] = NetworkUtilities::getIPAddress(vpnConfigData.value(config_key::hostName).toString());
|
||||||
|
m_rawConfig.insert(protocolName + "_config_data", vpnConfigData);
|
||||||
|
m_rawConfig[config_key::hostName] = NetworkUtilities::getIPAddress(m_rawConfig[config_key::hostName].toString());
|
||||||
|
|
||||||
m_impl->activate(m_rawConfig);
|
m_impl->activate(m_rawConfig);
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
76
client/protocols/xrayprotocol.cpp
Normal file → Executable file
76
client/protocols/xrayprotocol.cpp
Normal file → Executable file
|
|
@ -17,6 +17,7 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent):
|
||||||
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||||
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
||||||
|
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
||||||
}
|
}
|
||||||
|
|
||||||
XrayProtocol::~XrayProtocol()
|
XrayProtocol::~XrayProtocol()
|
||||||
|
|
@ -43,7 +44,9 @@ ErrorCode XrayProtocol::start()
|
||||||
m_xrayCfgFile.setAutoRemove(false);
|
m_xrayCfgFile.setAutoRemove(false);
|
||||||
#endif
|
#endif
|
||||||
m_xrayCfgFile.open();
|
m_xrayCfgFile.open();
|
||||||
m_xrayCfgFile.write(QJsonDocument(m_xrayConfig).toJson());
|
QString config = QJsonDocument(m_xrayConfig).toJson();
|
||||||
|
config.replace(m_remoteHost, m_remoteAddress);
|
||||||
|
m_xrayCfgFile.write(config.toUtf8());
|
||||||
m_xrayCfgFile.close();
|
m_xrayCfgFile.close();
|
||||||
|
|
||||||
QStringList args = QStringList() << "-c" << m_xrayCfgFile.fileName() << "-format=json";
|
QStringList args = QStringList() << "-c" << m_xrayCfgFile.fileName() << "-format=json";
|
||||||
|
|
@ -63,7 +66,7 @@ ErrorCode XrayProtocol::start()
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
connect(&m_xrayProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
qDebug().noquote() << "XrayProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
|
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
if (exitStatus != QProcess::NormalExit) {
|
if (exitStatus != QProcess::NormalExit) {
|
||||||
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
|
||||||
|
|
@ -89,63 +92,32 @@ ErrorCode XrayProtocol::start()
|
||||||
|
|
||||||
ErrorCode XrayProtocol::startTun2Sock()
|
ErrorCode XrayProtocol::startTun2Sock()
|
||||||
{
|
{
|
||||||
if (!QFileInfo::exists(Utils::tun2socksPath())) {
|
m_t2sProcess->start();
|
||||||
setLastError(ErrorCode::Tun2SockExecutableMissing);
|
|
||||||
return lastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_t2sProcess = IpcClient::CreatePrivilegedProcess();
|
|
||||||
|
|
||||||
if (!m_t2sProcess) {
|
|
||||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_t2sProcess->waitForSource(1000);
|
|
||||||
if (!m_t2sProcess->isInitialized()) {
|
|
||||||
qWarning() << "IpcProcess replica is not connected!";
|
|
||||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString XrayConStr = "socks5://127.0.0.1:" + QString::number(m_localPort);
|
|
||||||
|
|
||||||
m_t2sProcess->setProgram(PermittedProcess::Tun2Socks);
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
|
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
|
||||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up",
|
|
||||||
QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255").arg(amnezia::protocols::xray::defaultLocalAddr)});
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr});
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
QStringList arguments({"-device", "utun22", "-proxy", XrayConStr});
|
|
||||||
#endif
|
|
||||||
m_t2sProcess->setArguments(arguments);
|
|
||||||
|
|
||||||
qDebug() << arguments.join(" ");
|
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::stateChanged, this,
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::errorOccurred,
|
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
|
||||||
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
|
|
||||||
|
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::stateChanged,
|
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this,
|
||||||
[&](QProcess::ProcessState newState) {
|
[&](int vpnState) {
|
||||||
qDebug() << "PrivilegedProcess stateChanged" << newState;
|
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
|
||||||
if (newState == QProcess::Running)
|
if (vpnState == Vpn::ConnectionState::Connected)
|
||||||
{
|
{
|
||||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
QList<QHostAddress> dnsAddr;
|
QList<QHostAddress> dnsAddr;
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
||||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QThread::msleep(8000);
|
||||||
|
#endif
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
QThread::msleep(5000);
|
QThread::msleep(5000);
|
||||||
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
|
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
|
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
QThread::msleep(15000);
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QThread::msleep(1000);
|
QThread::msleep(1000);
|
||||||
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
|
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
|
||||||
|
|
@ -154,6 +126,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||||
// killSwitch toggle
|
// killSwitch toggle
|
||||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||||
|
m_configData.insert("vpnServer", m_remoteAddress);
|
||||||
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -184,21 +157,15 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||||
#endif
|
#endif
|
||||||
setConnectionState(Vpn::ConnectionState::Connected);
|
setConnectionState(Vpn::ConnectionState::Connected);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(Q_OS_MACOS)
|
#if !defined(Q_OS_MACOS)
|
||||||
connect(m_t2sProcess.data(), &PrivilegedProcess::finished, this,
|
if (vpnState == Vpn::ConnectionState::Disconnected) {
|
||||||
[&]() {
|
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
IpcClient::Interface()->deleteTun("tun2");
|
IpcClient::Interface()->deleteTun("tun2");
|
||||||
IpcClient::Interface()->StartRoutingIpv6();
|
IpcClient::Interface()->StartRoutingIpv6();
|
||||||
IpcClient::Interface()->clearSavedRoutes();
|
IpcClient::Interface()->clearSavedRoutes();
|
||||||
});
|
}
|
||||||
#endif
|
#endif
|
||||||
|
});
|
||||||
m_t2sProcess->start();
|
|
||||||
|
|
||||||
|
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +179,7 @@ void XrayProtocol::stop()
|
||||||
qDebug() << "XrayProtocol::stop()";
|
qDebug() << "XrayProtocol::stop()";
|
||||||
m_xrayProcess.terminate();
|
m_xrayProcess.terminate();
|
||||||
if (m_t2sProcess) {
|
if (m_t2sProcess) {
|
||||||
m_t2sProcess->close();
|
m_t2sProcess->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
@ -238,7 +205,8 @@ void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
||||||
}
|
}
|
||||||
m_xrayConfig = xrayConfiguration;
|
m_xrayConfig = xrayConfiguration;
|
||||||
m_localPort = QString(amnezia::protocols::xray::defaultLocalProxyPort).toInt();
|
m_localPort = QString(amnezia::protocols::xray::defaultLocalProxyPort).toInt();
|
||||||
m_remoteAddress = configuration.value(amnezia::config_key::hostName).toString();
|
m_remoteHost = configuration.value(amnezia::config_key::hostName).toString();
|
||||||
|
m_remoteAddress = NetworkUtilities::getIPAddress(m_remoteHost);
|
||||||
m_routeMode = configuration.value(amnezia::config_key::splitTunnelType).toInt();
|
m_routeMode = configuration.value(amnezia::config_key::splitTunnelType).toInt();
|
||||||
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
||||||
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ private:
|
||||||
static QString tun2SocksExecPath();
|
static QString tun2SocksExecPath();
|
||||||
private:
|
private:
|
||||||
int m_localPort;
|
int m_localPort;
|
||||||
|
QString m_remoteHost;
|
||||||
QString m_remoteAddress;
|
QString m_remoteAddress;
|
||||||
int m_routeMode;
|
int m_routeMode;
|
||||||
QJsonObject m_configData;
|
QJsonObject m_configData;
|
||||||
|
|
@ -33,9 +34,10 @@ private:
|
||||||
QString m_secondaryDNS;
|
QString m_secondaryDNS;
|
||||||
#ifndef Q_OS_IOS
|
#ifndef Q_OS_IOS
|
||||||
QProcess m_xrayProcess;
|
QProcess m_xrayProcess;
|
||||||
QSharedPointer<PrivilegedProcess> m_t2sProcess;
|
QSharedPointer<IpcProcessTun2SocksReplica> m_t2sProcess;
|
||||||
#endif
|
#endif
|
||||||
QTemporaryFile m_xrayCfgFile;
|
QTemporaryFile m_xrayCfgFile;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // XRAYPROTOCOL_H
|
#endif // XRAYPROTOCOL_H
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,8 @@
|
||||||
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
<file>server_scripts/socks5_proxy/configure_container.sh</file>
|
||||||
<file>server_scripts/socks5_proxy/start.sh</file>
|
<file>server_scripts/socks5_proxy/start.sh</file>
|
||||||
<file>server_scripts/ipsec/template.conf</file>
|
<file>server_scripts/ipsec/template.conf</file>
|
||||||
|
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
|
||||||
|
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
|
||||||
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
|
||||||
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
|
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
|
||||||
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
|
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,5 @@ sudo docker network connect amnezia-dns-net $CONTAINER_NAME
|
||||||
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
|
||||||
|
|
||||||
# Prevent to route packets outside of the container in case if server behind of the NAT
|
# Prevent to route packets outside of the container in case if server behind of the NAT
|
||||||
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
|
#sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
|
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
|
||||||
|
|
||||||
echo "Container startup"
|
echo "Container startup"
|
||||||
ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up
|
#ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up
|
||||||
|
|
||||||
iptables -A INPUT -i lo -j ACCEPT
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ private:
|
||||||
mutable SecureQSettings m_settings;
|
mutable SecureQSettings m_settings;
|
||||||
|
|
||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
bool m_isDevGatewayEnv;
|
bool m_isDevGatewayEnv = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation>شبكة VPN كلاسيكية للعمل المريح وتنزيل الملفات الكبيرة ومشاهدة مقاطع الفيديو. تعمل مع أي موقع. تصل السرعة إلى %1 ميجابت/ثانية</translation>
|
<translation>شبكة VPN كلاسيكية للعمل المريح وتنزيل الملفات الكبيرة ومشاهدة مقاطع الفيديو. تعمل مع أي موقع. تصل السرعة إلى %1 ميجابت/ثانية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation>شبكة VPN للولوج للمواقع المحظورة في بلاد ذو مستوي عالي من الرقابة علي الانترنت. </translation>
|
<translation>شبكة VPN للولوج للمواقع المحظورة في بلاد ذو مستوي عالي من الرقابة علي الانترنت. </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation>Amenzia Premium - شبكة VPN للعمل المريح, تحميل ملفات كبيرة الحجم, ومشاهدة مقاطع الفيديو ب جودة عالية. تعمل لجميع المواقع, حتي في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
|
<translation>Amenzia Premium - شبكة VPN للعمل المريح, تحميل ملفات كبيرة الحجم, ومشاهدة مقاطع الفيديو ب جودة عالية. تعمل لجميع المواقع, حتي في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation>Amnezia Free هو VPN مجاني لتخطي الحظر في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
|
<translation>Amnezia Free هو VPN مجاني لتخطي الحظر في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation>%1 ميجابت/ثانية</translation>
|
<translation>%1 ميجابت/ثانية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation>%1 ايام</translation>
|
<translation>%1 ايام</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation>سيقوم VPN فقط بفتح المواقع المشهورة المحظورة في بلدك, مثل Instagram, Facebook, Twitter و مواقع اخري. المواقع الاخري ستٌفتح من عنوان ال IP الحقيقي الخاص بك, <a href="%1/free" style="color: #FBB26A;">معلومات اخري علي الموقع.</a></translation>
|
<translation>سيقوم VPN فقط بفتح المواقع المشهورة المحظورة في بلدك, مثل Instagram, Facebook, Twitter و مواقع اخري. المواقع الاخري ستٌفتح من عنوان ال IP الحقيقي الخاص بك, <a href="%1/free" style="color: #FBB26A;">معلومات اخري علي الموقع.</a></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation>مجاني</translation>
|
<translation>مجاني</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation>%1 دولار/الشهر</translation>
|
<translation>%1 دولار/الشهر</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>غير قادر علي قطع الاتصال اثناء إعداد التكوين</translation>
|
<translation>غير قادر علي قطع الاتصال اثناء إعداد التكوين</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -186,9 +191,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>خطأ في الوصول!</translation>
|
<translation type="vanished">خطأ في الوصول!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -254,18 +258,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>غير قادر علي فتح الملف</translation>
|
<translation>غير قادر علي فتح الملف</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>ملف تكوين غير صحيح</translation>
|
<translation>ملف تكوين غير صحيح</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>تم فحص%1 من %2.</translation>
|
<translation>تم فحص%1 من %2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation>في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة:</translation>
|
<translation>في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة:</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation>نقطة نهاية البوابة</translation>
|
<translation>نقطة نهاية البوابة</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>لا يمكن تغير الخادم بينما هناك اتصال مفعل</translation>
|
<translation>لا يمكن تغير الخادم بينما هناك اتصال مفعل</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">اعدادات AmneziaWG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">منفذ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">احفظ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">احفظ الإعدادات؟</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">واصل</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">إلغاء</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>اعدادات AmneziaWG</translation>
|
<translation>اعدادات AmneziaWG</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -490,92 +552,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>منفذ</translation>
|
<translation>منفذ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>MTU</source>
|
|
||||||
<translation></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري.</translation>
|
<translation>جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>احفظ</translation>
|
<translation>احفظ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation>Jc - عدد الحزم غير المرغوب فيها</translation>
|
<translation>Jc - عدد الحزم غير المرغوب فيها</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation>Jmin - الحجم الادني للحزم الغير مرغوب فيها</translation>
|
<translation>Jmin - الحجم الادني للحزم الغير مرغوب فيها</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation>Jmax - الحجم الاقصي للحزم الغير مرغوب فيها</translation>
|
<translation>Jmax - الحجم الاقصي للحزم الغير مرغوب فيها</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation>S1 - حجم حزمة البيانات العشوائية الأولية</translation>
|
<translation>S1 - حجم حزمة البيانات العشوائية الأولية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation>S2 - حجم حزمة الاستجابة غير المرغوب فيها</translation>
|
<translation>S2 - حجم حزمة الاستجابة غير المرغوب فيها</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation>H1 - حزمة رأس سحرية مبدئية</translation>
|
<translation>H1 - حزمة رأس سحرية مبدئية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation>H2 - رأس حزمة الاستجابة السحرية</translation>
|
<translation>H2 - رأس حزمة الاستجابة السحرية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation>H4 - رأس حزمة النقل السحرية</translation>
|
<translation>H4 - رأس حزمة النقل السحرية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation>H3 - رأس حزمة السحر غير المحمل</translation>
|
<translation>H3 - رأس حزمة السحر غير المحمل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>يجب أن تكون قيم الحقول H1-H4 فريدة</translation>
|
<translation>يجب أن تكون قيم الحقول H1-H4 فريدة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>يجب ألا تساوي قيمة الحقل S1 + حجم بدء الرسالة (148) S2 + حجم استجابة الرسالة (92)</translation>
|
<translation>يجب ألا تساوي قيمة الحقل S1 + حجم بدء الرسالة (148) S2 + حجم استجابة الرسالة (92)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>احفظ الإعدادات؟</translation>
|
<translation>احفظ الإعدادات؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>واصل</translation>
|
<translation>واصل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>إلغاء</translation>
|
<translation>إلغاء</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -862,30 +919,98 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">إعدادات WG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">منفذ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">احفظ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">احفظ الإعدادات؟</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">واصل</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">إلغاء</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>إعدادات WG</translation>
|
<translation>إعدادات WG</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>منفذ</translation>
|
<translation>منفذ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
<source>MTU</source>
|
<source>Save settings?</source>
|
||||||
<translation></translation>
|
<translation type="unfinished">احفظ الإعدادات؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">واصل</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">إلغاء</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>احفظ</translation>
|
<translation>احفظ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1205,9 +1330,13 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>البريد</translation>
|
<translation type="vanished">البريد</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1215,32 +1344,37 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>لل مراجعات والابلاغات عن المشاكل</translation>
|
<translation>لل مراجعات والابلاغات عن المشاكل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>موقع</translation>
|
<translation>موقع</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>%1 :إصدار البرنامج</translation>
|
<translation>%1 :إصدار البرنامج</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>تحقق من وجود تحديثات</translation>
|
<translation>تحقق من وجود تحديثات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>سياسات الخصوصية</translation>
|
<translation>سياسات الخصوصية</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1689,72 +1823,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل.</translation>
|
<translation type="vanished">تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>التسجيل</translation>
|
<translation>التسجيل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>سيتم حفظ سجلات البرنامج بشكل تلقائي عند تفعيل هذه الميزة, بشكل افتراضي, هذه الميزة مٌعطلة. قم بتفعيل هذه الميزة في حالة هناك خلل في التطبيق.</translation>
|
<translation>سيتم حفظ سجلات البرنامج بشكل تلقائي عند تفعيل هذه الميزة, بشكل افتراضي, هذه الميزة مٌعطلة. قم بتفعيل هذه الميزة في حالة هناك خلل في التطبيق.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>احفظ السجلات</translation>
|
<translation type="vanished">احفظ السجلات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>افتح مجلد يحتوي علي سجلات</translation>
|
<translation type="vanished">افتح مجلد يحتوي علي سجلات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>احفظ</translation>
|
<translation>احفظ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>ملفات الولوج (*.log)</translation>
|
<translation>ملفات الولوج (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>تم حفظ ملف السجل</translation>
|
<translation>تم حفظ ملف السجل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>احفظ السجلات في ملف</translation>
|
<translation type="vanished">احفظ السجلات في ملف</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>مسح السجلات؟</translation>
|
<translation>مسح السجلات؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>واصل</translation>
|
<translation>واصل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>إلغاء</translation>
|
<translation>إلغاء</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>تم مسح السجلات</translation>
|
<translation>تم مسح السجلات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>احذف السجلات</translation>
|
<translation>احذف السجلات</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1914,12 +2084,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> الإعدادات</translation>
|
<translation> الإعدادات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>مسح ملف تعريف %1</translation>
|
<translation type="vanished">مسح ملف تعريف %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>مسح ملف تعريف %1؟</translation>
|
<translation>مسح ملف تعريف %1؟</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1929,39 +2098,64 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>غير قادر على مسح ملف تعريف %1 أثناء وجود اتصال نشط</translation>
|
<translation>غير قادر على مسح ملف تعريف %1 أثناء وجود اتصال نشط</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>احذف </translation>
|
<translation>احذف </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>احذف %1 من الخادم؟</translation>
|
<translation>احذف %1 من الخادم؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان.</translation>
|
<translation>جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>لا يمكن إزالة الحاوية النشطة</translation>
|
<translation>لا يمكن إزالة الحاوية النشطة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>واصل</translation>
|
<translation>واصل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>إلغاء</translation>
|
<translation>إلغاء</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2129,82 +2323,92 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>الاتصال</translation>
|
<translation>الاتصال</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation>أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة</translation>
|
<translation>أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation>أدخل مفتاح</translation>
|
<translation>أدخل مفتاح</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation>أدخل</translation>
|
<translation>أدخل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>واصل</translation>
|
<translation>واصل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation>اختيارات اتصال اخري</translation>
|
<translation>اختيارات اتصال اخري</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation>VPN بواسطة Amnezia</translation>
|
<translation>VPN بواسطة Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation>اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia</translation>
|
<translation>اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation>VPN ذاتية الاستضافة</translation>
|
<translation>VPN ذاتية الاستضافة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation>قم بتكوين Amnezia VPN على الخادم الخاص بك</translation>
|
<translation>قم بتكوين Amnezia VPN على الخادم الخاص بك</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation>استرجاع من ملف يحتوي علي نسخة احتياطية</translation>
|
<translation>استرجاع من ملف يحتوي علي نسخة احتياطية</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation>افتح ملف نسخ احتياطي</translation>
|
<translation>افتح ملف نسخ احتياطي</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation>ملفات نٌسخ احتياطية (*.backup)</translation>
|
<translation>ملفات نٌسخ احتياطية (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>ملف إعدادات اتصال</translation>
|
<translation>ملف إعدادات اتصال</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>افتح ملف تكوين</translation>
|
<translation>افتح ملف تكوين</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>رمز QR</translation>
|
<translation>رمز QR</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation>ليس لدي اي شئ</translation>
|
<translation>ليس لدي اي شئ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2717,12 +2921,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>مشاركة</translation>
|
<translation>مشاركة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">خطأ في الوصول!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>اتصال إلي </translation>
|
<translation>اتصال إلي </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>معلف مع إعدادات الاتصال إلي </translation>
|
<translation>معلف مع إعدادات الاتصال إلي </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2739,6 +2948,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation>تم تحميل الإعدادات من ملف نسخة احتياطية</translation>
|
<translation>تم تحميل الإعدادات من ملف نسخة احتياطية</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -2777,12 +2991,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>لم يتم العثور علي كلمة المرور</translation>
|
<translation>لم يتم العثور علي كلمة المرور</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>فشل فتح مخزن المفاتيح</translation>
|
<translation>فشل فتح مخزن المفاتيح</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>فشل حذف المفتاح الخاص من مخزن المفاتيح</translation>
|
<translation>فشل حذف المفتاح الخاص من مخزن المفاتيح</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2958,27 +3172,27 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>فشل في فتح مخزن المفاتيح</translation>
|
<translation>فشل في فتح مخزن المفاتيح</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>فشل ف إنشاء مولد المفاتيح الخاصة</translation>
|
<translation>فشل ف إنشاء مولد المفاتيح الخاصة</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>فشل في إنشاء مفتاح خاص جديد</translation>
|
<translation>فشل في إنشاء مفتاح خاص جديد</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>فشل في استرداد مفتاح خاص من مخزن المفاتيح</translation>
|
<translation>فشل في استرداد مفتاح خاص من مخزن المفاتيح</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>فشل في إنشاء شفرة التشفير</translation>
|
<translation>فشل في إنشاء شفرة التشفير</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>فشل في تشفير الداتا</translation>
|
<translation>فشل في تشفير الداتا</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3675,12 +3889,12 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>ملف النسخه الاحتياطيه تالف</translation>
|
<translation>ملف النسخه الاحتياطيه تالف</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>تم استرجاع جميع الإعدادات للإعدادات الافتراضية</translation>
|
<translation>تم استرجاع جميع الإعدادات للإعدادات الافتراضية</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3812,7 +4026,7 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation>برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیوها، از VPN کلاسیک استفاده کنید. این VPN برای هر سایتی کار میکند و سرعت آن تا %1 مگابیت بر ثانیه است.</translation>
|
<translation>برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیوها، از VPN کلاسیک استفاده کنید. این VPN برای هر سایتی کار میکند و سرعت آن تا %1 مگابیت بر ثانیه است.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation>وی پی ان برای دسترسی به سایتهای مسدود شده در مناطق با سانسور شدید اینترنت.</translation>
|
<translation>وی پی ان برای دسترسی به سایتهای مسدود شده در مناطق با سانسور شدید اینترنت.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation>امنزیا پریمیوم - یک وی پی ان کلاسیک برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیو با کیفیت بالا. قابل استفاده برای تمامی سایتها، حتی در کشورهایی با بالاترین سطح سانسور اینترنت.</translation>
|
<translation>امنزیا پریمیوم - یک وی پی ان کلاسیک برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیو با کیفیت بالا. قابل استفاده برای تمامی سایتها، حتی در کشورهایی با بالاترین سطح سانسور اینترنت.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation>امنزیا رایگان یک وی پی ان رایگان برای دور زدن مسدودیتها در کشورهایی با سطح بالای سانسور اینترنت است.</translation>
|
<translation>امنزیا رایگان یک وی پی ان رایگان برای دور زدن مسدودیتها در کشورهایی با سطح بالای سانسور اینترنت است.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation>%1 MBit/s</translation>
|
<translation>%1 MBit/s</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation>%1 روز</translation>
|
<translation>%1 روز</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation>وی پی ان فقط سایتهای محبوبی را که در منطقه شما مسدود شدهاند، مانند اینستاگرام، فیسبوک، توییتر و غیره باز میکند. سایر سایتها با آدرس آیپی واقعی شما باز خواهند شد. <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></translation>
|
<translation>وی پی ان فقط سایتهای محبوبی را که در منطقه شما مسدود شدهاند، مانند اینستاگرام، فیسبوک، توییتر و غیره باز میکند. سایر سایتها با آدرس آیپی واقعی شما باز خواهند شد. <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation>رایگان</translation>
|
<translation>رایگان</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation>%1 $/ماه</translation>
|
<translation>%1 $/ماه</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>در هنگام آمادهسازی پیکربندی، نمیتوان از اتصال خارج شد.</translation>
|
<translation>در هنگام آمادهسازی پیکربندی، نمیتوان از اتصال خارج شد.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -188,9 +193,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>خطای دسترسی!</translation>
|
<translation type="vanished">خطای دسترسی!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -259,18 +263,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>نمیتوان فایل را باز کرد.</translation>
|
<translation>نمیتوان فایل را باز کرد.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>فایل پیکربندی نامعتبر است.</translation>
|
<translation>فایل پیکربندی نامعتبر است.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>ارزیابی %1 از %2.</translation>
|
<translation>ارزیابی %1 از %2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation>در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند:</translation>
|
<translation>در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند:</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>امکان تغییر سرور در هنگام متصل بودن وجود ندارد</translation>
|
<translation>امکان تغییر سرور در هنگام متصل بودن وجود ندارد</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">تنظیمات AmneziaWG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">پورت</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">ذخیره</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">تنظیمات را ذخیره کن?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>تنظیمات AmneziaWG</translation>
|
<translation>تنظیمات AmneziaWG</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -493,11 +555,6 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>پورت</translation>
|
<translation>پورت</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Remove AmneziaWG</source>
|
<source>Remove AmneziaWG</source>
|
||||||
<translation type="vanished">حذف AmneziaWG</translation>
|
<translation type="vanished">حذف AmneziaWG</translation>
|
||||||
|
|
@ -507,87 +564,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">آیا میخواهید AmneziaWG از سرور حذف شود؟</translation>
|
<translation type="vanished">آیا میخواهید AmneziaWG از سرور حذف شود؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>همه کاربرانی که با آنها ارتباطی به اشتراک گذاشتهاید دیگر قادر به اتصال به آن نخواهند بود.</translation>
|
<translation>همه کاربرانی که با آنها ارتباطی به اشتراک گذاشتهاید دیگر قادر به اتصال به آن نخواهند بود.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>ذخیره</translation>
|
<translation>ذخیره</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>تنظیمات را ذخیره کن?</translation>
|
<translation>تنظیمات را ذخیره کن?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ادامه</translation>
|
<translation>ادامه</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>کنسل</translation>
|
<translation>کنسل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -898,25 +955,88 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">تنظیمات WG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">پورت</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">ذخیره</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">تنظیمات را ذخیره کن?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>تنظیمات WG</translation>
|
<translation>تنظیمات WG</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>پورت</translation>
|
<translation>پورت</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
<source>MTU</source>
|
<source>Save settings?</source>
|
||||||
<translation></translation>
|
<translation type="unfinished">تنظیمات را ذخیره کن?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">همه کاربرانی که با آنها ارتباطی به اشتراک گذاشتهاید دیگر قادر به اتصال به آن نخواهند بود.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -925,11 +1045,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="obsolete">تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
|
<translation type="obsolete">تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation type="obsolete">کنسل</translation>
|
<translation type="unfinished">کنسل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>ذخیره</translation>
|
<translation>ذخیره</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1289,8 +1410,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>ایمیل</translation>
|
<translation type="vanished">ایمیل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1298,17 +1423,22 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>برای ارائه نظرات و گزارشات باگ</translation>
|
<translation>برای ارائه نظرات و گزارشات باگ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished">کپی شد</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>وب سایت</translation>
|
<translation>وب سایت</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1317,17 +1447,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">https://amnezia.org</translation>
|
<translation type="vanished">https://amnezia.org</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>%1 :نسخه نرمافزار</translation>
|
<translation>%1 :نسخه نرمافزار</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>بررسی بروزرسانی</translation>
|
<translation>بررسی بروزرسانی</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1776,72 +1906,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع بهطور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایلهای ثبت وقایع حذف خواهند شد.</translation>
|
<translation type="vanished">ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع بهطور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایلهای ثبت وقایع حذف خواهند شد.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>گزارشات</translation>
|
<translation>گزارشات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>فعال کردن این عملکرد باعث ذخیره خودکار لاگهای برنامه میشود. به طور پیشفرض، قابلیت ثبت لاگ غیرفعال است. در صورت بروز خطا در برنامه، ذخیره لاگ را فعال کنید.</translation>
|
<translation>فعال کردن این عملکرد باعث ذخیره خودکار لاگهای برنامه میشود. به طور پیشفرض، قابلیت ثبت لاگ غیرفعال است. در صورت بروز خطا در برنامه، ذخیره لاگ را فعال کنید.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>ذخیره گزارشات</translation>
|
<translation type="vanished">ذخیره گزارشات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>باز کردن پوشه گزارشات</translation>
|
<translation type="vanished">باز کردن پوشه گزارشات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>ذخیره</translation>
|
<translation>ذخیره</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>Logs files (*.log)</translation>
|
<translation>Logs files (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>فایل گزارشات ذخیره شد</translation>
|
<translation>فایل گزارشات ذخیره شد</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>ذخیره گزارشات در فایل</translation>
|
<translation type="vanished">ذخیره گزارشات در فایل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>پاک کردن گزارشات؟</translation>
|
<translation>پاک کردن گزارشات؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ادامه</translation>
|
<translation>ادامه</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>کنسل</translation>
|
<translation>کنسل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>گزارشات پاک شدند</translation>
|
<translation>گزارشات پاک شدند</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>پاک کردن گزارشات</translation>
|
<translation>پاک کردن گزارشات</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2013,12 +2179,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> تنظیمات</translation>
|
<translation> تنظیمات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>پاک کردن پروفایل %1</translation>
|
<translation type="vanished">پاک کردن پروفایل %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>آیا میخواهید پروفایل %1 را پاک کنید؟</translation>
|
<translation>آیا میخواهید پروفایل %1 را پاک کنید؟</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2028,39 +2193,64 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>نمیتوان پروفایل %1 را در حین اتصال فعال پاک کرد.</translation>
|
<translation>نمیتوان پروفایل %1 را در حین اتصال فعال پاک کرد.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>حذف </translation>
|
<translation>حذف </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>حذف %1 از سرور؟</translation>
|
<translation>حذف %1 از سرور؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
|
<translation>تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>نمیتوان کانتینر فعال را حذف کرد.</translation>
|
<translation>نمیتوان کانتینر فعال را حذف کرد.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ادامه</translation>
|
<translation>ادامه</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>کنسل</translation>
|
<translation>کنسل</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2243,7 +2433,7 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation type="vanished">چی داری؟</translation>
|
<translation type="vanished">چی داری؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>فایل شامل تنظیمات اتصال</translation>
|
<translation>فایل شامل تنظیمات اتصال</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2257,77 +2447,87 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>ارتباط</translation>
|
<translation>ارتباط</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation>کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید</translation>
|
<translation>کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation>کلید را وارد کنید</translation>
|
<translation>کلید را وارد کنید</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation>وارد کردن</translation>
|
<translation>وارد کردن</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ادامه دهید</translation>
|
<translation>ادامه دهید</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation>گزینههای اتصال دیگر</translation>
|
<translation>گزینههای اتصال دیگر</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation>VPN توسط Amnezia</translation>
|
<translation>VPN توسط Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation>اتصال به سرویسهای VPN کلاسیک پولی و رایگان از Amnezia</translation>
|
<translation>اتصال به سرویسهای VPN کلاسیک پولی و رایگان از Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation>Self-hosted VPN</translation>
|
<translation>Self-hosted VPN</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation>پیکربندی VPN Amnezia بر روی سرور خودتان</translation>
|
<translation>پیکربندی VPN Amnezia بر روی سرور خودتان</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation>بازیابی از پشتیبان</translation>
|
<translation>بازیابی از پشتیبان</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation>باز کردن فایل پشتیبان</translation>
|
<translation>باز کردن فایل پشتیبان</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation>Backup files (*.backup)</translation>
|
<translation>Backup files (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>باز کردن فایل تنظیمات</translation>
|
<translation>باز کردن فایل تنظیمات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>QR-Code</translation>
|
<translation>QR-Code</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation>من هیچی ندارم</translation>
|
<translation>من هیچی ندارم</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2499,7 +2699,7 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>نصب</translation>
|
<translation>نصب</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation>پورت باید در محدوده ۱ تا ۶۵۵۳۵ باشد</translation>
|
<translation>پورت باید در محدوده ۱ تا ۶۵۵۳۵ باشد</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2867,12 +3067,17 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>اشتراکگذاری</translation>
|
<translation>اشتراکگذاری</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">خطای دسترسی!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>ارتباط با </translation>
|
<translation>ارتباط با </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>فایل شامل تنظیمات ارتباط با </translation>
|
<translation>فایل شامل تنظیمات ارتباط با </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2889,6 +3094,11 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation>تنظیمات از فایل پشتیبان بازیابی شد</translation>
|
<translation>تنظیمات از فایل پشتیبان بازیابی شد</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -2927,12 +3137,12 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>Password not found</translation>
|
<translation>Password not found</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>Could not open keystore</translation>
|
<translation>Could not open keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>Could not remove private key from keystore</translation>
|
<translation>Could not remove private key from keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3108,27 +3318,27 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>Could not open keystore</translation>
|
<translation>Could not open keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>Could not create private key generator</translation>
|
<translation>Could not create private key generator</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>Could not generate new private key</translation>
|
<translation>Could not generate new private key</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>Could not retrieve private key from keystore</translation>
|
<translation>Could not retrieve private key from keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>Could not create encryption cipher</translation>
|
<translation>Could not create encryption cipher</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>Could not encrypt data</translation>
|
<translation>Could not encrypt data</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3883,7 +4093,7 @@ For more detailed information, you can
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>تمام تنظیمات به مقادیر پیش فرض ریست شد</translation>
|
<translation>تمام تنظیمات به مقادیر پیش فرض ریست شد</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3892,7 +4102,7 @@ For more detailed information, you can
|
||||||
<translation type="vanished">پروفایل ذخیره شده پاک شد</translation>
|
<translation type="vanished">پروفایل ذخیره شده پاک شد</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>فایل بکآپ خراب شده است</translation>
|
<translation>فایل بکآپ خراب شده است</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4024,7 +4234,7 @@ For more detailed information, you can
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation>Mbps</translation>
|
<translation>Mbps</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>कॉन्फ़िगरेशन तैयारी के दौरान डिस्कनेक्ट करने में असमर्थ</translation>
|
<translation>कॉन्फ़िगरेशन तैयारी के दौरान डिस्कनेक्ट करने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -187,9 +192,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>प्रवेश त्रुटि!</translation>
|
<translation type="vanished">प्रवेश त्रुटि!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -255,18 +259,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>फाइल खोलने में असमर्थ</translation>
|
<translation>फाइल खोलने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>अमान्य कॉन्फ़िगरेशन फ़ाइल</translation>
|
<translation>अमान्य कॉन्फ़िगरेशन फ़ाइल</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>%2 में से %1 स्कैन किया गया.</translation>
|
<translation>%2 में से %1 स्कैन किया गया.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>सक्रिय कनेक्शन होने पर सर्वर बदलने में असमर्थ</translation>
|
<translation>सक्रिय कनेक्शन होने पर सर्वर बदलने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">Amneziaडब्ल्यूजी सेटिंग्स</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">एमटीयू</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">सहेजें</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">सेटिंग्स सेव करें?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">जारी रखना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">रद्द करना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>Amneziaडब्ल्यूजी सेटिंग्स</translation>
|
<translation>Amneziaडब्ल्यूजी सेटिंग्स</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>पोर्ट</translation>
|
<translation>पोर्ट</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>एमटीयू</translation>
|
<translation type="vanished">एमटीयू</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>सहेजें</translation>
|
<translation>सहेजें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>H1-H4 फ़ील्ड का मान अद्वितीय होना चाहिए</translation>
|
<translation>H1-H4 फ़ील्ड का मान अद्वितीय होना चाहिए</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>फ़ील्ड S1 + संदेश आरंभ आकार (148) का मान S2 + संदेश प्रतिक्रिया आकार (92) के बराबर नहीं होना चाहिए</translation>
|
<translation>फ़ील्ड S1 + संदेश आरंभ आकार (148) का मान S2 + संदेश प्रतिक्रिया आकार (92) के बराबर नहीं होना चाहिए</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>सेटिंग्स सेव करें?</translation>
|
<translation>सेटिंग्स सेव करें?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे.</translation>
|
<translation>वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>जारी रखना</translation>
|
<translation>जारी रखना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>रद्द करना</translation>
|
<translation>रद्द करना</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">डब्ल्यूजी सेटिंग्स</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">एमटीयू</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">सहेजें</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">सेटिंग्स सेव करें?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">जारी रखना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">रद्द करना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>डब्ल्यूजी सेटिंग्स</translation>
|
<translation>डब्ल्यूजी सेटिंग्स</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>बंदरगाह</translation>
|
<translation>बंदरगाह</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>एमटीयू</translation>
|
<translation type="vanished">एमटीयू</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>सहेजें</translation>
|
<translation>सहेजें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">सेटिंग्स सेव करें?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">जारी रखना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">रद्द करना</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
<translation>सक्रिय कनेक्शन होने पर सेटिंग बदलने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1237,9 +1370,13 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>मेल</translation>
|
<translation type="vanished">मेल</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1247,32 +1384,37 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>समीक्षाओं और बग रिपोर्टों के लिए</translation>
|
<translation>समीक्षाओं और बग रिपोर्टों के लिए</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished">कॉपी किया गया</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>वेबसाइट</translation>
|
<translation>वेबसाइट</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>सॉफ़्टवेयर संस्करण: %1</translation>
|
<translation>सॉफ़्टवेयर संस्करण: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>अद्यतन के लिए जाँच</translation>
|
<translation>अद्यतन के लिए जाँच</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>गोपनीयता नीति</translation>
|
<translation>गोपनीयता नीति</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1729,72 +1871,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>लॉगिंग सक्षम है. ध्यान दें कि 14 दिनों के बाद लॉग स्वचालित रूप से अक्षम हो जाएंगे, और सभी लॉग फ़ाइलें हटा दी जाएंगी.</translation>
|
<translation type="vanished">लॉगिंग सक्षम है. ध्यान दें कि 14 दिनों के बाद लॉग स्वचालित रूप से अक्षम हो जाएंगे, और सभी लॉग फ़ाइलें हटा दी जाएंगी.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>लॉगिंग</translation>
|
<translation>लॉगिंग</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>इस फ़ंक्शन को सक्षम करने से एप्लिकेशन के लॉग स्वचालित रूप से सहेजे जाएंगे, डिफ़ॉल्ट रूप से, लॉगिंग कार्यक्षमता अक्षम है। एप्लिकेशन की खराबी की स्थिति में लॉग सेविंग सक्षम करें.</translation>
|
<translation>इस फ़ंक्शन को सक्षम करने से एप्लिकेशन के लॉग स्वचालित रूप से सहेजे जाएंगे, डिफ़ॉल्ट रूप से, लॉगिंग कार्यक्षमता अक्षम है। एप्लिकेशन की खराबी की स्थिति में लॉग सेविंग सक्षम करें.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>लॉग सहेजें</translation>
|
<translation type="vanished">लॉग सहेजें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>लॉग के साथ फ़ोल्डर खोलें</translation>
|
<translation type="vanished">लॉग के साथ फ़ोल्डर खोलें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>सहेजें</translation>
|
<translation>सहेजें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>लॉग फ़ाइलें (*.log)</translation>
|
<translation>लॉग फ़ाइलें (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>लॉग फ़ाइल सहेजी गई</translation>
|
<translation>लॉग फ़ाइल सहेजी गई</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>फ़ाइल में लॉग सहेजें</translation>
|
<translation type="vanished">फ़ाइल में लॉग सहेजें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>लॉग साफ़ करें?</translation>
|
<translation>लॉग साफ़ करें?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>जारी रखना</translation>
|
<translation>जारी रखना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>रद्द करना</translation>
|
<translation>रद्द करना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>लॉग साफ़ कर दिए गए हैं</translation>
|
<translation>लॉग साफ़ कर दिए गए हैं</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>लॉग साफ़ करें</translation>
|
<translation>लॉग साफ़ करें</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1954,12 +2132,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> समायोजन</translation>
|
<translation> समायोजन</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>%1 प्रोफ़ाइल साफ़ करें</translation>
|
<translation type="vanished">%1 प्रोफ़ाइल साफ़ करें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>%1 प्रोफ़ाइल साफ़ करें?</translation>
|
<translation>%1 प्रोफ़ाइल साफ़ करें?</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1969,39 +2146,64 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>सक्रिय कनेक्शन होने पर %1 प्रोफ़ाइल साफ़ करने में असमर्थ</translation>
|
<translation>सक्रिय कनेक्शन होने पर %1 प्रोफ़ाइल साफ़ करने में असमर्थ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>निकालना </translation>
|
<translation>निकालना </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे.</translation>
|
<translation>वे सभी उपयोगकर्ता जिनके साथ आपने कनेक्शन साझा किया था, वे अब इससे कनेक्ट नहीं हो पाएंगे.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>सक्रिय कंटेनर को हटाया नहीं जा सकता</translation>
|
<translation>सक्रिय कंटेनर को हटाया नहीं जा सकता</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>सर्वर से %1 हटाएँ?</translation>
|
<translation>सर्वर से %1 हटाएँ?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>जारी रखना</translation>
|
<translation>जारी रखना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>रद्द करना</translation>
|
<translation>रद्द करना</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2185,82 +2387,92 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="unfinished">कनेक्शन</translation>
|
<translation type="unfinished">कनेक्शन</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation type="unfinished">डालना</translation>
|
<translation type="unfinished">डालना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation type="unfinished">जारी रखना</translation>
|
<translation type="unfinished">जारी रखना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation type="unfinished">बैकअप से बहाल करना</translation>
|
<translation type="unfinished">बैकअप से बहाल करना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation type="unfinished">बैकअप फ़ाइल खोलें</translation>
|
<translation type="unfinished">बैकअप फ़ाइल खोलें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation type="unfinished">बैकअप फ़ाइलें (*.backup)</translation>
|
<translation type="unfinished">बैकअप फ़ाइलें (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>कनेक्शन सेटिंग्स वाली फ़ाइल</translation>
|
<translation>कनेक्शन सेटिंग्स वाली फ़ाइल</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>कॉन्फ़िग फ़ाइल खोलें</translation>
|
<translation>कॉन्फ़िग फ़ाइल खोलें</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>क्यू आर संहिता</translation>
|
<translation>क्यू आर संहिता</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation type="unfinished">मेरे पास कुछ नहीं है</translation>
|
<translation type="unfinished">मेरे पास कुछ नहीं है</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2432,7 +2644,7 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>स्थापित करना</translation>
|
<translation>स्थापित करना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2804,12 +3016,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>शेयर करना</translation>
|
<translation>शेयर करना</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">प्रवेश त्रुटि!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>के लिए कनेक्शन </translation>
|
<translation>के लिए कनेक्शन </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>कनेक्शन सेटिंग्स वाली फ़ाइल </translation>
|
<translation>कनेक्शन सेटिंग्स वाली फ़ाइल </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2826,6 +3043,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation type="unfinished">बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं</translation>
|
<translation type="unfinished">बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -2864,12 +3086,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>पासवर्ड नहीं मिला</translation>
|
<translation>पासवर्ड नहीं मिला</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>कीस्टोर नहीं खुल सका</translation>
|
<translation>कीस्टोर नहीं खुल सका</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>कीस्टोर से निजी कुंजी नहीं हटाई जा सकी</translation>
|
<translation>कीस्टोर से निजी कुंजी नहीं हटाई जा सकी</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3045,27 +3267,27 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>कीस्टोर नहीं खुल सका</translation>
|
<translation>कीस्टोर नहीं खुल सका</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>निजी कुंजी जेनरेटर नहीं बनाया जा सका</translation>
|
<translation>निजी कुंजी जेनरेटर नहीं बनाया जा सका</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>नई निजी कुंजी उत्पन्न नहीं हो सकी</translation>
|
<translation>नई निजी कुंजी उत्पन्न नहीं हो सकी</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>कीस्टोर से निजी कुंजी पुनर्प्राप्त नहीं की जा सकी</translation>
|
<translation>कीस्टोर से निजी कुंजी पुनर्प्राप्त नहीं की जा सकी</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>एन्क्रिप्शन सिफर नहीं बनाया जा सका</translation>
|
<translation>एन्क्रिप्शन सिफर नहीं बनाया जा सका</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>डेटा एन्क्रिप्ट नहीं किया जा सका</translation>
|
<translation>डेटा एन्क्रिप्ट नहीं किया जा सका</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3763,12 +3985,12 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>बैकअप फ़ाइल दूषित है</translation>
|
<translation>बैकअप फ़ाइल दूषित है</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>सभी सेटिंग्स को डिफ़ॉल्ट मानों पर रीसेट कर दिया गया है</translation>
|
<translation>सभी सेटिंग्स को डिफ़ॉल्ट मानों पर रीसेट कर दिया गया है</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3900,7 +4122,7 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation>သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ မည်သည့်ဆိုက်များအတွက်မဆိုအလုပ်လုပ်ပြီး လိုင်းအရှိန် %1 MBit/s အထိအသုံးပြုနိုင်ပါတယ်။</translation>
|
<translation>သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ မည်သည့်ဆိုက်များအတွက်မဆိုအလုပ်လုပ်ပြီး လိုင်းအရှိန် %1 MBit/s အထိအသုံးပြုနိုင်ပါတယ်။</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation>အင်တာနက် ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသော ဒေသများရှိ ပိတ်ဆို့ထားသော ဆိုက်များကို ဝင်ရောက်ရန် VPN။. </translation>
|
<translation>အင်တာနက် ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသော ဒေသများရှိ ပိတ်ဆို့ထားသော ဆိုက်များကို ဝင်ရောက်ရန် VPN။. </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation>Amnezia Premium - သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကိုကြည်လင်ပြတ်သားစွာကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ အင်တာနက်ဆင်ဆာဖြတ်မှု အဆင့်အမြင့်ဆုံးနိုင်ငံများတွင်ပင် မည်သည့်ဆိုက်များအတွက်မဆို အလုပ်လုပ်ပါသည်။.</translation>
|
<translation>Amnezia Premium - သက်တောင့်သက်သာအလုပ်လုပ်နိုင်ဖို့အတွက်နှင့် ကြီးမားသောဖိုင်များကိုဒေါင်းလုဒ်လုပ်ခြင်းနှင့် ဗီဒီယိုများကိုကြည်လင်ပြတ်သားစွာကြည့်ရှုခြင်းတို့အတွက် အသုံးပြုနိုင်သော VPN ဖြစ်ပါတယ်။ အင်တာနက်ဆင်ဆာဖြတ်မှု အဆင့်အမြင့်ဆုံးနိုင်ငံများတွင်ပင် မည်သည့်ဆိုက်များအတွက်မဆို အလုပ်လုပ်ပါသည်။.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation>Amnezia Free သည် အင်တာနက်ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသောနိုင်ငံများတွင် ပိတ်ဆို့ခြင်းကို ကျော်ဖြတ်ရန်အတွက် အခမဲ့ VPN တစ်ခုဖြစ်ပါသည်။</translation>
|
<translation>Amnezia Free သည် အင်တာနက်ဆင်ဆာဖြတ်တောက်မှု မြင့်မားသောနိုင်ငံများတွင် ပိတ်ဆို့ခြင်းကို ကျော်ဖြတ်ရန်အတွက် အခမဲ့ VPN တစ်ခုဖြစ်ပါသည်။</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation>%1 MBit/s</translation>
|
<translation>%1 MBit/s</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation>%1 ရက်</translation>
|
<translation>%1 ရက်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation>ဤ VPN သည် သင့်ဒေသရှိ Instagram၊ Facebook၊ Twitter နှင့် အခြားသော လူကြိုက်များသော ဆိုက်များကိုသာ ဖွင့်ပေးပါမည်။ အခြားဝဘ်ဆိုက်များကိုမူ သင်၏ IP လိပ်စာအစစ်အမှန်ဖြင့်သာ ဖွင့်ပေးပါမည်၊ <a href="%1/free" style="color: #FBB26A;">နောက်ထပ်အသေးစိတ်အချက်အလက်များကို ဝဘ်ဆိုဒ်ပေါ်တွင်ကြည့်ရန်</a></translation>
|
<translation>ဤ VPN သည် သင့်ဒေသရှိ Instagram၊ Facebook၊ Twitter နှင့် အခြားသော လူကြိုက်များသော ဆိုက်များကိုသာ ဖွင့်ပေးပါမည်။ အခြားဝဘ်ဆိုက်များကိုမူ သင်၏ IP လိပ်စာအစစ်အမှန်ဖြင့်သာ ဖွင့်ပေးပါမည်၊ <a href="%1/free" style="color: #FBB26A;">နောက်ထပ်အသေးစိတ်အချက်အလက်များကို ဝဘ်ဆိုဒ်ပေါ်တွင်ကြည့်ရန်</a></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation>အခမဲ့</translation>
|
<translation>အခမဲ့</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation>%1 $/တစ်လ</translation>
|
<translation>%1 $/တစ်လ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>Configuration ပြင်ဆင်ခြင်းလုပ်ဆောင်နေချိန်အတွင်း ချိတ်ဆက်မှုဖြတ်တောက်၍မရပါ</translation>
|
<translation>Configuration ပြင်ဆင်ခြင်းလုပ်ဆောင်နေချိန်အတွင်း ချိတ်ဆက်မှုဖြတ်တောက်၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -187,9 +192,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်!</translation>
|
<translation type="vanished">အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -255,18 +259,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>ဖိုင်ကိုဖွင့်၍မရပါ</translation>
|
<translation>ဖိုင်ကိုဖွင့်၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>Configuration ဖိုင် မမှန်ကန်ပါ</translation>
|
<translation>Configuration ဖိုင် မမှန်ကန်ပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>%2 ၏ %1 ကို စကင်န်ဖတ်ထားသည်.</translation>
|
<translation>%2 ၏ %1 ကို စကင်န်ဖတ်ထားသည်.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation>တင်သွင်းသည့် configuration တွင်၊ အန္တရာယ်ရှိနိုင်သည့်စာလိုင်းများကို တွေ့ရှိခဲ့သည်:</translation>
|
<translation>တင်သွင်းသည့် configuration တွင်၊ အန္တရာယ်ရှိနိုင်သည့်စာလိုင်းများကို တွေ့ရှိခဲ့သည်:</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation>Gateway အဆုံးမှတ်</translation>
|
<translation>Gateway အဆုံးမှတ်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆာဗာကို ပြောင်းလဲ၍မရပါ</translation>
|
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆာဗာကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">AmneziaWG ဆက်တင်များ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Port</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">သိမ်းဆည်းမည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">ဆက်တင်များကို သိမ်းဆည်းမည်လား?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">ပယ်ဖျက်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>AmneziaWG ဆက်တင်များ</translation>
|
<translation>AmneziaWG ဆက်တင်များ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Port</translation>
|
<translation>Port</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>MTU</translation>
|
<translation type="vanished">MTU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.</translation>
|
<translation>သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>သိမ်းဆည်းမည်</translation>
|
<translation>သိမ်းဆည်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation>Jc - Junk packet အရေအတွက်</translation>
|
<translation>Jc - Junk packet အရေအတွက်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation>Jmin - Junk packet အသေးငယ်ဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
<translation>Jmin - Junk packet အသေးငယ်ဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation>Jmax - Junk packet အကြီးဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
<translation>Jmax - Junk packet အကြီးဆုံးလက်ခံနိုင်မှုအရွယ်အစား</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation>S1 - Init packet junk အရွယ်အစား</translation>
|
<translation>S1 - Init packet junk အရွယ်အစား</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation>S2 - Response packet junk အရွယ်အစား</translation>
|
<translation>S2 - Response packet junk အရွယ်အစား</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation>H1 - Init packet magic header</translation>
|
<translation>H1 - Init packet magic header</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation>H2 - Response packet magic header</translation>
|
<translation>H2 - Response packet magic header</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation>H4 - Transport packet magic header</translation>
|
<translation>H4 - Transport packet magic header</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation>H3 - Underload packet magic header</translation>
|
<translation>H3 - Underload packet magic header</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>H1-H4 အကွက်များ၏ တန်ဖိုးများသည် အခြားတန်ဖိုးများနှင့်မတူ တမူထူးခြားနေရပါမည်</translation>
|
<translation>H1-H4 အကွက်များ၏ တန်ဖိုးများသည် အခြားတန်ဖိုးများနှင့်မတူ တမူထူးခြားနေရပါမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>အကွက် S1 + မက်ဆေ့ချ် စတင်ခြင်း အရွယ်အစား (148) ၏ တန်ဖိုးသည် S2 + မက်ဆေ့ချ် တုံ့ပြန်မှု အရွယ်အစား (92) နှင့် မညီမျှရပါ</translation>
|
<translation>အကွက် S1 + မက်ဆေ့ချ် စတင်ခြင်း အရွယ်အစား (148) ၏ တန်ဖိုးသည် S2 + မက်ဆေ့ချ် တုံ့ပြန်မှု အရွယ်အစား (92) နှင့် မညီမျှရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>ဆက်တင်များကို သိမ်းဆည်းမည်လား?</translation>
|
<translation>ဆက်တင်များကို သိမ်းဆည်းမည်လား?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>ပယ်ဖျက်မည်</translation>
|
<translation>ပယ်ဖျက်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">WG ဆက်တင်များ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Port</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">သိမ်းဆည်းမည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">ဆက်တင်များကို သိမ်းဆည်းမည်လား?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">ပယ်ဖျက်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>WG ဆက်တင်များ</translation>
|
<translation>WG ဆက်တင်များ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>Port</translation>
|
<translation>Port</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
<source>MTU</source>
|
<source>Save settings?</source>
|
||||||
<translation>MTU</translation>
|
<translation type="unfinished">ဆက်တင်များကို သိမ်းဆည်းမည်လား?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">ပယ်ဖျက်မည်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="vanished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် ဆက်တင်များကို ပြောင်းလဲ၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>သိမ်းဆည်းမည်</translation>
|
<translation>သိမ်းဆည်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1205,9 +1338,13 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>https://t.me/amnezia_vpn</translation>
|
<translation>https://t.me/amnezia_vpn</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>မေးလ်</translation>
|
<translation type="vanished">မေးလ်</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1215,32 +1352,37 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>သုံးသပ်ချက်များနှင့် ချွတ်ယွင်းချက်အစီရင်ခံစာများအတွက်</translation>
|
<translation>သုံးသပ်ချက်များနှင့် ချွတ်ယွင်းချက်အစီရင်ခံစာများအတွက်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished">ကူးယူပြီးပါပြီ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>ဝဘ်ဆိုက်</translation>
|
<translation>ဝဘ်ဆိုက်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>ဆော့ဖ်ဝဲဗားရှင်း: %1</translation>
|
<translation>ဆော့ဖ်ဝဲဗားရှင်း: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>အပ်ဒိတ်များရှိမရှိ စစ်ဆေးမည်</translation>
|
<translation>အပ်ဒိတ်များရှိမရှိ စစ်ဆေးမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>ကိုယ်ရေးအချက်အလက်မူဝါဒ</translation>
|
<translation>ကိုယ်ရေးအချက်အလက်မူဝါဒ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1689,73 +1831,109 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>Logging ကို ဖွင့်ထားသည်။ မှတ်တမ်းများကို ၁၄ ရက်အကြာတွင် အလိုအလျောက်ပိတ်ထားမည်ဖြစ်ပြီး မှတ်တမ်းဖိုင်များအားလုံး ပျက်သွားမည်ဖြစ်ကြောင်း သတိပြုပါ။.</translation>
|
<translation type="vanished">Logging ကို ဖွင့်ထားသည်။ မှတ်တမ်းများကို ၁၄ ရက်အကြာတွင် အလိုအလျောက်ပိတ်ထားမည်ဖြစ်ပြီး မှတ်တမ်းဖိုင်များအားလုံး ပျက်သွားမည်ဖြစ်ကြောင်း သတိပြုပါ။.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>Logging</translation>
|
<translation>Logging</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>ဤလုပ်ဆောင်ချက်ကို ဖွင့်ခြင်းဖြင့် အပလီကေးရှင်း၏ မှတ်တမ်းများကို အလိုအလျောက် သိမ်းဆည်းပေးမည် ဖြစ်သည်။ ပုံမှန်အတိုင်းဆိုလျှင် Logging လုပ်ဆောင်ချက်ကို ပိတ်ထားမည်ဖြစ်သည်။ အပလီကေးရှင်းချို့ယွင်းချက်ရှိခဲ့ပါသော် မှတ်တမ်းကိုပြန်လည်ကြည့်ရှုနိုင်ရန် မှတ်တမ်းသိမ်းဆည်းမှုကို ဖွင့်ထားလိုက်ပါ။.</translation>
|
<translation>ဤလုပ်ဆောင်ချက်ကို ဖွင့်ခြင်းဖြင့် အပလီကေးရှင်း၏ မှတ်တမ်းများကို အလိုအလျောက် သိမ်းဆည်းပေးမည် ဖြစ်သည်။ ပုံမှန်အတိုင်းဆိုလျှင် Logging လုပ်ဆောင်ချက်ကို ပိတ်ထားမည်ဖြစ်သည်။ အပလီကေးရှင်းချို့ယွင်းချက်ရှိခဲ့ပါသော် မှတ်တမ်းကိုပြန်လည်ကြည့်ရှုနိုင်ရန် မှတ်တမ်းသိမ်းဆည်းမှုကို ဖွင့်ထားလိုက်ပါ။.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>မှတ်တမ်းများကိုသိမ်းဆည်းမည်</translation>
|
<translation type="vanished">မှတ်တမ်းများကိုသိမ်းဆည်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>မှတ်တမ်းများရှိသောဖိုင်တွဲကိုဖွင့်မည်</translation>
|
<translation type="vanished">မှတ်တမ်းများရှိသောဖိုင်တွဲကိုဖွင့်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>သိမ်းဆည်းမည်</translation>
|
<translation>သိမ်းဆည်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translatorcomment>မှတ်တမ်းဖိုင်များ (*.log)</translatorcomment>
|
<translatorcomment>မှတ်တမ်းဖိုင်များ (*.log)</translatorcomment>
|
||||||
<translation>မှတ်တမ်းဖိုင်များ (*.log)</translation>
|
<translation>မှတ်တမ်းဖိုင်များ (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>မှတ်တမ်းဖိုင်များသိမ်းဆည်းပြီးပါပြီ</translation>
|
<translation>မှတ်တမ်းဖိုင်များသိမ်းဆည်းပြီးပါပြီ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>မှတ်တမ်းများကို ဖိုင်တွင်သိမ်းဆည်းမည်</translation>
|
<translation type="vanished">မှတ်တမ်းများကို ဖိုင်တွင်သိမ်းဆည်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>မှတ်တမ်းများရှင်းလင်းမည်လား?</translation>
|
<translation>မှတ်တမ်းများရှင်းလင်းမည်လား?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>ပယ်ဖျက်မည်</translation>
|
<translation>ပယ်ဖျက်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>မှတ်တမ်းများကို ရှင်းလင်းပြီးပါပြီ</translation>
|
<translation>မှတ်တမ်းများကို ရှင်းလင်းပြီးပါပြီ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>မှတ်တမ်းများရှင်းလင်းမည်</translation>
|
<translation>မှတ်တမ်းများရှင်းလင်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1915,12 +2093,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> ဆက်တင်များ</translation>
|
<translation> ဆက်တင်များ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>%1 ပရိုဖိုင်ကို ရှင်းလင်းမည်</translation>
|
<translation type="vanished">%1 ပရိုဖိုင်ကို ရှင်းလင်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>%1 ပရိုဖိုင်ကို ရှင်းလင်းမည်လား?</translation>
|
<translation>%1 ပရိုဖိုင်ကို ရှင်းလင်းမည်လား?</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1930,39 +2107,64 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် %1 ပရိုဖိုင်ကို ရှင်းလင်း၍မရပါ</translation>
|
<translation>လက်ရှိချိတ်ဆက်မှုတစ်ခုရှိနေချိန်တွင် %1 ပရိုဖိုင်ကို ရှင်းလင်း၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>ဖယ်ရှားမည် </translation>
|
<translation>ဖယ်ရှားမည် </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>%1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား?</translation>
|
<translation>%1 ကို ဆာဗာမှ ဖယ်ရှားမည်လား?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ဤချိတ်ဆက်မှုကိုချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.</translation>
|
<translation>သင်နှင့်အတူချိတ်ဆက်မှုတစ်ခုကို မျှဝေထားသည့် အသုံးပြုသူအားလုံး ဤချိတ်ဆက်မှုကိုချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>Active container ကိုဖယ်ရှား၍မရပါ</translation>
|
<translation>Active container ကိုဖယ်ရှား၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>ပယ်ဖျက်မည်</translation>
|
<translation>ပယ်ဖျက်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2125,7 +2327,7 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSetupWizardConfigSource</name>
|
<name>PageSetupWizardConfigSource</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>ချိတ်ဆက်မှုဆက်တင်များပါဝင်သောဖိုင်</translation>
|
<translation>ချိတ်ဆက်မှုဆက်တင်များပါဝင်သောဖိုင်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2135,77 +2337,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>ချိတ်ဆက်မှု</translation>
|
<translation>ချိတ်ဆက်မှု</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation>Key ကိုထည့်မည်၊ ဖွဲ့စည်းမှုဖိုင်တစ်ခုကိုထည့်မည် သို့မဟုတ် QR-ကုဒ်ကို စကင်န်ဖတ်မည်</translation>
|
<translation>Key ကိုထည့်မည်၊ ဖွဲ့စည်းမှုဖိုင်တစ်ခုကိုထည့်မည် သို့မဟုတ် QR-ကုဒ်ကို စကင်န်ဖတ်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation>Key ကိုထည့်သွင်းမည်</translation>
|
<translation>Key ကိုထည့်သွင်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation>ထည့်သွင်းမည်</translation>
|
<translation>ထည့်သွင်းမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
<translation>ဆက်လက်လုပ်ဆောင်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation>အခြားချိတ်ဆက်မှုရွေးချယ်စရာများ</translation>
|
<translation>အခြားချိတ်ဆက်မှုရွေးချယ်စရာများ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation>Amnezia မှ VPN</translation>
|
<translation>Amnezia မှ VPN</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation>Amnezia မှ အခပေးနှင့် အခမဲ့ မူလ VPN ဝန်ဆောင်မှုများသို့ ချိတ်ဆက်မည်</translation>
|
<translation>Amnezia မှ အခပေးနှင့် အခမဲ့ မူလ VPN ဝန်ဆောင်မှုများသို့ ချိတ်ဆက်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation>ကိုယ်တိုင် host လုပ်ထားသော VPN</translation>
|
<translation>ကိုယ်တိုင် host လုပ်ထားသော VPN</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation>Amnezia VPN ကို သင်၏ကိုယ်ပိုင်ဆာဗာပေါ်တွင် စီစဥ်ချိန်ညှိမည်</translation>
|
<translation>Amnezia VPN ကို သင်၏ကိုယ်ပိုင်ဆာဗာပေါ်တွင် စီစဥ်ချိန်ညှိမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation>အရံဖိုင်မှ ပြန်လည်ရယူမည်</translation>
|
<translation>အရံဖိုင်မှ ပြန်လည်ရယူမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation>အရံဖိုင်ကို ဖွင့်မည်</translation>
|
<translation>အရံဖိုင်ကို ဖွင့်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation>အရံဖိုင်များ (*.backup)</translation>
|
<translation>အရံဖိုင်များ (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>config ဖိုင်ကိုဖွင့်မည်</translation>
|
<translation>config ဖိုင်ကိုဖွင့်မည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>QR-ကုဒ်</translation>
|
<translation>QR-ကုဒ်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation>ကျွန်ုပ်တွင်ဘာမှမရှိပါ</translation>
|
<translation>ကျွန်ုပ်တွင်ဘာမှမရှိပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2717,12 +2929,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>မျှဝေမည်</translation>
|
<translation>မျှဝေမည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">အသုံးပြုခွင့်တွင်အမှားပါနေပါသည်!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>ဤဆာဗာသို့ချိတ်ဆက်မှု </translation>
|
<translation>ဤဆာဗာသို့ချိတ်ဆက်မှု </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>ဤဆာဗာနှင့်ချိတ်ဆက်မှု ဆက်တင်များပါရှိသော ဖိုင် </translation>
|
<translation>ဤဆာဗာနှင့်ချိတ်ဆက်မှု ဆက်တင်များပါရှိသော ဖိုင် </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2739,6 +2956,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation>ဆက်တင်များကို အရံဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ</translation>
|
<translation>ဆက်တင်များကို အရံဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -2777,12 +2999,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>စကားဝှက်ကို ရှာမတွေ့ပါ</translation>
|
<translation>စကားဝှက်ကို ရှာမတွေ့ပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>keystore ကို ဖွင့်၍မရပါ</translation>
|
<translation>keystore ကို ဖွင့်၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>Key store မှ ကိုယ်ပိုင် key ကို ဖယ်ရှား၍မရပါ</translation>
|
<translation>Key store မှ ကိုယ်ပိုင် key ကို ဖယ်ရှား၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2958,27 +3180,27 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>keystore ကို ဖွင့်၍မရပါ</translation>
|
<translation>keystore ကို ဖွင့်၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>ကိုယ်ပိုင် key ဖန်တီးမှုစက်ကိုမဖန်တီးနိုင်ပါ</translation>
|
<translation>ကိုယ်ပိုင် key ဖန်တီးမှုစက်ကိုမဖန်တီးနိုင်ပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>ကိုယ်ပိုင် key အသစ် မထုတ်ပေးနိုင်ပါ</translation>
|
<translation>ကိုယ်ပိုင် key အသစ် မထုတ်ပေးနိုင်ပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>Key store မှ ကိုယ်ပိုင် key ကို ထုတ်ယူ၍မရပါ</translation>
|
<translation>Key store မှ ကိုယ်ပိုင် key ကို ထုတ်ယူ၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>ကုတ်ဝှက်ဖြည်ခြင်းဖန်တီး၍မရပါ</translation>
|
<translation>ကုတ်ဝှက်ဖြည်ခြင်းဖန်တီး၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>ဒေတာကို ကုတ်ဝှက်၍မရပါ</translation>
|
<translation>ဒေတာကို ကုတ်ဝှက်၍မရပါ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3672,12 +3894,12 @@ For more detailed information, you can
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>ဆက်တင်အားလုံးကို မူရင်းတန်ဖိုးများအဖြစ် ပြန်လည်သတ်မှတ်ထားသည်</translation>
|
<translation>ဆက်တင်အားလုံးကို မူရင်းတန်ဖိုးများအဖြစ် ပြန်လည်သတ်မှတ်ထားသည်</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>အရံဖိုင်ပျက်ဆီးနေသည်</translation>
|
<translation>အရံဖိုင်ပျက်ဆီးနေသည်</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3809,7 +4031,7 @@ For more detailed information, you can
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation>Mbps</translation>
|
<translation>Mbps</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation>Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Работает для любых сайтов. Скорость до %1 Мбит/с</translation>
|
<translation>Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Работает для любых сайтов. Скорость до %1 Мбит/с</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation>VPN для доступа к заблокированным сайтам в регионах с высоким уровнем интернет-цензуры. </translation>
|
<translation>VPN для доступа к заблокированным сайтам в регионах с высоким уровнем интернет-цензуры. </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation>Amnezia Premium — классический VPN для комфортной работы, загрузки больших файлов и просмотра видео в высоком разрешении. Работает на всех сайтах, даже в странах с самым высоким уровнем интернет-цензуры.</translation>
|
<translation>Amnezia Premium — классический VPN для комфортной работы, загрузки больших файлов и просмотра видео в высоком разрешении. Работает на всех сайтах, даже в странах с самым высоким уровнем интернет-цензуры.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation>Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры</translation>
|
<translation>Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation>%1 дней</translation>
|
<translation>%1 дней</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation>Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1/free" style="color: #FBB26A;">подробности на сайте.</a></translation>
|
<translation>Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, <a href="%1/free" style="color: #FBB26A;">подробности на сайте.</a></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation>Бесплатно</translation>
|
<translation>Бесплатно</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation>%1 $/месяц</translation>
|
<translation>%1 $/месяц</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>Невозможно отключиться во время подготовки конфигурации</translation>
|
<translation>Невозможно отключиться во время подготовки конфигурации</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -187,9 +192,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>Ошибка доступа!</translation>
|
<translation type="vanished">Ошибка доступа!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -259,18 +263,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>Невозможно открыть файл</translation>
|
<translation>Невозможно открыть файл</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>Неверный файл конфигурации</translation>
|
<translation>Неверный файл конфигурации</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>Отсканировано %1 из %2.</translation>
|
<translation>Отсканировано %1 из %2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation>В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
|
<translation>В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Невозможно изменить сервер во время активного соединения</translation>
|
<translation>Невозможно изменить сервер во время активного соединения</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">Настройки AmneziaWG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Порт</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">Сохранить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">Сохранить настройки?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">Продолжить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">Отменить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">Невозможно изменить настройки во время активного соединения</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>Настройки AmneziaWG</translation>
|
<translation>Настройки AmneziaWG</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -494,9 +556,8 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Порт</translation>
|
<translation>Порт</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>MTU</translation>
|
<translation type="vanished">MTU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Remove AmneziaWG</source>
|
<source>Remove AmneziaWG</source>
|
||||||
|
|
@ -507,87 +568,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Удалить AmneziaWG с сервера?</translation>
|
<translation type="vanished">Удалить AmneziaWG с сервера?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Сохранить</translation>
|
<translation>Сохранить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>Значения в полях H1-H4 должны быть уникальными</translation>
|
<translation>Значения в полях H1-H4 должны быть уникальными</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92)</translation>
|
<translation>Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>Сохранить настройки?</translation>
|
<translation>Сохранить настройки?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продолжить</translation>
|
<translation>Продолжить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Отменить</translation>
|
<translation>Отменить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -898,25 +959,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">Настройки WG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Порт</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">Сохранить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">Сохранить настройки?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">Продолжить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">Отменить</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">Невозможно изменить настройки во время активного соединения</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>Настройки WG</translation>
|
<translation>Настройки WG</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>Порт</translation>
|
<translation>Порт</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
<source>MTU</source>
|
<source>Save settings?</source>
|
||||||
<translation>MTU</translation>
|
<translation type="unfinished">Сохранить настройки?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="vanished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
<translation>Невозможно изменить настройки во время активного соединения</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -933,15 +1056,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
<translation type="vanished">Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation type="vanished">Продолжить</translation>
|
<translation>Продолжить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation type="vanished">Отменить</translation>
|
<translation>Отменить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Сохранить</translation>
|
<translation>Сохранить</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1305,8 +1430,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>Почта</translation>
|
<translation type="vanished">Почта</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1314,17 +1443,22 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Для отзывов и сообщений об ошибках</translation>
|
<translation>Для отзывов и сообщений об ошибках</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished">Скопировано</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>Веб-сайт</translation>
|
<translation>Веб-сайт</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1333,17 +1467,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">https://amnezia.org</translation>
|
<translation type="vanished">https://amnezia.org</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>Версия ПО: %1</translation>
|
<translation>Версия ПО: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>Проверить обновления</translation>
|
<translation>Проверить обновления</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>Политика конфиденциальности</translation>
|
<translation>Политика конфиденциальности</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1816,72 +1950,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены.</translation>
|
<translation type="vanished">Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>Логирование</translation>
|
<translation>Логирование</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения.</translation>
|
<translation>Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>Сохранять логи</translation>
|
<translation type="vanished">Сохранять логи</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>Открыть папку с логами</translation>
|
<translation type="vanished">Открыть папку с логами</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Сохранить</translation>
|
<translation>Сохранить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>Файлы логов (*.log)</translation>
|
<translation>Файлы логов (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>Файл с логами сохранен</translation>
|
<translation>Файл с логами сохранен</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>Сохранить логи в файл</translation>
|
<translation type="vanished">Сохранить логи в файл</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>Очистить логи?</translation>
|
<translation>Очистить логи?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продолжить</translation>
|
<translation>Продолжить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Отменить</translation>
|
<translation>Отменить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>Логи очищены</translation>
|
<translation>Логи очищены</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>Очистить логи</translation>
|
<translation>Очистить логи</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2069,12 +2239,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> настройки</translation>
|
<translation> настройки</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>Очистить профиль %1</translation>
|
<translation type="vanished">Очистить профиль %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>Очистить профиль %1?</translation>
|
<translation>Очистить профиль %1?</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2084,27 +2253,52 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>Невозможно очистить профиль %1 во время активного соединения</translation>
|
<translation>Невозможно очистить профиль %1 во время активного соединения</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>Удалить </translation>
|
<translation>Удалить </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>Удалить %1 с сервера?</translation>
|
<translation>Удалить %1 с сервера?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>Невозможно удалить активный контейнер</translation>
|
<translation>Невозможно удалить активный контейнер</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2113,14 +2307,14 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Все пользователи, с которыми вы поделились VPN, больше не смогут к нему подключаться.</translation>
|
<translation type="vanished">Все пользователи, с которыми вы поделились VPN, больше не смогут к нему подключаться.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продолжить</translation>
|
<translation>Продолжить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Отменить</translation>
|
<translation>Отменить</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2311,7 +2505,7 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation type="vanished">Что у вас есть?</translation>
|
<translation type="vanished">Что у вас есть?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>Файл с настройками подключения</translation>
|
<translation>Файл с настройками подключения</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2325,77 +2519,87 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>Соединение</translation>
|
<translation>Соединение</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation>Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код</translation>
|
<translation>Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation>Вставьте ключ</translation>
|
<translation>Вставьте ключ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation>Вставить</translation>
|
<translation>Вставить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продолжить</translation>
|
<translation>Продолжить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation>Другие варианты подключения</translation>
|
<translation>Другие варианты подключения</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation>VPN от Amnezia</translation>
|
<translation>VPN от Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation>Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation>
|
<translation>Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation>Self-hosted VPN</translation>
|
<translation>Self-hosted VPN</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation>Настроить VPN на собственном сервере</translation>
|
<translation>Настроить VPN на собственном сервере</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation>Восстановить из резервной копии</translation>
|
<translation>Восстановить из резервной копии</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation>Открыть резервную копию</translation>
|
<translation>Открыть резервную копию</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation>Файлы резервных копий (*.backup)</translation>
|
<translation>Файлы резервных копий (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>Открыть файл с конфигурацией</translation>
|
<translation>Открыть файл с конфигурацией</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>QR-код</translation>
|
<translation>QR-код</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation>У меня ничего нет</translation>
|
<translation>У меня ничего нет</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2600,7 +2804,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Установить</translation>
|
<translation>Установить</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation>Порт должен быть в диапазоне от 1 до 65535</translation>
|
<translation>Порт должен быть в диапазоне от 1 до 65535</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2996,12 +3200,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Поделиться</translation>
|
<translation>Поделиться</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">Ошибка доступа!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>Подключение к </translation>
|
<translation>Подключение к </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>Файл с настройками подключения к </translation>
|
<translation>Файл с настройками подключения к </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3018,6 +3227,11 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation>Настройки восстановлены из бэкап файла</translation>
|
<translation>Настройки восстановлены из бэкап файла</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -3056,12 +3270,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Пароль не найден</translation>
|
<translation>Пароль не найден</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>Не удалось открыть хранилище ключей</translation>
|
<translation>Не удалось открыть хранилище ключей</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>Не удалось удалить закрытый ключ из хранилища ключей</translation>
|
<translation>Не удалось удалить закрытый ключ из хранилища ключей</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3237,27 +3451,27 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Не удалось открыть хранилище ключей</translation>
|
<translation>Не удалось открыть хранилище ключей</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>Не удалось создать генератор закрытых ключей</translation>
|
<translation>Не удалось создать генератор закрытых ключей</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>Не удалось сгенерировать новый закрытый ключ</translation>
|
<translation>Не удалось сгенерировать новый закрытый ключ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>Не удалось получить закрытый ключ из хранилища ключей</translation>
|
<translation>Не удалось получить закрытый ключ из хранилища ключей</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>Не удалось создать шифр шифрования</translation>
|
<translation>Не удалось создать шифр шифрования</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>Не удалось зашифровать данные</translation>
|
<translation>Не удалось зашифровать данные</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4094,7 +4308,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>Все настройки сброшены до значений по умолчанию</translation>
|
<translation>Все настройки сброшены до значений по умолчанию</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4103,7 +4317,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<translation type="vanished">Закэшированные профили очищены</translation>
|
<translation type="vanished">Закэшированные профили очищены</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>Файл резервной копии поврежден</translation>
|
<translation>Файл резервной копии поврежден</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4235,7 +4449,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation>Мбит/с</translation>
|
<translation>Мбит/с</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -27,47 +27,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation>Звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео. Працює для будь-яких сайтів. Швидкість до %1 MBit/s</translation>
|
<translation>Звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео. Працює для будь-яких сайтів. Швидкість до %1 MBit/s</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation>VPN для доступу до заблокованих сайтів у регіонах з високим рівнем інтернет-цензури. </translation>
|
<translation>VPN для доступу до заблокованих сайтів у регіонах з високим рівнем інтернет-цензури. </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation>Amnezia Premium - звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео у високій роздільній здатності. Працює для всіх вебсайтів, навіть у країнах з найвищим рівнем інтернет-цензури.</translation>
|
<translation>Amnezia Premium - звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео у високій роздільній здатності. Працює для всіх вебсайтів, навіть у країнах з найвищим рівнем інтернет-цензури.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation>Amnezia Free — це безкоштовний VPN для обходу блокувань у країнах з високим рівнем інтернет-цензури</translation>
|
<translation>Amnezia Free — це безкоштовний VPN для обходу блокувань у країнах з високим рівнем інтернет-цензури</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation>%1 MBit/s</translation>
|
<translation>%1 MBit/s</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation>%1 днів</translation>
|
<translation>%1 днів</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation>Лише популярні сайти, які заблоковані у вашому регіоні, будуть відкриватись за допомогою VPN підключення (Instagram, Facebook, Twitter та ін.). Звичайні сайти будуть відкриватися без використання VPN, <a href="%1/free" style="color: #FBB26A;">більш детально на нашому сайті.</a></translation>
|
<translation>Лише популярні сайти, які заблоковані у вашому регіоні, будуть відкриватись за допомогою VPN підключення (Instagram, Facebook, Twitter та ін.). Звичайні сайти будуть відкриватися без використання VPN, <a href="%1/free" style="color: #FBB26A;">більш детально на нашому сайті.</a></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation>Безкоштовно</translation>
|
<translation>Безкоштовно</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation>%1 $/місяць</translation>
|
<translation>%1 $/місяць</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -98,7 +103,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>Неможливо відключитися під час підготовки конфігурації</translation>
|
<translation>Неможливо відключитися під час підготовки конфігурації</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -210,9 +215,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>Помилка доступу!</translation>
|
<translation type="vanished">Помилка доступу!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -286,18 +290,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>Неможливо відкрити файл</translation>
|
<translation>Неможливо відкрити файл</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>Недійсний файл конфігурації</translation>
|
<translation>Недійсний файл конфігурації</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>Відскановано %1 з %2.</translation>
|
<translation>Відскановано %1 з %2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation>У імпортованій конфігурації знайдено потенційно небезпечні рядки:</translation>
|
<translation>У імпортованій конфігурації знайдено потенційно небезпечні рядки:</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -473,6 +477,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -507,10 +516,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Не можна змінити сервер при активному підключенні</translation>
|
<translation>Не можна змінити сервер при активному підключенні</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">налаштування AmneziaWG</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Порт</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">Зберегти</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">Зберегти налаштування?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">Продовжити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">Відмінити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">Неможливо змінити налаштування, поки є активне підключення</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>налаштування AmneziaWG</translation>
|
<translation>налаштування AmneziaWG</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -521,81 +583,76 @@ Already installed containers were found on the server. All installed containers
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>MTU</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Зберегти</translation>
|
<translation>Зберегти</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>Значення полів H1-H4 мають бути унікальними</translation>
|
<translation>Значення полів H1-H4 мають бути унікальними</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>Значення поля S1 + розмір повідомлення ініціалізації (148) не має бути рівним значенню S2 + розмір повідомлення відповіді (92)</translation>
|
<translation>Значення поля S1 + розмір повідомлення ініціалізації (148) не має бути рівним значенню S2 + розмір повідомлення відповіді (92)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>Зберегти налаштування?</translation>
|
<translation>Зберегти налаштування?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього.</translation>
|
<translation>Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
|
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -616,12 +673,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продовжити</translation>
|
<translation>Продовжити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Відмінити</translation>
|
<translation>Відмінити</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -960,30 +1017,102 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Зберегти і перезавантажити</translation>
|
<translation type="vanished">Зберегти і перезавантажити</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">MTU</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">Порт</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">Зберегти</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">Зберегти налаштування?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">Продовжити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">Відмінити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">Неможливо змінити налаштування, поки є активне підключення</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>Порт</translation>
|
<translation>Порт</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>MTU</translation>
|
<translation type="vanished">MTU</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Зберегти</translation>
|
<translation>Зберегти</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">Зберегти налаштування?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">Продовжити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">Відмінити</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
|
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1375,8 +1504,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>Пошта</translation>
|
<translation type="vanished">Пошта</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1384,17 +1517,22 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>Для відгуків і повідомлень про помилки</translation>
|
<translation>Для відгуків і повідомлень про помилки</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished">Скопійовано</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>Веб-сайт</translation>
|
<translation>Веб-сайт</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1403,17 +1541,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">https://amnezia.org</translation>
|
<translation type="vanished">https://amnezia.org</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>Версія ПЗ: %1</translation>
|
<translation>Версія ПЗ: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>Перевірити оновлення</translation>
|
<translation>Перевірити оновлення</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>Політика конфіденційності</translation>
|
<translation>Політика конфіденційності</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1886,72 +2024,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені.</translation>
|
<translation type="vanished">Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>Логування</translation>
|
<translation>Логування</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>Увімкнення цієї функції автоматично зберігатиме журнали додатка. За замовчуванням функція логування вимкнена. Увімкніть збереження журналів у випадку збою додатка.</translation>
|
<translation>Увімкнення цієї функції автоматично зберігатиме журнали додатка. За замовчуванням функція логування вимкнена. Увімкніть збереження журналів у випадку збою додатка.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>Зберегти логи</translation>
|
<translation type="vanished">Зберегти логи</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>Відкрити папку з логами</translation>
|
<translation type="vanished">Відкрити папку з логами</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>Зберегти</translation>
|
<translation>Зберегти</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>Logs files (*.log)</translation>
|
<translation>Logs files (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>Файл з логами збережено</translation>
|
<translation>Файл з логами збережено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>Зберегти логи в файл</translation>
|
<translation type="vanished">Зберегти логи в файл</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>Очистити логи?</translation>
|
<translation>Очистити логи?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продовжити</translation>
|
<translation>Продовжити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Відмінити</translation>
|
<translation>Відмінити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>Логи видалено</translation>
|
<translation>Логи видалено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>Видалити логи</translation>
|
<translation>Видалити логи</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2151,22 +2325,46 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> Налаштування</translation>
|
<translation> Налаштування</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>Очистити профіль %1</translation>
|
<translation type="vanished">Очистити профіль %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>Очистити профіль %1?</translation>
|
<translation>Очистити профіль %1?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>Неможливо очистити профіль %1 під час активного підключення</translation>
|
<translation>Неможливо очистити профіль %1 під час активного підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>Неможливо видалити активний контейнер</translation>
|
<translation>Неможливо видалити активний контейнер</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2176,17 +2374,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>Видалити </translation>
|
<translation>Видалити </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>Видалити %1 з сервера?</translation>
|
<translation>Видалити %1 з сервера?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
<translation>Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2195,14 +2393,14 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продовжити</translation>
|
<translation>Продовжити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>Відмінити</translation>
|
<translation>Відмінити</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2393,7 +2591,7 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation type="vanished">Виберіть що у вас є</translation>
|
<translation type="vanished">Виберіть що у вас є</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>Файл з налаштуваннями підключення</translation>
|
<translation>Файл з налаштуваннями підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2407,77 +2605,87 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation>Підключення</translation>
|
<translation>Підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation>Вставте ключ, додайте файл конфігурації або відскануйте QR-код</translation>
|
<translation>Вставте ключ, додайте файл конфігурації або відскануйте QR-код</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation>Вставити ключ</translation>
|
<translation>Вставити ключ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation>Вставити</translation>
|
<translation>Вставити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>Продовжити</translation>
|
<translation>Продовжити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation>Інші параметри підключення</translation>
|
<translation>Інші параметри підключення</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation>VPN від Amnezia</translation>
|
<translation>VPN від Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation>Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia</translation>
|
<translation>Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation>Self-hosted VPN</translation>
|
<translation>Self-hosted VPN</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation>Налаштуйте Amnezia VPN на власному сервері</translation>
|
<translation>Налаштуйте Amnezia VPN на власному сервері</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation>Відновити із бекапа</translation>
|
<translation>Відновити із бекапа</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation>Відкрити бекап файл</translation>
|
<translation>Відкрити бекап файл</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation>Файли резервної копії (*.backup)</translation>
|
<translation>Файли резервної копії (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>Відкрити файл з конфігурацією</translation>
|
<translation>Відкрити файл з конфігурацією</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>QR-код</translation>
|
<translation>QR-код</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation>У мене нічого нема</translation>
|
<translation>У мене нічого нема</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2691,7 +2899,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Встановити</translation>
|
<translation>Встановити</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation>Порт повинен бути в межах від 1 до 65535</translation>
|
<translation>Порт повинен бути в межах від 1 до 65535</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3086,12 +3294,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Поділитись</translation>
|
<translation>Поділитись</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">Помилка доступу!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>Підключення до </translation>
|
<translation>Підключення до </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>Файл з налаштуванням доступу до </translation>
|
<translation>Файл з налаштуванням доступу до </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3108,6 +3321,11 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation>Відновлення налаштувань із бекап файлу</translation>
|
<translation>Відновлення налаштувань із бекап файлу</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -3146,12 +3364,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Пароль не знайдено</translation>
|
<translation>Пароль не знайдено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>Could not open keystore</translation>
|
<translation>Could not open keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>Could not remove private key from keystore</translation>
|
<translation>Could not remove private key from keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3327,27 +3545,27 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>Could not open keystore</translation>
|
<translation>Could not open keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>Could not create private key generator</translation>
|
<translation>Could not create private key generator</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>Could not generate new private key</translation>
|
<translation>Could not generate new private key</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>Could not retrieve private key from keystore</translation>
|
<translation>Could not retrieve private key from keystore</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>Could not create encryption cipher</translation>
|
<translation>Could not create encryption cipher</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>Could not encrypt data</translation>
|
<translation>Could not encrypt data</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4167,7 +4385,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>Всі налаштування були скинуті до значення "По замовчуванню"</translation>
|
<translation>Всі налаштування були скинуті до значення "По замовчуванню"</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4176,7 +4394,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<translation type="vanished">Кеш профілю очищено</translation>
|
<translation type="vanished">Кеш профілю очищено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>Backup файл пошкодженно</translation>
|
<translation>Backup файл пошкодженно</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4308,7 +4526,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation>Mbps</translation>
|
<translation>Mbps</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation>تشکیل کی تیاری کے دوران منقطع ہونا ممکن نہیں ہے</translation>
|
<translation>تشکیل کی تیاری کے دوران منقطع ہونا ممکن نہیں ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -186,9 +191,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>رساءی ناممکن!</translation>
|
<translation type="vanished">رساءی ناممکن!</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -253,18 +257,18 @@ Can't be disabled for current server</source>
|
||||||
<translation>فائل کو کھولنے سے قاصر ہے</translation>
|
<translation>فائل کو کھولنے سے قاصر ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation>غلط کنفیگریشن فائل</translation>
|
<translation>غلط کنفیگریشن فائل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>سکین%1 کی%2.</translation>
|
<translation>سکین%1 کی%2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>فعال کنکشن موجود ہونے کی وجہ سے سرور تبدیل کرنے میں ناکام ہیں</translation>
|
<translation>فعال کنکشن موجود ہونے کی وجہ سے سرور تبدیل کرنے میں ناکام ہیں</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">امنیزیا وی جی کی ترتیبات</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">ام ٹی یو</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">پورٹ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">ترتیبات محفوظ کریں?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>امنیزیا وی جی کی ترتیبات</translation>
|
<translation>امنیزیا وی جی کی ترتیبات</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>پورٹ</translation>
|
<translation>پورٹ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation>ام ٹی یو</translation>
|
<translation type="vanished">ام ٹی یو</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>آپ جن لوگوں کے ساتھ آپ نے اس کنکشن کا اشتراک کیا تھا، وہ اس سے مزید جڑ نہیں سکیں گے۔</translation>
|
<translation>آپ جن لوگوں کے ساتھ آپ نے اس کنکشن کا اشتراک کیا تھا، وہ اس سے مزید جڑ نہیں سکیں گے۔</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>محفوظ کریں</translation>
|
<translation>محفوظ کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation>H1 تا H4 فیلڈز کی قیمتیں مخصوص ہونی چاہیے</translation>
|
<translation>H1 تا H4 فیلڈز کی قیمتیں مخصوص ہونی چاہیے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation>S1 + پیغام شروع کار (148) کے فیلڈ کی قیمت S2 + پیغام جواب (92) کے سائز کے برابر نہیں ہونی چاہئے</translation>
|
<translation>S1 + پیغام شروع کار (148) کے فیلڈ کی قیمت S2 + پیغام جواب (92) کے سائز کے برابر نہیں ہونی چاہئے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>ترتیبات محفوظ کریں?</translation>
|
<translation>ترتیبات محفوظ کریں?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>جاری رکھیں</translation>
|
<translation>جاری رکھیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>منسوخ کریں</translation>
|
<translation>منسوخ کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished">وائر گارڈ ترتیبات</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished">ام ٹی یو</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">پورٹ</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">ترتیبات محفوظ کریں?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished">جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation>وائر گارڈ ترتیبات</translation>
|
<translation>وائر گارڈ ترتیبات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>پورٹ</translation>
|
<translation>پورٹ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
<source>MTU</source>
|
<source>Save settings?</source>
|
||||||
<translation>ام ٹی یو</translation>
|
<translation type="unfinished">ترتیبات محفوظ کریں?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="vanished">ام ٹی یو</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>محفوظ کریں</translation>
|
<translation>محفوظ کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1241,9 +1374,13 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>میل</translation>
|
<translation type="vanished">میل</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1251,32 +1388,37 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>جائزہ اور بگ رپورٹس کے لئے</translation>
|
<translation>جائزہ اور بگ رپورٹس کے لئے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>گِٹ ہَب</translation>
|
<translation>گِٹ ہَب</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>ویب سائٹ</translation>
|
<translation>ویب سائٹ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>سافٹ ویئر ورژن: %1</translation>
|
<translation>سافٹ ویئر ورژن: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>اپ ڈیٹس چیک کریں</translation>
|
<translation>اپ ڈیٹس چیک کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>رازداری کی پالیسی</translation>
|
<translation>رازداری کی پالیسی</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1733,72 +1875,108 @@ Already installed containers were found on the server. All installed containers
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
||||||
<translation>لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی.</translation>
|
<translation type="vanished">لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>لاگنگ</translation>
|
<translation>لاگنگ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>اس فعل کو فعال کرنے سے، ایپلیکیشن کے لاگ خود بخود محفوظ ہوجائیں گے۔ پہلے سے، لاگنگ کی فعالیت غیر فعال ہوتی ہے۔ اگر ایپلیکیشن میں کوئی خرابی ہو، تو لاگ کو بچانا فعال کریں.</translation>
|
<translation>اس فعل کو فعال کرنے سے، ایپلیکیشن کے لاگ خود بخود محفوظ ہوجائیں گے۔ پہلے سے، لاگنگ کی فعالیت غیر فعال ہوتی ہے۔ اگر ایپلیکیشن میں کوئی خرابی ہو، تو لاگ کو بچانا فعال کریں.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>لاگوں کو محفوظ کریں</translation>
|
<translation type="vanished">لاگوں کو محفوظ کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>فائلوں کے فولڈر کو کھولیں</translation>
|
<translation type="vanished">فائلوں کے فولڈر کو کھولیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>محفوظ</translation>
|
<translation>محفوظ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation>لاگ فائلیں (*.log)</translation>
|
<translation>لاگ فائلیں (*.log)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>لاگ فائل محفوظ ہوگئی</translation>
|
<translation>لاگ فائل محفوظ ہوگئی</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>لاگوں کو فائل میں محفوظ کریں</translation>
|
<translation type="vanished">لاگوں کو فائل میں محفوظ کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>کیا آپ لاگوں کو صاف کرنا چاہتے ہیں؟</translation>
|
<translation>کیا آپ لاگوں کو صاف کرنا چاہتے ہیں؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>براہ کرم جاری رکھیں</translation>
|
<translation>براہ کرم جاری رکھیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>منسوخ</translation>
|
<translation>منسوخ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>تم مسح السجلاتلاگوں کو صاف کر دیا گیا ہے</translation>
|
<translation>تم مسح السجلاتلاگوں کو صاف کر دیا گیا ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>لاگوں کو صاف کریں</translation>
|
<translation>لاگوں کو صاف کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1958,22 +2136,21 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation> ترتیبات</translation>
|
<translation> ترتیبات</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
|
||||||
<source>Clear %1 profile</source>
|
<source>Clear %1 profile</source>
|
||||||
<translation>%1 پروفائل کو صاف کریں</translation>
|
<translation type="vanished">%1 پروفائل کو صاف کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation>کیا آپ واقعی %1 پروفائل کو صاف کرنا چاہتے ہیں؟</translation>
|
<translation>کیا آپ واقعی %1 پروفائل کو صاف کرنا چاہتے ہیں؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation>فعال کنکشن کے دوران %1 پروفائل کو صاف نہیں کیا جا سکتا</translation>
|
<translation>فعال کنکشن کے دوران %1 پروفائل کو صاف نہیں کیا جا سکتا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation>فعال کنٹینر کو ہٹانا ممکن نہیں</translation>
|
<translation>فعال کنٹینر کو ہٹانا ممکن نہیں</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1983,29 +2160,54 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>ہٹائیں </translation>
|
<translation>ہٹائیں </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>آپ نے جن کے ساتھ کنکشن شئیر کیا تھا، ان تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی.</translation>
|
<translation>آپ نے جن کے ساتھ کنکشن شئیر کیا تھا، ان تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>کیا آپ سرور سے %1 کو ہٹانا چاہتے ہیں؟</translation>
|
<translation>کیا آپ سرور سے %1 کو ہٹانا چاہتے ہیں؟</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>براہ کرم جاری رکھیں</translation>
|
<translation>براہ کرم جاری رکھیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>منسوخ</translation>
|
<translation>منسوخ</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2189,82 +2391,92 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="unfinished">کنکشن</translation>
|
<translation type="unfinished">کنکشن</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation type="unfinished">داخل کریں</translation>
|
<translation type="unfinished">داخل کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation type="unfinished">بیک اپ سے بحال کریں</translation>
|
<translation type="unfinished">بیک اپ سے بحال کریں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation type="unfinished">بیک اپ فائل کو کھولیں</translation>
|
<translation type="unfinished">بیک اپ فائل کو کھولیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation type="unfinished">بیک اپ فائلیں (*.backup)</translation>
|
<translation type="unfinished">بیک اپ فائلیں (*.backup)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>کنکشن کی ترتیبات والی فائل</translation>
|
<translation>کنکشن کی ترتیبات والی فائل</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>کنفیگ فائل کو کھولیں</translation>
|
<translation>کنفیگ فائل کو کھولیں</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>QR کوڈ</translation>
|
<translation>QR کوڈ</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation type="unfinished">میرے پاس کچھ نہیں ہے</translation>
|
<translation type="unfinished">میرے پاس کچھ نہیں ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2436,7 +2648,7 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>انسٹال</translation>
|
<translation>انسٹال</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2808,12 +3020,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>شیئر</translation>
|
<translation>شیئر</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">رساءی ناممکن!</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>کنکشن کو </translation>
|
<translation>کنکشن کو </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>کنکشن کی ترتیبات کی فائل </translation>
|
<translation>کنکشن کی ترتیبات کی فائل </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2830,6 +3047,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation type="unfinished">ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں</translation>
|
<translation type="unfinished">ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -2868,12 +3090,12 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>پاس ورڈ نہیں ملا</translation>
|
<translation>پاس ورڈ نہیں ملا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>کی اسٹور کھولا نہیں جا سکا</translation>
|
<translation>کی اسٹور کھولا نہیں جا سکا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>خصوصی کلید کو کی اسٹور سے ہٹانا نہیں ہو سکا</translation>
|
<translation>خصوصی کلید کو کی اسٹور سے ہٹانا نہیں ہو سکا</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3049,27 +3271,27 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>کی اسٹور کھولنے میں ناکام</translation>
|
<translation>کی اسٹور کھولنے میں ناکام</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>پرائیویٹ کلید جنریٹر تخلیق نہیں کیا</translation>
|
<translation>پرائیویٹ کلید جنریٹر تخلیق نہیں کیا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>نیا نجی کلید تخلیق نہیں کیا جا سکا</translation>
|
<translation>نیا نجی کلید تخلیق نہیں کیا جا سکا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>کی اسٹور سے نجی کلید حاصل نہیں کیا</translation>
|
<translation>کی اسٹور سے نجی کلید حاصل نہیں کیا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>تشکیل تشکیل نہیں کر سکا</translation>
|
<translation>تشکیل تشکیل نہیں کر سکا</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>ڈیٹا کو محفوظ کرنے میں ناکام</translation>
|
<translation>ڈیٹا کو محفوظ کرنے میں ناکام</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3709,12 +3931,12 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>بیک اپ فائل خراب ہو گئی ہے</translation>
|
<translation>بیک اپ فائل خراب ہو گئی ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>تمام ترتیبات کو ڈیفالٹ اقدار پر دوبارہ ترتیب دیا گیا ہے</translation>
|
<translation>تمام ترتیبات کو ڈیفالٹ اقدار پر دوبارہ ترتیب دیا گیا ہے</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3846,7 +4068,7 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation>ایم بی پی ایس</translation>
|
<translation>ایم بی پی ایس</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -4,47 +4,52 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ApiServicesModel</name>
|
<name>ApiServicesModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="63"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="65"/>
|
||||||
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
<source>Classic VPN for comfortable work, downloading large files and watching videos. Works for any sites. Speed up to %1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="67"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="69"/>
|
||||||
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
<source>VPN to access blocked sites in regions with high levels of Internet censorship. </source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
|
||||||
|
<source><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></source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/models/apiServicesModel.cpp" line="78"/>
|
||||||
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
<source>Amnezia Premium - A classic VPN for comfortable work, downloading large files, and watching videos in high resolution. It works for all websites, even in countries with the highest level of internet censorship.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="75"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="81"/>
|
||||||
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
<source>Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
|
||||||
<source>%1 MBit/s</source>
|
<source>%1 MBit/s</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
|
||||||
<source>%1 days</source>
|
<source>%1 days</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="96"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="110"/>
|
||||||
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
<source>VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. Other sites will be opened from your real IP address, <a href="%1/free" style="color: #FBB26A;">more details on the website.</a></source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
|
||||||
<source>Free</source>
|
<source>Free</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
|
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
|
||||||
<source>%1 $/month</source>
|
<source>%1 $/month</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -75,7 +80,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ConnectButton</name>
|
<name>ConnectButton</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Components/ConnectButton.qml" line="27"/>
|
<location filename="../ui/qml/Components/ConnectButton.qml" line="28"/>
|
||||||
<source>Unable to disconnect during configuration preparation</source>
|
<source>Unable to disconnect during configuration preparation</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -186,9 +191,8 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ExportController</name>
|
<name>ExportController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/exportController.cpp" line="30"/>
|
|
||||||
<source>Access error!</source>
|
<source>Access error!</source>
|
||||||
<translation>访问错误</translation>
|
<translation type="vanished">访问错误</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|
@ -258,18 +262,18 @@ Can't be disabled for current server</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="186"/>
|
<location filename="../ui/controllers/importController.cpp" line="187"/>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="191"/>
|
<location filename="../ui/controllers/importController.cpp" line="192"/>
|
||||||
<source>Invalid configuration file</source>
|
<source>Invalid configuration file</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="606"/>
|
<location filename="../ui/controllers/importController.cpp" line="617"/>
|
||||||
<source>Scanned %1 of %2.</source>
|
<source>Scanned %1 of %2.</source>
|
||||||
<translation>扫描 %1 of %2.</translation>
|
<translation>扫描 %1 of %2.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/importController.cpp" line="641"/>
|
<location filename="../ui/controllers/importController.cpp" line="652"/>
|
||||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -469,6 +473,11 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Gateway endpoint</source>
|
<source>Gateway endpoint</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
|
||||||
|
<source>Dev gateway environment</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageHome</name>
|
<name>PageHome</name>
|
||||||
|
|
@ -503,10 +512,63 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation>已建立连接时无法更改服务器配置</translation>
|
<translation>已建立连接时无法更改服务器配置</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolAwgClientSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="96"/>
|
||||||
|
<source>AmneziaWG settings</source>
|
||||||
|
<translation type="unfinished">AmneziaWG 配置</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="104"/>
|
||||||
|
<source>MTU</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="184"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="194"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">端口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="284"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">保存</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">保存设置?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="291"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="292"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">继续</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="293"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">取消</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="297"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolAwgSettings</name>
|
<name>PageProtocolAwgSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
|
||||||
<source>AmneziaWG settings</source>
|
<source>AmneziaWG settings</source>
|
||||||
<translation>AmneziaWG 配置</translation>
|
<translation>AmneziaWG 配置</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -515,11 +577,6 @@ Already installed containers were found on the server. All installed containers
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>端口</translation>
|
<translation>端口</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
|
||||||
<source>MTU</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Remove AmneziaWG</source>
|
<source>Remove AmneziaWG</source>
|
||||||
<translation type="vanished">移除AmneziaWG</translation>
|
<translation type="vanished">移除AmneziaWG</translation>
|
||||||
|
|
@ -529,87 +586,87 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="vanished">从服务上移除AmneziaWG?</translation>
|
<translation type="vanished">从服务上移除AmneziaWG?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="374"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="357"/>
|
||||||
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
<translation>与您共享连接的所有用户将无法再连接到该连接。</translation>
|
<translation>与您共享连接的所有用户将无法再连接到该连接。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>保存</translation>
|
<translation>保存</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="147"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
|
||||||
<source>Jc - Junk packet count</source>
|
<source>Jc - Junk packet count</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="151"/>
|
||||||
<source>Jmin - Junk packet minimum size</source>
|
<source>Jmin - Junk packet minimum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="172"/>
|
||||||
<source>Jmax - Junk packet maximum size</source>
|
<source>Jmax - Junk packet maximum size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="193"/>
|
||||||
<source>S1 - Init packet junk size</source>
|
<source>S1 - Init packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="214"/>
|
||||||
<source>S2 - Response packet junk size</source>
|
<source>S2 - Response packet junk size</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="235"/>
|
||||||
<source>H1 - Init packet magic header</source>
|
<source>H1 - Init packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="256"/>
|
||||||
<source>H2 - Response packet magic header</source>
|
<source>H2 - Response packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="298"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="277"/>
|
||||||
<source>H4 - Transport packet magic header</source>
|
<source>H4 - Transport packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="320"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="299"/>
|
||||||
<source>H3 - Underload packet magic header</source>
|
<source>H3 - Underload packet magic header</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="345"/>
|
||||||
<source>The values of the H1-H4 fields must be unique</source>
|
<source>The values of the H1-H4 fields must be unique</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="369"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="351"/>
|
||||||
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
<source>The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
|
||||||
<source>Save settings?</source>
|
<source>Save settings?</source>
|
||||||
<translation>保存设置?</translation>
|
<translation>保存设置?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>继续</translation>
|
<translation>继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>取消</translation>
|
<translation>取消</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="382"/>
|
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="363"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -933,24 +990,82 @@ Already installed containers were found on the server. All installed containers
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PageProtocolWireGuardSettings</name>
|
<name>PageProtocolWireGuardClientSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
|
||||||
<source>WG settings</source>
|
<source>WG settings</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
|
||||||
<source>Port</source>
|
|
||||||
<translation type="unfinished">端口</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
|
|
||||||
<source>MTU</source>
|
<source>MTU</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="157"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="118"/>
|
||||||
|
<source>Server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="128"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">端口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="151"/>
|
||||||
|
<source>Save</source>
|
||||||
|
<translation type="unfinished">保存</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="157"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">保存设置?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="158"/>
|
||||||
|
<source>Only the settings for this device will be changed</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="159"/>
|
||||||
|
<source>Continue</source>
|
||||||
|
<translation type="unfinished">继续</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="160"/>
|
||||||
|
<source>Cancel</source>
|
||||||
|
<translation type="unfinished">取消</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="164"/>
|
||||||
|
<source>Unable change settings while there is an active connection</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageProtocolWireGuardSettings</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
|
||||||
|
<source>WG settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
|
||||||
|
<source>Port</source>
|
||||||
|
<translation type="unfinished">端口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="138"/>
|
||||||
|
<source>Save settings?</source>
|
||||||
|
<translation type="unfinished">保存设置?</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="139"/>
|
||||||
|
<source>All users with whom you shared a connection with will no longer be able to connect to it.</source>
|
||||||
|
<translation type="unfinished">与您共享连接的所有用户将无法再连接到该连接。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="145"/>
|
||||||
<source>Unable change settings while there is an active connection</source>
|
<source>Unable change settings while there is an active connection</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -959,15 +1074,17 @@ Already installed containers were found on the server. All installed containers
|
||||||
<translation type="obsolete">与您共享连接的所有用户将无法再连接到该连接。</translation>
|
<translation type="obsolete">与您共享连接的所有用户将无法再连接到该连接。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation type="obsolete">继续</translation>
|
<translation type="unfinished">继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation type="obsolete">取消</translation>
|
<translation type="unfinished">取消</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
|
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>保存</translation>
|
<translation>保存</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1329,9 +1446,13 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
|
||||||
<source>Mail</source>
|
<source>Mail</source>
|
||||||
<translation>邮件</translation>
|
<translation type="vanished">邮件</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
|
||||||
|
<source>support@amnezia.org</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
|
||||||
|
|
@ -1339,32 +1460,37 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation>用于评论和提交软件的缺陷</translation>
|
<translation>用于评论和提交软件的缺陷</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="132"/>
|
||||||
|
<source>Copied</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="143"/>
|
||||||
<source>GitHub</source>
|
<source>GitHub</source>
|
||||||
<translation>GitHub</translation>
|
<translation>GitHub</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="148"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="150"/>
|
||||||
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
<source>https://github.com/amnezia-vpn/amnezia-client</source>
|
||||||
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
|
||||||
<source>Website</source>
|
<source>Website</source>
|
||||||
<translation>官网</translation>
|
<translation>官网</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="179"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="181"/>
|
||||||
<source>Software version: %1</source>
|
<source>Software version: %1</source>
|
||||||
<translation>软件版本: %1</translation>
|
<translation>软件版本: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="208"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="210"/>
|
||||||
<source>Check for updates</source>
|
<source>Check for updates</source>
|
||||||
<translation>检查更新</translation>
|
<translation>检查更新</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
|
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
|
||||||
<source>Privacy Policy</source>
|
<source>Privacy Policy</source>
|
||||||
<translation>隐私政策</translation>
|
<translation>隐私政策</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -1849,72 +1975,104 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<context>
|
<context>
|
||||||
<name>PageSettingsLogging</name>
|
<name>PageSettingsLogging</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="24"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
|
||||||
<source>Logging is enabled. Note that logs will be automatically disabled after 14 days, and all log files will be deleted.</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
|
|
||||||
<source>Logging</source>
|
<source>Logging</source>
|
||||||
<translation>日志</translation>
|
<translation>日志</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="70"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="57"/>
|
||||||
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
<source>Enabling this function will save application's logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
|
||||||
<translation>默认情况下,日志功能是禁用的。如果应用程序出现故障,则启用日志保存功能。</translation>
|
<translation>默认情况下,日志功能是禁用的。如果应用程序出现故障,则启用日志保存功能。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
|
|
||||||
<source>Save logs</source>
|
<source>Save logs</source>
|
||||||
<translation>记录日志</translation>
|
<translation type="vanished">记录日志</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
|
|
||||||
<source>Open folder with logs</source>
|
<source>Open folder with logs</source>
|
||||||
<translation>打开日志文件夹</translation>
|
<translation type="vanished">打开日志文件夹</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="171"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="255"/>
|
||||||
<source>Save</source>
|
<source>Save</source>
|
||||||
<translation>保存</translation>
|
<translation>保存</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="172"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="256"/>
|
||||||
<source>Logs files (*.log)</source>
|
<source>Logs files (*.log)</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="181"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="265"/>
|
||||||
<source>Logs file saved</source>
|
<source>Logs file saved</source>
|
||||||
<translation>日志文件已保存</translation>
|
<translation>日志文件已保存</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
|
|
||||||
<source>Save logs to file</source>
|
<source>Save logs to file</source>
|
||||||
<translation>保存日志到文件</translation>
|
<translation type="vanished">保存日志到文件</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="184"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="68"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="93"/>
|
||||||
<source>Clear logs?</source>
|
<source>Clear logs?</source>
|
||||||
<translation>清理日志?</translation>
|
<translation>清理日志?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>继续</translation>
|
<translation>继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>取消</translation>
|
<translation>取消</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="101"/>
|
||||||
<source>Logs have been cleaned up</source>
|
<source>Logs have been cleaned up</source>
|
||||||
<translation>日志已清理</translation>
|
<translation>日志已清理</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="211"/>
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="122"/>
|
||||||
|
<source>Client logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="132"/>
|
||||||
|
<source>AmneziaVPN logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="141"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="220"/>
|
||||||
|
<source>Open logs folder</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="160"/>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="244"/>
|
||||||
|
<source>Export logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="196"/>
|
||||||
|
<source>Service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="208"/>
|
||||||
|
<source>AmneziaVPN-service logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="86"/>
|
||||||
<source>Clear logs</source>
|
<source>Clear logs</source>
|
||||||
<translation>清理日志</translation>
|
<translation>清理日志</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2102,12 +2260,7 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation>配置</translation>
|
<translation>配置</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||||
<source>Clear %1 profile</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="138"/>
|
|
||||||
<source>Clear %1 profile?</source>
|
<source>Clear %1 profile?</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2117,22 +2270,47 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="145"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="100"/>
|
||||||
|
<source> connection settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="112"/>
|
||||||
|
<source>Click the "connect" button to create a connection configuration</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="132"/>
|
||||||
|
<source> server settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="173"/>
|
||||||
|
<source>Clear profile</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="177"/>
|
||||||
|
<source>The connection configuration will be deleted for this device only</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="183"/>
|
||||||
<source>Unable to clear %1 profile while there is an active connection</source>
|
<source>Unable to clear %1 profile while there is an active connection</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
|
||||||
<source>Remove </source>
|
<source>Remove </source>
|
||||||
<translation>移除</translation>
|
<translation>移除</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="191"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="229"/>
|
||||||
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
<source>All users with whom you shared a connection will no longer be able to connect to it.</source>
|
||||||
<translation>与您共享连接的所有用户将无法再连接到该连接。</translation>
|
<translation>与您共享连接的所有用户将无法再连接到该连接。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="236"/>
|
||||||
<source>Cannot remove active container</source>
|
<source>Cannot remove active container</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2145,7 +2323,7 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation type="obsolete"> 从服务器</translation>
|
<translation type="obsolete"> 从服务器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="190"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="228"/>
|
||||||
<source>Remove %1 from server?</source>
|
<source>Remove %1 from server?</source>
|
||||||
<translation>从服务器移除 %1 ?</translation>
|
<translation>从服务器移除 %1 ?</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2154,14 +2332,14 @@ And if you don't like the app, all the more support it - the donation will
|
||||||
<translation type="obsolete">与您共享连接的所有用户将无法再连接到此链接</translation>
|
<translation type="obsolete">与您共享连接的所有用户将无法再连接到此链接</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation>继续</translation>
|
<translation>继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
|
||||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
|
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<translation>取消</translation>
|
<translation>取消</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2376,82 +2554,92 @@ It's okay as long as it's from someone you trust.</source>
|
||||||
<translation type="unfinished">连接</translation>
|
<translation type="unfinished">连接</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="67"/>
|
<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="91"/>
|
||||||
|
<source>Enable logs</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="112"/>
|
||||||
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
<source>Insert the key, add a configuration file or scan the QR-code</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
|
||||||
<source>Insert key</source>
|
<source>Insert key</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
|
||||||
<source>Insert</source>
|
<source>Insert</source>
|
||||||
<translation type="unfinished">插入</translation>
|
<translation type="unfinished">插入</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
|
||||||
<source>Continue</source>
|
<source>Continue</source>
|
||||||
<translation type="unfinished">继续</translation>
|
<translation type="unfinished">继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
|
||||||
<source>Other connection options</source>
|
<source>Other connection options</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
|
||||||
<source>VPN by Amnezia</source>
|
<source>VPN by Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
|
||||||
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
<source>Connect to classic paid and free VPN services from Amnezia</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
|
||||||
<source>Self-hosted VPN</source>
|
<source>Self-hosted VPN</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
|
||||||
<source>Configure Amnezia VPN on your own server</source>
|
<source>Configure Amnezia VPN on your own server</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
|
||||||
<source>Restore from backup</source>
|
<source>Restore from backup</source>
|
||||||
<translation type="unfinished">从备份还原</translation>
|
<translation type="unfinished">从备份还原</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
|
||||||
<source>Open backup file</source>
|
<source>Open backup file</source>
|
||||||
<translation type="unfinished">打开备份文件</translation>
|
<translation type="unfinished">打开备份文件</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
|
||||||
<source>Backup files (*.backup)</source>
|
<source>Backup files (*.backup)</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
|
||||||
<source>File with connection settings</source>
|
<source>File with connection settings</source>
|
||||||
<translation>包含连接配置的文件</translation>
|
<translation>包含连接配置的文件</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
|
||||||
<source>Open config file</source>
|
<source>Open config file</source>
|
||||||
<translation>打开配置文件</translation>
|
<translation>打开配置文件</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
|
||||||
<source>QR code</source>
|
<source>QR code</source>
|
||||||
<translation>二维码</translation>
|
<translation>二维码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
|
||||||
<source>I have nothing</source>
|
<source>I have nothing</source>
|
||||||
<translation type="unfinished">我没有</translation>
|
<translation type="unfinished">我没有</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -2661,7 +2849,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>安装</translation>
|
<translation>安装</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="267"/>
|
<location filename="../ui/qml/Pages2/PageSetupWizardProtocolSettings.qml" line="268"/>
|
||||||
<source>The port must be in the range of 1 to 65535</source>
|
<source>The port must be in the range of 1 to 65535</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3077,12 +3265,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>共享</translation>
|
<translation>共享</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="143"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="147"/>
|
||||||
|
<source>Access error!</source>
|
||||||
|
<translation type="unfinished">访问错误</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="153"/>
|
||||||
<source>Connection to </source>
|
<source>Connection to </source>
|
||||||
<translation>连接到 </translation>
|
<translation>连接到 </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="144"/>
|
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="154"/>
|
||||||
<source>File with connection settings to </source>
|
<source>File with connection settings to </source>
|
||||||
<translation>连接配置文件的内容为 </translation>
|
<translation>连接配置文件的内容为 </translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3099,6 +3292,11 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<source>Settings restored from backup file</source>
|
<source>Settings restored from backup file</source>
|
||||||
<translation type="unfinished">从备份文件还原配置</translation>
|
<translation type="unfinished">从备份文件还原配置</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<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>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PopupType</name>
|
<name>PopupType</name>
|
||||||
|
|
@ -3137,12 +3335,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>未发现密码</translation>
|
<translation>未发现密码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="173"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="175"/>
|
||||||
<source>Could not open keystore</source>
|
<source>Could not open keystore</source>
|
||||||
<translation>无法打开密钥库</translation>
|
<translation>无法打开密钥库</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="179"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="181"/>
|
||||||
<source>Could not remove private key from keystore</source>
|
<source>Could not remove private key from keystore</source>
|
||||||
<translation>无法从密钥库中删除私钥</translation>
|
<translation>无法从密钥库中删除私钥</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -3318,27 +3516,27 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||||
<translation>无法打开密钥库</translation>
|
<translation>无法打开密钥库</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="124"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="126"/>
|
||||||
<source>Could not create private key generator</source>
|
<source>Could not create private key generator</source>
|
||||||
<translation>无法创建私钥生成器</translation>
|
<translation>无法创建私钥生成器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="131"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="133"/>
|
||||||
<source>Could not generate new private key</source>
|
<source>Could not generate new private key</source>
|
||||||
<translation>无法生成新的私钥</translation>
|
<translation>无法生成新的私钥</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="139"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="141"/>
|
||||||
<source>Could not retrieve private key from keystore</source>
|
<source>Could not retrieve private key from keystore</source>
|
||||||
<translation>无法从密钥库检索私钥</translation>
|
<translation>无法从密钥库检索私钥</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="147"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="149"/>
|
||||||
<source>Could not create encryption cipher</source>
|
<source>Could not create encryption cipher</source>
|
||||||
<translation>无法创建加密密码</translation>
|
<translation>无法创建加密密码</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="155"/>
|
<location filename="../3rd/qtkeychain/qtkeychain/keychain_android.cpp" line="157"/>
|
||||||
<source>Could not encrypt data</source>
|
<source>Could not encrypt data</source>
|
||||||
<translation>无法加密数据</translation>
|
<translation>无法加密数据</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4169,12 +4367,12 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsController</name>
|
<name>SettingsController</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
|
||||||
<source>Backup file is corrupted</source>
|
<source>Backup file is corrupted</source>
|
||||||
<translation>备份文件已损坏</translation>
|
<translation>备份文件已损坏</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui/controllers/settingsController.cpp" line="160"/>
|
<location filename="../ui/controllers/settingsController.cpp" line="174"/>
|
||||||
<source>All settings have been reset to default values</source>
|
<source>All settings have been reset to default values</source>
|
||||||
<translation>所配置恢复为默认值</translation>
|
<translation>所配置恢复为默认值</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
@ -4314,7 +4512,7 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||||
<context>
|
<context>
|
||||||
<name>VpnConnection</name>
|
<name>VpnConnection</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../vpnconnection.cpp" line="375"/>
|
<location filename="../vpnconnection.cpp" line="408"/>
|
||||||
<source>Mbps</source>
|
<source>Mbps</source>
|
||||||
<translation></translation>
|
<translation></translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,13 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
|
||||||
|
|
||||||
void ConnectionController::openConnection()
|
void ConnectionController::openConnection()
|
||||||
{
|
{
|
||||||
// #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||||
// if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
|
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
|
||||||
// {
|
{
|
||||||
// emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
|
emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
|
|
@ -51,8 +51,11 @@ void ConnectionController::openConnection()
|
||||||
if (configVersion == ApiConfigSources::Telegram
|
if (configVersion == ApiConfigSources::Telegram
|
||||||
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||||
emit updateApiConfigFromTelegram();
|
emit updateApiConfigFromTelegram();
|
||||||
|
} else if (configVersion == ApiConfigSources::AmneziaGateway
|
||||||
|
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
|
||||||
|
emit updateApiConfigFromGateway();
|
||||||
} else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
|
} 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) {
|
if (configVersion == ApiConfigSources::Telegram) {
|
||||||
emit updateApiConfigFromTelegram();
|
emit updateApiConfigFromTelegram();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -121,9 +121,8 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container
|
||||||
|
|
||||||
jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
||||||
|
|
||||||
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg) {
|
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
|
||||||
auto clientId = jsonNativeConfig.value(config_key::clientId).toString();
|
errorCode = m_clientManagementModel->appendClient(jsonNativeConfig, clientName, container, credentials, serverController);
|
||||||
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials, serverController);
|
|
||||||
}
|
}
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
@ -248,10 +247,10 @@ void ExportController::generateCloakConfig()
|
||||||
emit exportConfigChanged();
|
emit exportConfigChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportController::generateXrayConfig()
|
void ExportController::generateXrayConfig(const QString &clientName)
|
||||||
{
|
{
|
||||||
QJsonObject nativeConfig;
|
QJsonObject nativeConfig;
|
||||||
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
|
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, clientName, Proto::Xray, nativeConfig);
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
emit exportErrorOccurred(errorCode);
|
emit exportErrorOccurred(errorCode);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ public slots:
|
||||||
void generateAwgConfig(const QString &clientName);
|
void generateAwgConfig(const QString &clientName);
|
||||||
void generateShadowSocksConfig();
|
void generateShadowSocksConfig();
|
||||||
void generateCloakConfig();
|
void generateCloakConfig();
|
||||||
void generateXrayConfig();
|
void generateXrayConfig(const QString &clientName);
|
||||||
|
|
||||||
QString getConfig();
|
QString getConfig();
|
||||||
QString getNativeConfigString();
|
QString getNativeConfigString();
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
#include <QUrlQuery>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QUrlQuery>
|
||||||
|
|
||||||
#include "utilities.h"
|
|
||||||
#include "core/serialization/serialization.h"
|
|
||||||
#include "core/errorstrings.h"
|
#include "core/errorstrings.h"
|
||||||
|
#include "core/serialization/serialization.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
#include "platforms/android/android_controller.h"
|
#include "platforms/android/android_controller.h"
|
||||||
|
|
@ -39,11 +39,12 @@ namespace
|
||||||
const QString amneziaConfigPatternUserName = "userName";
|
const QString amneziaConfigPatternUserName = "userName";
|
||||||
const QString amneziaConfigPatternPassword = "password";
|
const QString amneziaConfigPatternPassword = "password";
|
||||||
const QString amneziaFreeConfigPattern = "api_key";
|
const QString amneziaFreeConfigPattern = "api_key";
|
||||||
|
const QString amneziaPremiumConfigPattern = "auth_data";
|
||||||
const QString backupPattern = "Servers/serversList";
|
const QString backupPattern = "Servers/serversList";
|
||||||
|
|
||||||
if (config.contains(backupPattern)) {
|
if (config.contains(backupPattern)) {
|
||||||
return ConfigTypes::Backup;
|
return ConfigTypes::Backup;
|
||||||
} else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern)
|
} else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern) || config.contains(amneziaPremiumConfigPattern)
|
||||||
|| (config.contains(amneziaConfigPatternHostName) && config.contains(amneziaConfigPatternUserName)
|
|| (config.contains(amneziaConfigPatternHostName) && config.contains(amneziaConfigPatternUserName)
|
||||||
&& config.contains(amneziaConfigPatternPassword))) {
|
&& config.contains(amneziaConfigPatternPassword))) {
|
||||||
return ConfigTypes::Amnezia;
|
return ConfigTypes::Amnezia;
|
||||||
|
|
@ -84,7 +85,7 @@ bool ImportController::extractConfigFromFile(const QString &fileName)
|
||||||
return extractConfigFromData(data);
|
return extractConfigFromData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit importErrorOccurred(tr("Unable to open file"), false);
|
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,36 +97,40 @@ bool ImportController::extractConfigFromData(QString data)
|
||||||
|
|
||||||
if (config.startsWith("vless://")) {
|
if (config.startsWith("vless://")) {
|
||||||
m_configType = ConfigTypes::Xray;
|
m_configType = ConfigTypes::Xray;
|
||||||
m_config = extractXrayConfig(Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg),
|
m_config = extractXrayConfig(
|
||||||
QJsonDocument::JsonFormat::Compact), prefix);
|
Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||||
|
prefix);
|
||||||
return m_config.empty() ? false : true;
|
return m_config.empty() ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.startsWith("vmess://") && config.contains("@")) {
|
if (config.startsWith("vmess://") && config.contains("@")) {
|
||||||
m_configType = ConfigTypes::Xray;
|
m_configType = ConfigTypes::Xray;
|
||||||
m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg),
|
m_config = extractXrayConfig(
|
||||||
QJsonDocument::JsonFormat::Compact), prefix);
|
Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||||
|
prefix);
|
||||||
return m_config.empty() ? false : true;
|
return m_config.empty() ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.startsWith("vmess://")) {
|
if (config.startsWith("vmess://")) {
|
||||||
m_configType = ConfigTypes::Xray;
|
m_configType = ConfigTypes::Xray;
|
||||||
m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg),
|
m_config = extractXrayConfig(
|
||||||
QJsonDocument::JsonFormat::Compact), prefix);
|
Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||||
|
prefix);
|
||||||
return m_config.empty() ? false : true;
|
return m_config.empty() ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.startsWith("trojan://")) {
|
if (config.startsWith("trojan://")) {
|
||||||
m_configType = ConfigTypes::Xray;
|
m_configType = ConfigTypes::Xray;
|
||||||
m_config = extractXrayConfig(Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg),
|
m_config = extractXrayConfig(
|
||||||
QJsonDocument::JsonFormat::Compact), prefix);
|
Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||||
|
prefix);
|
||||||
return m_config.empty() ? false : true;
|
return m_config.empty() ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.startsWith("ss://") && !config.contains("plugin=")) {
|
if (config.startsWith("ss://") && !config.contains("plugin=")) {
|
||||||
m_configType = ConfigTypes::ShadowSocks;
|
m_configType = ConfigTypes::ShadowSocks;
|
||||||
m_config = extractXrayConfig(Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg),
|
m_config = extractXrayConfig(
|
||||||
QJsonDocument::JsonFormat::Compact), prefix);
|
Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), prefix);
|
||||||
return m_config.empty() ? false : true;
|
return m_config.empty() ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,6 +178,7 @@ bool ImportController::extractConfigFromData(QString data)
|
||||||
}
|
}
|
||||||
case ConfigTypes::Amnezia: {
|
case ConfigTypes::Amnezia: {
|
||||||
m_config = QJsonDocument::fromJson(config.toUtf8()).object();
|
m_config = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||||
|
processAmneziaConfig(m_config);
|
||||||
if (!m_config.empty()) {
|
if (!m_config.empty()) {
|
||||||
checkForMaliciousStrings(m_config);
|
checkForMaliciousStrings(m_config);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -183,12 +189,12 @@ bool ImportController::extractConfigFromData(QString data)
|
||||||
if (!m_serversModel->getServersCount()) {
|
if (!m_serversModel->getServersCount()) {
|
||||||
emit restoreAppConfig(config.toUtf8());
|
emit restoreAppConfig(config.toUtf8());
|
||||||
} else {
|
} else {
|
||||||
emit importErrorOccurred(tr("Invalid configuration file"), false);
|
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ConfigTypes::Invalid: {
|
case ConfigTypes::Invalid: {
|
||||||
emit importErrorOccurred(tr("Invalid configuration file"), false);
|
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,24 +243,26 @@ void ImportController::processNativeWireGuardConfig()
|
||||||
auto containers = m_config.value(config_key::containers).toArray();
|
auto containers = m_config.value(config_key::containers).toArray();
|
||||||
if (!containers.isEmpty()) {
|
if (!containers.isEmpty()) {
|
||||||
auto container = containers.at(0).toObject();
|
auto container = containers.at(0).toObject();
|
||||||
auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
|
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
|
||||||
auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
|
auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
|
||||||
|
|
||||||
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
|
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
|
||||||
QString junkPacketMinSize = QString::number(10);
|
QString junkPacketMinSize = QString::number(10);
|
||||||
QString junkPacketMaxSize = QString::number(50);
|
QString junkPacketMaxSize = QString::number(50);
|
||||||
protocolConfig[config_key::junkPacketCount] = junkPacketCount;
|
clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount;
|
||||||
protocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
|
clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
|
||||||
protocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
|
clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
|
||||||
protocolConfig[config_key::initPacketJunkSize] = "0";
|
clientProtocolConfig[config_key::initPacketJunkSize] = "0";
|
||||||
protocolConfig[config_key::responsePacketJunkSize] = "0";
|
clientProtocolConfig[config_key::responsePacketJunkSize] = "0";
|
||||||
protocolConfig[config_key::initPacketMagicHeader] = "1";
|
clientProtocolConfig[config_key::initPacketMagicHeader] = "1";
|
||||||
protocolConfig[config_key::responsePacketMagicHeader] = "2";
|
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
|
||||||
protocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
||||||
protocolConfig[config_key::transportPacketMagicHeader] = "4";
|
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
||||||
|
|
||||||
containerConfig[config_key::last_config] = QString(QJsonDocument(protocolConfig).toJson());
|
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
||||||
container["wireguard"] = containerConfig;
|
|
||||||
|
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
||||||
|
container["wireguard"] = serverProtocolConfig;
|
||||||
containers.replace(0, container);
|
containers.replace(0, container);
|
||||||
m_config[config_key::containers] = containers;
|
m_config[config_key::containers] = containers;
|
||||||
}
|
}
|
||||||
|
|
@ -353,20 +361,19 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||||
QJsonObject lastConfig;
|
QJsonObject lastConfig;
|
||||||
lastConfig[config_key::config] = data;
|
lastConfig[config_key::config] = data;
|
||||||
|
|
||||||
const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)");
|
auto url { QUrl::fromUserInput(configMap.value("Endpoint")) };
|
||||||
QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(data);
|
|
||||||
QString hostName;
|
QString hostName;
|
||||||
QString port;
|
QString port;
|
||||||
if (hostNameAndPortMatch.hasCaptured(1)) {
|
if (!url.host().isEmpty()) {
|
||||||
hostName = hostNameAndPortMatch.captured(1);
|
hostName = url.host();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Key parameter 'Endpoint' is missing";
|
qDebug() << "Key parameter 'Endpoint' is missing or has an invalid format";
|
||||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hostNameAndPortMatch.hasCaptured(2)) {
|
if (url.port() != -1) {
|
||||||
port = hostNameAndPortMatch.captured(2);
|
port = QString::number(url.port());
|
||||||
} else {
|
} else {
|
||||||
port = protocols::wireguard::defaultPort;
|
port = protocols::wireguard::defaultPort;
|
||||||
}
|
}
|
||||||
|
|
@ -395,6 +402,10 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||||
lastConfig[config_key::mtu] = configMap.value("MTU");
|
lastConfig[config_key::mtu] = configMap.value("MTU");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!configMap.value("PersistentKeepalive").isEmpty()) {
|
||||||
|
lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive");
|
||||||
|
}
|
||||||
|
|
||||||
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
|
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
|
||||||
|
|
||||||
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
||||||
|
|
@ -419,6 +430,12 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||||
m_configType = ConfigTypes::Awg;
|
m_configType = ConfigTypes::Awg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!configMap.value("MTU").isEmpty()) {
|
||||||
|
lastConfig[config_key::mtu] = configMap.value("MTU");
|
||||||
|
} else {
|
||||||
|
lastConfig[config_key::mtu] = protocolName == "awg" ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject wireguardConfig;
|
QJsonObject wireguardConfig;
|
||||||
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
|
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
|
||||||
wireguardConfig[config_key::isThirdPartyConfig] = true;
|
wireguardConfig[config_key::isThirdPartyConfig] = true;
|
||||||
|
|
@ -646,3 +663,28 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImportController::processAmneziaConfig(QJsonObject &config)
|
||||||
|
{
|
||||||
|
auto containers = config.value(config_key::containers).toArray();
|
||||||
|
for (auto i = 0; i < containers.size(); i++) {
|
||||||
|
auto container = containers.at(i).toObject();
|
||||||
|
auto dockerContainer = ContainerProps::containerFromString(container.value(config_key::container).toString());
|
||||||
|
if (dockerContainer == DockerContainer::Awg || dockerContainer == DockerContainer::WireGuard) {
|
||||||
|
auto containerConfig = container.value(ContainerProps::containerTypeToString(dockerContainer)).toObject();
|
||||||
|
auto protocolConfig = containerConfig.value(config_key::last_config).toString();
|
||||||
|
if (protocolConfig.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject jsonConfig = QJsonDocument::fromJson(protocolConfig.toUtf8()).object();
|
||||||
|
jsonConfig[config_key::mtu] = dockerContainer == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
|
||||||
|
|
||||||
|
containerConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
||||||
|
|
||||||
|
container[ContainerProps::containerTypeToString(dockerContainer)] = containerConfig;
|
||||||
|
containers.replace(i, container);
|
||||||
|
config.insert(config_key::containers, containers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void importFinished();
|
void importFinished();
|
||||||
void importErrorOccurred(const QString &errorMessage, bool goToPageHome);
|
|
||||||
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
|
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
|
||||||
|
|
||||||
void qrDecodingFinished();
|
void qrDecodingFinished();
|
||||||
|
|
@ -68,6 +67,8 @@ private:
|
||||||
|
|
||||||
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
|
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
|
||||||
|
|
||||||
|
void processAmneziaConfig(QJsonObject &config);
|
||||||
|
|
||||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||||
void stopDecodingQr();
|
void stopDecodingQr();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
47
client/ui/controllers/installController.cpp
Normal file → Executable file
47
client/ui/controllers/installController.cpp
Normal file → Executable file
|
|
@ -32,32 +32,8 @@ namespace
|
||||||
constexpr char availableCountries[] = "available_countries";
|
constexpr char availableCountries[] = "available_countries";
|
||||||
|
|
||||||
constexpr char apiConfig[] = "api_config";
|
constexpr char apiConfig[] = "api_config";
|
||||||
|
constexpr char authData[] = "auth_data";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
QString getNextDriverLetter()
|
|
||||||
{
|
|
||||||
QProcess drivesProc;
|
|
||||||
drivesProc.start("wmic logicaldisk get caption");
|
|
||||||
drivesProc.waitForFinished();
|
|
||||||
QString drives = drivesProc.readAll();
|
|
||||||
qDebug() << drives;
|
|
||||||
|
|
||||||
QString letters = "CFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
QString letter;
|
|
||||||
for (int i = letters.size() - 1; i > 0; i--) {
|
|
||||||
letter = letters.at(i);
|
|
||||||
if (!drives.contains(letter + ":"))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (letter == "C:") {
|
|
||||||
// set err info
|
|
||||||
qDebug() << "Can't find free drive letter";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return letter;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||||
|
|
@ -135,10 +111,10 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||||
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
|
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
|
||||||
} else if (container == DockerContainer::Sftp) {
|
} else if (container == DockerContainer::Sftp) {
|
||||||
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
|
||||||
containerConfig.insert(config_key::password, Utils::getRandomString(10));
|
containerConfig.insert(config_key::password, Utils::getRandomString(16));
|
||||||
} else if (container == DockerContainer::Socks5Proxy) {
|
} else if (container == DockerContainer::Socks5Proxy) {
|
||||||
containerConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
|
containerConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
|
||||||
containerConfig.insert(config_key::password, Utils::getRandomString(10));
|
containerConfig.insert(config_key::password, Utils::getRandomString(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
config.insert(config_key::container, ContainerProps::containerToString(container));
|
config.insert(config_key::container, ContainerProps::containerToString(container));
|
||||||
|
|
@ -667,7 +643,7 @@ void InstallController::mountSftpDrive(const QString &port, const QString &passw
|
||||||
QString hostname = serverCredentials.hostName;
|
QString hostname = serverCredentials.hostName;
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
mountPath = getNextDriverLetter() + ":";
|
mountPath = Utils::getNextDriverLetter() + ":";
|
||||||
// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3")
|
// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3")
|
||||||
// .arg(labelTftpUserNameText())
|
// .arg(labelTftpUserNameText())
|
||||||
// .arg(labelTftpPortText())
|
// .arg(labelTftpPortText())
|
||||||
|
|
@ -768,7 +744,7 @@ bool InstallController::checkSshConnection(QSharedPointer<ServerController> serv
|
||||||
} else {
|
} else {
|
||||||
if (output.contains(tr("Please login as the user"))) {
|
if (output.contains(tr("Please login as the user"))) {
|
||||||
output.replace("\n", "");
|
output.replace("\n", "");
|
||||||
emit installationErrorOccurred(output);
|
emit wrongInstallationUser(output);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -826,7 +802,7 @@ bool InstallController::installServiceFromApi()
|
||||||
|
|
||||||
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
|
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
|
||||||
m_apiServicesModel->getSelectedServiceType(),
|
m_apiServicesModel->getSelectedServiceType(),
|
||||||
m_apiServicesModel->getSelectedServiceProtocol(), "", serverConfig);
|
m_apiServicesModel->getSelectedServiceProtocol(), "", QJsonObject(), serverConfig);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
emit installationErrorOccurred(errorCode);
|
emit installationErrorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -853,24 +829,25 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
|
||||||
|
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||||
|
auto authData = serverConfig.value(configKey::authData).toObject();
|
||||||
|
|
||||||
QJsonObject newServerConfig;
|
QJsonObject newServerConfig;
|
||||||
ErrorCode errorCode =
|
ErrorCode errorCode = apiController.getConfigForService(
|
||||||
apiController.getConfigForService(m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
|
m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
|
||||||
apiConfig.value(configKey::serviceType).toString(),
|
apiConfig.value(configKey::serviceType).toString(), apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode,
|
||||||
apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode, newServerConfig);
|
authData, newServerConfig);
|
||||||
if (errorCode != ErrorCode::NoError) {
|
if (errorCode != ErrorCode::NoError) {
|
||||||
emit installationErrorOccurred(errorCode);
|
emit installationErrorOccurred(errorCode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
||||||
newApiConfig.insert(configKey::serviceInfo, apiConfig.value(configKey::serviceInfo));
|
|
||||||
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
||||||
newApiConfig.insert(configKey::serviceType, apiConfig.value(configKey::serviceType));
|
newApiConfig.insert(configKey::serviceType, apiConfig.value(configKey::serviceType));
|
||||||
newApiConfig.insert(configKey::serviceProtocol, apiConfig.value(configKey::serviceProtocol));
|
newApiConfig.insert(configKey::serviceProtocol, apiConfig.value(configKey::serviceProtocol));
|
||||||
|
|
||||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||||
|
newServerConfig.insert(configKey::authData, authData);
|
||||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||||
|
|
||||||
if (reloadServiceConfig) {
|
if (reloadServiceConfig) {
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ signals:
|
||||||
void removeAllContainersFinished(const QString &finishedMessage);
|
void removeAllContainersFinished(const QString &finishedMessage);
|
||||||
void removeProcessedContainerFinished(const QString &finishedMessage);
|
void removeProcessedContainerFinished(const QString &finishedMessage);
|
||||||
|
|
||||||
void installationErrorOccurred(const QString &errorMessage);
|
|
||||||
void installationErrorOccurred(ErrorCode errorCode);
|
void installationErrorOccurred(ErrorCode errorCode);
|
||||||
|
void wrongInstallationUser(const QString &message);
|
||||||
|
|
||||||
void serverAlreadyExists(int serverIndex);
|
void serverAlreadyExists(int serverIndex);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ void PageController::showOnStartup()
|
||||||
if (!m_settings->isStartMinimized()) {
|
if (!m_settings->isStartMinimized()) {
|
||||||
emit raiseMainWindow();
|
emit raiseMainWindow();
|
||||||
} else {
|
} else {
|
||||||
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||||
emit hideMainWindow();
|
emit hideMainWindow();
|
||||||
#elif defined Q_OS_MACX
|
#elif defined Q_OS_MACX
|
||||||
setDockIconVisible(false);
|
setDockIconVisible(false);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ namespace PageLoader
|
||||||
PageProtocolIKev2Settings,
|
PageProtocolIKev2Settings,
|
||||||
PageProtocolRaw,
|
PageProtocolRaw,
|
||||||
|
|
||||||
|
PageProtocolWireGuardClientSettings,
|
||||||
|
PageProtocolAwgClientSettings,
|
||||||
|
|
||||||
PageShareFullAccess,
|
PageShareFullAccess,
|
||||||
|
|
||||||
PageDevMenu
|
PageDevMenu
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ QVariant ApiCountryModel::data(const QModelIndex &index, int role) const
|
||||||
case CountryNameRole: {
|
case CountryNameRole: {
|
||||||
return countryInfo.value(configKey::serverCountryName).toString();
|
return countryInfo.value(configKey::serverCountryName).toString();
|
||||||
}
|
}
|
||||||
|
case CountryImageCodeRole: {
|
||||||
|
return countryInfo.value(configKey::serverCountryCode).toString().toUpper();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -76,5 +79,6 @@ QHash<int, QByteArray> ApiCountryModel::roleNames() const
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
roles[CountryNameRole] = "countryName";
|
roles[CountryNameRole] = "countryName";
|
||||||
roles[CountryCodeRole] = "countryCode";
|
roles[CountryCodeRole] = "countryCode";
|
||||||
|
roles[CountryImageCodeRole] = "countryImageCode";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ class ApiCountryModel : public QAbstractListModel
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
CountryNameRole = Qt::UserRole + 1,
|
CountryNameRole = Qt::UserRole + 1,
|
||||||
CountryCodeRole
|
CountryCodeRole,
|
||||||
|
CountryImageCodeRole
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ApiCountryModel(QObject *parent = nullptr);
|
explicit ApiCountryModel(QObject *parent = nullptr);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ namespace
|
||||||
constexpr char storeEndpoint[] = "store_endpoint";
|
constexpr char storeEndpoint[] = "store_endpoint";
|
||||||
|
|
||||||
constexpr char isAvailable[] = "is_available";
|
constexpr char isAvailable[] = "is_available";
|
||||||
|
|
||||||
|
constexpr char subscription[] = "subscription";
|
||||||
|
constexpr char endDate[] = "end_date";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace serviceType
|
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()))
|
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
QJsonObject service = m_services.at(index.row()).toObject();
|
auto apiServiceData = m_services.at(index.row());
|
||||||
QJsonObject serviceInfo = service.value(configKey::serviceInfo).toObject();
|
auto serviceType = apiServiceData.type;
|
||||||
auto serviceType = service.value(configKey::serviceType).toString();
|
auto isServiceAvailable = apiServiceData.isServiceAvailable;
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case NameRole: {
|
case NameRole: {
|
||||||
return serviceInfo.value(configKey::name).toString();
|
return apiServiceData.serviceInfo.name;
|
||||||
}
|
}
|
||||||
case CardDescriptionRole: {
|
case CardDescriptionRole: {
|
||||||
auto speed = serviceInfo.value(configKey::speed).toString();
|
auto speed = apiServiceData.serviceInfo.speed;
|
||||||
if (serviceType == serviceType::amneziaPremium) {
|
if (serviceType == serviceType::amneziaPremium) {
|
||||||
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
|
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
|
||||||
"Works for any sites. Speed up to %1 MBit/s")
|
"Works for any sites. Speed up to %1 MBit/s")
|
||||||
.arg(speed);
|
.arg(speed);
|
||||||
} else if (serviceType == serviceType::amneziaFree){
|
} else if (serviceType == serviceType::amneziaFree){
|
||||||
QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
|
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>");
|
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;
|
return description;
|
||||||
|
|
@ -83,25 +86,24 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
case IsServiceAvailableRole: {
|
case IsServiceAvailableRole: {
|
||||||
if (serviceType == serviceType::amneziaFree) {
|
if (serviceType == serviceType::amneziaFree) {
|
||||||
if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
|
if (isServiceAvailable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case SpeedRole: {
|
case SpeedRole: {
|
||||||
auto speed = serviceInfo.value(configKey::speed).toString();
|
return tr("%1 MBit/s").arg(apiServiceData.serviceInfo.speed);
|
||||||
return tr("%1 MBit/s").arg(speed);
|
|
||||||
}
|
}
|
||||||
case WorkPeriodRole: {
|
case TimeLimitRole: {
|
||||||
auto timelimit = serviceInfo.value(configKey::timelimit).toString();
|
auto timeLimit = apiServiceData.serviceInfo.timeLimit;
|
||||||
if (timelimit == "0") {
|
if (timeLimit == "0") {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return tr("%1 days").arg(timelimit);
|
return tr("%1 days").arg(timeLimit);
|
||||||
}
|
}
|
||||||
case RegionRole: {
|
case RegionRole: {
|
||||||
return serviceInfo.value(configKey::region).toString();
|
return apiServiceData.serviceInfo.region;
|
||||||
}
|
}
|
||||||
case FeaturesRole: {
|
case FeaturesRole: {
|
||||||
if (serviceType == serviceType::amneziaPremium) {
|
if (serviceType == serviceType::amneziaPremium) {
|
||||||
|
|
@ -113,12 +115,15 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case PriceRole: {
|
case PriceRole: {
|
||||||
auto price = serviceInfo.value(configKey::price).toString();
|
auto price = apiServiceData.serviceInfo.price;
|
||||||
if (price == "free") {
|
if (price == "free") {
|
||||||
return tr("Free");
|
return tr("Free");
|
||||||
}
|
}
|
||||||
return tr("%1 $/month").arg(price);
|
return tr("%1 $/month").arg(price);
|
||||||
}
|
}
|
||||||
|
case EndDateRole: {
|
||||||
|
return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -128,15 +133,18 @@ void ApiServicesModel::updateModel(const QJsonObject &data)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
m_countryCode = data.value(configKey::userCountryCode).toString();
|
m_services.clear();
|
||||||
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.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;
|
m_selectedServiceIndex = 0;
|
||||||
|
} else {
|
||||||
|
for (const auto &service : services) {
|
||||||
|
m_services.push_back(getApiServicesData(service.toObject()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
@ -149,32 +157,32 @@ void ApiServicesModel::setServiceIndex(const int index)
|
||||||
|
|
||||||
QJsonObject ApiServicesModel::getSelectedServiceInfo()
|
QJsonObject ApiServicesModel::getSelectedServiceInfo()
|
||||||
{
|
{
|
||||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return service.value(configKey::serviceInfo).toObject();
|
return service.serviceInfo.object;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ApiServicesModel::getSelectedServiceType()
|
QString ApiServicesModel::getSelectedServiceType()
|
||||||
{
|
{
|
||||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return service.value(configKey::serviceType).toString();
|
return service.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ApiServicesModel::getSelectedServiceProtocol()
|
QString ApiServicesModel::getSelectedServiceProtocol()
|
||||||
{
|
{
|
||||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return service.value(configKey::serviceProtocol).toString();
|
return service.protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ApiServicesModel::getSelectedServiceName()
|
QString ApiServicesModel::getSelectedServiceName()
|
||||||
{
|
{
|
||||||
auto modelIndex = index(m_selectedServiceIndex, 0);
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return data(modelIndex, ApiServicesModel::Roles::NameRole).toString();
|
return service.serviceInfo.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray ApiServicesModel::getSelectedServiceCountries()
|
QJsonArray ApiServicesModel::getSelectedServiceCountries()
|
||||||
{
|
{
|
||||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return service.value(configKey::availableCountries).toArray();
|
return service.availableCountries;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ApiServicesModel::getCountryCode()
|
QString ApiServicesModel::getCountryCode()
|
||||||
|
|
@ -184,8 +192,8 @@ QString ApiServicesModel::getCountryCode()
|
||||||
|
|
||||||
QString ApiServicesModel::getStoreEndpoint()
|
QString ApiServicesModel::getStoreEndpoint()
|
||||||
{
|
{
|
||||||
QJsonObject service = m_services.at(m_selectedServiceIndex).toObject();
|
auto service = m_services.at(m_selectedServiceIndex);
|
||||||
return service.value(configKey::storeEndpoint).toString();
|
return service.storeEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
|
QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
|
||||||
|
|
@ -209,10 +217,46 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
||||||
roles[ServiceDescriptionRole] = "serviceDescription";
|
roles[ServiceDescriptionRole] = "serviceDescription";
|
||||||
roles[IsServiceAvailableRole] = "isServiceAvailable";
|
roles[IsServiceAvailableRole] = "isServiceAvailable";
|
||||||
roles[SpeedRole] = "speed";
|
roles[SpeedRole] = "speed";
|
||||||
roles[WorkPeriodRole] = "workPeriod";
|
roles[TimeLimitRole] = "timeLimit";
|
||||||
roles[RegionRole] = "region";
|
roles[RegionRole] = "region";
|
||||||
roles[FeaturesRole] = "features";
|
roles[FeaturesRole] = "features";
|
||||||
roles[PriceRole] = "price";
|
roles[PriceRole] = "price";
|
||||||
|
roles[EndDateRole] = "endDate";
|
||||||
|
|
||||||
return roles;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
class ApiServicesModel : public QAbstractListModel
|
class ApiServicesModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
|
|
@ -15,10 +16,11 @@ public:
|
||||||
ServiceDescriptionRole,
|
ServiceDescriptionRole,
|
||||||
IsServiceAvailableRole,
|
IsServiceAvailableRole,
|
||||||
SpeedRole,
|
SpeedRole,
|
||||||
WorkPeriodRole,
|
TimeLimitRole,
|
||||||
RegionRole,
|
RegionRole,
|
||||||
FeaturesRole,
|
FeaturesRole,
|
||||||
PriceRole
|
PriceRole,
|
||||||
|
EndDateRole
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ApiServicesModel(QObject *parent = nullptr);
|
explicit ApiServicesModel(QObject *parent = nullptr);
|
||||||
|
|
@ -48,8 +50,40 @@ protected:
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
private:
|
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;
|
QString m_countryCode;
|
||||||
QJsonArray m_services;
|
QVector<ApiServicesData> m_services;
|
||||||
|
|
||||||
int m_selectedServiceIndex;
|
int m_selectedServiceIndex;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ namespace
|
||||||
constexpr char latestHandshake[] = "latestHandshake";
|
constexpr char latestHandshake[] = "latestHandshake";
|
||||||
constexpr char dataReceived[] = "dataReceived";
|
constexpr char dataReceived[] = "dataReceived";
|
||||||
constexpr char dataSent[] = "dataSent";
|
constexpr char dataSent[] = "dataSent";
|
||||||
|
constexpr char allowedIps[] = "allowedIps";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
|
||||||
case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString();
|
case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString();
|
||||||
case DataReceivedRole: return userData.value(configKey::dataReceived).toString();
|
case DataReceivedRole: return userData.value(configKey::dataReceived).toString();
|
||||||
case DataSentRole: return userData.value(configKey::dataSent).toString();
|
case DataSentRole: return userData.value(configKey::dataSent).toString();
|
||||||
|
case AllowedIpsRole: return userData.value(configKey::allowedIps).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -75,6 +77,7 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_clientsTable = QJsonArray();
|
m_clientsTable = QJsonArray();
|
||||||
|
endResetModel();
|
||||||
|
|
||||||
ErrorCode error = ErrorCode::NoError;
|
ErrorCode error = ErrorCode::NoError;
|
||||||
|
|
||||||
|
|
@ -88,10 +91,10 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
|
||||||
const QByteArray clientsTableString = serverController->getTextFileFromContainer(container, credentials, clientsTableFile, error);
|
const QByteArray clientsTableString = serverController->getTextFileFromContainer(container, credentials, clientsTableFile, error);
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
logger.error() << "Failed to get the clientsTable file from the server";
|
logger.error() << "Failed to get the clientsTable file from the server";
|
||||||
endResetModel();
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
|
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
|
||||||
|
|
||||||
if (m_clientsTable.isEmpty()) {
|
if (m_clientsTable.isEmpty()) {
|
||||||
|
|
@ -103,6 +106,8 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
|
||||||
error = getOpenVpnClients(container, credentials, serverController, count);
|
error = getOpenVpnClients(container, credentials, serverController, count);
|
||||||
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
||||||
error = getWireGuardClients(container, credentials, serverController, count);
|
error = getWireGuardClients(container, credentials, serverController, count);
|
||||||
|
} else if (container == DockerContainer::Xray) {
|
||||||
|
error = getXrayClients(container, credentials, serverController, count);
|
||||||
}
|
}
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
@ -141,6 +146,10 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
|
||||||
userData[configKey::dataSent] = client.dataSent;
|
userData[configKey::dataSent] = client.dataSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!client.allowedIps.isEmpty()) {
|
||||||
|
userData[configKey::allowedIps] = client.allowedIps;
|
||||||
|
}
|
||||||
|
|
||||||
obj[configKey::userData] = userData;
|
obj[configKey::userData] = userData;
|
||||||
m_clientsTable.replace(i, obj);
|
m_clientsTable.replace(i, obj);
|
||||||
break;
|
break;
|
||||||
|
|
@ -232,6 +241,68 @@ ErrorCode ClientManagementModel::getWireGuardClients(const DockerContainer conta
|
||||||
}
|
}
|
||||||
return error;
|
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,
|
ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
|
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
|
||||||
|
|
@ -266,8 +337,9 @@ ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const S
|
||||||
const auto peerList = parts.filter("peer:");
|
const auto peerList = parts.filter("peer:");
|
||||||
const auto latestHandshakeList = parts.filter("latest handshake:");
|
const auto latestHandshakeList = parts.filter("latest handshake:");
|
||||||
const auto transferredDataList = parts.filter("transfer:");
|
const auto transferredDataList = parts.filter("transfer:");
|
||||||
|
const auto allowedIpsList = parts.filter("allowed ips:");
|
||||||
|
|
||||||
if (latestHandshakeList.isEmpty() || transferredDataList.isEmpty() || peerList.isEmpty()) {
|
if (allowedIpsList.isEmpty() || latestHandshakeList.isEmpty() || transferredDataList.isEmpty() || peerList.isEmpty()) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,19 +353,20 @@ ErrorCode ClientManagementModel::wgShow(const DockerContainer container, const S
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < peerList.size() && i < transferredDataList.size() && i < latestHandshakeList.size(); ++i) {
|
for (int i = 0; i < peerList.size() && i < transferredDataList.size() && i < latestHandshakeList.size() && i < allowedIpsList.size(); ++i) {
|
||||||
|
|
||||||
const auto transferredData = getStrValue(transferredDataList[i]).split(",");
|
const auto transferredData = getStrValue(transferredDataList[i]).split(",");
|
||||||
auto latestHandshake = getStrValue(latestHandshakeList[i]);
|
auto latestHandshake = getStrValue(latestHandshakeList[i]);
|
||||||
auto serverBytesReceived = transferredData.front().trimmed();
|
auto serverBytesReceived = transferredData.front().trimmed();
|
||||||
auto serverBytesSent = transferredData.back().trimmed();
|
auto serverBytesSent = transferredData.back().trimmed();
|
||||||
|
auto allowedIps = getStrValue(allowedIpsList[i]);
|
||||||
|
|
||||||
changeHandshakeFormat(latestHandshake);
|
changeHandshakeFormat(latestHandshake);
|
||||||
|
|
||||||
serverBytesReceived.chop(QStringLiteral(" received").length());
|
serverBytesReceived.chop(QStringLiteral(" received").length());
|
||||||
serverBytesSent.chop(QStringLiteral(" sent").length());
|
serverBytesSent.chop(QStringLiteral(" sent").length());
|
||||||
|
|
||||||
data.push_back({ getStrValue(peerList[i]), latestHandshake, serverBytesSent, serverBytesReceived });
|
data.push_back({ getStrValue(peerList[i]), latestHandshake, serverBytesSent, serverBytesReceived, allowedIps });
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
@ -317,17 +390,67 @@ ErrorCode ClientManagementModel::appendClient(const DockerContainer container, c
|
||||||
const QSharedPointer<ServerController> &serverController)
|
const QSharedPointer<ServerController> &serverController)
|
||||||
{
|
{
|
||||||
Proto protocol;
|
Proto protocol;
|
||||||
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|
switch (container) {
|
||||||
|
case DockerContainer::ShadowSocks:
|
||||||
|
case DockerContainer::Cloak:
|
||||||
protocol = Proto::OpenVpn;
|
protocol = Proto::OpenVpn;
|
||||||
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
break;
|
||||||
|
case DockerContainer::OpenVpn:
|
||||||
|
case DockerContainer::WireGuard:
|
||||||
|
case DockerContainer::Awg:
|
||||||
|
case DockerContainer::Xray:
|
||||||
protocol = ContainerProps::defaultProtocol(container);
|
protocol = ContainerProps::defaultProtocol(container);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
|
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,
|
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
|
||||||
|
|
@ -413,10 +536,27 @@ ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContain
|
||||||
auto client = m_clientsTable.at(row).toObject();
|
auto client = m_clientsTable.at(row).toObject();
|
||||||
QString clientId = client.value(configKey::clientId).toString();
|
QString clientId = client.value(configKey::clientId).toString();
|
||||||
|
|
||||||
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);
|
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
|
||||||
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
break;
|
||||||
|
}
|
||||||
|
case DockerContainer::WireGuard:
|
||||||
|
case DockerContainer::Awg: {
|
||||||
errorCode = revokeWireGuard(row, container, credentials, serverController);
|
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) {
|
if (errorCode == ErrorCode::NoError) {
|
||||||
|
|
@ -454,19 +594,69 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
Proto protocol;
|
Proto protocol;
|
||||||
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|
|
||||||
|
switch(container)
|
||||||
|
{
|
||||||
|
case DockerContainer::ShadowSocks:
|
||||||
|
case DockerContainer::Cloak: {
|
||||||
protocol = Proto::OpenVpn;
|
protocol = Proto::OpenVpn;
|
||||||
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
break;
|
||||||
|
}
|
||||||
|
case DockerContainer::OpenVpn:
|
||||||
|
case DockerContainer::WireGuard:
|
||||||
|
case DockerContainer::Awg:
|
||||||
|
case DockerContainer::Xray: {
|
||||||
protocol = ContainerProps::defaultProtocol(container);
|
protocol = ContainerProps::defaultProtocol(container);
|
||||||
} else {
|
break;
|
||||||
return ErrorCode::NoError;
|
}
|
||||||
|
default: {
|
||||||
|
logger.error() << "Internal error: received unexpected container type";
|
||||||
|
return ErrorCode::InternalError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
|
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;
|
int row;
|
||||||
bool clientExists = false;
|
bool clientExists = false;
|
||||||
QString clientId = protocolConfig.value(config_key::clientId).toString();
|
|
||||||
for (row = 0; row < rowCount(); row++) {
|
for (row = 0; row < rowCount(); row++) {
|
||||||
auto client = m_clientsTable.at(row).toObject();
|
auto client = m_clientsTable.at(row).toObject();
|
||||||
if (clientId == client.value(configKey::clientId).toString()) {
|
if (clientId == client.value(configKey::clientId).toString()) {
|
||||||
|
|
@ -478,11 +668,28 @@ ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig
|
||||||
return errorCode;
|
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);
|
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController);
|
||||||
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
break;
|
||||||
errorCode = revokeWireGuard(row, container, credentials, serverController);
|
|
||||||
}
|
}
|
||||||
|
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;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -585,6 +792,117 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
|
||||||
return ErrorCode::NoError;
|
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> ClientManagementModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
|
|
@ -593,5 +911,6 @@ QHash<int, QByteArray> ClientManagementModel::roleNames() const
|
||||||
roles[LatestHandshakeRole] = "latestHandshake";
|
roles[LatestHandshakeRole] = "latestHandshake";
|
||||||
roles[DataReceivedRole] = "dataReceived";
|
roles[DataReceivedRole] = "dataReceived";
|
||||||
roles[DataSentRole] = "dataSent";
|
roles[DataSentRole] = "dataSent";
|
||||||
|
roles[AllowedIpsRole] = "allowedIps";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,8 @@ public:
|
||||||
CreationDateRole,
|
CreationDateRole,
|
||||||
LatestHandshakeRole,
|
LatestHandshakeRole,
|
||||||
DataReceivedRole,
|
DataReceivedRole,
|
||||||
DataSentRole
|
DataSentRole,
|
||||||
|
AllowedIpsRole
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WgShowData
|
struct WgShowData
|
||||||
|
|
@ -26,6 +27,7 @@ public:
|
||||||
QString latestHandshake;
|
QString latestHandshake;
|
||||||
QString dataReceived;
|
QString dataReceived;
|
||||||
QString dataSent;
|
QString dataSent;
|
||||||
|
QString allowedIps;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
|
|
@ -38,6 +40,8 @@ public slots:
|
||||||
const QSharedPointer<ServerController> &serverController);
|
const QSharedPointer<ServerController> &serverController);
|
||||||
ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials, const QJsonObject &containerConfig,
|
ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials, const QJsonObject &containerConfig,
|
||||||
const QString &clientName, const QSharedPointer<ServerController> &serverController);
|
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,
|
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
|
||||||
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
|
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
|
||||||
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, const ServerCredentials &credentials,
|
||||||
|
|
@ -62,11 +66,15 @@ private:
|
||||||
const QSharedPointer<ServerController> &serverController);
|
const QSharedPointer<ServerController> &serverController);
|
||||||
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController);
|
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,
|
ErrorCode getOpenVpnClients(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController, int &count);
|
const QSharedPointer<ServerController> &serverController, int &count);
|
||||||
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
|
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController, int &count);
|
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,
|
ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
|
||||||
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data);
|
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data);
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,30 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
|
case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break;
|
||||||
case Roles::MtuRole: m_protocolConfig.insert(config_key::mtu, value.toString()); break;
|
|
||||||
case Roles::JunkPacketCountRole: m_protocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, value.toString()); break;
|
||||||
case Roles::JunkPacketMinSizeRole: m_protocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
||||||
case Roles::JunkPacketMaxSizeRole: m_protocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
||||||
case Roles::InitPacketJunkSizeRole: m_protocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break;
|
case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
||||||
case Roles::ResponsePacketJunkSizeRole: m_protocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); break;
|
|
||||||
case Roles::InitPacketMagicHeaderRole: m_protocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break;
|
case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
|
||||||
case Roles::ResponsePacketMagicHeaderRole: m_protocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); break;
|
case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
|
||||||
case Roles::UnderloadPacketMagicHeaderRole: m_protocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString()); break;
|
case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
||||||
case Roles::TransportPacketMagicHeaderRole: m_protocolConfig.insert(config_key::transportPacketMagicHeader, value.toString()); break;
|
case Roles::ServerInitPacketJunkSizeRole: m_serverProtocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break;
|
||||||
|
case Roles::ServerResponsePacketJunkSizeRole:
|
||||||
|
m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
|
||||||
|
break;
|
||||||
|
case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break;
|
||||||
|
case Roles::ServerResponsePacketMagicHeaderRole:
|
||||||
|
m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
|
||||||
|
break;
|
||||||
|
case Roles::ServerUnderloadPacketMagicHeaderRole:
|
||||||
|
m_serverProtocolConfig.insert(config_key::underloadPacketMagicHeader, value.toString());
|
||||||
|
break;
|
||||||
|
case Roles::ServerTransportPacketMagicHeaderRole:
|
||||||
|
m_serverProtocolConfig.insert(config_key::transportPacketMagicHeader, value.toString());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit dataChanged(index, index, QList { role });
|
emit dataChanged(index, index, QList { role });
|
||||||
|
|
@ -45,17 +58,22 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString();
|
case Roles::PortRole: return m_serverProtocolConfig.value(config_key::port).toString();
|
||||||
case Roles::MtuRole: return m_protocolConfig.value(config_key::mtu).toString();
|
|
||||||
case Roles::JunkPacketCountRole: return m_protocolConfig.value(config_key::junkPacketCount);
|
case Roles::ClientMtuRole: return m_clientProtocolConfig.value(config_key::mtu);
|
||||||
case Roles::JunkPacketMinSizeRole: return m_protocolConfig.value(config_key::junkPacketMinSize);
|
case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount);
|
||||||
case Roles::JunkPacketMaxSizeRole: return m_protocolConfig.value(config_key::junkPacketMaxSize);
|
case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize);
|
||||||
case Roles::InitPacketJunkSizeRole: return m_protocolConfig.value(config_key::initPacketJunkSize);
|
case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize);
|
||||||
case Roles::ResponsePacketJunkSizeRole: return m_protocolConfig.value(config_key::responsePacketJunkSize);
|
|
||||||
case Roles::InitPacketMagicHeaderRole: return m_protocolConfig.value(config_key::initPacketMagicHeader);
|
case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount);
|
||||||
case Roles::ResponsePacketMagicHeaderRole: return m_protocolConfig.value(config_key::responsePacketMagicHeader);
|
case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize);
|
||||||
case Roles::UnderloadPacketMagicHeaderRole: return m_protocolConfig.value(config_key::underloadPacketMagicHeader);
|
case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize);
|
||||||
case Roles::TransportPacketMagicHeaderRole: return m_protocolConfig.value(config_key::transportPacketMagicHeader);
|
case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize);
|
||||||
|
case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize);
|
||||||
|
case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader);
|
||||||
|
case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
|
||||||
|
case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
||||||
|
case Roles::ServerTransportPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::transportPacketMagicHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
@ -68,51 +86,63 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||||
|
|
||||||
m_fullConfig = config;
|
m_fullConfig = config;
|
||||||
|
|
||||||
QJsonObject protocolConfig = config.value(config_key::awg).toObject();
|
QJsonObject serverProtocolConfig = config.value(config_key::awg).toObject();
|
||||||
|
|
||||||
auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg);
|
auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg);
|
||||||
m_protocolConfig.insert(config_key::transport_proto, protocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
|
m_serverProtocolConfig.insert(config_key::transport_proto,
|
||||||
m_protocolConfig[config_key::last_config] = protocolConfig.value(config_key::last_config);
|
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
|
||||||
m_protocolConfig[config_key::port] = protocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
|
||||||
m_protocolConfig[config_key::mtu] = protocolConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu);
|
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
||||||
m_protocolConfig[config_key::junkPacketCount] =
|
m_serverProtocolConfig[config_key::junkPacketCount] =
|
||||||
protocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||||
m_protocolConfig[config_key::junkPacketMinSize] =
|
m_serverProtocolConfig[config_key::junkPacketMinSize] =
|
||||||
protocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||||
m_protocolConfig[config_key::junkPacketMaxSize] =
|
m_serverProtocolConfig[config_key::junkPacketMaxSize] =
|
||||||
protocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||||
m_protocolConfig[config_key::initPacketJunkSize] =
|
m_serverProtocolConfig[config_key::initPacketJunkSize] =
|
||||||
protocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||||
m_protocolConfig[config_key::responsePacketJunkSize] =
|
m_serverProtocolConfig[config_key::responsePacketJunkSize] =
|
||||||
protocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||||
m_protocolConfig[config_key::initPacketMagicHeader] =
|
m_serverProtocolConfig[config_key::initPacketMagicHeader] =
|
||||||
protocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||||
m_protocolConfig[config_key::responsePacketMagicHeader] =
|
m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
|
||||||
protocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||||
m_protocolConfig[config_key::underloadPacketMagicHeader] =
|
m_serverProtocolConfig[config_key::underloadPacketMagicHeader] =
|
||||||
protocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||||
m_protocolConfig[config_key::transportPacketMagicHeader] =
|
m_serverProtocolConfig[config_key::transportPacketMagicHeader] =
|
||||||
protocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||||
|
|
||||||
|
auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString();
|
||||||
|
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
||||||
|
m_clientProtocolConfig[config_key::mtu] = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu);
|
||||||
|
m_clientProtocolConfig[config_key::junkPacketCount] =
|
||||||
|
clientProtocolConfig.value(config_key::junkPacketCount).toString(m_serverProtocolConfig[config_key::junkPacketCount].toString());
|
||||||
|
m_clientProtocolConfig[config_key::junkPacketMinSize] =
|
||||||
|
clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString());
|
||||||
|
m_clientProtocolConfig[config_key::junkPacketMaxSize] =
|
||||||
|
clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString());
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject AwgConfigModel::getConfig()
|
QJsonObject AwgConfigModel::getConfig()
|
||||||
{
|
{
|
||||||
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
||||||
const AwgConfig newConfig(m_protocolConfig);
|
const AwgConfig newConfig(m_serverProtocolConfig);
|
||||||
|
|
||||||
if (!oldConfig.hasEqualServerSettings(newConfig)) {
|
if (!oldConfig.hasEqualServerSettings(newConfig)) {
|
||||||
m_protocolConfig.remove(config_key::last_config);
|
m_serverProtocolConfig.remove(config_key::last_config);
|
||||||
} else {
|
} else {
|
||||||
auto lastConfig = m_protocolConfig.value(config_key::last_config).toString();
|
auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString();
|
||||||
QJsonObject jsonConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
QJsonObject jsonConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
||||||
jsonConfig[config_key::mtu] = newConfig.mtu;
|
jsonConfig[config_key::mtu] = m_clientProtocolConfig[config_key::mtu];
|
||||||
|
jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount];
|
||||||
|
jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize];
|
||||||
|
jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize];
|
||||||
|
|
||||||
m_protocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fullConfig.insert(config_key::awg, m_protocolConfig);
|
m_fullConfig.insert(config_key::awg, m_serverProtocolConfig);
|
||||||
return m_fullConfig;
|
return m_fullConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,50 +156,73 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2)
|
||||||
return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2);
|
return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AwgConfigModel::isServerSettingsEqual()
|
||||||
|
{
|
||||||
|
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
||||||
|
const AwgConfig newConfig(m_serverProtocolConfig);
|
||||||
|
|
||||||
|
return oldConfig.hasEqualServerSettings(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> AwgConfigModel::roleNames() const
|
QHash<int, QByteArray> AwgConfigModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
|
|
||||||
roles[PortRole] = "port";
|
roles[PortRole] = "port";
|
||||||
roles[MtuRole] = "mtu";
|
|
||||||
roles[JunkPacketCountRole] = "junkPacketCount";
|
roles[ClientMtuRole] = "clientMtu";
|
||||||
roles[JunkPacketMinSizeRole] = "junkPacketMinSize";
|
roles[ClientJunkPacketCountRole] = "clientJunkPacketCount";
|
||||||
roles[JunkPacketMaxSizeRole] = "junkPacketMaxSize";
|
roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize";
|
||||||
roles[InitPacketJunkSizeRole] = "initPacketJunkSize";
|
roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize";
|
||||||
roles[ResponsePacketJunkSizeRole] = "responsePacketJunkSize";
|
|
||||||
roles[InitPacketMagicHeaderRole] = "initPacketMagicHeader";
|
roles[ServerJunkPacketCountRole] = "serverJunkPacketCount";
|
||||||
roles[ResponsePacketMagicHeaderRole] = "responsePacketMagicHeader";
|
roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize";
|
||||||
roles[UnderloadPacketMagicHeaderRole] = "underloadPacketMagicHeader";
|
roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize";
|
||||||
roles[TransportPacketMagicHeaderRole] = "transportPacketMagicHeader";
|
roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize";
|
||||||
|
roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize";
|
||||||
|
roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader";
|
||||||
|
roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader";
|
||||||
|
roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader";
|
||||||
|
roles[ServerTransportPacketMagicHeaderRole] = "serverTransportPacketMagicHeader";
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
AwgConfig::AwgConfig(const QJsonObject &jsonConfig)
|
AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
|
||||||
{
|
{
|
||||||
port = jsonConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
auto lastConfig = serverProtocolConfig.value(config_key::last_config).toString();
|
||||||
mtu = jsonConfig.value(config_key::mtu).toString(protocols::awg::defaultMtu);
|
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
||||||
junkPacketCount = jsonConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
clientMtu = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu);
|
||||||
junkPacketMinSize = jsonConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||||
junkPacketMaxSize = jsonConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||||
initPacketJunkSize = jsonConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||||
responsePacketJunkSize = jsonConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
|
||||||
initPacketMagicHeader = jsonConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
|
||||||
responsePacketMagicHeader =
|
serverJunkPacketCount = serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||||
jsonConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
serverJunkPacketMinSize = serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||||
underloadPacketMagicHeader =
|
serverJunkPacketMaxSize = serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||||
jsonConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||||
transportPacketMagicHeader =
|
serverResponsePacketJunkSize =
|
||||||
jsonConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||||
|
serverInitPacketMagicHeader =
|
||||||
|
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||||
|
serverResponsePacketMagicHeader =
|
||||||
|
serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||||
|
serverUnderloadPacketMagicHeader =
|
||||||
|
serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||||
|
serverTransportPacketMagicHeader =
|
||||||
|
serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||||
{
|
{
|
||||||
if (port != other.port || junkPacketCount != other.junkPacketCount || junkPacketMinSize != other.junkPacketMinSize
|
if (port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|
||||||
|| junkPacketMaxSize != other.junkPacketMaxSize || initPacketJunkSize != other.initPacketJunkSize
|
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|
||||||
|| responsePacketJunkSize != other.responsePacketJunkSize || initPacketMagicHeader != other.initPacketMagicHeader
|
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|
||||||
|| responsePacketMagicHeader != other.responsePacketMagicHeader || underloadPacketMagicHeader != other.underloadPacketMagicHeader
|
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
|
||||||
|| transportPacketMagicHeader != other.transportPacketMagicHeader) {
|
|| serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader
|
||||||
|
|| serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader
|
||||||
|
|| serverTransportPacketMagicHeader != other.serverTransportPacketMagicHeader) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -177,7 +230,8 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||||
|
|
||||||
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
|
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
|
||||||
{
|
{
|
||||||
if (mtu != other.mtu) {
|
if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount
|
||||||
|
|| clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,21 @@ struct AwgConfig
|
||||||
AwgConfig(const QJsonObject &jsonConfig);
|
AwgConfig(const QJsonObject &jsonConfig);
|
||||||
|
|
||||||
QString port;
|
QString port;
|
||||||
QString mtu;
|
|
||||||
QString junkPacketCount;
|
QString clientMtu;
|
||||||
QString junkPacketMinSize;
|
QString clientJunkPacketCount;
|
||||||
QString junkPacketMaxSize;
|
QString clientJunkPacketMinSize;
|
||||||
QString initPacketJunkSize;
|
QString clientJunkPacketMaxSize;
|
||||||
QString responsePacketJunkSize;
|
|
||||||
QString initPacketMagicHeader;
|
QString serverJunkPacketCount;
|
||||||
QString responsePacketMagicHeader;
|
QString serverJunkPacketMinSize;
|
||||||
QString underloadPacketMagicHeader;
|
QString serverJunkPacketMaxSize;
|
||||||
QString transportPacketMagicHeader;
|
QString serverInitPacketJunkSize;
|
||||||
|
QString serverResponsePacketJunkSize;
|
||||||
|
QString serverInitPacketMagicHeader;
|
||||||
|
QString serverResponsePacketMagicHeader;
|
||||||
|
QString serverUnderloadPacketMagicHeader;
|
||||||
|
QString serverTransportPacketMagicHeader;
|
||||||
|
|
||||||
bool hasEqualServerSettings(const AwgConfig &other) const;
|
bool hasEqualServerSettings(const AwgConfig &other) const;
|
||||||
bool hasEqualClientSettings(const AwgConfig &other) const;
|
bool hasEqualClientSettings(const AwgConfig &other) const;
|
||||||
|
|
@ -39,16 +44,21 @@ class AwgConfigModel : public QAbstractListModel
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
PortRole = Qt::UserRole + 1,
|
PortRole = Qt::UserRole + 1,
|
||||||
MtuRole,
|
|
||||||
JunkPacketCountRole,
|
ClientMtuRole,
|
||||||
JunkPacketMinSizeRole,
|
ClientJunkPacketCountRole,
|
||||||
JunkPacketMaxSizeRole,
|
ClientJunkPacketMinSizeRole,
|
||||||
InitPacketJunkSizeRole,
|
ClientJunkPacketMaxSizeRole,
|
||||||
ResponsePacketJunkSizeRole,
|
|
||||||
InitPacketMagicHeaderRole,
|
ServerJunkPacketCountRole,
|
||||||
ResponsePacketMagicHeaderRole,
|
ServerJunkPacketMinSizeRole,
|
||||||
UnderloadPacketMagicHeaderRole,
|
ServerJunkPacketMaxSizeRole,
|
||||||
TransportPacketMagicHeaderRole
|
ServerInitPacketJunkSizeRole,
|
||||||
|
ServerResponsePacketJunkSizeRole,
|
||||||
|
ServerInitPacketMagicHeaderRole,
|
||||||
|
ServerResponsePacketMagicHeaderRole,
|
||||||
|
ServerUnderloadPacketMagicHeaderRole,
|
||||||
|
ServerTransportPacketMagicHeaderRole
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit AwgConfigModel(QObject *parent = nullptr);
|
explicit AwgConfigModel(QObject *parent = nullptr);
|
||||||
|
|
@ -65,12 +75,15 @@ public slots:
|
||||||
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
|
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
|
||||||
bool isPacketSizeEqual(const int s1, const int s2);
|
bool isPacketSizeEqual(const int s1, const int s2);
|
||||||
|
|
||||||
|
bool isServerSettingsEqual();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DockerContainer m_container;
|
DockerContainer m_container;
|
||||||
QJsonObject m_protocolConfig;
|
QJsonObject m_serverProtocolConfig;
|
||||||
|
QJsonObject m_clientProtocolConfig;
|
||||||
QJsonObject m_fullConfig;
|
QJsonObject m_fullConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue