Compare commits

...

222 Commits

Author SHA1 Message Date
Cyril Anisimov
25a24bf38c focusControl => FocusControl 2024-12-30 18:10:25 +01:00
Cyril Anisimov
5e492e8392 remove debug output from focusControl 2024-12-30 18:05:31 +01:00
Cyril Anisimov
b25d911328 remove debug output from ListViewFocusController 2024-12-30 18:04:05 +01:00
Cyril Anisimov
caf29fb982 remove debug output from FocusController 2024-12-30 18:03:26 +01:00
Cyril Anisimov
32ef1eae84 fix PageDevMenu 2024-12-30 00:19:11 +01:00
Cyril Anisimov
b0fdbe6c4f fix PageSettingsAppSplitTunneling 2024-12-29 22:11:35 +01:00
Cyril Anisimov
dccfcde6f6 fix PageProtocolCloakSettings 2024-12-29 22:04:00 +01:00
Cyril Anisimov
26ba520022 fix ListViewWithLabelsType 2024-12-29 22:01:41 +01:00
Cyril Anisimov
0f98fc955f remove comments and clean up 2024-12-29 21:19:56 +01:00
Cyril Anisimov
2c1f3eaf3a refactor PageSetupWizardProtocols 2024-12-29 20:26:22 +01:00
Cyril Anisimov
867ad8ee3c fix focus movement on dynamic delegates in listView 2024-12-29 00:34:20 +01:00
Cyril Anisimov
f8f4d75cb7 Merge commit 'b88ab8e432fbd2ab5002856cd83ef57181a6d7fa' into improve_navigation_cpp 2024-12-23 09:36:55 +01:00
albexk
b88ab8e432 fix(build): fix aqtinstall (#1312) 2024-12-23 08:27:09 +07:00
Cyril Anisimov
13e680f6e1 fix PageSetupWizardApiServicesList 2024-12-22 16:38:07 +01:00
Cyril Anisimov
8767f487b8 fix ScrollBarType 2024-12-22 16:28:13 +01:00
Cyril Anisimov
0cdd2ff826 fix CMakeLists.txt 2024-12-20 15:35:40 +01:00
Cyril Anisimov
c973b8868b rename focusControl to qmlUtils 2024-12-20 15:30:20 +01:00
Cyril Anisimov
53aa14a2ee fix back button on SelectLanguageDrawer 2024-12-20 02:26:05 +01:00
Cyril Anisimov
b29b5962d2 I have nothing is visible only on start screen 2024-12-20 02:17:50 +01:00
Cyril Anisimov
441a2f6df6 Restore from backup is visible only on start screen 2024-12-20 02:15:48 +01:00
Cyril Anisimov
fa64c8d68d fix focus movement in ServersListView 2024-12-20 02:05:28 +01:00
Nethius
48f6cf904e chore/minor UI fixes (#1308)
* chore: corrected the translation error

* bugfix: fixed basic button left iamge color
2024-12-19 14:36:20 +07:00
Cyril Anisimov
ae31bafeb9 remove arrow from Close application item 2024-12-19 00:22:59 +01:00
Cyril Anisimov
14d67503a8 add printSectionName method to listViewController 2024-12-19 00:00:36 +01:00
Cyril Anisimov
1029142b47 refactor focusConroller according to focusControl 2024-12-18 23:59:14 +01:00
Cyril Anisimov
7670d9dace refactor listViewFocusController acoording to focusControl 2024-12-18 23:57:08 +01:00
Cyril Anisimov
2266702a0b add focusControl with utility functions for
focus control
2024-12-18 23:47:52 +01:00
Cyril Anisimov
11d20974f0 format FocusController 2024-12-16 22:12:15 +01:00
Cyril Anisimov
a57e94e4f2 format ListViewFocusController 2024-12-16 22:12:00 +01:00
Cyril Anisimov
9620a24d6a remove manual focus control on PageShare 2024-12-15 23:23:15 +01:00
Cyril Anisimov
62be292833 Fix list view focus moving on PageShare 2024-12-15 23:14:52 +01:00
Cyril Anisimov
10e91b06f4 PageShare readonly properties 2024-12-15 23:12:59 +01:00
Cyril Anisimov
3a62f1f20b fix hide/unhide password 2024-12-14 23:44:15 +01:00
Cyril Anisimov
3021066180 refactor SwitcherType 2024-12-14 19:34:24 +01:00
Cyril Anisimov
378db1a9e5 make unchangable properties readonly 2024-12-14 19:33:54 +01:00
Cyril Anisimov
906cf7b939 fix split tunneling settings 2024-12-14 19:32:46 +01:00
Cyril Anisimov
8bc31b60a1 fix checked item in lists 2024-12-14 19:29:35 +01:00
Cyril Anisimov
149c9d12d3 Merge commit '367789bda28f33a11a72d61b222453c5b502299e' into improve_navigation_cpp 2024-12-14 18:38:41 +01:00
Cyril Anisimov
b33b97802e update logging settings page 2024-12-14 18:01:34 +01:00
KsZnak
367789bda2 Update README_RU.md (#1300)
* Update README_RU.md
2024-12-14 19:29:33 +07:00
Cyril Anisimov
d18f50a3e0 Update select language list 2024-12-13 22:27:21 +01:00
Cyril Anisimov
ef2ffce47a Fix selection in language change list 2024-12-13 22:14:27 +01:00
Cyril Anisimov
53f41408b8 Scrollbar is on if the content is larger than a screen 2024-12-13 22:09:37 +01:00
Cyril Anisimov
d06924c59d feature/xray user management (#972)
* feature: implement client management functionality for Xray

---------

Co-authored-by: aiamnezia <ai@amnezia.org>
Co-authored-by: vladimir.kuznetsov <nethiuswork@gmail.com>
2024-12-10 09:17:16 +07:00
albexk
5b9ba8c027 fix: get rid of the assign function call 2024-12-09 20:56:58 +03:00
Nethius
2db99715b1 feature: added subscription expiration date for premium v2 (#1261)
* feature: added subscription expiration date for premium v2

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

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

* bugfix: renamed public_key->end_date to public_key->expires_at according to the changes on the backend
2024-12-09 13:32:49 +07:00
Cyril Anisimov
882c288d92 make minor fixes and clean up 2024-12-09 01:53:48 +01:00
Cyril Anisimov
ea39447708 fix focus behavior on new page/popup 2024-12-09 01:35:10 +01:00
Cyril Anisimov
3cc70790bd add setDelegateIndex method to listViewFocusController 2024-12-09 01:32:11 +01:00
Cyril Anisimov
f331c11f51 refactor credentials setup page to handle the focus navigation 2024-12-09 01:30:11 +01:00
Cyril Anisimov
39cbe6de28 update initial config page 2024-12-09 01:28:57 +01:00
pokamest
9688a8e52d Merge pull request #1292 from amnezia-vpn/Add-english-option
Update README.md
2024-12-08 10:40:20 +01:00
pokamest
b2c429f74d Merge pull request #1291 from amnezia-vpn/readme_ru_update
Update README_RU.md
2024-12-08 10:39:01 +01:00
Nethius
6ea6ab1bd9 chore: added clang-format config files (#1293) 2024-12-08 12:14:22 +07:00
KsZnak
c5aa070bf4 Update README_RU.md 2024-12-08 05:49:26 +02:00
KsZnak
d67201ede9 Update README.md 2024-12-08 05:34:18 +02:00
pokamest
4323fb2063 Merge pull request #1290 from amnezia-vpn/Readme_ru
Add files via upload
2024-12-07 15:36:56 +01:00
pokamest
6d5452b8ee Merge pull request #1288 from amnezia-vpn/Readme-ru
Update README_RU.md
2024-12-07 15:36:08 +01:00
KsZnak
569d63ef0f Add files via upload 2024-12-07 15:53:40 +02:00
Cyril Anisimov
87d00116e1 add ScrollBarType 2024-12-06 22:59:12 +01:00
KsZnak
ea910ba300 Update README_RU.md 2024-12-06 22:15:01 +02:00
Pokamest Nikak
1c1e74d06f ru readme 2024-12-06 12:40:04 +00:00
Nethius
5dc16c06f1 chore: increased the api request timeout (#1276) 2024-12-03 12:47:33 +07:00
Cyril Anisimov
f992252c6e Merge commit into improve_navigation_cpp 2024-12-02 11:10:30 +01:00
Nethius
4efaf20a1c chore: fix deploy workflow (#1280) 2024-12-02 14:46:20 +07:00
Pokamest Nikak
9d96b1cd13 Update Readme 2024-11-29 22:10:35 +00:00
Anton Sosnin
1d721ffb9a SteamDeck/OS installation fix (#1270) 2024-11-27 09:55:23 +07:00
Nethius
2130131a9d bugfix: added scroll on page with services list (#1262)
* added scroll on page with services list

* fixed margins on PageSetupWizardApiServicesList
2024-11-26 11:41:17 +07:00
Aftershock669
e0b091b474 Update readme (#1267) 2024-11-25 23:51:46 +07:00
albexk
c9205afbd4 chore: bump version code 2024-11-25 14:08:25 +03:00
albexk
09b1f322ba fix: hide UI elements that use file saving 2024-11-25 13:56:14 +03:00
albexk
4d2d7e4071 fix: add the touch emulation method for Android TV 2024-11-25 12:33:34 +03:00
albexk
c72d76aec7 Merge branch 'improve_navigation_cpp' into feature/android-tv 2024-11-25 12:20:31 +03:00
albexk
50bd364f29 Merge branch 'dev' into feature/android-tv
# Conflicts:
#	CMakeLists.txt
2024-11-25 12:19:52 +03:00
albexk
3eeab2f2e7 fix: null uri processing 2024-11-25 12:17:22 +03:00
albexk
2987e03a86 fix: add the touch emulation method for Android TV 2024-11-25 12:17:22 +03:00
albexk
392cacaabc refactor: make TvFilePicker activity more sustainable 2024-11-25 12:17:22 +03:00
albexk
51092e91cf fix: change the banner format for TV 2024-11-25 12:17:22 +03:00
albexk
d02a6dfb22 fix: add a workaround to open files on Android TV due to lack of SAF 2024-11-25 12:17:22 +03:00
Nethius
4e1862a802 chore: minor fixes (#1235) 2024-11-25 12:15:36 +03:00
albexk
53e766f6d3 Fix connection check for AWG/WG 2024-11-25 12:15:36 +03:00
albexk
341d6f569b fix(android): add CHANGE_NETWORK_STATE permission for all Android versions 2024-11-25 12:15:36 +03:00
albexk
a5abab8caf fix: add separate method for reading files to fix file reading on Android TV 2024-11-25 12:15:36 +03:00
albexk
7df050371e Fix importing files on TVs 2024-11-25 12:15:36 +03:00
albexk
65870ad5c9 Add mandatory requirement for android.software.leanback. 2024-11-25 12:15:36 +03:00
albexk
940806a6fa Bump version 2024-11-25 12:15:36 +03:00
Cyril Anisimov
0620b4536a update popup 2024-11-21 19:11:57 +01:00
Cyril Anisimov
d956be901d refactor page logging settings for focus navigation 2024-11-21 19:11:57 +01:00
Cyril Anisimov
942805cca2 fix focus move on qr code on share page 2024-11-21 19:11:57 +01:00
Cyril Anisimov
ed6fc27e52 fix focus navigation in dynamic delegate of list view 2024-11-21 19:11:57 +01:00
Cyril Anisimov
416421cba7 fix crash on return with esc key 2024-11-21 19:11:57 +01:00
Cyril Anisimov
45b8235a81 update config page for scrolling with tab 2024-11-21 19:11:57 +01:00
Cyril Anisimov
a92f706524 fix focus on notification 2024-11-21 19:11:57 +01:00
Cyril Anisimov
5e9202f6ac refactor focusController to make the logic more
straightforward
2024-11-21 19:11:57 +01:00
Cyril Anisimov
dc6c1cdf49 refactor listViewFocusController 2024-11-21 19:11:57 +01:00
Cyril Anisimov
f020bdb6e8 fix drawer open close usage 2024-11-21 19:11:57 +01:00
Cyril Anisimov
88958c042f fix share details drawer 2024-11-21 19:11:57 +01:00
Cyril Anisimov
e4d21dc4d7 fix spawn signals on switch 2024-11-21 19:11:57 +01:00
Cyril Anisimov
2e896ed34f fix server list back button handler 2024-11-21 19:11:57 +01:00
Cyril Anisimov
163399816f minor fixes 2024-11-21 19:11:57 +01:00
Cyril Anisimov
3d7209ee7a fix focus move on list views with header and-or footer 2024-11-21 19:11:57 +01:00
Cyril Anisimov
42645a98f8 refactor about page for correct focus move 2024-11-21 19:11:57 +01:00
Cyril Anisimov
7c3d08d80e fix page share default server selection 2024-11-21 19:11:57 +01:00
Cyril Anisimov
c77e01fb37 fix server rename 2024-11-21 19:11:57 +01:00
Cyril Anisimov
b6c59b08a1 clean up page share 2024-11-21 19:11:56 +01:00
Cyril Anisimov
766e1c92fc fix focus on users on page share 2024-11-21 19:11:56 +01:00
Cyril Anisimov
21755cbd54 fix protocol settings focus move 2024-11-21 19:11:56 +01:00
Cyril Anisimov
dac45a9f7f fix crashes after ListView navigation 2024-11-21 19:11:56 +01:00
Cyril Anisimov
db5d289edc fix back navigation on default focus item 2024-11-21 19:11:56 +01:00
Cyril Anisimov
c962211068 fix PageSetupWizardProtocolSettings focus move 2024-11-21 19:11:56 +01:00
Cyril Anisimov
9cfa4c1389 fix drawer layout and focus move 2024-11-21 19:11:56 +01:00
Cyril Anisimov
2c9fa10b8b fix drawer radio buttons selection 2024-11-21 19:11:56 +01:00
Cyril Anisimov
626b9e1e76 fix reverse focus move on listView 2024-11-21 19:11:56 +01:00
Cyril Anisimov
ada3f9a7fa remove useless slots, logs, Drawer open and close 2024-11-21 19:11:56 +01:00
Cyril Anisimov
063851445a remove useless key navigation 2024-11-21 19:11:56 +01:00
Cyril Anisimov
852e90e317 update CardType for using with focus navigation 2024-11-21 19:11:56 +01:00
Cyril Anisimov
89ac585e07 fix ListView navigation 2024-11-21 19:11:56 +01:00
Cyril Anisimov
f3df9eb5f5 add ListViewFocusController 2024-11-21 19:11:56 +01:00
Cyril Anisimov
75f189e256 update pages 2024-11-21 19:11:56 +01:00
Cyril Anisimov
3c655d0051 update transitions 2024-11-21 19:11:56 +01:00
Cyril Anisimov
b4f4ec4ac9 add default focus item 2024-11-21 19:11:56 +01:00
Cyril Anisimov
f189f7b6af add reverse focus change to FocusController 2024-11-21 19:11:56 +01:00
Cyril Anisimov
78a4caa47e fixed language selector 2024-11-21 19:11:56 +01:00
Cyril Anisimov
01e31b4b4d add focus navigation to qml 2024-11-21 19:11:56 +01:00
Cyril Anisimov
cecee3769e add more key handlers 2024-11-21 19:11:55 +01:00
Cyril Anisimov
02bbcd3a31 add focusController class 2024-11-21 19:11:55 +01:00
Nethius
8547de82ea bump xcode-version for macos build (#1249) 2024-11-14 10:58:04 +07:00
Nethius
aa871bd1c9 feature: added country selection on home page drawer (#1215) 2024-11-12 13:22:34 +07:00
albexk
23806e1def chore: bump version to 4.8.2.4 (#1240) 2024-11-08 15:22:16 +07:00
Nethius
31867993ce chore: minor fixes (#1235) 2024-11-06 12:57:39 +07:00
pokamest
7b7a922d92 Merge pull request #1226 from amnezia-vpn/fix/android-awg-connection
Fix connection check for AWG/WG
2024-11-05 12:25:49 +01:00
pokamest
09bd958d8d Merge pull request #1231 from amnezia-vpn/fix/android-network-state
Add CHANGE_NETWORK_STATE permission for all Android versions
2024-11-05 12:25:11 +01:00
albexk
576e2226fe fix(android): add CHANGE_NETWORK_STATE permission for all Android versions 2024-11-03 16:11:23 +03:00
albexk
1533270e4e Fix connection check for AWG/WG 2024-11-02 00:54:24 +03:00
albexk
e7b25719e4 Chore/bump version (#1204)
* chore: bump Android version code

---------

Co-authored-by: Nethius <nethiuswork@gmail.com>
2024-10-25 23:23:05 +07:00
pokamest
7183e8541c Merge pull request #1202 from Aftershock669/update-readme
Fix / Update README
2024-10-25 16:43:50 +01:00
Nethius
9e71e64cbd chore: bump version to 4.8.2.3 (#1203) 2024-10-25 22:19:28 +07:00
Aftershock669
4f3bae4a9a Fix / Update README 2024-10-25 17:00:28 +03:00
pokamest
990059f8a6 Merge pull request #1200 from amnezia-vpn/bugfix/proxy-bypass-enc-check 2024-10-25 10:50:07 +01:00
vladimir.kuznetsov
af55af5e76 bugfix: fixed proxy bypass encryption check 2024-10-25 17:48:22 +08:00
pokamest
82d96a9691 Merge pull request #1197 from Aftershock669/update-readme
Update README
2024-10-24 23:57:58 +01:00
Aftershock669
9f3f215452 Update README
- add website mirror links
- remove direct platform download links
- add "Testiny" sponsored badge
2024-10-24 22:32:35 +03:00
pokamest
2dfc6a87b8 Merge pull request #1196 from amnezia-vpn/bump-version
Bump version to 4.8.2.1
2024-10-24 17:36:50 +01:00
albexk
7261a86c48 Bump version to 4.8.2.1 2024-10-24 19:25:44 +03:00
pokamest
2946dd2278 Merge pull request #1124 from amnezia-vpn/bugfix/page-share-recursive-rearrange
bugfix: fixed clientInfoDrawer.expandedHeight recursive rearrange
2024-10-24 16:39:04 +01:00
vladimir.kuznetsov
5065262aac bugfix: fixed clientInfoDrawer recursive rearrange 2024-10-24 23:37:42 +08:00
Nethius
4685d3b543 bugfix/api auth data saving (#1195)
* bugfix: fixed authData saving

* bugfix: added serviceInfo processing from api response
2024-10-24 16:12:53 +01:00
pokamest
7a389e8755 Merge pull request #1188 from amnezia-vpn/chore/global-network-manager
chore/using the global network manager
2024-10-24 16:10:57 +01:00
vladimir.kuznetsov
4e5daf22a3 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into chore/global-network-manager 2024-10-24 22:53:56 +08:00
pokamest
3bf9c10d7d Merge pull request #1192 from amnezia-vpn/bugfix/awg-wg-routes-vpnconnection
bugfix/removed adding routes in vpnconnection class for awg and wg protocols
2024-10-24 14:11:26 +01:00
pokamest
2e175cb9fc Merge pull request #1189 from amnezia-vpn/feature/support-tag
feature/added support tag to PageSetupWizardConfigSource
2024-10-24 14:08:28 +01:00
pokamest
823c1b5d3a Merge pull request #1190 from amnezia-vpn/chore/win-routes-logger
chore/displaying route addresses when adding to split tunneling fails
2024-10-24 14:04:45 +01:00
pokamest
92bc1a6f09 Merge pull request #1194 from amnezia-vpn/feature/proxy-bypass-checks
feature/proxy bypass checks
2024-10-24 14:03:56 +01:00
vladimir.kuznetsov
d511220f8b added a randomized proxy bypass 2024-10-24 10:59:50 +08:00
vladimir.kuznetsov
923e358aaa added a check to trigger proxy bypass 2024-10-24 01:02:30 +08:00
vladimir.kuznetsov
92b19eccf6 bugfix/removed adding routes in vpnconnection class for awg and wg protocols 2024-10-23 00:33:22 +08:00
vladimir.kuznetsov
5358aaeb00 chore/displaying route addresses when adding to split tunneling fails 2024-10-22 23:14:41 +08:00
vladimir.kuznetsov
e31a2066c0 feature/added support tag to PageSetupWizardConfigSource 2024-10-22 23:05:58 +08:00
vladimir.kuznetsov
928c4f18c9 chore/using the global network manager 2024-10-22 22:24:23 +08:00
pokamest
628e22869d Merge pull request #1085 from amnezia-vpn/bugfix/win_check_ps
Refactoring wmic to winapi
2024-10-18 15:45:32 +01:00
Pokamest Nikak
c9cd860654 Merge branch 'dev' into bugfix/win_check_ps 2024-10-18 15:42:08 +01:00
pokamest
17984adae5 Merge pull request #1181 from amnezia-vpn/chore/workflow-envs
chore: added new env for workflows
2024-10-18 15:02:36 +01:00
vladimir.kuznetsov
5601bc4fdf chore: added new env for workflows 2024-10-18 21:39:09 +08:00
pokamest
e14681801e Merge pull request #1086 from amnezia-vpn/bugfix/pw_rnd_gen
Switched to secure PRNG & some pw len increased
2024-10-18 14:17:33 +01:00
pokamest
f106b4d367 Merge pull request #1117 from amnezia-vpn/feature/process-auth-data
added processing of auth_data section when requesting api config
2024-10-18 10:57:57 +01:00
Nethius
74802f30ed feature/proxy storage bypass (#1179)
* feature: added proxy storage bypass
- added encryption error handling to apiController

* chore: fixed include
2024-10-18 10:57:38 +01:00
albexk
d63bf15011 Android qt 6.7.3 (#1143)
* Up Qt to 6.7.3

* Bump version to 4.8.2.0

* Raise the minimum Android version to 8 (API 26)

* Update version code to separate versions for new and old Androids

* Fix mouse not working on TVs

* Refactor logging

* Bump version code
2024-10-18 10:52:24 +01:00
Nethius
60de146f03 chore/mozilla upstream (#1136)
* cherry-pick commit 5a51e292d44ec0fb07867aff0401b4c2a8fca1e8 from mozila upstream

* cherry-pick commit e8ecb857dcfb804b7766a54e725b442fc6c0e661 from mozila upstream

* cherry-pick commit 16269ffa600905b09678014f64951748fb0ff8ad from mozila upstream
2024-10-18 10:47:53 +01:00
pokamest
c4f32eed31 Merge pull request #1180 from amnezia-vpn/bugfix/open-file-error-missing-text
bugfix: added missing text in the errors [no ci]
2024-10-18 10:45:10 +01:00
vladimir.kuznetsov
2c9067b0de bugfix: added missing text in the errors 2024-10-18 14:57:20 +08:00
pokamest
6844a2375b Merge pull request #1107 from amnezia-vpn/chore/fix-warnings
chore: added clear() after extractConfigFromData() on android
2024-10-13 12:18:46 +01:00
Nethius
7b838e77a0 bugfix: removed the importErrorOccurred() signal overload, since qml does not know how to handle signal overloads (#1111) 2024-10-13 12:14:43 +01:00
Nethius
694e781beb bugfix: fixed path to log folder for wireguard on windows (#1137) 2024-10-11 08:58:53 +07:00
Nethius
399a8c6d28 bugfix: fixed qml warnings when loading user list on PageShare (#1119) 2024-10-11 08:58:30 +07:00
vladimir.kuznetsov
dce08b3ecc added processing of auth_data section when requesting api config
- fixed saving api_config section when processing backend response
2024-10-06 13:23:19 +08:00
vladimir.kuznetsov
2763da960f chore: added clear() after extractConfigFromData() on android 2024-10-02 13:20:16 +08:00
pokamest
d4fff4af3c Merge pull request #1092 from amnezia-vpn/refactoring/remove-single-application
replaced QSingleApplication with QLocalServer
2024-09-30 17:52:45 +01:00
albexk
f0903c32f3 Bump version to 4.8.1.9 (#1103) 2024-09-30 21:31:54 +07:00
pokamest
ea8875478e Merge pull request #1102 from amnezia-vpn/fix/android-host-exception
Fix UnknownHostException
2024-09-30 11:43:00 +01:00
albexk
4c08e9f3bc Fix UnknownHostException 2024-09-30 13:38:48 +03:00
albexk
e8736102bf Bump Android version code (#1100) 2024-09-29 22:37:07 +07:00
Nethius
371cadcc02 chore: bump version to 4.8.1.8 (#1099)
- fixed m_isDevGatewayEnv initialization in Settings class
2024-09-29 21:29:36 +07:00
albexk
c3805195af Bump version to 4.8.1.1 (#1096) 2024-09-28 00:02:46 +07:00
Mykola Baibuz
2ef267bc44 Revert iOS OpenVPN version (#1078) 2024-09-26 00:10:36 +07:00
vladimir.kuznetsov
02a98b9d68 replaced QSingleApplication with QLocalServer 2024-09-25 11:42:02 +05:00
pokamest
94bae4b859 Merge pull request #1088 from amnezia-vpn/bugfix/android-native-wg-obfuscation
Add support for obfuscated WG on Android
2024-09-23 13:16:58 -07:00
albexk
425acc5f8b Add support for obfuscated WG on Android 2024-09-23 17:53:56 +03:00
pokamest
bb87c0838d Merge pull request #1083 from amnezia-vpn/bugfix/ios-native-wg-obfuscation
bugfix: fixed parameter handling for native wg obfuscation
2024-09-23 07:51:06 -07:00
Pokamest Nikak
1542adba82 Switched to secure PRNG & some pw len increased 2024-09-23 00:44:25 +01:00
Pokamest Nikak
3aa8a46f6e wip 2024-09-23 01:19:46 +03:00
Pokamest Nikak
1f08d78b43 wip 2024-09-22 22:52:59 +01:00
vladimir.kuznetsov
268adfb0a1 bugfix: fixed parameter handling for native wg obfuscation 2024-09-22 23:05:07 +05:00
pokamest
c681611102 Bump version to 4.8.1.0 2024-09-20 13:08:28 +01:00
pokamest
4fc2a23f49 Merge pull request #1076 from amnezia-vpn/fix/android-protocol-libs
Exclude protocol libraries from loading at application startup
2024-09-20 05:06:41 -07:00
pokamest
23f4a6ec8e Merge pull request #1077 from amnezia-vpn/bugfix/linux-page-home-drawer-size
bugfix: fixed drawer size to pageHome on first startup
2024-09-20 04:38:24 -07:00
vladimir.kuznetsov
504862c2b8 bugfix: fixed drawer size to pageHome on first startup 2024-09-20 15:36:20 +04:00
Mykola Baibuz
a22a9448ca Some XRay improvements (#1075) 2024-09-20 12:12:22 +01:00
pokamest
862e83ddf5 Merge pull request #1073 from amnezia-vpn/bugfix/awg-wg-persistent-keep-alive-variable-type
returned awg/wg persistentKeepAlive variable type to string
2024-09-20 03:08:27 -07:00
albexk
8735eee662 Exclude protocol libraries from loading at application startup 2024-09-19 23:41:37 +03:00
pokamest
ff82cf5dc4 Merge pull request #1074 from amnezia-vpn/fix/gh-ios-build
Fix iOS build on GHA
2024-09-19 09:24:32 -07:00
Iurii Egorov
8648790583 Fix iOS build on GHA 2024-09-19 18:47:20 +03:00
vladimir.kuznetsov
b881d92a80 bugfix: returned awg/wg persistentKeepAlive variable type to string 2024-09-19 16:04:36 +04:00
pokamest
7ad7f31e4d Merge pull request #1072 from amnezia-vpn/fix/android-xray-domain-name
Fix domain name resolution for XRay
2024-09-19 13:59:06 +03:00
albexk
138e6f70a4 Fix domain name resolution for XRay 2024-09-19 13:31:59 +03:00
Pokamest Nikak
6f94f4646a Fix Xray connection timeout for Windows 2024-09-19 11:18:40 +01:00
pokamest
4a01d2cf20 Merge pull request #1070 from amnezia-vpn/bugfix/awg-wg-persistent-keep-alive-variable-type
bugfix: fixed awg/wg persistentKeepAlive variable type
2024-09-18 17:13:53 +03:00
vladimir.kuznetsov
8948601caa bugfix: fixed awg/wg persistentKeepAlive variable type 2024-09-17 15:11:14 +04:00
Vitaly
aa92ccd06d Small improve on next IP generation / WireGuard, AWG (#1054)
Small improve on next IP generation
2024-09-17 13:29:01 +07:00
Vitaly
253ae75795 Added list of AllowedIPs for WireGuard/AWG connections on Share -> Users ->ExpandedContent page (#1055)
Added list of AllowedIPs for WireGuard/AWG connections on Share -> Users ->ExpandedContent page
2024-09-17 13:28:44 +07:00
pokamest
87cb5f620a Bump version to 4.8.0.4 2024-09-16 22:18:45 +01:00
Nethius
46cd740a84 added domain name resolving before connection for wg/awg and xray protocols (#814)
added domain name resolving before connection
2024-09-16 22:14:13 +01:00
Pokamest Nikak
76e5039578 Update translations 2024-09-15 11:09:59 +01:00
Pokamest Nikak
c6b131aa4c Bump version to 4.8.0.1 2024-09-13 18:25:04 +01:00
pokamest
5e72bf945c Merge pull request #1064 from amnezia-vpn/fix/android-window-hiding
Fix window hiding on startup on Android
2024-09-13 18:21:49 +03:00
albexk
eebf7eccec Fix window hiding on startup on Android 2024-09-13 18:14:25 +03:00
pokamest
168c293bfe Merge pull request #979 from amnezia-vpn/feature/update-tap
Update TAP-Windows driver
2024-09-13 15:00:31 +03:00
Nethius
aae3cdcac1 added saving allowed_ips to the array of strings for old configs (#926)
* added saving allowed_ips to the array of strings for old configs

* Remove config string processing, add getting all AWG, WG parameters from JSON

* fixed checking of default routes when adding split tunneling from the application

* added check when processing siteBasedSplitTunneling
2024-09-13 10:53:21 +01:00
Nethius
96566f04ee feature/mtu connection config (#833)
* added the ability to change mtu for connection-only configs
* added replacing MTU with default when importing awg/wg configs in amnezia
2024-09-13 09:38:48 +01:00
pokamest
fff15fffe2 Bug fix for iOS 2024-09-11 09:51:07 -07:00
pokamest
4e5a03e7f1 Merge pull request #1059 from amnezia-vpn/chore/dev-key 2024-09-10 21:38:45 +03:00
vladimir.kuznetsov
7571bbc36e chore: added dev key to deploy workflow
- added m_isDevEnvironment initialization
2024-09-10 22:03:10 +04:00
Mykola Baibuz
b83e74427e Update TAP-Windows driver 2024-08-15 19:51:49 +03:00
233 changed files with 9779 additions and 6890 deletions

39
.clang-format Normal file
View File

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

20
.clang-format-ignore Normal file
View File

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

View File

@@ -16,6 +16,10 @@ jobs:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
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:
- name: 'Install Qt'
@@ -82,6 +86,10 @@ jobs:
QIF_VERSION: 4.7
BUILD_ARCH: 64
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:
- name: 'Get sources'
@@ -144,6 +152,10 @@ jobs:
CC: cc
CXX: c++
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:
- name: 'Setup xcode'
@@ -178,7 +190,7 @@ jobs:
- name: 'Install go'
uses: actions/setup-go@v5
with:
go-version: '1.20'
go-version: '1.22.1'
cache: false
- name: 'Setup gomobile'
@@ -205,7 +217,11 @@ jobs:
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/ios/bin"
export QT_MACOS_ROOT_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos"
export PATH=$PATH:~/go/bin
sh deploy/build_ios.sh
sh deploy/build_ios.sh | \
sed -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DPROD_AGW_PUBLIC_KEY/d' | \
sed -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/,/-Xcc/ { /-Xcc/!d; }' -e '/-Xcc -DDEV_AGW_PUBLIC_KEY/d' | \
sed -e '/-DPROD_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DPROD_AGW_PUBLIC_KEY/d' | \
sed -e '/-DDEV_AGW_PUBLIC_KEY/,/-D/ { /-D/!d; }' -e '/-DDEV_AGW_PUBLIC_KEY/d'
env:
IOS_TRUST_CERT_BASE64: ${{ secrets.IOS_TRUST_CERT_BASE64 }}
IOS_SIGNING_CERT_BASE64: ${{ secrets.IOS_SIGNING_CERT_BASE64 }}
@@ -235,12 +251,16 @@ jobs:
QT_VERSION: 6.4.3
QIF_VERSION: 4.6
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:
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '14.3.1'
xcode-version: '15.4.0'
- name: 'Install Qt'
uses: jurplel/install-qt-action@v3
@@ -297,9 +317,13 @@ jobs:
env:
ANDROID_BUILD_PLATFORM: android-34
QT_VERSION: 6.7.2
QT_VERSION: 6.7.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
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:
- name: 'Install desktop Qt'
@@ -311,7 +335,8 @@ jobs:
arch: 'linux_gcc_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86_64 Qt'
uses: jurplel/install-qt-action@v4
@@ -322,7 +347,8 @@ jobs:
arch: 'android_x86_64'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_x86 Qt'
uses: jurplel/install-qt-action@v4
@@ -333,7 +359,8 @@ jobs:
arch: 'android_x86'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_armv7 Qt'
uses: jurplel/install-qt-action@v4
@@ -344,7 +371,8 @@ jobs:
arch: 'android_armv7'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install android_arm64_v8a Qt'
uses: jurplel/install-qt-action@v4
@@ -355,7 +383,8 @@ jobs:
arch: 'android_arm64_v8a'
modules: ${{ env.QT_MODULES }}
dir: ${{ runner.temp }}
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
py7zrversion: '==0.22.*'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Grant execute permission for qt-cmake'
shell: bash

View File

@@ -16,6 +16,10 @@ jobs:
QT_VERSION: 6.4.1
QIF_VERSION: 4.5
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:
- name: 'Install desktop Qt'

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.8.0.0
project(${PROJECT} VERSION 4.8.3.0
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 58)
set(APP_ANDROID_VERSION_CODE 2072)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")

View File

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

181
README_RU.md Normal file
View File

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

View File

@@ -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()

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -25,10 +25,11 @@ execute_process(
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
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_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
if(IOS)
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))
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
endif()
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
@@ -144,6 +146,7 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.h
)
# Mozilla headres
@@ -195,6 +198,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
${CMAKE_CURRENT_LIST_DIR}/utils/qmlUtils.cpp
)
# Mozilla sources

View File

@@ -10,6 +10,8 @@
#include <QTextDocument>
#include <QTimer>
#include <QTranslator>
#include <QLocalSocket>
#include <QLocalServer>
#include "logger.h"
#include "ui/models/installedAppsModel.h"
@@ -28,13 +30,7 @@
#include <AmneziaVPN-Swift.h>
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
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);
@@ -115,10 +111,11 @@ void AmneziaApplication::init()
qFatal("Android controller initialization failed");
}
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) {
m_pageController->goToPageHome();
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig();
data.clear();
emit m_pageController->goToPageViewConfig();
});
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
@@ -126,16 +123,16 @@ void AmneziaApplication::init()
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
m_pageController->goToPageHome();
connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig();
emit m_pageController->goToPageViewConfig();
});
connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
m_pageController->goToPageHome();
connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
emit m_pageController->goToPageHome();
m_pageController->goToPageSettingsBackup();
m_settingsController->importBackupFromOutside(filePath);
emit m_settingsController->importBackupFromOutside(filePath);
});
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
@@ -180,16 +177,6 @@ void AmneziaApplication::init()
m_pageController->showOnStartup();
#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
// Text from TextArea always has "text/html" mime-type:
// /qt/6.6.1/Src/qtdeclarative/src/quick/items/qquicktextcontrol.cpp:1865
@@ -294,6 +281,24 @@ bool AmneziaApplication::parseCommands()
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
{
return m_engine;
@@ -399,6 +404,9 @@ void AmneziaApplication::initControllers()
m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
m_focusController.reset(new FocusController(m_engine, this));
m_engine->rootContext()->setContextProperty("FocusController", m_focusController.get());
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_clientManagementModel,
m_apiServicesModel, m_settings));
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());

View File

@@ -19,6 +19,7 @@
#include "ui/controllers/exportController.h"
#include "ui/controllers/importController.h"
#include "ui/controllers/installController.h"
#include "ui/controllers/focusController.h"
#include "ui/controllers/pageController.h"
#include "ui/controllers/settingsController.h"
#include "ui/controllers/sitesController.h"
@@ -53,22 +54,14 @@
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#define AMNEZIA_BASE_CLASS QGuiApplication
#else
#define AMNEZIA_BASE_CLASS SingleApplication
#define QAPPLICATION_CLASS QApplication
#include "singleapplication.h"
#define AMNEZIA_BASE_CLASS QApplication
#endif
class AmneziaApplication : public AMNEZIA_BASE_CLASS
{
Q_OBJECT
public:
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
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();
void init();
@@ -78,6 +71,10 @@ public:
void updateTranslator(const QLocale &locale);
bool parseCommands();
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
void startLocalServer();
#endif
QQmlApplicationEngine *qmlEngine() const;
QNetworkAccessManager *manager() { return m_nam; }
@@ -128,6 +125,7 @@ private:
#endif
QScopedPointer<ConnectionController> m_connectionController;
QScopedPointer<FocusController> m_focusController;
QScopedPointer<PageController> m_pageController;
QScopedPointer<InstallController> m_installController;
QScopedPointer<ImportController> m_importController;

View File

@@ -11,7 +11,7 @@
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<!-- for TV -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.software.leanback" android:required="true" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<!-- The following comment will be replaced upon deployment with default features based on the dependencies
@@ -20,7 +20,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<!-- To request network state -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
@@ -91,6 +91,13 @@
android:exported="false"
android:theme="@style/Translucent" />
<activity android:name=".TvFilePicker"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity=""
android:exported="false"
android:theme="@style/Translucent" />
<activity
android:name=".ImportConfigActivity"
android:excludeFromRecents="true"

View File

@@ -1,81 +1,21 @@
package org.amnezia.vpn.protocol.awg
import org.amnezia.vpn.protocol.wireguard.Wireguard
import org.amnezia.vpn.protocol.wireguard.WireguardConfig
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() {
override val ifName: String = "awg0"
override fun parseConfig(config: JSONObject): AwgConfig {
val configDataJson = config.getJSONObject("awg_config_data")
val configData = parseConfigData(configDataJson.getString("config"))
return AwgConfig.build {
configWireguard(configData, configDataJson)
override fun parseConfig(config: JSONObject): WireguardConfig {
val configData = config.getJSONObject("awg_config_data")
return WireguardConfig.build {
setUseProtocolExtension(true)
configExtensionParameters(configData)
configWireguard(config, configData)
configSplitTunneling(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()) }
}
}
}

View File

@@ -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()
}
}

View File

@@ -3,40 +3,16 @@ package org.amnezia.vpn.protocol.cloak
import android.util.Base64
import net.openvpn.ovpn3.ClientAPI_Config
import org.amnezia.vpn.protocol.openvpn.OpenVpn
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
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() {
override fun internalInit() {
super.internalInit()
if (!isInitialized) loadSharedLibrary(context, "ck-ovpn-plugin")
}
override fun parseConfig(config: JSONObject): ClientAPI_Config {
val openVpnConfig = ClientAPI_Config()

View File

@@ -33,7 +33,7 @@ android.library.defaults.buildfeatures.androidresources=false
# For development copy and set local values for these parameters in local.properties
#androidCompileSdkVersion=android-34
#androidBuildToolsVersion=34.0.0
#qtMinSdkVersion=24
#qtMinSdkVersion=26
#qtTargetSdkVersion=34
#androidNdkVersion=26.1.10909125
#qtTargetAbiList=x86_64

View File

@@ -11,28 +11,12 @@ import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
import org.amnezia.vpn.protocol.Statistics
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.getLocalNetworks
import org.amnezia.vpn.util.net.parseInetAddress
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() {
private var openVpnClient: OpenVpnClient? = null
@@ -51,7 +35,10 @@ open class OpenVpn : Protocol() {
}
override fun internalInit() {
if (!isInitialized) loadSharedLibrary(context, "ovpn3")
if (!isInitialized) {
loadSharedLibrary(context, "ovpn3")
loadSharedLibrary(context, "ovpnutil")
}
if (this::scope.isInitialized) {
scope.cancel()
}

View File

@@ -2,7 +2,6 @@ package org.amnezia.vpn.protocol
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 VpnStartException(message: String? = null, cause: Throwable? = null) : ProtocolException(message, cause)

View File

@@ -1,6 +1,5 @@
package org.amnezia.vpn.protocol
import android.annotation.SuppressLint
import android.content.Context
import android.net.IpPrefix
import android.net.VpnService
@@ -8,9 +7,6 @@ import android.net.VpnService.Builder
import android.os.Build
import android.system.OsConstants
import androidx.annotation.RequiresApi
import java.io.File
import java.io.FileOutputStream
import java.util.zip.ZipFile
import kotlinx.coroutines.flow.MutableStateFlow
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.net.InetNetwork
@@ -158,60 +154,6 @@ abstract class Protocol {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
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)

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_banner_background"/>
<foreground android:drawable="@mipmap/ic_banner_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -23,4 +23,6 @@
<string name="notificationSettingsDialogTitle">Настройки уведомлений</string>
<string name="notificationSettingsDialogMessage">Для показа уведомлений необходимо включить уведомления в системных настройках</string>
<string name="openNotificationSettings">Открыть настройки уведомлений</string>
<string name="tvNoFileBrowser">Пожалуйста, установите приложение для просмотра файлов</string>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_banner_background">#1E1E1F</color>
</resources>

View File

@@ -3,7 +3,6 @@
<!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
<array name="bundled_libs">
<!-- %%INSERT_EXTRA_LIBS%% -->
</array>
<array name="qt_libs">

View File

@@ -23,4 +23,6 @@
<string name="notificationSettingsDialogTitle">Notification settings</string>
<string name="notificationSettingsDialogMessage">To show notifications, you must enable notifications in the system settings</string>
<string name="openNotificationSettings">Open notification settings</string>
<string name="tvNoFileBrowser">Please install a file management utility to browse files</string>
</resources>

View File

@@ -4,6 +4,7 @@ import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.NotificationManager
import android.content.ActivityNotFoundException
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Intent
@@ -12,6 +13,7 @@ import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.net.VpnService
import android.os.Build
import android.os.Bundle
@@ -20,7 +22,13 @@ import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.os.ParcelFileDescriptor
import android.os.SystemClock
import android.provider.OpenableColumns
import android.provider.Settings
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams
import android.webkit.MimeTypeMap
import android.widget.Toast
@@ -29,6 +37,7 @@ import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE
import kotlin.coroutines.CoroutineContext
import kotlin.text.RegexOption.IGNORE_CASE
import AppListProvider
import kotlinx.coroutines.CompletableDeferred
@@ -43,6 +52,7 @@ import kotlinx.coroutines.withContext
import org.amnezia.vpn.protocol.getStatistics
import org.amnezia.vpn.protocol.getStatus
import org.amnezia.vpn.qt.QtAndroidController
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.Prefs
import org.json.JSONException
@@ -69,6 +79,7 @@ class AmneziaActivity : QtActivity() {
private var isInBoundState = false
private var notificationStateReceiver: BroadcastReceiver? = null
private lateinit var vpnServiceMessenger: IpcMessenger
private var pfd: ParcelFileDescriptor? = null
private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>()
@@ -157,7 +168,8 @@ class AmneziaActivity : QtActivity() {
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "Create Amnezia activity: $intent")
Log.d(TAG, "Create Amnezia activity")
loadLibs()
window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
statusBarColor = getColor(R.color.black)
@@ -179,6 +191,17 @@ class AmneziaActivity : QtActivity() {
runBlocking { vpnProto = proto.await() }
}
private fun loadLibs() {
listOf(
"rsapss",
"crypto_3",
"ssl_3",
"ssh"
).forEach {
loadSharedLibrary(this.applicationContext, it)
}
}
private fun registerBroadcastReceivers() {
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
registerBroadcastReceiver(
@@ -187,7 +210,7 @@ class AmneziaActivity : QtActivity() {
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
)
) {
Log.d(
Log.v(
TAG, "Notification state changed: ${it?.action}, blocked = " +
"${it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)}"
)
@@ -201,7 +224,7 @@ class AmneziaActivity : QtActivity() {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
Log.d(TAG, "onNewIntent: $intent")
Log.v(TAG, "onNewIntent: $intent")
intent?.let(::processIntent)
}
@@ -390,7 +413,7 @@ class AmneziaActivity : QtActivity() {
@MainThread
private fun startVpn(vpnConfig: String) {
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 (proto.serviceClass == vpnProto?.serviceClass) {
vpnProto = proto
@@ -500,21 +523,25 @@ class AmneziaActivity : QtActivity() {
type = "text/*"
putExtra(Intent.EXTRA_TITLE, fileName)
}.also {
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
onSuccess = {
it?.data?.let { uri ->
Log.d(TAG, "Save file to $uri")
try {
contentResolver.openOutputStream(uri)?.use { os ->
os.bufferedWriter().use { it.write(data) }
try {
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
onSuccess = {
it?.data?.let { uri ->
Log.v(TAG, "Save file to $uri")
try {
contentResolver.openOutputStream(uri)?.use { os ->
os.bufferedWriter().use { it.write(data) }
}
} catch (e: IOException) {
Log.e(TAG, "Failed to save file $uri: $e")
// todo: send error to Qt
}
} catch (e: IOException) {
Log.e(TAG, "Failed to save file $uri: $e")
// todo: send error to Qt
}
}
}
))
))
} catch (_: ActivityNotFoundException) {
Toast.makeText(this@AmneziaActivity, "Unsupported", Toast.LENGTH_LONG).show()
}
}
}
}
@@ -523,46 +550,115 @@ class AmneziaActivity : QtActivity() {
fun openFile(filter: String?) {
Log.v(TAG, "Open file with filter: $filter")
mainScope.launch {
val mimeTypes = if (!filter.isNullOrEmpty()) {
val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
val mime = MimeTypeMap.getSingleton()
extensionRegex.findAll(filter).map {
it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
}.toSet()
} else emptySet()
val intent = if (!isOnTv()) {
val mimeTypes = if (!filter.isNullOrEmpty()) {
val extensionRegex = "\\*\\.([a-z0-9]+)".toRegex(IGNORE_CASE)
val mime = MimeTypeMap.getSingleton()
extensionRegex.findAll(filter).map {
it.groups[1]?.value?.let { mime.getMimeTypeFromExtension(it) } ?: "*/*"
}.toSet()
} else emptySet()
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
Log.v(TAG, "File mimyType filter: $mimeTypes")
if ("*/*" in mimeTypes) {
type = "*/*"
} else {
when (mimeTypes.size) {
1 -> type = mimeTypes.first()
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
Log.v(TAG, "File mimyType filter: $mimeTypes")
if ("*/*" in mimeTypes) {
type = "*/*"
} else {
when (mimeTypes.size) {
1 -> type = mimeTypes.first()
in 2..Int.MAX_VALUE -> {
type = "*/*"
putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
in 2..Int.MAX_VALUE -> {
type = "*/*"
putExtra(EXTRA_MIME_TYPES, mimeTypes.toTypedArray())
}
else -> type = "*/*"
}
else -> type = "*/*"
}
}
}.also {
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
} else {
Intent(this@AmneziaActivity, TvFilePicker::class.java)
}
try {
startActivityForResult(intent, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
val uri = it?.data?.toString() ?: ""
Log.d(TAG, "Open file: $uri")
if (isOnTv() && it?.hasExtra("activityNotFound") == true) {
showNoFileBrowserAlertDialog()
}
val uri = it?.data?.apply {
grantUriPermission(packageName, this, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}?.toString() ?: ""
Log.v(TAG, "Open file: $uri")
mainScope.launch {
qtInitialized.await()
QtAndroidController.onFileOpened(uri)
}
}
))
} catch (_: ActivityNotFoundException) {
showNoFileBrowserAlertDialog()
mainScope.launch {
qtInitialized.await()
QtAndroidController.onFileOpened("")
}
}
}
}
private fun showNoFileBrowserAlertDialog() {
AlertDialog.Builder(this)
.setMessage(R.string.tvNoFileBrowser)
.setCancelable(false)
.setPositiveButton(android.R.string.ok) { _, _ ->
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
} catch (_: Throwable) {}
}
.show()
}
@Suppress("unused")
fun getFd(fileName: String): Int {
Log.v(TAG, "Get fd for $fileName")
return blockingCall {
try {
pfd = contentResolver.openFileDescriptor(Uri.parse(fileName), "r")
pfd?.fd ?: -1
} catch (e: Exception) {
Log.e(TAG, "Failed to get fd: $e")
-1
}
}
}
@Suppress("unused")
fun closeFd() {
Log.v(TAG, "Close fd")
mainScope.launch {
pfd?.close()
pfd = null
}
}
@Suppress("unused")
fun getFileName(uri: String): String {
Log.v(TAG, "Get file name for uri: $uri")
return blockingCall {
try {
contentResolver.query(Uri.parse(uri), arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
if (cursor.moveToFirst() && !cursor.isNull(0)) {
return@blockingCall cursor.getString(0) ?: ""
}
}
} catch (e: Exception) {
Log.e(TAG, "Failed to get file name: $e")
}
""
}
}
@Suppress("unused")
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
@@ -707,9 +803,121 @@ class AmneziaActivity : QtActivity() {
}
}
// method to workaround Qt's problem with calling the keyboard on TVs
@Suppress("unused")
fun sendTouch(x: Float, y: Float) {
Log.v(TAG, "Send touch: $x, $y")
blockingCall {
findQtWindow(window.decorView)?.let {
Log.v(TAG, "Send touch to $it")
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN))
it.dispatchTouchEvent(createEvent(x, y, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP))
}
}
}
private fun findQtWindow(view: View): View? {
Log.v(TAG, "findQtWindow: process $view")
if (view::class.simpleName == "QtWindow") return view
else if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val result = findQtWindow(view.getChildAt(i))
if (result != null) return result
}
return null
} else return null
}
private fun createEvent(x: Float, y: Float, eventTime: Long, action: Int): MotionEvent =
MotionEvent.obtain(
eventTime,
eventTime,
action,
1,
arrayOf(MotionEvent.PointerProperties().apply {
id = 0
toolType = MotionEvent.TOOL_TYPE_FINGER
}),
arrayOf(MotionEvent.PointerCoords().apply {
this.x = x
this.y = y
pressure = 1f
size = 1f
}),
0, 0, 1.0f, 1.0f, 0, 0, 0,0
)
// 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 {
Log.v(TAG, "dispatchTouch: $ev")
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
*/
private fun <T> blockingCall(
context: CoroutineContext = Dispatchers.Main.immediate,
block: suspend () -> T
) = runBlocking {
mainScope.async(context) { block() }.await()
}
companion object {
private fun actionCodeToString(actionCode: Int): String =
when (actionCode) {

View File

@@ -22,6 +22,7 @@ import androidx.annotation.MainThread
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import java.net.UnknownHostException
import java.util.concurrent.ConcurrentHashMap
import kotlin.LazyThreadSafetyMode.NONE
import kotlinx.coroutines.CoroutineExceptionHandler
@@ -40,7 +41,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
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.CONNECTING
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
@@ -50,6 +50,7 @@ import org.amnezia.vpn.protocol.ProtocolState.UNKNOWN
import org.amnezia.vpn.protocol.VpnException
import org.amnezia.vpn.protocol.VpnStartException
import org.amnezia.vpn.protocol.putStatus
import org.amnezia.vpn.util.LoadLibraryException
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.Prefs
import org.amnezia.vpn.util.net.NetworkState
@@ -127,6 +128,8 @@ open class AmneziaVpnService : VpnService() {
is LoadLibraryException -> onError("${e.message}. Caused: ${e.cause?.message}")
is UnknownHostException -> onError("Unknown host")
else -> throw e
}
}
@@ -297,7 +300,7 @@ open class AmneziaVpnService : VpnService() {
arrayOf(ACTION_CONNECT, ACTION_DISCONNECT), ContextCompat.RECEIVER_NOT_EXPORTED
) {
it?.action?.let { action ->
Log.d(TAG, "Broadcast request received: $action")
Log.v(TAG, "Broadcast request received: $action")
when (action) {
ACTION_CONNECT -> connect()
ACTION_DISCONNECT -> disconnect()
@@ -314,7 +317,7 @@ open class AmneziaVpnService : VpnService() {
)
) {
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) {
enableNotification()
} else {
@@ -447,7 +450,7 @@ open class AmneziaVpnService : VpnService() {
serviceNotification.isNotificationEnabled() &&
getSystemService<PowerManager>()?.isInteractive != false
) {
Log.d(TAG, "Launch traffic stats update")
Log.v(TAG, "Launch traffic stats update")
trafficStats.reset()
startTrafficStatsUpdateJob()
}

View File

@@ -66,7 +66,7 @@ class AuthActivity : FragmentActivity() {
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
super.onAuthenticationSucceeded(result)
Log.d(TAG, "Authentication succeeded")
Log.v(TAG, "Authentication succeeded")
QtAndroidController.onAuthResult(true)
finish()
}

View File

@@ -29,20 +29,20 @@ class ImportConfigActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "Create Import Config Activity: $intent")
Log.v(TAG, "Create Import Config Activity: $intent")
intent?.let(::readConfig)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.d(TAG, "onNewIntent: $intent")
Log.v(TAG, "onNewIntent: $intent")
intent.let(::readConfig)
}
private fun readConfig(intent: Intent) {
when (intent.action) {
ACTION_SEND -> {
Log.d(TAG, "Process SEND action, type: ${intent.type}")
Log.v(TAG, "Process SEND action, type: ${intent.type}")
when (intent.type) {
"application/octet-stream" -> {
intent.getUriCompat()?.let { uri ->
@@ -60,7 +60,7 @@ class ImportConfigActivity : ComponentActivity() {
}
ACTION_VIEW -> {
Log.d(TAG, "Process VIEW action, scheme: ${intent.scheme}")
Log.v(TAG, "Process VIEW action, scheme: ${intent.scheme}")
when (intent.scheme) {
"file", "content" -> {
intent.data?.let { uri ->

View File

@@ -62,7 +62,7 @@ class ServiceNotification(private val context: Context) {
fun buildNotification(serverName: String?, protocol: String?, state: ProtocolState): Notification {
val speedString = if (state == CONNECTED) zeroSpeed else null
Log.d(TAG, "Build notification: $serverName, $state")
Log.v(TAG, "Build notification: $serverName, $state")
return notificationBuilder
.setSmallIcon(R.drawable.ic_amnezia_round)
@@ -88,17 +88,15 @@ class ServiceNotification(private val context: Context) {
fun isNotificationEnabled(): Boolean {
if (!context.isNotificationPermissionGranted()) return false
if (!notificationManager.areNotificationsEnabled()) return false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
?.let { it.importance != NotificationManager.IMPORTANCE_NONE } ?: true
}
return true
return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)?.let {
it.importance != NotificationManager.IMPORTANCE_NONE
} ?: true
}
@SuppressLint("MissingPermission")
fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) {
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))
}
}

View File

@@ -0,0 +1,45 @@
package org.amnezia.vpn
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import org.amnezia.vpn.util.Log
private const val TAG = "TvFilePicker"
class TvFilePicker : ComponentActivity() {
private val fileChooseResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
setResult(RESULT_OK, Intent().apply { data = it })
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.v(TAG, "onCreate")
getFile()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
Log.v(TAG, "onNewIntent")
getFile()
}
private fun getFile() {
try {
Log.v(TAG, "getFile")
fileChooseResultLauncher.launch("*/*")
} catch (_: ActivityNotFoundException) {
Log.w(TAG, "Activity not found")
setResult(RESULT_CANCELED, Intent().apply { putExtra("activityNotFound", true) })
finish()
} catch (e: Exception) {
Log.e(TAG, "Failed to get file: $e")
setResult(RESULT_CANCELED)
finish()
}
}
}

View 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 }

View 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)

View File

@@ -1,8 +1,6 @@
package org.amnezia.vpn.util
import android.content.Context
import android.icu.text.DateFormat
import android.icu.text.SimpleDateFormat
import android.os.Build
import android.os.Process
import java.io.File
@@ -12,8 +10,6 @@ import java.nio.channels.FileChannel
import java.nio.channels.FileLock
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Date
import java.util.Locale
import java.util.concurrent.locks.ReentrantLock
import org.amnezia.vpn.util.Log.Priority.D
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 |
*/
object Log {
private val dateTimeFormat: Any =
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 val dateTimeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
private lateinit var logDir: File
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 {
val date = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LocalDateTime.now().format(dateTimeFormat as DateTimeFormatter)
} else {
@Suppress("UNCHECKED_CAST")
(dateTimeFormat as ThreadLocal<DateFormat>).get()?.format(Date())
}
val date = LocalDateTime.now().format(dateTimeFormat)
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
"$tag: $msg\n"
}

View File

@@ -42,18 +42,12 @@ class NetworkState(
private val networkCallback: NetworkCallback by lazy(NONE) {
object : NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d(TAG, "onAvailable: $network")
Log.v(TAG, "onAvailable: $network")
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
Log.d(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
checkNetworkState(network, networkCapabilities)
} else {
handler.post {
checkNetworkState(network, networkCapabilities)
}
}
Log.v(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
checkNetworkState(network, networkCapabilities)
}
private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) {
@@ -73,11 +67,11 @@ class NetworkState(
}
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
Log.d(TAG, "onBlockedStatusChanged: $network, $blocked")
Log.v(TAG, "onBlockedStatusChanged: $network, $blocked")
}
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")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
} else {
val numberAttempts = 300
var attemptCount = 0
while(true) {
@@ -108,8 +102,6 @@ class NetworkState(
}
}
}
} else {
connectivityManager.requestNetwork(networkRequest, networkCallback)
}
isListenerBound = true
}

View File

@@ -35,7 +35,7 @@ fun getLocalNetworks(context: Context, ipv6: Boolean): List<InetNetwork> {
return emptyList()
}
fun parseInetAddress(address: String): InetAddress = parseNumericAddressCompat(address)
fun parseInetAddress(address: String): InetAddress = InetAddress.getByName(address)
private val parseNumericAddressCompat: (String) -> InetAddress =
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
.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) {
hostAddress!!
} else {

View File

@@ -1,65 +1,35 @@
package org.amnezia.vpn.protocol.wireguard
import android.net.VpnService.Builder
import java.io.IOException
import java.util.Locale
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.withContext
import kotlinx.coroutines.launch
import org.amnezia.awg.GoBackend
import org.amnezia.vpn.protocol.Protocol
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
import org.amnezia.vpn.protocol.Statistics
import org.amnezia.vpn.protocol.VpnStartException
import org.amnezia.vpn.util.LibraryLoader.loadSharedLibrary
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.InetNetwork
import org.amnezia.vpn.util.net.parseInetAddress
import org.amnezia.vpn.util.optStringOrNull
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"
open class Wireguard : Protocol() {
private var tunnelHandle: Int = -1
protected open val ifName: String = "amn0"
private lateinit var scope: CoroutineScope
private var statusJob: Job? = null
override val statistics: Statistics
get() {
@@ -82,101 +52,78 @@ open class Wireguard : Protocol() {
override fun internalInit() {
if (!isInitialized) loadSharedLibrary(context, "wg-go")
if (this::scope.isInitialized) {
scope.cancel()
}
scope = CoroutineScope(Dispatchers.IO)
}
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
val wireguardConfig = parseConfig(config)
val startTime = System.currentTimeMillis()
start(wireguardConfig, vpnBuilder, protect)
waitForConnection(startTime)
state.value = CONNECTED
}
private suspend fun waitForConnection(startTime: Long) {
Log.d(TAG, "Waiting for connection")
withContext(Dispatchers.IO) {
val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
try {
delay(1000)
var log = getLogcat(time)
Log.d(TAG, "First waiting log: $log")
// check that there is a connection log,
// to avoid infinite connection
if (!log.contains("Attaching to interface")) {
Log.w(TAG, "Logs do not contain a connection log")
return@withContext
}
while (!log.contains("Received handshake response")) {
delay(1000)
log = getLogcat(time)
}
} catch (e: IOException) {
Log.e(TAG, "Failed to get logcat: $e")
}
}
}
private fun getLogcat(time: String): String =
ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
.redirectErrorStream(true)
.start()
.inputStream.reader().readText()
protected open fun parseConfig(config: JSONObject): WireguardConfig {
val configDataJson = config.getJSONObject("wireguard_config_data")
val configData = parseConfigData(configDataJson.getString("config"))
val configData = config.getJSONObject("wireguard_config_data")
return WireguardConfig.build {
configWireguard(configData, configDataJson)
configWireguard(config, configData)
configSplitTunneling(config)
configAppSplitTunneling(config)
}
}
protected fun WireguardConfig.Builder.configWireguard(configData: Map<String, String>, configDataJson: JSONObject) {
configData["Address"]?.split(",")?.map { address ->
protected fun WireguardConfig.Builder.configWireguard(config: JSONObject, configData: JSONObject) {
configData.getString("client_ip").split(",").map { address ->
InetNetwork.parse(address.trim())
}?.forEach(::addAddress)
}.forEach(::addAddress)
configData["DNS"]?.split(",")?.map { dns ->
parseInetAddress(dns.trim())
}?.forEach(::addDnsServer)
config.optStringOrNull("dns1")?.let { dns ->
addDnsServer(parseInetAddress(dns.trim()))
}
config.optStringOrNull("dns2")?.let { dns ->
addDnsServer(parseInetAddress(dns.trim()))
}
val defRoutes = hashSetOf(
InetNetwork("0.0.0.0", 0),
InetNetwork("::", 0)
)
val routes = hashSetOf<InetNetwork>()
configData["AllowedIPs"]?.split(",")?.map { route ->
configData.getJSONArray("allowed_ips").asSequence<String>().map { route ->
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 (routes.any { it !in defRoutes }) disableSplitTunneling()
addRoutes(routes)
configDataJson.optString("mtu").let { mtu ->
if (mtu.isNotEmpty()) {
setMtu(mtu.toInt())
} else {
configData["MTU"]?.let { setMtu(it.toInt()) }
}
configData.optStringOrNull("mtu")?.let { setMtu(it.toInt()) }
val host = configData.getString("hostName").let { parseInetAddress(it.trim()) }
val port = configData.getInt("port")
setEndpoint(InetEndpoint(host, port))
if (configData.optBoolean("isObfuscationEnabled")) {
setUseProtocolExtension(true)
configExtensionParameters(configData)
}
configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) }
configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) }
configData["PrivateKey"]?.let { setPrivateKeyHex(it.base64ToHex()) }
configData["PublicKey"]?.let { setPublicKeyHex(it.base64ToHex()) }
configData["PresharedKey"]?.let { setPreSharedKeyHex(it.base64ToHex()) }
configData.optStringOrNull("persistent_keep_alive")?.let { setPersistentKeepalive(it.toInt()) }
configData.getString("client_priv_key").let { setPrivateKeyHex(it.base64ToHex()) }
configData.getString("server_pub_key").let { setPublicKeyHex(it.base64ToHex()) }
configData.optStringOrNull("psk_key")?.let { setPreSharedKeyHex(it.base64ToHex()) }
}
protected fun parseConfigData(data: String): Map<String, String> {
val parsedData = TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER)
data.lineSequence()
.filter { it.isNotEmpty() && !it.startsWith('[') }
.forEach { line ->
val attr = line.split("=", limit = 2)
parsedData[attr.first().trim()] = attr.last().trim()
}
return parsedData
protected fun WireguardConfig.Builder.configExtensionParameters(configData: JSONObject) {
configData.optStringOrNull("Jc")?.let { setJc(it.toInt()) }
configData.optStringOrNull("Jmin")?.let { setJmin(it.toInt()) }
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
}
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {
@@ -205,6 +152,43 @@ open class Wireguard : Protocol() {
tunnelHandle = -1
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
}
launchStatusJob()
}
private fun launchStatusJob() {
Log.d(TAG, "Launch status job")
statusJob = scope.launch {
while (true) {
val lastHandshake = getLastHandshake()
Log.v(TAG, "lastHandshake=$lastHandshake")
if (lastHandshake == 0L) {
delay(1000)
continue
}
if (lastHandshake == -2L || lastHandshake > 0L) state.value = CONNECTED
else if (lastHandshake == -1L) state.value = DISCONNECTED
statusJob = null
break
}
}
}
private fun getLastHandshake(): Long {
if (tunnelHandle == -1) {
Log.e(TAG, "Trying to get config of a non-existent tunnel")
return -1
}
val config = GoBackend.awgGetConfig(tunnelHandle)
if (config == null) {
Log.e(TAG, "Failed to get tunnel config")
return -2
}
val lastHandshake = config.lines().find { it.startsWith("last_handshake_time_sec=") }?.substring(24)?.toLong()
if (lastHandshake == null) {
Log.e(TAG, "Failed to get last_handshake_time_sec")
return -2
}
return lastHandshake
}
override fun stopVpn() {
@@ -212,6 +196,8 @@ open class Wireguard : Protocol() {
Log.w(TAG, "Tunnel already down")
return
}
statusJob?.cancel()
statusJob = null
val handleToClose = tunnelHandle
tunnelHandle = -1
GoBackend.awgTurnOff(handleToClose)

View File

@@ -1,6 +1,7 @@
package org.amnezia.vpn.protocol.wireguard
import android.util.Base64
import org.amnezia.vpn.protocol.BadConfigException
import org.amnezia.vpn.protocol.ProtocolConfig
import org.amnezia.vpn.util.net.InetEndpoint
@@ -12,7 +13,17 @@ open class WireguardConfig protected constructor(
val persistentKeepalive: Int,
val publicKeyHex: 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) {
protected constructor(builder: Builder) : this(
@@ -21,7 +32,17 @@ open class WireguardConfig protected constructor(
builder.persistentKeepalive,
builder.publicKeyHex,
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()) {
@@ -33,6 +54,30 @@ open class WireguardConfig protected constructor(
open fun appendDeviceLine(sb: StringBuilder) = with(sb) {
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) {
@@ -65,6 +110,18 @@ open class WireguardConfig protected constructor(
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 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 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) }
}

View File

@@ -17,72 +17,10 @@ import org.amnezia.vpn.protocol.xray.libXray.Logger
import org.amnezia.vpn.protocol.xray.libXray.Tun2SocksConfig
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.net.InetNetwork
import org.amnezia.vpn.util.net.ip
import org.amnezia.vpn.util.net.parseInetAddress
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 LIBXRAY_TAG = "libXray"
@@ -124,7 +62,15 @@ class Xray : Protocol() {
.put("loglevel", "warning")
.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
isRunning = true
}
@@ -184,8 +130,8 @@ class Xray : Protocol() {
LibXray.initXray(assetsPath)
val geoDir = File(assetsPath, "geo").absolutePath
val configPath = File(context.cacheDir, "config.json")
Log.d(TAG, "xray.location.asset: $geoDir")
Log.d(TAG, "config: $configPath")
Log.v(TAG, "xray.location.asset: $geoDir")
Log.v(TAG, "config: $configPath")
try {
configPath.writeText(configJson)
} catch (e: IOException) {

View File

@@ -2,10 +2,6 @@ set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
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)
set(LIBS ${LIBS} SortFilterProxyModel)
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)

View File

@@ -1,6 +1,6 @@
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
"The minimum API level supported by the application or library" FORCE)

View File

@@ -95,6 +95,18 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
stdOut.replace("/32", "");
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
if (ips.isEmpty()) {
nextIpNumber = "2";
@@ -187,6 +199,10 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
jConfig[config_key::server_pub_key] = connData.serverPubKey;
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;
return QJsonDocument(jConfig).toJson();

View File

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

View File

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

View File

@@ -1,5 +1,8 @@
#include "apiController.h"
#include <algorithm>
#include <random>
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@@ -11,6 +14,7 @@
#include "amnezia_application.h"
#include "configurators/wireguard_configurator.h"
#include "core/enums/apiEnums.h"
#include "utilities.h"
#include "version.h"
namespace
@@ -33,6 +37,7 @@ namespace
constexpr char userCountryCode[] = "user_country_code";
constexpr char serverCountryCode[] = "server_country_code";
constexpr char serviceType[] = "service_type";
constexpr char serviceInfo[] = "service_info";
constexpr char aesKey[] = "aes_key";
constexpr char aesIv[] = "aes_iv";
@@ -40,9 +45,12 @@ namespace
constexpr char apiPayload[] = "api_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)
{
@@ -63,6 +71,28 @@ namespace
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)
@@ -94,8 +124,8 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
} else if (protocol == configKey::awg) {
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
auto serverConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
auto containers = serverConfig.value(config_key::containers).toArray();
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
auto containers = newServerConfig.value(config_key::containers).toArray();
if (containers.isEmpty()) {
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);
container[containerName] = containerConfig;
containers.replace(0, container);
serverConfig[config_key::containers] = containers;
configStr = QString(QJsonDocument(serverConfig).toJson());
newServerConfig[config_key::containers] = containers;
configStr = QString(QJsonDocument(newServerConfig).toJson());
}
QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
if (apiConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
serverConfig[config_key::configVersion] = apiConfig.value(config_key::configVersion);
serverConfig[config_key::description] = apiConfig.value(config_key::description);
serverConfig[config_key::name] = apiConfig.value(config_key::name);
if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
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;
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;
}
QStringList ApiController::getProxyUrls()
{
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QEventLoop wait;
QList<QSslError> sslErrors;
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) {
request.setUrl(proxyStorageUrl);
reply = amnApp->manager()->get(request);
@@ -166,11 +215,23 @@ QStringList ApiController::getProxyUrls()
EVP_PKEY *privateKey = nullptr;
QByteArray responseBody;
try {
QByteArray key = PROD_PROXY_STORAGE_KEY;
QSimpleCrypto::QRsa rsa;
privateKey = rsa.getPrivateKeyFromByteArray(key, "");
responseBody = rsa.decrypt(encryptedResponseBody, privateKey, RSA_PKCS1_PADDING);
if (!m_isDevEnvironment) {
QCryptographicHash hash(QCryptographicHash::Sha512);
hash.addData(key);
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 (...) {
Utils::logException();
qCritical() << "error loading private key from environment variables or decrypting payload";
return {};
}
@@ -221,7 +282,7 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
if (serverConfig.value(config_key::configVersion).toInt()) {
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
@@ -277,7 +338,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
#endif
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
@@ -292,40 +353,53 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
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();
std::random_device randomDevice;
std::mt19937 generator(randomDevice());
std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
for (const QString &proxyUrl : m_proxyUrls) {
qDebug() << "Go to the next endpoint";
request.setUrl(QString("%1v1/services").arg(proxyUrl));
reply->deleteLater(); // delete the previous reply
reply = amnApp->manager()->get(request);
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
wait.exec();
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
responseBody = reply->readAll();
if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) {
break;
}
reply->deleteLater();
}
}
responseBody = reply->readAll();
auto errorCode = checkErrors(sslErrors, reply);
reply->deleteLater();
if (errorCode == ErrorCode::NoError) {
if (!responseBody.contains("services")) {
return ErrorCode::ApiServicesMissingError;
}
}
return errorCode;
}
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
IosController::Instance()->requestInetAccess();
QThread::msleep(10);
#endif
QNetworkAccessManager manager;
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setTransferTimeout(requestTimeoutMsecs);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
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::uuid] = installationUuid;
if (!authData.isEmpty()) {
apiPayload[configKey::authData] = authData;
}
QSimpleCrypto::QBlockCipher blockCipher;
QByteArray key = blockCipher.generatePrivateSalt(32);
@@ -357,10 +434,11 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
EVP_PKEY *publicKey = nullptr;
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;
publicKey = rsa.getPublicKeyFromByteArray(key);
publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
} catch (...) {
Utils::logException();
qCritical() << "error loading public key from environment variables";
return ErrorCode::ApiMissingAgwPublicKey;
}
@@ -370,14 +448,16 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
} catch (...) { // todo change error handling in QSimpleCrypto?
Utils::logException();
qCritical() << "error when encrypting the request body";
return ErrorCode::ApiConfigDecryptionError;
}
QJsonObject requestBody;
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.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;
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; });
wait.exec();
if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
if (m_proxyUrls.isEmpty()) {
m_proxyUrls = getProxyUrls();
}
auto encryptedResponseBody = reply->readAll();
if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
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) {
qDebug() << "Go to the next endpoint";
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);
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
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;
}
reply->deleteLater();
}
}
auto errorCode = checkErrors(sslErrors, reply);
reply->deleteLater();
if (errorCode) {
return errorCode;
}
auto encryptedResponseBody = reply->readAll();
reply->deleteLater();
try {
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
} catch (...) { // todo change error handling in QSimpleCrypto?
Utils::logException();
qCritical() << "error when decrypting the request body";
return ErrorCode::ApiConfigDecryptionError;
}
return errorCode;

View File

@@ -21,7 +21,7 @@ public slots:
ErrorCode getServicesList(QByteArray &responseBody);
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:
void errorOccurred(ErrorCode errorCode);
@@ -44,7 +44,7 @@ private:
QString m_gatewayEndpoint;
QStringList m_proxyUrls;
bool m_isDevEnvironment;
bool m_isDevEnvironment = false;
};
#endif // APICONTROLLER_H

View File

@@ -104,7 +104,8 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
if (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);
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
@@ -424,7 +425,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
if (errorCode)
return errorCode;
errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),dockerFilePath);
errorCode = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(), dockerFilePath);
if (errorCode)
return errorCode;
@@ -435,9 +436,10 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
return ErrorCode::NoError;
};
errorCode = runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
cbReadStdOut);
errorCode =
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container), genVarsForScript(credentials, container, config)),
cbReadStdOut);
if (errorCode)
return errorCode;
@@ -619,13 +621,15 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
// Socks5 proxy vars
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
auto username = socks5ProxyConfig.value(config_key:: userName).toString();
auto username = socks5ProxyConfig.value(config_key::userName).toString();
auto password = socks5ProxyConfig.value(config_key::password).toString();
QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : "";
vars.append({ { "$SOCKS5_USER", socks5user } });
vars.append({ { "$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong" } });
vars.append({ { "$SOCKS5_USER", socks5user } });
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()) {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
} else {
@@ -711,7 +715,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
udpProtoScript.append("' | grep -i udp");
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) {
return errorCode;
}

View File

@@ -100,7 +100,13 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QStr
protocolConfigString = configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
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);
}

View File

@@ -96,6 +96,7 @@ namespace amnezia
// import and install errors
ImportInvalidConfigError = 900,
ImportOpenConfigError = 901,
// Android errors
AndroidError = 1000,
@@ -107,6 +108,8 @@ namespace amnezia
ApiConfigTimeoutError = 1103,
ApiConfigSslError = 1104,
ApiMissingAgwPublicKey = 1105,
ApiConfigDecryptionError = 1106,
ApiServicesMissingError = 1107,
// QFile errors
OpenError = 1200,

View File

@@ -50,6 +50,7 @@ QString errorString(ErrorCode code) {
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::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
// Android errors
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
@@ -61,7 +62,9 @@ QString errorString(ErrorCode code) {
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::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
case (ErrorCode::ApiConfigDecryptionError): errorMessage = QObject::tr("Failed to decrypt response payload"); break;
case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
case(ErrorCode::ReadError): errorMessage = QObject::tr("QFile error: An error occurred when reading from the file"); break;

View File

@@ -29,6 +29,12 @@ QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
return Instance()->m_ipcClient;
}
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
{
if (!Instance()) return nullptr;
return Instance()->m_Tun2SocksClient;
}
bool IpcClient::init(IpcClient *instance)
{
m_instance = instance;
@@ -44,6 +50,12 @@ bool IpcClient::init(IpcClient *instance)
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](){
@@ -51,16 +63,16 @@ bool IpcClient::init(IpcClient *instance)
});
Instance()->m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
Instance()->m_localSocket->waitForConnected();
if (!Instance()->m_ipcClient) {
qDebug() << "IpcClient::init failed";
return false;
}
qDebug() << "IpcClient::init succeed";
return Instance()->m_ipcClient->isReplicaValid();
return (Instance()->m_ipcClient->isReplicaValid() && Instance()->m_Tun2SocksClient->isReplicaValid());
}
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()

View File

@@ -6,6 +6,7 @@
#include "ipc.h"
#include "rep_ipc_interface_replica.h"
#include "rep_ipc_process_tun2socks_replica.h"
#include "privileged_process.h"
@@ -18,6 +19,7 @@ public:
static IpcClient *Instance();
static bool init(IpcClient *instance);
static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
bool isSocketConnected() const;
@@ -28,8 +30,11 @@ private:
~IpcClient() override;
QRemoteObjectNode m_ClientNode;
QRemoteObjectNode m_Tun2SocksNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QPointer<QLocalSocket> m_localSocket;
QPointer<QLocalSocket> m_tun2socksSocket;
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;
struct ProcessDescriptor {
ProcessDescriptor () {

View File

@@ -109,7 +109,10 @@ QStringList NetworkUtilities::summarizeRoutes(const QStringList &ips, const QStr
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;
}

View File

@@ -78,7 +78,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
return false;
}
if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
if (!dnsutils()->restoreResolvers()) {
return false;
}
@@ -165,10 +165,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
}
bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
if (!supportDnsUtils()) {
return true;
}
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) {
QList<QHostAddress> resolvers;
@@ -423,13 +419,8 @@ bool Daemon::deactivate(bool emitSignals) {
}
// Cleanup DNS
if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
return false;
}
if (!wgutils()->interfaceExists()) {
logger.warning() << "Wireguard interface does not exist.";
return false;
if (!dnsutils()->restoreResolvers()) {
logger.warning() << "Failed to restore DNS resolvers.";
}
// Cleanup peers and routing
@@ -449,13 +440,9 @@ bool Daemon::deactivate(bool emitSignals) {
}
m_excludedAddrSet.clear();
// Delete the interface
if (!wgutils()->deleteInterface()) {
return false;
}
m_connections.clear();
return true;
// Delete the interface
return wgutils()->deleteInterface();
}
QString Daemon::logs() {

View File

@@ -69,7 +69,6 @@ class Daemon : public QObject {
virtual WireguardUtils* wgutils() const = 0;
virtual bool supportIPUtils() const { return false; }
virtual IPUtils* iputils() { return nullptr; }
virtual bool supportDnsUtils() const { return false; }
virtual DnsUtils* dnsutils() { return nullptr; }
static bool parseStringList(const QJsonObject& obj, const QString& name,

View File

@@ -92,6 +92,17 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
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") {
InterfaceConfig config;
if (!Daemon::parseConfig(obj, config)) {
@@ -115,8 +126,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
if (type == "status") {
QJsonObject obj = Daemon::instance()->getStatus();
obj.insert("type", "status");
m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
m_socket->write("\n");
write(obj);
return;
}
@@ -124,8 +134,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
QJsonObject obj;
obj.insert("type", "logs");
obj.insert("logs", Daemon::instance()->logs().replace("\n", "|"));
m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
m_socket->write("\n");
write(obj);
return;
}

View File

@@ -15,13 +15,24 @@
#include "platforms/ios/QtAppDelegate-C-Interface.h"
#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[])
{
Migrations migrationsManager;
migrationsManager.doMigrations();
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
#ifdef Q_OS_WIN
AllowSetForegroundWindow(ASFW_ANY);
#endif
@@ -32,16 +43,14 @@ int main(int argc, char *argv[])
qputenv("ANDROID_OPENSSL_SUFFIX", "_3");
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
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(); });
return app.exec();
}
app.startLocalServer();
#endif
// Allow to raise app window if secondary instance launched

View File

@@ -34,8 +34,8 @@ LocalSocketController::LocalSocketController() {
m_socket = new QLocalSocket(this);
connect(m_socket, &QLocalSocket::connected, this,
&LocalSocketController::daemonConnected);
connect(m_socket, &QLocalSocket::disconnected, this,
&LocalSocketController::disconnected);
connect(m_socket, &QLocalSocket::disconnected, this,
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
connect(m_socket, &QLocalSocket::errorOccurred, this,
&LocalSocketController::errorOccurred);
connect(m_socket, &QLocalSocket::readyRead, this,
@@ -149,7 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
QJsonArray jsAllowedIPAddesses;
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()) {
// Use AllowedIP list from WG config because of higher priority

View File

@@ -163,9 +163,7 @@ QString AndroidController::openFile(const QString &filter)
QString fileName;
connect(this, &AndroidController::fileOpened, this,
[&fileName, &wait](const QString &uri) {
qDebug() << "Android event: file opened; uri:" << uri;
fileName = QQmlFile::urlToLocalFileOrQrc(uri);
qDebug() << "Android opened filename:" << fileName;
fileName = uri;
wait.quit();
},
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
@@ -175,6 +173,25 @@ QString AndroidController::openFile(const QString &filter)
return fileName;
}
int AndroidController::getFd(const QString &fileName)
{
return callActivityMethod<jint>("getFd", "(Ljava/lang/String;)I",
QJniObject::fromString(fileName).object<jstring>());
}
void AndroidController::closeFd()
{
callActivityMethod("closeFd", "()V");
}
QString AndroidController::getFileName(const QString &uri)
{
auto fileName = callActivityMethod<jstring, jstring>("getFileName", "(Ljava/lang/String;)Ljava/lang/String;",
QJniObject::fromString(uri).object<jstring>());
QJniEnvironment env;
return AndroidUtils::convertJString(env.jniEnv(), fileName.object<jstring>());
}
bool AndroidController::isCameraPresent()
{
return callActivityMethod<jboolean>("isCameraPresent", "()Z");
@@ -287,6 +304,11 @@ bool AndroidController::requestAuthentication()
return result;
}
void AndroidController::sendTouch(float x, float y)
{
callActivityMethod("sendTouch", "(FF)V", x, y);
}
// Moving log processing to the Android side
jclass AndroidController::log;
jmethodID AndroidController::logDebug;

View File

@@ -34,6 +34,9 @@ public:
void resetLastServer(int serverIndex);
void saveFile(const QString &fileName, const QString &data);
QString openFile(const QString &filter);
int getFd(const QString &fileName);
void closeFd();
QString getFileName(const QString &uri);
bool isCameraPresent();
bool isOnTv();
void startQrReaderActivity();
@@ -48,6 +51,7 @@ public:
bool isNotificationPermissionGranted();
void requestNotificationPermission();
bool requestAuthentication();
void sendTouch(float x, float y);
static bool initLogging();
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);

View File

@@ -351,8 +351,6 @@ void IosController::vpnStatusDidChange(void *pNotification)
}
}
}
} else {
qDebug() << "Disconnect error is absent";
}
}];
} else {
@@ -501,6 +499,20 @@ bool IosController::setupWireGuard()
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);
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
@@ -835,7 +847,7 @@ QString IosController::openFile() {
void IosController::requestInetAccess() {
NSURL *url = [NSURL URLWithString:@"http://captive.apple.com/generate_204"];
if (url) {
if (!url) {
qDebug() << "IosController::requestInetAccess URL error";
return;
}
@@ -847,7 +859,6 @@ void IosController::requestInetAccess() {
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
QString responseBody = QString::fromUtf8((const char*)data.bytes, data.length);
qDebug() << "IosController::requestInetAccess server response:" << httpResponse.statusCode << "\n\n" <<responseBody;
}
}];
[task resume];

View File

@@ -22,7 +22,6 @@ class LinuxDaemon final : public Daemon {
protected:
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override { return m_iputils; }

View File

@@ -21,7 +21,6 @@ class MacOSDaemon final : public Daemon {
protected:
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override { return m_iputils; }

View File

@@ -26,7 +26,6 @@ class WindowsDaemon final : public Daemon {
protected:
bool run(Op op, const InterfaceConfig& config) override;
WireguardUtils* wgutils() const override { return m_wgutils; }
bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
private:

View File

@@ -502,7 +502,7 @@ QString WindowsSplitTunnel::convertPath(const QString& path) {
// device should contain : for e.g C:
return "";
}
QByteArray buffer(2048, 0xFF);
QByteArray buffer(2048, 0xFFu);
auto ok = QueryDosDeviceW(qUtf16Printable(driveLetter),
(wchar_t*)buffer.data(), buffer.size() / 2);

View File

@@ -248,7 +248,7 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
}
if (result != NO_ERROR) {
logger.error() << "Failed to create route to"
<< logger.sensitive(prefix.toString())
<< prefix.toString()
<< "result:" << result;
}
return result == NO_ERROR;
@@ -265,7 +265,7 @@ bool WireguardUtilsWindows::deleteRoutePrefix(const IPAddress& prefix) {
}
if (result != NO_ERROR) {
logger.error() << "Failed to delete route to"
<< logger.sensitive(prefix.toString())
<< prefix.toString()
<< "result:" << result;
}
return result == NO_ERROR;

View File

@@ -21,7 +21,7 @@
#include "platforms/windows/windowsutils.h"
constexpr const char* VPN_NAME = "AmneziaVPN";
constexpr const char* WIREGUARD_DIR = "WireGuard";
constexpr const char* WIREGUARD_DIR = "AmneziaWG";
constexpr const char* DATA_DIR = "Data";
namespace {

View File

@@ -6,6 +6,7 @@
#include <QTcpSocket>
#include <QNetworkInterface>
#include "core/networkUtilities.h"
#include "logger.h"
#include "openvpnprotocol.h"
#include "utilities.h"
@@ -127,7 +128,6 @@ void OpenVpnProtocol::sendManagementCommand(const QString &command)
uint OpenVpnProtocol::selectMgmtPort()
{
for (int i = 0; i < 100; ++i) {
quint32 port = QRandomGenerator::global()->generate();
port = (double)(65000 - 15001) * port / UINT32_MAX + 15001;
@@ -137,7 +137,6 @@ uint OpenVpnProtocol::selectMgmtPort()
if (ok)
return port;
}
return m_managementPort;
}
@@ -343,7 +342,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
}
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
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);
}
}
@@ -352,6 +352,8 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
// killSwitch toggle
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);
}
#endif

View File

@@ -65,6 +65,7 @@ namespace amnezia
constexpr char last_config[] = "last_config";
constexpr char isThirdPartyConfig[] = "isThirdPartyConfig";
constexpr char isObfuscationEnabled[] = "isObfuscationEnabled";
constexpr char junkPacketCount[] = "Jc";
constexpr char junkPacketMinSize[] = "Jmin";

View File

@@ -4,9 +4,8 @@
#include <QTcpSocket>
#include <QThread>
#include "logger.h"
#include "utilities.h"
#include "wireguardprotocol.h"
#include "core/networkUtilities.h"
#include "mozilla/localsocketcontroller.h"
@@ -37,6 +36,12 @@ void WireguardProtocol::stop()
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);
return ErrorCode::NoError;
}

192
client/protocols/xrayprotocol.cpp Normal file → Executable file
View File

@@ -17,6 +17,7 @@ XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent):
m_routeGateway = NetworkUtilities::getGatewayAndIface();
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
m_t2sProcess = IpcClient::InterfaceTun2Socks();
}
XrayProtocol::~XrayProtocol()
@@ -43,7 +44,9 @@ ErrorCode XrayProtocol::start()
m_xrayCfgFile.setAutoRemove(false);
#endif
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();
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) {
qDebug().noquote() << "XrayProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
qDebug().noquote() << "XrayProtocol finished, exitCode, exitStatus" << exitCode << exitStatus;
setConnectionState(Vpn::ConnectionState::Disconnected);
if (exitStatus != QProcess::NormalExit) {
emit protocolError(amnezia::ErrorCode::XrayExecutableCrashed);
@@ -89,116 +92,80 @@ ErrorCode XrayProtocol::start()
ErrorCode XrayProtocol::startTun2Sock()
{
if (!QFileInfo::exists(Utils::tun2socksPath())) {
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
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
#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(), &PrivilegedProcess::errorOccurred,
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
connect(m_t2sProcess.data(), &PrivilegedProcess::stateChanged,
[&](QProcess::ProcessState newState) {
qDebug() << "PrivilegedProcess stateChanged" << newState;
if (newState == QProcess::Running)
{
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
#ifdef Q_OS_MACOS
QThread::msleep(5000);
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
#endif
#ifdef Q_OS_WINDOWS
QThread::msleep(15000);
#endif
#ifdef Q_OS_LINUX
QThread::msleep(1000);
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
#endif
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
// killSwitch toggle
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
}
#endif
if (m_routeMode == 0) {
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
}
IpcClient::Interface()->StopRoutingIpv6();
#ifdef Q_OS_WIN
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
for (int i = 0; i < netInterfaces.size(); i++) {
for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++)
{
// killSwitch toggle
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
}
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer", m_remoteAddress);
IpcClient::Interface()->enablePeerTraffic(m_configData);
}
}
}
#endif
setConnectionState(Vpn::ConnectionState::Connected);
}
});
#if !defined(Q_OS_MACOS)
connect(m_t2sProcess.data(), &PrivilegedProcess::finished, this,
[&]() {
setConnectionState(Vpn::ConnectionState::Disconnected);
IpcClient::Interface()->deleteTun("tun2");
IpcClient::Interface()->StartRoutingIpv6();
IpcClient::Interface()->clearSavedRoutes();
});
#endif
m_t2sProcess->start();
#ifdef Q_OS_WIN
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
#endif
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::stateChanged, this,
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this,
[&](int vpnState) {
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
if (vpnState == Vpn::ConnectionState::Connected)
{
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
#ifdef Q_OS_WIN
QThread::msleep(8000);
#endif
#ifdef Q_OS_MACOS
QThread::msleep(5000);
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
#endif
#ifdef Q_OS_LINUX
QThread::msleep(1000);
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
#endif
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
// killSwitch toggle
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
m_configData.insert("vpnServer", m_remoteAddress);
IpcClient::Interface()->enableKillSwitch(m_configData, 0);
}
#endif
if (m_routeMode == 0) {
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
}
IpcClient::Interface()->StopRoutingIpv6();
#ifdef Q_OS_WIN
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
for (int i = 0; i < netInterfaces.size(); i++) {
for (int j = 0; j < netInterfaces.at(i).addressEntries().size(); j++)
{
// killSwitch toggle
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
}
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer", m_remoteAddress);
IpcClient::Interface()->enablePeerTraffic(m_configData);
}
}
}
#endif
setConnectionState(Vpn::ConnectionState::Connected);
}
#if !defined(Q_OS_MACOS)
if (vpnState == Vpn::ConnectionState::Disconnected) {
setConnectionState(Vpn::ConnectionState::Disconnected);
IpcClient::Interface()->deleteTun("tun2");
IpcClient::Interface()->StartRoutingIpv6();
IpcClient::Interface()->clearSavedRoutes();
}
#endif
});
return ErrorCode::NoError;
}
@@ -212,7 +179,7 @@ void XrayProtocol::stop()
qDebug() << "XrayProtocol::stop()";
m_xrayProcess.terminate();
if (m_t2sProcess) {
m_t2sProcess->close();
m_t2sProcess->stop();
}
#ifdef Q_OS_WIN
@@ -238,7 +205,8 @@ void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
}
m_xrayConfig = xrayConfiguration;
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_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();

View File

@@ -26,6 +26,7 @@ private:
static QString tun2SocksExecPath();
private:
int m_localPort;
QString m_remoteHost;
QString m_remoteAddress;
int m_routeMode;
QJsonObject m_configData;
@@ -33,9 +34,10 @@ private:
QString m_secondaryDNS;
#ifndef Q_OS_IOS
QProcess m_xrayProcess;
QSharedPointer<PrivilegedProcess> m_t2sProcess;
QSharedPointer<IpcProcessTun2SocksReplica> m_t2sProcess;
#endif
QTemporaryFile m_xrayCfgFile;
};
#endif // XRAYPROTOCOL_H

View File

@@ -1,223 +1,227 @@
<RCC>
<qresource prefix="/">
<file>fonts/pt-root-ui_vf.ttf</file>
<file>images/amneziaBigLogo.png</file>
<file>images/AmneziaVPN.png</file>
<file>images/controls/alert-circle.svg</file>
<file>images/controls/amnezia.svg</file>
<file>images/controls/app.svg</file>
<file>images/controls/archive-restore.svg</file>
<file>images/controls/arrow-left.svg</file>
<file>images/controls/arrow-right.svg</file>
<file>images/controls/bug.svg</file>
<file>images/controls/check.svg</file>
<file>images/controls/chevron-down.svg</file>
<file>images/controls/chevron-right.svg</file>
<file>images/controls/chevron-up.svg</file>
<file>images/controls/close.svg</file>
<file>images/controls/copy.svg</file>
<file>images/controls/delete.svg</file>
<file>images/controls/download.svg</file>
<file>images/controls/edit-3.svg</file>
<file>images/controls/eye-off.svg</file>
<file>images/controls/eye.svg</file>
<file>images/controls/file-check-2.svg</file>
<file>images/controls/file-cog-2.svg</file>
<file>images/controls/folder-open.svg</file>
<file>images/controls/folder-search-2.svg</file>
<file>images/controls/gauge.svg</file>
<file>images/controls/github.svg</file>
<file>images/controls/help-circle.svg</file>
<file>images/controls/history.svg</file>
<file>images/controls/home.svg</file>
<file>images/controls/info.svg</file>
<file>images/controls/mail.svg</file>
<file>images/controls/map-pin.svg</file>
<file>images/controls/more-vertical.svg</file>
<file>images/controls/plus.svg</file>
<file>images/controls/qr-code.svg</file>
<file>images/controls/radio-button-inner-circle-pressed.png</file>
<file>images/controls/radio-button-inner-circle.png</file>
<file>images/controls/radio-button-pressed.svg</file>
<file>images/controls/radio-button.svg</file>
<file>images/controls/radio.svg</file>
<file>images/controls/refresh-cw.svg</file>
<file>images/controls/save.svg</file>
<file>images/controls/scan-line.svg</file>
<file>images/controls/search.svg</file>
<file>images/controls/server.svg</file>
<file>images/controls/settings-2.svg</file>
<file>images/controls/settings.svg</file>
<file>images/controls/share-2.svg</file>
<file>images/controls/split-tunneling.svg</file>
<file>images/controls/tag.svg</file>
<file>images/controls/telegram.svg</file>
<file>images/controls/text-cursor.svg</file>
<file>images/controls/trash.svg</file>
<file>images/controls/x-circle.svg</file>
<file>images/tray/active.png</file>
<file>images/tray/default.png</file>
<file>images/tray/error.png</file>
<file>images/AmneziaVPN.png</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>server_scripts/openvpn_cloak/Dockerfile</file>
<file>server_scripts/awg/configure_container.sh</file>
<file>server_scripts/awg/Dockerfile</file>
<file>server_scripts/awg/run_container.sh</file>
<file>server_scripts/awg/start.sh</file>
<file>server_scripts/awg/template.conf</file>
<file>server_scripts/build_container.sh</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/check_server_is_busy.sh</file>
<file>server_scripts/check_user_in_sudo.sh</file>
<file>server_scripts/dns/configure_container.sh</file>
<file>server_scripts/dns/Dockerfile</file>
<file>server_scripts/dns/run_container.sh</file>
<file>server_scripts/install_docker.sh</file>
<file>server_scripts/ipsec/configure_container.sh</file>
<file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/mobileconfig.plist</file>
<file>server_scripts/ipsec/run_container.sh</file>
<file>server_scripts/ipsec/start.sh</file>
<file>server_scripts/ipsec/strongswan.profile</file>
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
<file>server_scripts/openvpn_cloak/Dockerfile</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
<file>server_scripts/openvpn_cloak/start.sh</file>
<file>server_scripts/openvpn_cloak/template.ovpn</file>
<file>server_scripts/install_docker.sh</file>
<file>server_scripts/build_container.sh</file>
<file>server_scripts/prepare_host.sh</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
<file>server_scripts/openvpn/configure_container.sh</file>
<file>server_scripts/openvpn/run_container.sh</file>
<file>server_scripts/openvpn/template.ovpn</file>
<file>server_scripts/openvpn/Dockerfile</file>
<file>server_scripts/openvpn/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/configure_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/Dockerfile</file>
<file>server_scripts/openvpn_shadowsocks/run_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/template.ovpn</file>
<file>server_scripts/openvpn/configure_container.sh</file>
<file>server_scripts/openvpn/Dockerfile</file>
<file>server_scripts/openvpn/run_container.sh</file>
<file>server_scripts/openvpn/start.sh</file>
<file>server_scripts/openvpn/template.ovpn</file>
<file>server_scripts/prepare_host.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>server_scripts/sftp/configure_container.sh</file>
<file>server_scripts/sftp/Dockerfile</file>
<file>server_scripts/sftp/run_container.sh</file>
<file>server_scripts/socks5_proxy/configure_container.sh</file>
<file>server_scripts/socks5_proxy/Dockerfile</file>
<file>server_scripts/socks5_proxy/run_container.sh</file>
<file>server_scripts/socks5_proxy/start.sh</file>
<file>server_scripts/website_tor/configure_container.sh</file>
<file>server_scripts/website_tor/Dockerfile</file>
<file>server_scripts/website_tor/run_container.sh</file>
<file>server_scripts/wireguard/configure_container.sh</file>
<file>server_scripts/wireguard/Dockerfile</file>
<file>server_scripts/wireguard/run_container.sh</file>
<file>server_scripts/wireguard/start.sh</file>
<file>server_scripts/wireguard/template.conf</file>
<file>server_scripts/website_tor/configure_container.sh</file>
<file>server_scripts/website_tor/run_container.sh</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
<file>ui/qml/Config/qmldir</file>
<file>server_scripts/check_server_is_busy.sh</file>
<file>server_scripts/dns/configure_container.sh</file>
<file>server_scripts/dns/Dockerfile</file>
<file>server_scripts/dns/run_container.sh</file>
<file>server_scripts/sftp/configure_container.sh</file>
<file>server_scripts/sftp/Dockerfile</file>
<file>server_scripts/sftp/run_container.sh</file>
<file>server_scripts/ipsec/configure_container.sh</file>
<file>server_scripts/ipsec/Dockerfile</file>
<file>server_scripts/ipsec/run_container.sh</file>
<file>server_scripts/ipsec/start.sh</file>
<file>server_scripts/ipsec/mobileconfig.plist</file>
<file>server_scripts/ipsec/strongswan.profile</file>
<file>server_scripts/website_tor/Dockerfile</file>
<file>server_scripts/check_user_in_sudo.sh</file>
<file>ui/qml/Controls2/BasicButtonType.qml</file>
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
<file>images/controls/arrow-right.svg</file>
<file>images/controls/chevron-right.svg</file>
<file>ui/qml/Controls2/ImageButtonType.qml</file>
<file>ui/qml/Controls2/CardType.qml</file>
<file>ui/qml/Controls2/CheckBoxType.qml</file>
<file>images/controls/check.svg</file>
<file>ui/qml/Controls2/DropDownType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
<file>ui/qml/main2.qml</file>
<file>images/amneziaBigLogo.png</file>
<file>ui/qml/Controls2/FlickableType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
<file>ui/qml/Controls2/HeaderType.qml</file>
<file>images/controls/arrow-left.svg</file>
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
<file>images/controls/chevron-down.svg</file>
<file>images/controls/chevron-up.svg</file>
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
<file>ui/qml/Controls2/SwitcherType.qml</file>
<file>ui/qml/Controls2/TabButtonType.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>images/controls/folder-open.svg</file>
<file>images/controls/qr-code.svg</file>
<file>images/controls/text-cursor.svg</file>
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file>
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
<file>images/controls/home.svg</file>
<file>images/controls/settings-2.svg</file>
<file>images/controls/share-2.svg</file>
<file>ui/qml/Pages2/PageHome.qml</file>
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
<file>ui/qml/Pages2/PageShare.qml</file>
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
<file>ui/qml/Controls2/Header2Type.qml</file>
<file>images/controls/plus.svg</file>
<file>ui/qml/Components/ConnectButton.qml</file>
<file>images/controls/download.svg</file>
<file>ui/qml/Controls2/ProgressBarType.qml</file>
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
<file>ui/qml/Components/HomeContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
<file>images/controls/settings.svg</file>
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
<file>ui/qml/Controls2/PageType.qml</file>
<file>ui/qml/Controls2/PopupType.qml</file>
<file>images/controls/edit-3.svg</file>
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>images/controls/amnezia.svg</file>
<file>images/controls/app.svg</file>
<file>images/controls/radio.svg</file>
<file>images/controls/save.svg</file>
<file>images/controls/server.svg</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>images/controls/file-cog-2.svg</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
<file>images/controls/radio-button.svg</file>
<file>images/controls/radio-button-inner-circle.png</file>
<file>images/controls/radio-button-pressed.svg</file>
<file>images/controls/radio-button-inner-circle-pressed.png</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
<file>images/controls/delete.svg</file>
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
<file>images/controls/github.svg</file>
<file>images/controls/mail.svg</file>
<file>images/controls/telegram.svg</file>
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
<file>images/controls/copy.svg</file>
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
<file>images/controls/eye.svg</file>
<file>images/controls/eye-off.svg</file>
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
<file>ui/qml/Controls2/ContextMenuType.qml</file>
<file>ui/qml/Controls2/TextAreaType.qml</file>
<file>images/controls/trash.svg</file>
<file>images/controls/more-vertical.svg</file>
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
<file>images/controls/x-circle.svg</file>
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
<file>server_scripts/awg/template.conf</file>
<file>server_scripts/awg/start.sh</file>
<file>server_scripts/awg/configure_container.sh</file>
<file>server_scripts/awg/run_container.sh</file>
<file>server_scripts/awg/Dockerfile</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>images/controls/close.svg</file>
<file>images/controls/search.svg</file>
<file>server_scripts/xray/configure_container.sh</file>
<file>server_scripts/xray/Dockerfile</file>
<file>server_scripts/xray/run_container.sh</file>
<file>server_scripts/xray/start.sh</file>
<file>server_scripts/xray/template.json</file>
<file>ui/qml/Pages2/PageProtocolWireGuardSettings.qml</file>
<file>ui/qml/Components/ConnectButton.qml</file>
<file>ui/qml/Components/ConnectionTypeSelectionDrawer.qml</file>
<file>ui/qml/Components/HomeContainersListView.qml</file>
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>images/controls/split-tunneling.svg</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
<file>images/controls/alert-circle.svg</file>
<file>images/controls/file-check-2.svg</file>
<file>ui/qml/Controls2/WarningType.qml</file>
<file>fonts/pt-root-ui_vf.ttf</file>
<file>ui/qml/Modules/Style/qmldir</file>
<file>ui/qml/Modules/Style/AmneziaStyle.qml</file>
<file>ui/qml/Pages2/PageServiceSocksProxySettings.qml</file>
<file>server_scripts/socks5_proxy/run_container.sh</file>
<file>server_scripts/socks5_proxy/Dockerfile</file>
<file>server_scripts/socks5_proxy/configure_container.sh</file>
<file>server_scripts/socks5_proxy/start.sh</file>
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Components/ServersListView.qml</file>
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
<file>ui/qml/Config/qmldir</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
<file>ui/qml/Controls2/BasicButtonType.qml</file>
<file>ui/qml/Controls2/BusyIndicatorType.qml</file>
<file>ui/qml/Controls2/CardType.qml</file>
<file>ui/qml/Controls2/CardWithIconsType.qml</file>
<file>images/controls/tag.svg</file>
<file>images/controls/history.svg</file>
<file>images/controls/gauge.svg</file>
<file>images/controls/map-pin.svg</file>
<file>ui/qml/Controls2/CheckBoxType.qml</file>
<file>ui/qml/Controls2/ContextMenuType.qml</file>
<file>ui/qml/Controls2/DividerType.qml</file>
<file>ui/qml/Controls2/DrawerType2.qml</file>
<file>ui/qml/Controls2/DropDownType.qml</file>
<file>ui/qml/Controls2/FlickableType.qml</file>
<file>ui/qml/Controls2/Header2Type.qml</file>
<file>ui/qml/Controls2/HeaderType.qml</file>
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/ImageButtonType.qml</file>
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
<file>ui/qml/Controls2/LabelWithImageType.qml</file>
<file>images/controls/info.svg</file>
<file>ui/qml/Controls2/ListViewWithLabelsType.qml</file>
<file>ui/qml/Controls2/ListViewWithRadioButtonType.qml</file>
<file>ui/qml/Controls2/PageType.qml</file>
<file>ui/qml/Controls2/PopupType.qml</file>
<file>ui/qml/Controls2/ProgressBarType.qml</file>
<file>ui/qml/Controls2/ScrollBarType.qml</file>
<file>ui/qml/Controls2/StackViewType.qml</file>
<file>ui/qml/Controls2/SwitcherType.qml</file>
<file>ui/qml/Controls2/TabButtonType.qml</file>
<file>ui/qml/Controls2/TabImageButtonType.qml</file>
<file>ui/qml/Controls2/TextAreaType.qml</file>
<file>ui/qml/Controls2/TextAreaWithFooterType.qml</file>
<file>images/controls/scan-line.svg</file>
<file>images/controls/folder-search-2.svg</file>
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
<file>images/controls/bug.svg</file>
<file>ui/qml/Controls2/TextFieldWithHeaderType.qml</file>
<file>ui/qml/Controls2/TextTypes/ButtonTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/CaptionTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header1TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/Header2TextType.qml</file>
<file>ui/qml/Controls2/TextTypes/LabelTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/ListItemTitleType.qml</file>
<file>ui/qml/Controls2/TextTypes/ParagraphTextType.qml</file>
<file>ui/qml/Controls2/TextTypes/SmallTextType.qml</file>
<file>ui/qml/Controls2/TopCloseButtonType.qml</file>
<file>ui/qml/Controls2/VerticalRadioButton.qml</file>
<file>ui/qml/Controls2/WarningType.qml</file>
<file>ui/qml/Filters/ContainersModelFilters.qml</file>
<file>ui/qml/main2.qml</file>
<file>ui/qml/Modules/Style/AmneziaStyle.qml</file>
<file>ui/qml/Modules/Style/qmldir</file>
<file>ui/qml/Pages2/PageDeinstalling.qml</file>
<file>ui/qml/Pages2/PageDevMenu.qml</file>
<file>images/controls/refresh-cw.svg</file>
<file>ui/qml/Pages2/PageHome.qml</file>
<file>ui/qml/Pages2/PageProtocolAwgSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolCloakSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolOpenVpnSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolRaw.qml</file>
<file>ui/qml/Pages2/PageProtocolShadowSocksSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolWireGuardSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolXraySettings.qml</file>
<file>ui/qml/Pages2/PageServiceDnsSettings.qml</file>
<file>ui/qml/Pages2/PageServiceSftpSettings.qml</file>
<file>ui/qml/Pages2/PageServiceSocksProxySettings.qml</file>
<file>ui/qml/Pages2/PageServiceTorWebsiteSettings.qml</file>
<file>ui/qml/Pages2/PageSettings.qml</file>
<file>ui/qml/Pages2/PageSettingsAbout.qml</file>
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
<file>images/controls/archive-restore.svg</file>
<file>images/controls/help-circle.svg</file>
<file>ui/qml/Pages2/PageSettingsApiServerInfo.qml</file>
<file>ui/qml/Pages2/PageSettingsApplication.qml</file>
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocol.qml</file>
<file>ui/qml/Pages2/PageSettingsServerProtocols.qml</file>
<file>ui/qml/Pages2/PageSettingsServerServices.qml</file>
<file>ui/qml/Pages2/PageSettingsServersList.qml</file>
<file>ui/qml/Pages2/PageSettingsSplitTunneling.qml</file>
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
<file>ui/qml/Pages2/PageSetupWizardEasy.qml</file>
<file>ui/qml/Pages2/PageSetupWizardInstalling.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocols.qml</file>
<file>ui/qml/Pages2/PageSetupWizardProtocolSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardQrReader.qml</file>
<file>ui/qml/Pages2/PageSetupWizardStart.qml</file>
<file>ui/qml/Pages2/PageSetupWizardTextKey.qml</file>
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
<file>ui/qml/Pages2/PageShare.qml</file>
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
<file>ui/qml/Pages2/PageStart.qml</file>
</qresource>
<qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file>

View 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'
# 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"

View File

@@ -3,7 +3,7 @@
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
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 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

View File

@@ -237,7 +237,7 @@ private:
mutable SecureQSettings m_settings;
QString m_gatewayEndpoint;
bool m_isDevGatewayEnv;
bool m_isDevGatewayEnv = false;
};
#endif // SETTINGS_H

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation>شبكة VPN كلاسيكية للعمل المريح وتنزيل الملفات الكبيرة ومشاهدة مقاطع الفيديو. تعمل مع أي موقع. تصل السرعة إلى %1 ميجابت/ثانية</translation>
</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>
<translation>شبكة VPN للولوج للمواقع المحظورة في بلاد ذو مستوي عالي من الرقابة علي الانترنت. </translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation>Amenzia Premium - شبكة VPN للعمل المريح, تحميل ملفات كبيرة الحجم, ومشاهدة مقاطع الفيديو ب جودة عالية. تعمل لجميع المواقع, حتي في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
</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>
<translation>Amnezia Free هو VPN مجاني لتخطي الحظر في البلاد ذو مستوي عالي من الرقابة علي الانترنت</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation>%1 ميجابت/ثانية</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation>%1 ايام</translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation>سيقوم VPN فقط بفتح المواقع المشهورة المحظورة في بلدك, مثل Instagram, Facebook, Twitter و مواقع اخري. المواقع الاخري ستٌفتح من عنوان ال IP الحقيقي الخاص بك, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;معلومات اخري علي الموقع.&lt;/a&gt;</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation>مجاني</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation>%1 دولار/الشهر</translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>غير قادر علي قطع الاتصال اثناء إعداد التكوين</translation>
</message>
@@ -186,9 +191,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>خطأ في الوصول!</translation>
<translation type="vanished">خطأ في الوصول!</translation>
</message>
</context>
<context>
@@ -254,18 +258,18 @@ Can&apos;t be disabled for current server</source>
<translation>غير قادر علي فتح الملف</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>ملف تكوين غير صحيح</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>تم فحص%1 من %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة:</translation>
</message>
@@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation>نقطة نهاية البوابة</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
<translation>لا يمكن تغير الخادم بينما هناك اتصال مفعل</translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>اعدادات AmneziaWG</translation>
</message>
@@ -490,92 +552,87 @@ Already installed containers were found on the server. All installed containers
<translation>منفذ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation></translation>
</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>
<translation>جميع المستخدمين الذين شاركت معهم اتصال لن يكونو قادرين علي الاتصال مرة اخري.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation>احفظ</translation>
</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>
<translation>Jc - عدد الحزم غير المرغوب فيها</translation>
</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>
<translation>Jmin - الحجم الادني للحزم الغير مرغوب فيها</translation>
</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>
<translation>Jmax - الحجم الاقصي للحزم الغير مرغوب فيها</translation>
</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>
<translation>S1 - حجم حزمة البيانات العشوائية الأولية</translation>
</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>
<translation>S2 - حجم حزمة الاستجابة غير المرغوب فيها</translation>
</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>
<translation>H1 - حزمة رأس سحرية مبدئية</translation>
</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>
<translation>H2 - رأس حزمة الاستجابة السحرية</translation>
</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>
<translation>H4 - رأس حزمة النقل السحرية</translation>
</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>
<translation>H3 - رأس حزمة السحر غير المحمل</translation>
</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>
<translation>يجب أن تكون قيم الحقول H1-H4 فريدة</translation>
</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>
<translation>يجب ألا تساوي قيمة الحقل S1 + حجم بدء الرسالة (148) S2 + حجم استجابة الرسالة (92)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>احفظ الإعدادات؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>إلغاء</translation>
</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>
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
</message>
@@ -862,30 +919,98 @@ Already installed containers were found on the server. All installed containers
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation>إعدادات WG</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>منفذ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation></translation>
<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="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>
<translation>لا يمكن تغيير الإعدادات أثناء وجود اتصال نشط</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation>احفظ</translation>
</message>
@@ -1205,9 +1330,13 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<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>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>موقع</translation>
</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>
<translation>%1 :إصدار البرنامج</translation>
</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>
<translation>تحقق من وجود تحديثات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation>سياسات الخصوصية</translation>
</message>
@@ -1689,72 +1823,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل.</translation>
<translation type="vanished">تم تمكين التسجيل. لاحظ أنه سيتم تعطيل السجلات تلقائيًا بعد 14 يومًا، وسيتم حذف جميع ملفات السجل.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>التسجيل</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>سيتم حفظ سجلات البرنامج بشكل تلقائي عند تفعيل هذه الميزة, بشكل افتراضي, هذه الميزة مٌعطلة. قم بتفعيل هذه الميزة في حالة هناك خلل في التطبيق.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>احفظ السجلات</translation>
<translation type="vanished">احفظ السجلات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>افتح مجلد يحتوي علي سجلات</translation>
<translation type="vanished">افتح مجلد يحتوي علي سجلات</translation>
</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>
<translation>احفظ</translation>
</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>
<translation>ملفات الولوج (*.log)</translation>
</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>
<translation>تم حفظ ملف السجل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>احفظ السجلات في ملف</translation>
<translation type="vanished">احفظ السجلات في ملف</translation>
</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>
<translation>مسح السجلات؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>إلغاء</translation>
</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>
<translation>تم مسح السجلات</translation>
</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>
<translation>احذف السجلات</translation>
</message>
@@ -1914,12 +2084,11 @@ Already installed containers were found on the server. All installed containers
<translation> الإعدادات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>مسح ملف تعريف %1</translation>
<translation type="vanished">مسح ملف تعريف %1</translation>
</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>
<translation>مسح ملف تعريف %1؟</translation>
</message>
@@ -1929,39 +2098,64 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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>
<translation>غير قادر على مسح ملف تعريف %1 أثناء وجود اتصال نشط</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>احذف </translation>
</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>
<translation>احذف %1 من الخادم؟</translation>
</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>
<translation>جميع المستخدمين الذين شاركت معاهم اتصال لن يستطيعو الاتصال بعد الان.</translation>
</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>
<translation>لا يمكن إزالة الحاوية النشطة</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation>واصل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<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 &quot;connect&quot; 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>
<translation>إلغاء</translation>
</message>
@@ -2129,82 +2323,92 @@ Already installed containers were found on the server. All installed containers
<translation>الاتصال</translation>
</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>
<translation>أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>أدخل مفتاح</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>أدخل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>واصل</translation>
</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>
<translation>اختيارات اتصال اخري</translation>
</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>
<translation>VPN بواسطة Amnezia</translation>
</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>
<translation>اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia</translation>
</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>
<translation>VPN ذاتية الاستضافة</translation>
</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>
<translation>قم بتكوين Amnezia VPN على الخادم الخاص بك</translation>
</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>
<translation>استرجاع من ملف يحتوي علي نسخة احتياطية</translation>
</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>
<translation>افتح ملف نسخ احتياطي</translation>
</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>
<translation>ملفات نٌسخ احتياطية (*.backup)</translation>
</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>
<translation>ملف إعدادات اتصال</translation>
</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>
<translation>افتح ملف تكوين</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>رمز QR</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>ليس لدي اي شئ</translation>
</message>
@@ -2717,12 +2921,17 @@ Already installed containers were found on the server. All installed containers
<translation>مشاركة</translation>
</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>
<translation>اتصال إلي </translation>
</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>
<translation>معلف مع إعدادات الاتصال إلي </translation>
</message>
@@ -2739,6 +2948,11 @@ Already installed containers were found on the server. All installed containers
<source>Settings restored from backup file</source>
<translation>تم تحميل الإعدادات من ملف نسخة احتياطية</translation>
</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>
<name>PopupType</name>
@@ -2777,12 +2991,12 @@ Already installed containers were found on the server. All installed containers
<translation>لم يتم العثور علي كلمة المرور</translation>
</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>
<translation>فشل فتح مخزن المفاتيح</translation>
</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>
<translation>فشل حذف المفتاح الخاص من مخزن المفاتيح</translation>
</message>
@@ -2958,27 +3172,27 @@ Already installed containers were found on the server. All installed containers
<translation>فشل في فتح مخزن المفاتيح</translation>
</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>
<translation>فشل ف إنشاء مولد المفاتيح الخاصة</translation>
</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>
<translation>فشل في إنشاء مفتاح خاص جديد</translation>
</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>
<translation>فشل في استرداد مفتاح خاص من مخزن المفاتيح</translation>
</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>
<translation>فشل في إنشاء شفرة التشفير</translation>
</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>
<translation>فشل في تشفير الداتا</translation>
</message>
@@ -3675,12 +3889,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>ملف النسخه الاحتياطيه تالف</translation>
</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>
<translation>تم استرجاع جميع الإعدادات للإعدادات الافتراضية</translation>
</message>
@@ -3812,7 +4026,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation>برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیوها، از VPN کلاسیک استفاده کنید. این VPN برای هر سایتی کار میکند و سرعت آن تا %1 مگابیت بر ثانیه است.</translation>
</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>
<translation>وی پی ان برای دسترسی به سایتهای مسدود شده در مناطق با سانسور شدید اینترنت.</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation>امنزیا پریمیوم - یک وی پی ان کلاسیک برای کار راحت، دانلود فایلهای بزرگ و تماشای ویدیو با کیفیت بالا. قابل استفاده برای تمامی سایتها، حتی در کشورهایی با بالاترین سطح سانسور اینترنت.</translation>
</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>
<translation>امنزیا رایگان یک وی پی ان رایگان برای دور زدن مسدودیتها در کشورهایی با سطح بالای سانسور اینترنت است.</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation>%1 MBit/s</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation>%1 روز</translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation>وی پی ان فقط سایتهای محبوبی را که در منطقه شما مسدود شدهاند، مانند اینستاگرام، فیسبوک، توییتر و غیره باز میکند. سایر سایتها با آدرس آیپی واقعی شما باز خواهند شد. &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation>رایگان</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation>%1 $/ماه</translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>در هنگام آمادهسازی پیکربندی، نمیتوان از اتصال خارج شد.</translation>
</message>
@@ -188,9 +193,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>خطای دسترسی!</translation>
<translation type="vanished">خطای دسترسی!</translation>
</message>
</context>
<context>
@@ -259,18 +263,18 @@ Can&apos;t be disabled for current server</source>
<translation>نمیتوان فایل را باز کرد.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>فایل پیکربندی نامعتبر است.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>ارزیابی %1 از %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند:</translation>
</message>
@@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers
<translation>امکان تغییر سرور در هنگام متصل بودن وجود ندارد</translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>تنظیمات AmneziaWG</translation>
</message>
@@ -493,11 +555,6 @@ Already installed containers were found on the server. All installed containers
<source>Port</source>
<translation>پورت</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remove AmneziaWG</source>
<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>
</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>
<translation>همه کاربرانی که با آنها ارتباطی به اشتراک گذاشتهاید دیگر قادر به اتصال به آن نخواهند بود.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation>ذخیره</translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>تنظیمات را ذخیره کن?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>ادامه</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>کنسل</translation>
</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>
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
</message>
@@ -898,25 +955,88 @@ Already installed containers were found on the server. All installed containers
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation>تنظیمات WG</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>پورت</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation></translation>
<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="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>
<translation>نمیتوان تنظیمات را تغییر داد در حالی که اتصال فعال است.</translation>
</message>
@@ -925,11 +1045,12 @@ Already installed containers were found on the server. All installed containers
<translation type="obsolete">تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
<source>Cancel</source>
<translation type="obsolete">کنسل</translation>
<translation type="unfinished">کنسل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation>ذخیره</translation>
</message>
@@ -1289,8 +1410,12 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<source>support@amnezia.org</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Mail</source>
<translation>ایمیل</translation>
<translation type="vanished">ایمیل</translation>
</message>
<message>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>وب سایت</translation>
</message>
@@ -1317,17 +1447,17 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">https://amnezia.org</translation>
</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>
<translation>%1 :نسخه نرمافزار</translation>
</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>
<translation>بررسی بروزرسانی</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation></translation>
</message>
@@ -1776,72 +1906,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع بهطور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایلهای ثبت وقایع حذف خواهند شد.</translation>
<translation type="vanished">ثبت وقایع فعال است. توجه داشته باشید که ثبت وقایع بهطور خودکار پس از ۱۴ روز غیرفعال شده و تمام فایلهای ثبت وقایع حذف خواهند شد.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>گزارشات</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>فعال کردن این عملکرد باعث ذخیره خودکار لاگهای برنامه میشود. به طور پیشفرض، قابلیت ثبت لاگ غیرفعال است. در صورت بروز خطا در برنامه، ذخیره لاگ را فعال کنید.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>ذخیره گزارشات</translation>
<translation type="vanished">ذخیره گزارشات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>باز کردن پوشه گزارشات</translation>
<translation type="vanished">باز کردن پوشه گزارشات</translation>
</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>
<translation>ذخیره</translation>
</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>
<translation>Logs files (*.log)</translation>
</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>
<translation>فایل گزارشات ذخیره شد</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>ذخیره گزارشات در فایل</translation>
<translation type="vanished">ذخیره گزارشات در فایل</translation>
</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>
<translation>پاک کردن گزارشات؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>ادامه</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>کنسل</translation>
</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>
<translation>گزارشات پاک شدند</translation>
</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>
<translation>پاک کردن گزارشات</translation>
</message>
@@ -2013,12 +2179,11 @@ Already installed containers were found on the server. All installed containers
<translation> تنظیمات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>پاک کردن پروفایل %1</translation>
<translation type="vanished">پاک کردن پروفایل %1</translation>
</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>
<translation>آیا میخواهید پروفایل %1 را پاک کنید؟</translation>
</message>
@@ -2028,39 +2193,64 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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>
<translation>نمیتوان پروفایل %1 را در حین اتصال فعال پاک کرد.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>حذف </translation>
</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>
<translation>حذف %1 از سرور؟</translation>
</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>
<translation>تمام کاربرانی که این ارتباط را با آنها به اشتراک گذاشتهاید دیگر نمیتوانند به آن متصل شوند.</translation>
</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>
<translation>نمیتوان کانتینر فعال را حذف کرد.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation>ادامه</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<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 &quot;connect&quot; 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>
<translation>کنسل</translation>
</message>
@@ -2243,7 +2433,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">چی داری؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>فایل شامل تنظیمات اتصال</translation>
</message>
@@ -2257,77 +2447,87 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>ارتباط</translation>
</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>
<translation>کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>کلید را وارد کنید</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>وارد کردن</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>ادامه دهید</translation>
</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>
<translation>گزینههای اتصال دیگر</translation>
</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>
<translation>VPN توسط Amnezia</translation>
</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>
<translation>اتصال به سرویسهای VPN کلاسیک پولی و رایگان از Amnezia</translation>
</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>
<translation>Self-hosted VPN</translation>
</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>
<translation>پیکربندی VPN Amnezia بر روی سرور خودتان</translation>
</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>
<translation>بازیابی از پشتیبان</translation>
</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>
<translation>باز کردن فایل پشتیبان</translation>
</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>
<translation>Backup files (*.backup)</translation>
</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>
<translation>باز کردن فایل تنظیمات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-Code</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>من هیچی ندارم</translation>
</message>
@@ -2499,7 +2699,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>نصب</translation>
</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>
<translation>پورت باید در محدوده ۱ تا ۶۵۵۳۵ باشد</translation>
</message>
@@ -2867,12 +3067,17 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>اشتراکگذاری</translation>
</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>
<translation>ارتباط با </translation>
</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>
<translation>فایل شامل تنظیمات ارتباط با </translation>
</message>
@@ -2889,6 +3094,11 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<source>Settings restored from backup file</source>
<translation>تنظیمات از فایل پشتیبان بازیابی شد</translation>
</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>
<name>PopupType</name>
@@ -2927,12 +3137,12 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>Password not found</translation>
</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>
<translation>Could not open keystore</translation>
</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>
<translation>Could not remove private key from keystore</translation>
</message>
@@ -3108,27 +3318,27 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>Could not open keystore</translation>
</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>
<translation>Could not create private key generator</translation>
</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>
<translation>Could not generate new private key</translation>
</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>
<translation>Could not retrieve private key from keystore</translation>
</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>
<translation>Could not create encryption cipher</translation>
</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>
<translation>Could not encrypt data</translation>
</message>
@@ -3883,7 +4093,7 @@ For more detailed information, you can
<context>
<name>SettingsController</name>
<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>
<translation>تمام تنظیمات به مقادیر پیش فرض ریست شد</translation>
</message>
@@ -3892,7 +4102,7 @@ For more detailed information, you can
<translation type="vanished">پروفایل ذخیره شده پاک شد</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>فایل بکآپ خراب شده است</translation>
</message>
@@ -4024,7 +4234,7 @@ For more detailed information, you can
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation type="unfinished"></translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation type="unfinished"></translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>ि ि </translation>
</message>
@@ -187,9 +192,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation> ि!</translation>
<translation type="vanished"> ि!</translation>
</message>
</context>
<context>
@@ -255,18 +259,18 @@ Can&apos;t be disabled for current server</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>%2 %1 ि .</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
<translation>ि </translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>Amneziaडब्ल्यूज ि</translation>
</message>
@@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation></translation>
<translation type="vanished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation></translation>
</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>
<translation>H1-H4 ि ि</translation>
</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>
<translation> S1 + (148) S2 + िि (92) ि</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>ि ?</translation>
</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>
<translation> ि ि , .</translation>
</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>
<translation>ि ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation> </translation>
</message>
@@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
<translation>ि ि </translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation> ि</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation></translation>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation></translation>
</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>
<translation>ि ि </translation>
</message>
@@ -1237,9 +1370,13 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<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>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation></translation>
</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>
<translation> : %1</translation>
</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>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation> ि</translation>
</message>
@@ -1729,72 +1871,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>ि . ि 14 ि ि , .</translation>
<translation type="vanished">ि . ि 14 ि ि , .</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>ि</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation> ि ि , ि , ि ि िि ि .</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation> </translation>
<translation type="vanished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation> </translation>
<translation type="vanished"> </translation>
</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>
<translation></translation>
</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>
<translation> (*.log)</translation>
</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>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation> </translation>
<translation type="vanished"> </translation>
</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>
<translation> ?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation> </translation>
</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>
<translation> ि </translation>
</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>
<translation> </translation>
</message>
@@ -1954,12 +2132,11 @@ Already installed containers were found on the server. All installed containers
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>%1 </translation>
<translation type="vanished">%1 </translation>
</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>
<translation>%1 ?</translation>
</message>
@@ -1969,39 +2146,64 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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>
<translation>ि %1 </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>ि </translation>
</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>
<translation> ि ि , .</translation>
</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>
<translation>ि </translation>
</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>
<translation> %1 ?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<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 &quot;connect&quot; 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>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
<source>Cancel</source>
<translation> </translation>
</message>
@@ -2185,82 +2387,92 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished"> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished"> (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation> ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>ि </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation> ि</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished"> </translation>
</message>
@@ -2432,7 +2644,7 @@ Already installed containers were found on the server. All installed containers
<translation>ि </translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -2804,12 +3016,17 @@ Already installed containers were found on the server. All installed containers
<translation> </translation>
</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>
<translation> ि </translation>
</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>
<translation> ि </translation>
</message>
@@ -2826,6 +3043,11 @@ Already installed containers were found on the server. All installed containers
<source>Settings restored from backup file</source>
<translation type="unfinished"> ि ि </translation>
</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>
<name>PopupType</name>
@@ -2864,12 +3086,12 @@ Already installed containers were found on the server. All installed containers
<translation> ि</translation>
</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>
<translation> </translation>
</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>
<translation> ि </translation>
</message>
@@ -3045,27 +3267,27 @@ Already installed containers were found on the server. All installed containers
<translation> </translation>
</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>
<translation>ि </translation>
</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>
<translation> ि </translation>
</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>
<translation> ि </translation>
</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>
<translation>ि ि </translation>
</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>
<translation> ि ि </translation>
</message>
@@ -3763,12 +3985,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation> ि </translation>
</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>
<translation> ि ि ि </translation>
</message>
@@ -3900,7 +4122,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation>ကကက ကက ကက VPN ကက %1 MBit/s </translation>
</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>
<translation>က က ကက က VPN. </translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation>Amnezia Premium - ကကက ကက ကကကက VPN က ကက .</translation>
</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>
<translation>Amnezia Free ကက က ကက VPN </translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation>%1 MBit/s</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation>%1 က</translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation> VPN Instagram Facebook Twitter ကက ကက ကက IP &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;ကကကက က&lt;/a&gt;</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation>%1 $/</translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>Configuration ကက</translation>
</message>
@@ -187,9 +192,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>!</translation>
<translation type="vanished">!</translation>
</message>
</context>
<context>
@@ -255,18 +259,18 @@ Can&apos;t be disabled for current server</source>
<translation>က</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>Configuration က</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>%2 %1 က က.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation> configuration က :</translation>
</message>
@@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation>Gateway </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
<translation>ကက က </translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>AmneziaWG က</translation>
</message>
@@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
<translation>Port</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation>MTU</translation>
<translation type="vanished">MTU</translation>
</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>
<translation>ကက က.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation></translation>
</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>
<translation>Jc - Junk packet က</translation>
</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>
<translation>Jmin - Junk packet က</translation>
</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>
<translation>Jmax - Junk packet ကက</translation>
</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>
<translation>S1 - Init packet junk </translation>
</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>
<translation>S2 - Response packet junk </translation>
</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>
<translation>H1 - Init packet magic header</translation>
</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>
<translation>H2 - Response packet magic header</translation>
</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>
<translation>H4 - Transport packet magic header</translation>
</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>
<translation>H3 - Underload packet magic header</translation>
</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>
<translation>H1-H4 ကက </translation>
</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>
<translation>ကက S1 + က (148) S2 + က (92) </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>ကက ?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>က</translation>
</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>
<translation>ကက ကက </translation>
</message>
@@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
<translation>ကက ကက </translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation>WG က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>Port</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation>MTU</translation>
<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="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>
<translation>ကက ကက </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation></translation>
</message>
@@ -1205,9 +1338,13 @@ Already installed containers were found on the server. All installed containers
<translation>https://t.me/amnezia_vpn</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<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>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>က</translation>
</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>
<translation>: %1</translation>
</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>
<translation> </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation>ကကက</translation>
</message>
@@ -1689,73 +1831,109 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>Logging က က ကက က ကက .</translation>
<translation type="vanished">Logging က က ကက က ကက .</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>Logging</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>ကက က က က Logging ကက ကက ကက က က.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>က</translation>
<translation type="vanished">က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>က</translation>
<translation type="vanished">က</translation>
</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>
<translation></translation>
</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>
<translatorcomment> (*.log)</translatorcomment>
<translation> (*.log)</translation>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>က </translation>
<translation type="vanished">က </translation>
</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>
<translation>?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>က</translation>
</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>
<translation>က </translation>
</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>
<translation></translation>
</message>
@@ -1915,12 +2093,11 @@ Already installed containers were found on the server. All installed containers
<translation> က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>%1 က </translation>
<translation type="vanished">%1 က </translation>
</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>
<translation>%1 က ?</translation>
</message>
@@ -1930,39 +2107,64 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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>
<translation>ကက %1 က </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation> </translation>
</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>
<translation>%1 က ?</translation>
</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>
<translation>ကက ကကက.</translation>
</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>
<translation>Active container က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation>ကက</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<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 &quot;connect&quot; 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>
<translation>က</translation>
</message>
@@ -2125,7 +2327,7 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSetupWizardConfigSource</name>
<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>
<translation>ကက</translation>
</message>
@@ -2135,77 +2337,87 @@ Already installed containers were found on the server. All installed containers
<translation>က</translation>
</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>
<translation>Key က က QR-ကက က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Key က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>ကက</translation>
</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>
<translation>က</translation>
</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>
<translation>Amnezia VPN</translation>
</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>
<translation>Amnezia VPN က</translation>
</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>
<translation>က host VPN</translation>
</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>
<translation>Amnezia VPN က က </translation>
</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>
<translation> </translation>
</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>
<translation>က </translation>
</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>
<translation> (*.backup)</translation>
</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>
<translation>config က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-က</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>က</translation>
</message>
@@ -2717,12 +2929,17 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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>
<translation>က </translation>
</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>
<translation>က က </translation>
</message>
@@ -2739,6 +2956,11 @@ Already installed containers were found on the server. All installed containers
<source>Settings restored from backup file</source>
<translation>ကက </translation>
</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>
<name>PopupType</name>
@@ -2777,12 +2999,12 @@ Already installed containers were found on the server. All installed containers
<translation>ကကက </translation>
</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>
<translation>keystore က </translation>
</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>
<translation>Key store က key က </translation>
</message>
@@ -2958,27 +3180,27 @@ Already installed containers were found on the server. All installed containers
<translation>keystore က </translation>
</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>
<translation>က key ကက</translation>
</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>
<translation>က key </translation>
</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>
<translation>Key store က key က </translation>
</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>
<translation>ကက</translation>
</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>
<translation>က ကက</translation>
</message>
@@ -3672,12 +3894,12 @@ For more detailed information, you can
<context>
<name>SettingsController</name>
<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>
<translation>ကက </translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>က</translation>
</message>
@@ -3809,7 +4031,7 @@ For more detailed information, you can
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation>Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Работает для любых сайтов. Скорость до %1 Мбит/с</translation>
</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>
<translation>VPN для доступа к заблокированным сайтам в регионах с высоким уровнем интернет-цензуры. </translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation>Amnezia Premium классический VPN для комфортной работы, загрузки больших файлов и просмотра видео в высоком разрешении. Работает на всех сайтах, даже в странах с самым высоким уровнем интернет-цензуры.</translation>
</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>
<translation>Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation>%1 дней</translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation>Через VPN будут открываться только популярные сайты, заблокированные в вашем регионе, такие как Instagram, Facebook, Twitter и другие. Остальные сайты будут открываться с вашего реального IP-адреса, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;подробности на сайте.&lt;/a&gt;</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation>Бесплатно</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation>%1 $/месяц</translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>Невозможно отключиться во время подготовки конфигурации</translation>
</message>
@@ -187,9 +192,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>Ошибка доступа!</translation>
<translation type="vanished">Ошибка доступа!</translation>
</message>
</context>
<context>
@@ -259,18 +263,18 @@ Can&apos;t be disabled for current server</source>
<translation>Невозможно открыть файл</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>Неверный файл конфигурации</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>Отсканировано %1 из %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
</message>
@@ -447,6 +451,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -481,10 +490,63 @@ Already installed containers were found on the server. All installed containers
<translation>Невозможно изменить сервер во время активного соединения</translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>Настройки AmneziaWG</translation>
</message>
@@ -494,9 +556,8 @@ Already installed containers were found on the server. All installed containers
<translation>Порт</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation>MTU</translation>
<translation type="vanished">MTU</translation>
</message>
<message>
<source>Remove AmneziaWG</source>
@@ -507,87 +568,87 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Удалить AmneziaWG с сервера?</translation>
</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>
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation>Сохранить</translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation>Значения в полях H1-H4 должны быть уникальными</translation>
</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>
<translation>Значение в поле S1 + размер инициации сообщения (148) не должно равняться значению в поле S2 + размер ответа на сообщение (92)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>Сохранить настройки?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>Отменить</translation>
</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>
<translation>Невозможно изменить настройки во время активного соединения</translation>
</message>
@@ -898,25 +959,87 @@ Already installed containers were found on the server. All installed containers
<translation>Невозможно изменить настройки во время активного соединения</translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation>Настройки WG</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>Порт</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation>MTU</translation>
<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="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>
<translation>Невозможно изменить настройки во время активного соединения</translation>
</message>
@@ -933,15 +1056,17 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
<source>Continue</source>
<translation type="vanished">Продолжить</translation>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
<source>Cancel</source>
<translation type="vanished">Отменить</translation>
<translation>Отменить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation>Сохранить</translation>
</message>
@@ -1305,8 +1430,12 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<source>support@amnezia.org</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Mail</source>
<translation>Почта</translation>
<translation type="vanished">Почта</translation>
</message>
<message>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>Веб-сайт</translation>
</message>
@@ -1333,17 +1467,17 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">https://amnezia.org</translation>
</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>
<translation>Версия ПО: %1</translation>
</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>
<translation>Проверить обновления</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation>Политика конфиденциальности</translation>
</message>
@@ -1816,72 +1950,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены.</translation>
<translation type="vanished">Логирование включено. Обратите внимание, что логирование будет автоматически отключено через 14 дней, и все логи будут удалены.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>Логирование</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>Включение этой функции позволяет сохранять логи на вашем устройстве. По умолчанию она отключена. Включите сохранение логов в случае сбоев в работе приложения.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>Сохранять логи</translation>
<translation type="vanished">Сохранять логи</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>Открыть папку с логами</translation>
<translation type="vanished">Открыть папку с логами</translation>
</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>
<translation>Сохранить</translation>
</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>
<translation>Файлы логов (*.log)</translation>
</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>
<translation>Файл с логами сохранен</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>Сохранить логи в файл</translation>
<translation type="vanished">Сохранить логи в файл</translation>
</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>
<translation>Очистить логи?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>Отменить</translation>
</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>
<translation>Логи очищены</translation>
</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>
<translation>Очистить логи</translation>
</message>
@@ -2069,12 +2239,11 @@ Already installed containers were found on the server. All installed containers
<translation> настройки</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>Очистить профиль %1</translation>
<translation type="vanished">Очистить профиль %1</translation>
</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>
<translation>Очистить профиль %1?</translation>
</message>
@@ -2084,27 +2253,52 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</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 &quot;connect&quot; 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>
<translation>Невозможно очистить профиль %1 во время активного соединения</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>Удалить </translation>
</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>
<translation>Удалить %1 с сервера?</translation>
</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>
<translation>Все пользователи, с которыми вы поделились конфигурацией вашего VPN, больше не смогут к нему подключаться.</translation>
</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>
<translation>Невозможно удалить активный контейнер</translation>
</message>
@@ -2113,14 +2307,14 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Все пользователи, с которыми вы поделились VPN, больше не смогут к нему подключаться.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
<source>Cancel</source>
<translation>Отменить</translation>
</message>
@@ -2311,7 +2505,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Что у вас есть?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>Файл с настройками подключения</translation>
</message>
@@ -2325,77 +2519,87 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>Соединение</translation>
</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>
<translation>Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Вставьте ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>Вставить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>Продолжить</translation>
</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>
<translation>Другие варианты подключения</translation>
</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>
<translation>VPN от Amnezia</translation>
</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>
<translation>Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation>
</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>
<translation>Self-hosted VPN</translation>
</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>
<translation>Настроить VPN на собственном сервере</translation>
</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>
<translation>Восстановить из резервной копии</translation>
</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>
<translation>Открыть резервную копию</translation>
</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>
<translation>Файлы резервных копий (*.backup)</translation>
</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>
<translation>Открыть файл с конфигурацией</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>У меня ничего нет</translation>
</message>
@@ -2475,7 +2679,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="154"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>Где взять данные для подключения, пошаговые инстуркции по покупке VPS</translation>
<translation>Где взять данные для подключения, пошаговые инструкции по покупке VPS</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="170"/>
@@ -2600,7 +2804,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Установить</translation>
</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>
<translation>Порт должен быть в диапазоне от 1 до 65535</translation>
</message>
@@ -2996,12 +3200,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Поделиться</translation>
</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>
<translation>Подключение к </translation>
</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>
<translation>Файл с настройками подключения к </translation>
</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>
<translation>Настройки восстановлены из бэкап файла</translation>
</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>
<name>PopupType</name>
@@ -3056,12 +3270,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Пароль не найден</translation>
</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>
<translation>Не удалось открыть хранилище ключей</translation>
</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>
<translation>Не удалось удалить закрытый ключ из хранилища ключей</translation>
</message>
@@ -3237,27 +3451,27 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Не удалось открыть хранилище ключей</translation>
</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>
<translation>Не удалось создать генератор закрытых ключей</translation>
</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>
<translation>Не удалось сгенерировать новый закрытый ключ</translation>
</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>
<translation>Не удалось получить закрытый ключ из хранилища ключей</translation>
</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>
<translation>Не удалось создать шифр шифрования</translation>
</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>
<translation>Не удалось зашифровать данные</translation>
</message>
@@ -4094,7 +4308,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>SettingsController</name>
<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>
<translation>Все настройки сброшены до значений по умолчанию</translation>
</message>
@@ -4103,7 +4317,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<translation type="vanished">Закэшированные профили очищены</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>Файл резервной копии поврежден</translation>
</message>
@@ -4235,7 +4449,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Мбит/с</translation>
</message>

View File

@@ -27,47 +27,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation>Звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео. Працює для будь-яких сайтів. Швидкість до %1 MBit/s</translation>
</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>
<translation>VPN для доступу до заблокованих сайтів у регіонах з високим рівнем інтернет-цензури. </translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation>Amnezia Premium - звичайний VPN для комфортної роботи, завантаження великих файлів та перегляду відео у високій роздільній здатності. Працює для всіх вебсайтів, навіть у країнах з найвищим рівнем інтернет-цензури.</translation>
</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>
<translation>Amnezia Free це безкоштовний VPN для обходу блокувань у країнах з високим рівнем інтернет-цензури</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation>%1 MBit/s</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation>%1 днів</translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation>Лише популярні сайти, які заблоковані у вашому регіоні, будуть відкриватись за допомогою VPN підключення (Instagram, Facebook, Twitter та ін.). Звичайні сайти будуть відкриватися без використання VPN, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;більш детально на нашому сайті.&lt;/a&gt;</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation>Безкоштовно</translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation>%1 $/місяць</translation>
</message>
@@ -98,7 +103,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>Неможливо відключитися під час підготовки конфігурації</translation>
</message>
@@ -210,9 +215,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>Помилка доступу!</translation>
<translation type="vanished">Помилка доступу!</translation>
</message>
</context>
<context>
@@ -286,18 +290,18 @@ Can&apos;t be disabled for current server</source>
<translation>Неможливо відкрити файл</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>Недійсний файл конфігурації</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>Відскановано %1 з %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation>У імпортованій конфігурації знайдено потенційно небезпечні рядки:</translation>
</message>
@@ -400,7 +404,7 @@ Already installed containers were found on the server. All installed containers
<source>application name</source>
<translation>назва застосунку</translation>
</message>
<message>
<message>
<location filename="../ui/qml/Components/InstalledAppsDrawer.qml" line="152"/>
<source>Add selected</source>
<translation>Додати вибране</translation>
@@ -473,6 +477,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -507,10 +516,63 @@ Already installed containers were found on the server. All installed containers
<translation>Не можна змінити сервер при активному підключенні</translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>налаштування AmneziaWG</translation>
</message>
@@ -521,81 +583,76 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation>Зберегти</translation>
</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>
<translation>Значення полів H1-H4 мають бути унікальними</translation>
</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>
<translation>Значення поля S1 + розмір повідомлення ініціалізації (148) не має бути рівним значенню S2 + розмір повідомлення відповіді (92)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>Зберегти налаштування?</translation>
</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>
<translation>Усі користувачі, з якими ви поділилися підключенням, більше не зможуть підключитися до нього.</translation>
</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>
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
</message>
@@ -616,12 +673,12 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>Відмінити</translation>
</message>
@@ -960,30 +1017,102 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Зберегти і перезавантажити</translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>Порт</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation>MTU</translation>
<translation type="vanished">MTU</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation>Зберегти</translation>
</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>
<translation>Неможливо змінити налаштування, поки є активне підключення</translation>
</message>
@@ -1000,7 +1129,7 @@ Already installed containers were found on the server. All installed containers
<source>Disguised as traffic from</source>
<translation>Замаскувати трафік під</translation>
</message>
<message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolXraySettings.qml" line="129"/>
<source>Save</source>
<translation>Зберегти</translation>
@@ -1375,8 +1504,12 @@ Already installed containers were found on the server. All installed containers
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<source>support@amnezia.org</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Mail</source>
<translation>Пошта</translation>
<translation type="vanished">Пошта</translation>
</message>
<message>
<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>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>Веб-сайт</translation>
</message>
@@ -1403,17 +1541,17 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">https://amnezia.org</translation>
</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>
<translation>Версія ПЗ: %1</translation>
</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>
<translation>Перевірити оновлення</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation>Політика конфіденційності</translation>
</message>
@@ -1604,7 +1742,7 @@ Already installed containers were found on the server. All installed containers
<translation>Запускати застосунок в згорнутому вигляді</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApplication.qml" line="189"/>
<location filename="../ui/qml/Pages2/PageSettingsApplication.qml" line="189"/>
<source>Language</source>
<translation>Мова</translation>
</message>
@@ -1886,72 +2024,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені.</translation>
<translation type="vanished">Логування увімкнене. Зверніть увагу, що логування буде автоматично вимкнене через 14 днів, а всі файли журналів будуть видалені.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>Логування</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>Увімкнення цієї функції автоматично зберігатиме журнали додатка. За замовчуванням функція логування вимкнена. Увімкніть збереження журналів у випадку збою додатка.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>Зберегти логи</translation>
<translation type="vanished">Зберегти логи</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>Відкрити папку з логами</translation>
<translation type="vanished">Відкрити папку з логами</translation>
</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>
<translation>Зберегти</translation>
</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>
<translation>Logs files (*.log)</translation>
</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>
<translation>Файл з логами збережено</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>Зберегти логи в файл</translation>
<translation type="vanished">Зберегти логи в файл</translation>
</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>
<translation>Очистити логи?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>Відмінити</translation>
</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>
<translation>Логи видалено</translation>
</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>
<translation>Видалити логи</translation>
</message>
@@ -2151,22 +2325,46 @@ Already installed containers were found on the server. All installed containers
<translation> Налаштування</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>Очистити профіль %1</translation>
<translation type="vanished">Очистити профіль %1</translation>
</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 &quot;connect&quot; 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>
<translation>Очистити профіль %1?</translation>
</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>
<translation>Неможливо очистити профіль %1 під час активного підключення</translation>
</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>
<translation>Неможливо видалити активний контейнер</translation>
</message>
@@ -2176,17 +2374,17 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>Видалити </translation>
</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>
<translation>Видалити %1 з сервера?</translation>
</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>
<translation>Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
</message>
@@ -2195,14 +2393,14 @@ Already installed containers were found on the server. All installed containers
<translation type="vanished">Користувачі, з якими ви поділились цим протоколм, більше не зможуть до нього підключитись.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
<source>Cancel</source>
<translation>Відмінити</translation>
</message>
@@ -2393,7 +2591,7 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="vanished">Виберіть що у вас є</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>Файл з налаштуваннями підключення</translation>
</message>
@@ -2407,77 +2605,87 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation>Підключення</translation>
</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>
<translation>Вставте ключ, додайте файл конфігурації або відскануйте QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation>Вставити ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation>Вставити</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation>Продовжити</translation>
</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>
<translation>Інші параметри підключення</translation>
</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>
<translation>VPN від Amnezia</translation>
</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>
<translation>Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia</translation>
</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>
<translation>Self-hosted VPN</translation>
</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>
<translation>Налаштуйте Amnezia VPN на власному сервері</translation>
</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>
<translation>Відновити із бекапа</translation>
</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>
<translation>Відкрити бекап файл</translation>
</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>
<translation>Файли резервної копії (*.backup)</translation>
</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>
<translation>Відкрити файл з конфігурацією</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR-код</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation>У мене нічого нема</translation>
</message>
@@ -2691,7 +2899,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Встановити</translation>
</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>
<translation>Порт повинен бути в межах від 1 до 65535</translation>
</message>
@@ -3009,7 +3217,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Користувач більше не зможе підключатись до вашого сервера </translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<location filename="../ui/qml/Pages2/PageShare.qml" line="961"/>
<source>Continue</source>
<translation>Продовжити</translation>
</message>
@@ -3086,12 +3294,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Поділитись</translation>
</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>
<translation>Підключення до </translation>
</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>
<translation>Файл з налаштуванням доступу до </translation>
</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>
<translation>Відновлення налаштувань із бекап файлу</translation>
</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>
<name>PopupType</name>
@@ -3146,12 +3364,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Пароль не знайдено</translation>
</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>
<translation>Could not open keystore</translation>
</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>
<translation>Could not remove private key from keystore</translation>
</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>
</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>
<translation>Could not create private key generator</translation>
</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>
<translation>Could not generate new private key</translation>
</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>
<translation>Could not retrieve private key from keystore</translation>
</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>
<translation>Could not create encryption cipher</translation>
</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>
<translation>Could not encrypt data</translation>
</message>
@@ -4167,7 +4385,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>SettingsController</name>
<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>
<translation>Всі налаштування були скинуті до значення &quot;По замовчуванню&quot;</translation>
</message>
@@ -4176,7 +4394,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<translation type="vanished">Кеш профілю очищено</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>Backup файл пошкодженно</translation>
</message>
@@ -4308,7 +4526,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>Mbps</translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation type="unfinished"></translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation type="unfinished"></translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation>تشکیل کی تیاری کے دوران منقطع ہونا ممکن نہیں ہے</translation>
</message>
@@ -186,9 +191,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>رساءی ناممکن!</translation>
<translation type="vanished">رساءی ناممکن!</translation>
</message>
</context>
<context>
@@ -253,18 +257,18 @@ Can&apos;t be disabled for current server</source>
<translation>فائل کو کھولنے سے قاصر ہے</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation>غلط کنفیگریشن فائل</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation>سکین%1 کی%2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -443,6 +447,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -477,10 +486,63 @@ Already installed containers were found on the server. All installed containers
<translation>فعال کنکشن موجود ہونے کی وجہ سے سرور تبدیل کرنے میں ناکام ہیں</translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>امنیزیا وی جی کی ترتیبات</translation>
</message>
@@ -490,92 +552,91 @@ Already installed containers were found on the server. All installed containers
<translation>پورٹ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation>ام ٹی یو</translation>
<translation type="vanished">ام ٹی یو</translation>
</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>
<translation>آپ جن لوگوں کے ساتھ آپ نے اس کنکشن کا اشتراک کیا تھا، وہ اس سے مزید جڑ نہیں سکیں گے۔</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation>محفوظ کریں</translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation>H1 تا H4 فیلڈز کی قیمتیں مخصوص ہونی چاہیے</translation>
</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>
<translation>S1 + پیغام شروع کار (148) کے فیلڈ کی قیمت S2 + پیغام جواب (92) کے سائز کے برابر نہیں ہونی چاہئے</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation>ترتیبات محفوظ کریں?</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation>جاری رکھیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation>منسوخ کریں</translation>
</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>
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
</message>
@@ -862,30 +923,102 @@ Already installed containers were found on the server. All installed containers
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
</message>
</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>
<name>PageProtocolWireGuardSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="97"/>
<source>WG settings</source>
<translation>وائر گارڈ ترتیبات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="107"/>
<source>Port</source>
<translation>پورٹ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<source>MTU</source>
<translation>ام ٹی یو</translation>
<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="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>
<translation>جب ایک فعال کنکشن موجود ہو تو ترتیبات کو تبدیل نہیں کیا جا سکتا</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation>محفوظ کریں</translation>
</message>
@@ -1241,9 +1374,13 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<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>
<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>
</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>
<translation>گِٹ ہَب</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation>ویب سائٹ</translation>
</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>
<translation>سافٹ ویئر ورژن: %1</translation>
</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>
<translation>اپ ڈیٹس چیک کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation>رازداری کی پالیسی</translation>
</message>
@@ -1733,72 +1875,108 @@ Already installed containers were found on the server. All installed containers
<context>
<name>PageSettingsLogging</name>
<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>
<translation>لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی.</translation>
<translation type="vanished">لاگنگ فعال ہے۔ یاد رہے کہ لاگوں کو 14 دنوں کے بعد خود بخود غیر فعال کر دیا جائے گا، اور تمام لاگ فائلیں حذف کردی جائیں گی.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation>لاگنگ</translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation>اس فعل کو فعال کرنے سے، ایپلیکیشن کے لاگ خود بخود محفوظ ہوجائیں گے۔ پہلے سے، لاگنگ کی فعالیت غیر فعال ہوتی ہے۔ اگر ایپلیکیشن میں کوئی خرابی ہو، تو لاگ کو بچانا فعال کریں.</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation>لاگوں کو محفوظ کریں</translation>
<translation type="vanished">لاگوں کو محفوظ کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation>فائلوں کے فولڈر کو کھولیں</translation>
<translation type="vanished">فائلوں کے فولڈر کو کھولیں</translation>
</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>
<translation>محفوظ</translation>
</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>
<translation>لاگ فائلیں (*.log)</translation>
</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>
<translation>لاگ فائل محفوظ ہوگئی</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation>لاگوں کو فائل میں محفوظ کریں</translation>
<translation type="vanished">لاگوں کو فائل میں محفوظ کریں</translation>
</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>
<translation>کیا آپ لاگوں کو صاف کرنا چاہتے ہیں؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation>براہ کرم جاری رکھیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation>منسوخ</translation>
</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>
<translation>تم مسح السجلاتلاگوں کو صاف کر دیا گیا ہے</translation>
</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>
<translation>لاگوں کو صاف کریں</translation>
</message>
@@ -1958,22 +2136,21 @@ Already installed containers were found on the server. All installed containers
<translation> ترتیبات</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation>%1 پروفائل کو صاف کریں</translation>
<translation type="vanished">%1 پروفائل کو صاف کریں</translation>
</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>
<translation>کیا آپ واقعی %1 پروفائل کو صاف کرنا چاہتے ہیں؟</translation>
</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>
<translation>فعال کنکشن کے دوران %1 پروفائل کو صاف نہیں کیا جا سکتا</translation>
</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>
<translation>فعال کنٹینر کو ہٹانا ممکن نہیں</translation>
</message>
@@ -1983,29 +2160,54 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation>ہٹائیں </translation>
</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>
<translation>آپ نے جن کے ساتھ کنکشن شئیر کیا تھا، ان تمام صارفین کو اس سے جڑنے کی اجازت نہیں ہوگی.</translation>
</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>
<translation>کیا آپ سرور سے %1 کو ہٹانا چاہتے ہیں؟</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<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 &quot;connect&quot; 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>
<translation>براہ کرم جاری رکھیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
<source>Cancel</source>
<translation>منسوخ</translation>
</message>
@@ -2189,82 +2391,92 @@ Already installed containers were found on the server. All installed containers
<translation type="unfinished">کنکشن</translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished">داخل کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished">بیک اپ سے بحال کریں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished">بیک اپ فائل کو کھولیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished">بیک اپ فائلیں (*.backup)</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation>کنکشن کی ترتیبات والی فائل</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation>کنفیگ فائل کو کھولیں</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation>QR کوڈ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished">میرے پاس کچھ نہیں ہے</translation>
</message>
@@ -2436,7 +2648,7 @@ Already installed containers were found on the server. All installed containers
<translation>انسٹال</translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -2808,12 +3020,17 @@ Already installed containers were found on the server. All installed containers
<translation>شیئر</translation>
</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>
<translation>کنکشن کو </translation>
</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>
<translation>کنکشن کی ترتیبات کی فائل </translation>
</message>
@@ -2830,6 +3047,11 @@ Already installed containers were found on the server. All installed containers
<source>Settings restored from backup file</source>
<translation type="unfinished">ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں</translation>
</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>
<name>PopupType</name>
@@ -2868,12 +3090,12 @@ Already installed containers were found on the server. All installed containers
<translation>پاس ورڈ نہیں ملا</translation>
</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>
<translation>کی اسٹور کھولا نہیں جا سکا</translation>
</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>
<translation>خصوصی کلید کو کی اسٹور سے ہٹانا نہیں ہو سکا</translation>
</message>
@@ -3049,27 +3271,27 @@ Already installed containers were found on the server. All installed containers
<translation>کی اسٹور کھولنے میں ناکام</translation>
</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>
<translation>پرائیویٹ کلید جنریٹر تخلیق نہیں کیا</translation>
</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>
<translation>نیا نجی کلید تخلیق نہیں کیا جا سکا</translation>
</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>
<translation>کی اسٹور سے نجی کلید حاصل نہیں کیا</translation>
</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>
<translation>تشکیل تشکیل نہیں کر سکا</translation>
</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>
<translation>ڈیٹا کو محفوظ کرنے میں ناکام</translation>
</message>
@@ -3709,12 +3931,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation>بیک اپ فائل خراب ہو گئی ہے</translation>
</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>
<translation>تمام ترتیبات کو ڈیفالٹ اقدار پر دوبارہ ترتیب دیا گیا ہے</translation>
</message>
@@ -3846,7 +4068,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation>ایم بی پی ایس</translation>
</message>

View File

@@ -4,47 +4,52 @@
<context>
<name>ApiServicesModel</name>
<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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="72"/>
<location filename="../ui/models/apiServicesModel.cpp" line="71"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.&lt;/a&gt;</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="80"/>
<location filename="../ui/models/apiServicesModel.cpp" line="94"/>
<source>%1 MBit/s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="87"/>
<location filename="../ui/models/apiServicesModel.cpp" line="101"/>
<source>%1 days</source>
<translation type="unfinished"></translation>
</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, &lt;a href=&quot;%1/free&quot; style=&quot;color: #FBB26A;&quot;&gt;more details on the website.&lt;/a&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="104"/>
<location filename="../ui/models/apiServicesModel.cpp" line="118"/>
<source>Free</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/models/apiServicesModel.cpp" line="106"/>
<location filename="../ui/models/apiServicesModel.cpp" line="120"/>
<source>%1 $/month</source>
<translation type="unfinished"></translation>
</message>
@@ -75,7 +80,7 @@
<context>
<name>ConnectButton</name>
<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>
<translation type="unfinished"></translation>
</message>
@@ -186,9 +191,8 @@
<context>
<name>ExportController</name>
<message>
<location filename="../ui/controllers/exportController.cpp" line="30"/>
<source>Access error!</source>
<translation>访</translation>
<translation type="vanished">访</translation>
</message>
</context>
<context>
@@ -258,18 +262,18 @@ Can&apos;t be disabled for current server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="186"/>
<location filename="../ui/controllers/importController.cpp" line="191"/>
<location filename="../ui/controllers/importController.cpp" line="187"/>
<location filename="../ui/controllers/importController.cpp" line="192"/>
<source>Invalid configuration file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="606"/>
<location filename="../ui/controllers/importController.cpp" line="617"/>
<source>Scanned %1 of %2.</source>
<translation> %1 of %2.</translation>
</message>
<message>
<location filename="../ui/controllers/importController.cpp" line="641"/>
<location filename="../ui/controllers/importController.cpp" line="652"/>
<source>In the imported configuration, potentially dangerous lines were found:</source>
<translation type="unfinished"></translation>
</message>
@@ -469,6 +473,11 @@ Already installed containers were found on the server. All installed containers
<source>Gateway endpoint</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="101"/>
<source>Dev gateway environment</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PageHome</name>
@@ -503,10 +512,63 @@ Already installed containers were found on the server. All installed containers
<translation></translation>
</message>
</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>
<name>PageProtocolAwgSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="96"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="94"/>
<source>AmneziaWG settings</source>
<translation>AmneziaWG </translation>
</message>
@@ -515,11 +577,6 @@ Already installed containers were found on the server. All installed containers
<source>Port</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="126"/>
<source>MTU</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remove AmneziaWG</source>
<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>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="333"/>
<source>Save</source>
<translation></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="373"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="356"/>
<source>Save settings?</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="375"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="358"/>
<source>Continue</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="376"/>
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="359"/>
<source>Cancel</source>
<translation></translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -933,24 +990,82 @@ Already installed containers were found on the server. All installed containers
</message>
</context>
<context>
<name>PageProtocolWireGuardSettings</name>
<name>PageProtocolWireGuardClientSettings</name>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="93"/>
<source>WG settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="102"/>
<source>Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="123"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="101"/>
<source>MTU</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -959,15 +1074,17 @@ Already installed containers were found on the server. All installed containers
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="140"/>
<source>Continue</source>
<translation type="obsolete"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="141"/>
<source>Cancel</source>
<translation type="obsolete"></translation>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="149"/>
<location filename="../ui/qml/Pages2/PageProtocolWireGuardSettings.qml" line="131"/>
<source>Save</source>
<translation></translation>
</message>
@@ -1329,9 +1446,13 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="123"/>
<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>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="124"/>
@@ -1339,32 +1460,37 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation></translation>
</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>
<translation>GitHub</translation>
</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>
<translation>https://github.com/amnezia-vpn/amnezia-client</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="159"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="161"/>
<source>Website</source>
<translation></translation>
</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>
<translation>: %1</translation>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="231"/>
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="233"/>
<source>Privacy Policy</source>
<translation></translation>
</message>
@@ -1849,72 +1975,104 @@ And if you don&apos;t like the app, all the more support it - the donation will
<context>
<name>PageSettingsLogging</name>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="69"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="56"/>
<source>Logging</source>
<translation></translation>
</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&apos;s logs automatically. By default, logging functionality is disabled. Enable log saving in case of application malfunction.</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="79"/>
<source>Save logs</source>
<translation></translation>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="117"/>
<source>Open folder with logs</source>
<translation></translation>
<translation type="vanished"></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="162"/>
<source>Save logs to file</source>
<translation></translation>
<translation type="vanished"></translation>
</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>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="185"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="94"/>
<source>Continue</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="95"/>
<source>Cancel</source>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</message>
@@ -2102,12 +2260,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="135"/>
<source>Clear %1 profile</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -2117,22 +2270,47 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation></translation>
</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 &quot;connect&quot; 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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="186"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="224"/>
<source>Remove </source>
<translation></translation>
</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>
<translation></translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -2145,7 +2323,7 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation type="obsolete"> </translation>
</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>
<translation> %1 ?</translation>
</message>
@@ -2154,14 +2332,14 @@ And if you don&apos;t like the app, all the more support it - the donation will
<translation type="obsolete"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="140"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="192"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="178"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="230"/>
<source>Continue</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="141"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="193"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="179"/>
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="231"/>
<source>Cancel</source>
<translation></translation>
</message>
@@ -2376,82 +2554,92 @@ It&apos;s okay as long as it&apos;s from someone you trust.</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="122"/>
<source>Insert key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="78"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="123"/>
<source>Insert</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="98"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="143"/>
<source>Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="116"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="161"/>
<source>Other connection options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="129"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="172"/>
<source>VPN by Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="130"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="173"/>
<source>Connect to classic paid and free VPN services from Amnezia</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="153"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="196"/>
<source>Self-hosted VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="154"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="197"/>
<source>Configure Amnezia VPN on your own server</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="174"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="217"/>
<source>Restore from backup</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="180"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="223"/>
<source>Open backup file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="181"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="224"/>
<source>Backup files (*.backup)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="198"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="241"/>
<source>File with connection settings</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="206"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="249"/>
<source>Open config file</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="225"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="268"/>
<source>QR code</source>
<translation></translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="248"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="291"/>
<source>I have nothing</source>
<translation type="unfinished"></translation>
</message>
@@ -2661,7 +2849,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</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>
<translation type="unfinished"></translation>
</message>
@@ -3077,12 +3265,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</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>
<translation> </translation>
</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>
<translation> </translation>
</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>
<translation type="unfinished"></translation>
</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>
<name>PopupType</name>
@@ -3137,12 +3335,12 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</message>
@@ -3318,27 +3516,27 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</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>
<translation></translation>
</message>
@@ -4169,12 +4367,12 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>SettingsController</name>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="138"/>
<location filename="../ui/controllers/settingsController.cpp" line="152"/>
<source>Backup file is corrupted</source>
<translation></translation>
</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>
<translation></translation>
</message>
@@ -4314,7 +4512,7 @@ While it offers a blend of security, stability, and speed, it&apos;s essential t
<context>
<name>VpnConnection</name>
<message>
<location filename="../vpnconnection.cpp" line="375"/>
<location filename="../vpnconnection.cpp" line="408"/>
<source>Mbps</source>
<translation></translation>
</message>

View File

@@ -34,13 +34,13 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
void ConnectionController::openConnection()
{
// #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
// if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
// {
// emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
// return;
// }
// #endif
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
{
emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
return;
}
#endif
int serverIndex = m_serversModel->getDefaultServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
@@ -51,8 +51,11 @@ void ConnectionController::openConnection()
if (configVersion == ApiConfigSources::Telegram
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
emit updateApiConfigFromTelegram();
} else if (configVersion == ApiConfigSources::AmneziaGateway
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
emit updateApiConfigFromGateway();
} else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
qDebug() << "attempt to update api config by end_date event";
qDebug() << "attempt to update api config by expires_at event";
if (configVersion == ApiConfigSources::Telegram) {
emit updateApiConfigFromTelegram();
} else {

View File

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

View File

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

View File

@@ -0,0 +1,210 @@
#include "focusController.h"
#include "utils/qmlUtils.h"
#include <QQmlApplicationEngine>
#include <QQuickWindow>
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
: QObject { parent },
m_engine { engine },
m_focusChain {},
m_focusedItem { nullptr },
m_rootObjects {},
m_defaultFocusItem { QSharedPointer<QQuickItem>() },
m_lvfc { nullptr }
{
QObject::connect(m_engine.get(), &QQmlApplicationEngine::objectCreated, this,
[this](QObject *object, const QUrl &url) {
QQuickItem *newDefaultFocusItem = object->findChild<QQuickItem *>("defaultFocusItem");
if (newDefaultFocusItem && m_defaultFocusItem != newDefaultFocusItem) {
m_defaultFocusItem.reset(newDefaultFocusItem);
}
});
QObject::connect(this, &FocusController::focusedItemChanged, this,
[this]() { m_focusedItem->forceActiveFocus(Qt::TabFocusReason); });
}
void FocusController::nextKeyTabItem()
{
nextItem(Direction::Forward);
}
void FocusController::previousKeyTabItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyUpItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyDownItem()
{
nextItem(Direction::Forward);
}
void FocusController::nextKeyLeftItem()
{
nextItem(Direction::Backward);
}
void FocusController::nextKeyRightItem()
{
nextItem(Direction::Forward);
}
void FocusController::setFocusItem(QQuickItem *item)
{
if (m_focusedItem != item) {
m_focusedItem = item;
}
emit focusedItemChanged();
}
void FocusController::setFocusOnDefaultItem()
{
setFocusItem(m_defaultFocusItem.get());
}
void FocusController::pushRootObject(QObject *object)
{
m_rootObjects.push(object);
dropListView();
// setFocusOnDefaultItem();
}
void FocusController::dropRootObject(QObject *object)
{
if (m_rootObjects.empty()) {
return;
}
if (m_rootObjects.top() == object) {
m_rootObjects.pop();
dropListView();
setFocusOnDefaultItem();
} else {
qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
}
}
void FocusController::resetRootObject()
{
m_rootObjects.clear();
}
void FocusController::reload(Direction direction)
{
m_focusChain.clear();
QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top());
if (!rootObject) {
qCritical() << "No ROOT OBJECT found!";
resetRootObject();
dropListView();
return;
}
m_focusChain.append(FocusControl::getSubChain(rootObject));
std::sort(m_focusChain.begin(), m_focusChain.end(),
direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore);
if (m_focusChain.empty()) {
qWarning() << "Focus chain is empty!";
resetRootObject();
dropListView();
return;
}
}
void FocusController::nextItem(Direction direction)
{
reload(direction);
if (m_lvfc && FocusControl::isListView(m_focusedItem)) {
direction == Direction::Forward ? focusNextListViewItem() : focusPreviousListViewItem();
return;
}
if (m_focusChain.empty()) {
qWarning() << "There are no items to navigate";
setFocusOnDefaultItem();
return;
}
auto focusedItemIndex = m_focusChain.indexOf(m_focusedItem);
if (focusedItemIndex == -1) {
focusedItemIndex = 0;
} else if (focusedItemIndex == (m_focusChain.size() - 1)) {
focusedItemIndex = 0;
} else {
focusedItemIndex++;
}
const auto focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(focusedItemIndex));
if (focusedItem == nullptr) {
qWarning() << "Failed to get item to focus on. Setting focus on default";
setFocusOnDefaultItem();
return;
}
if (FocusControl::isListView(focusedItem)) {
m_lvfc = new ListViewFocusController(focusedItem, this);
m_focusedItem = focusedItem;
if (direction == Direction::Forward) {
m_lvfc->nextDelegate();
focusNextListViewItem();
} else {
m_lvfc->previousDelegate();
focusPreviousListViewItem();
}
return;
}
setFocusItem(focusedItem);
}
void FocusController::focusNextListViewItem()
{
m_lvfc->reloadFocusChain();
if (m_lvfc->isLastFocusItemInListView() || m_lvfc->isReturnNeeded()) {
dropListView();
nextItem(Direction::Forward);
return;
} else if (m_lvfc->isLastFocusItemInDelegate()) {
m_lvfc->resetFocusChain();
m_lvfc->nextDelegate();
}
m_lvfc->focusNextItem();
}
void FocusController::focusPreviousListViewItem()
{
m_lvfc->reloadFocusChain();
if (m_lvfc->isFirstFocusItemInListView() || m_lvfc->isReturnNeeded()) {
dropListView();
nextItem(Direction::Backward);
return;
} else if (m_lvfc->isFirstFocusItemInDelegate()) {
m_lvfc->resetFocusChain();
m_lvfc->previousDelegate();
}
m_lvfc->focusPreviousItem();
}
void FocusController::dropListView()
{
if (m_lvfc) {
delete m_lvfc;
m_lvfc = nullptr;
}
}

View File

@@ -0,0 +1,57 @@
#ifndef FOCUSCONTROLLER_H
#define FOCUSCONTROLLER_H
#include "ui/controllers/listViewFocusController.h"
#include <QQmlApplicationEngine>
/*!
* \brief The FocusController class makes focus control more straightforward
* \details Focus is handled only for visible and enabled items which have
* `isFocused` property from top left to bottom right.
* \note There are items handled differently (e.g. ListView)
*/
class FocusController : public QObject
{
Q_OBJECT
public:
explicit FocusController(QQmlApplicationEngine *engine, QObject *parent = nullptr);
~FocusController() override = default;
Q_INVOKABLE void nextKeyTabItem();
Q_INVOKABLE void previousKeyTabItem();
Q_INVOKABLE void nextKeyUpItem();
Q_INVOKABLE void nextKeyDownItem();
Q_INVOKABLE void nextKeyLeftItem();
Q_INVOKABLE void nextKeyRightItem();
Q_INVOKABLE void setFocusItem(QQuickItem *item);
Q_INVOKABLE void setFocusOnDefaultItem();
Q_INVOKABLE void pushRootObject(QObject *object);
Q_INVOKABLE void dropRootObject(QObject *object);
Q_INVOKABLE void resetRootObject();
private:
enum class Direction {
Forward,
Backward,
};
void reload(Direction direction);
void nextItem(Direction direction);
void focusNextListViewItem();
void focusPreviousListViewItem();
void dropListView();
QSharedPointer<QQmlApplicationEngine> m_engine; // Pointer to engine to get root object
QList<QObject *> m_focusChain; // List of current objects to be focused
QQuickItem *m_focusedItem; // Pointer to the active focus item
QStack<QObject *> m_rootObjects;
QSharedPointer<QQuickItem> m_defaultFocusItem;
ListViewFocusController *m_lvfc; // ListView focus manager
signals:
void focusedItemChanged();
};
#endif // FOCUSCONTROLLER_H

View File

@@ -4,12 +4,13 @@
#include <QFileInfo>
#include <QQuickItem>
#include <QRandomGenerator>
#include <QUrlQuery>
#include <QStandardPaths>
#include <QUrlQuery>
#include "utilities.h"
#include "core/serialization/serialization.h"
#include "core/errorstrings.h"
#include "core/serialization/serialization.h"
#include "systemController.h"
#include "utilities.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
@@ -39,11 +40,12 @@ namespace
const QString amneziaConfigPatternUserName = "userName";
const QString amneziaConfigPatternPassword = "password";
const QString amneziaFreeConfigPattern = "api_key";
const QString amneziaPremiumConfigPattern = "auth_data";
const QString backupPattern = "Servers/serversList";
if (config.contains(backupPattern)) {
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(amneziaConfigPatternPassword))) {
return ConfigTypes::Amnezia;
@@ -75,17 +77,18 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo
bool ImportController::extractConfigFromFile(const QString &fileName)
{
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QString data = file.readAll();
m_configFileName = QFileInfo(file.fileName()).fileName();
return extractConfigFromData(data);
QString data;
if (!SystemController::readFile(fileName, data)) {
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
}
emit importErrorOccurred(tr("Unable to open file"), false);
return false;
m_configFileName = QFileInfo(QFile(fileName).fileName()).fileName();
#ifdef Q_OS_ANDROID
if (m_configFileName.isEmpty()) {
m_configFileName = AndroidController::instance()->getFileName(fileName);
}
#endif
return extractConfigFromData(data);
}
bool ImportController::extractConfigFromData(QString data)
@@ -96,36 +99,40 @@ bool ImportController::extractConfigFromData(QString data)
if (config.startsWith("vless://")) {
m_configType = ConfigTypes::Xray;
m_config = extractXrayConfig(Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg),
QJsonDocument::JsonFormat::Compact), prefix);
m_config = extractXrayConfig(
Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
prefix);
return m_config.empty() ? false : true;
}
if (config.startsWith("vmess://") && config.contains("@")) {
m_configType = ConfigTypes::Xray;
m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg),
QJsonDocument::JsonFormat::Compact), prefix);
m_config = extractXrayConfig(
Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
prefix);
return m_config.empty() ? false : true;
}
if (config.startsWith("vmess://")) {
m_configType = ConfigTypes::Xray;
m_config = extractXrayConfig(Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg),
QJsonDocument::JsonFormat::Compact), prefix);
m_config = extractXrayConfig(
Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
prefix);
return m_config.empty() ? false : true;
}
if (config.startsWith("trojan://")) {
m_configType = ConfigTypes::Xray;
m_config = extractXrayConfig(Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg),
QJsonDocument::JsonFormat::Compact), prefix);
m_config = extractXrayConfig(
Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
prefix);
return m_config.empty() ? false : true;
}
if (config.startsWith("ss://") && !config.contains("plugin=")) {
m_configType = ConfigTypes::ShadowSocks;
m_config = extractXrayConfig(Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg),
QJsonDocument::JsonFormat::Compact), prefix);
m_config = extractXrayConfig(
Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), prefix);
return m_config.empty() ? false : true;
}
@@ -173,6 +180,7 @@ bool ImportController::extractConfigFromData(QString data)
}
case ConfigTypes::Amnezia: {
m_config = QJsonDocument::fromJson(config.toUtf8()).object();
processAmneziaConfig(m_config);
if (!m_config.empty()) {
checkForMaliciousStrings(m_config);
return true;
@@ -183,12 +191,12 @@ bool ImportController::extractConfigFromData(QString data)
if (!m_serversModel->getServersCount()) {
emit restoreAppConfig(config.toUtf8());
} else {
emit importErrorOccurred(tr("Invalid configuration file"), false);
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
}
break;
}
case ConfigTypes::Invalid: {
emit importErrorOccurred(tr("Invalid configuration file"), false);
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
break;
}
}
@@ -237,24 +245,26 @@ void ImportController::processNativeWireGuardConfig()
auto containers = m_config.value(config_key::containers).toArray();
if (!containers.isEmpty()) {
auto container = containers.at(0).toObject();
auto containerConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
QString junkPacketMinSize = QString::number(10);
QString junkPacketMaxSize = QString::number(50);
protocolConfig[config_key::junkPacketCount] = junkPacketCount;
protocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
protocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
protocolConfig[config_key::initPacketJunkSize] = "0";
protocolConfig[config_key::responsePacketJunkSize] = "0";
protocolConfig[config_key::initPacketMagicHeader] = "1";
protocolConfig[config_key::responsePacketMagicHeader] = "2";
protocolConfig[config_key::underloadPacketMagicHeader] = "3";
protocolConfig[config_key::transportPacketMagicHeader] = "4";
clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount;
clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
clientProtocolConfig[config_key::initPacketJunkSize] = "0";
clientProtocolConfig[config_key::responsePacketJunkSize] = "0";
clientProtocolConfig[config_key::initPacketMagicHeader] = "1";
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
containerConfig[config_key::last_config] = QString(QJsonDocument(protocolConfig).toJson());
container["wireguard"] = containerConfig;
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
container["wireguard"] = serverProtocolConfig;
containers.replace(0, container);
m_config[config_key::containers] = containers;
}
@@ -353,20 +363,19 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
QJsonObject lastConfig;
lastConfig[config_key::config] = data;
const static QRegularExpression hostNameAndPortRegExp("Endpoint = (.*):([0-9]*)");
QRegularExpressionMatch hostNameAndPortMatch = hostNameAndPortRegExp.match(data);
auto url { QUrl::fromUserInput(configMap.value("Endpoint")) };
QString hostName;
QString port;
if (hostNameAndPortMatch.hasCaptured(1)) {
hostName = hostNameAndPortMatch.captured(1);
if (!url.host().isEmpty()) {
hostName = url.host();
} else {
qDebug() << "Key parameter 'Endpoint' is missing";
qDebug() << "Key parameter 'Endpoint' is missing or has an invalid format";
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return QJsonObject();
}
if (hostNameAndPortMatch.hasCaptured(2)) {
port = hostNameAndPortMatch.captured(2);
if (url.port() != -1) {
port = QString::number(url.port());
} else {
port = protocols::wireguard::defaultPort;
}
@@ -395,7 +404,11 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
lastConfig[config_key::mtu] = configMap.value("MTU");
}
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(","));
if (!configMap.value("PersistentKeepalive").isEmpty()) {
lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive");
}
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
@@ -419,6 +432,12 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
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;
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
wireguardConfig[config_key::isThirdPartyConfig] = true;
@@ -488,7 +507,7 @@ QJsonObject ImportController::extractXrayConfig(const QString &data, const QStri
if (m_configType == ConfigTypes::ShadowSocks) {
config[config_key::defaultContainer] = "amnezia-ssxray";
} else {
config[config_key::defaultContainer] = "amnezia-xray";
config[config_key::defaultContainer] = "amnezia-xray";
}
if (description.isEmpty()) {
config[config_key::description] = m_settings->nextAvailableServerName();
@@ -646,3 +665,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);
}
}
}

View File

@@ -54,7 +54,6 @@ public slots:
signals:
void importFinished();
void importErrorOccurred(const QString &errorMessage, bool goToPageHome);
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
void qrDecodingFinished();
@@ -68,6 +67,8 @@ private:
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
void processAmneziaConfig(QJsonObject &config);
#if defined Q_OS_ANDROID || defined Q_OS_IOS
void stopDecodingQr();
#endif

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