Compare commits

...

457 Commits

Author SHA1 Message Date
lunardunno
08c506a489 checking docker status
adding docker readiness status check to
servercontroller.cpp
2023-12-02 12:00:51 +04:00
lunardunno
9d49c5fb77 checking docker status
implementing docker readiness status check
2023-12-02 11:53:25 +04:00
lunardunno
b11c6fc6fe introduction "Failed to" for install_docker.sh 2023-11-22 08:31:16 +04:00
lunardunno
acfb021daa changes for test "Failed to" 2023-11-22 08:27:24 +04:00
lunardunno
394390ef1e test L18 2023-11-22 05:25:22 +04:00
lunardunno
e25d153d33 test 3 2023-11-22 04:53:05 +04:00
lunardunno
ddb05d594e test v2 2023-11-22 04:16:22 +04:00
lunardunno
bfc88ff171 docker replaced with sudo 2023-11-21 21:56:44 +04:00
lunardunno
1cbb7e8c14 test version 2023-11-21 15:31:23 +04:00
lunardunno
50d91526fb excluding for dist debian
excluding $dist debian from sudo systemctl enable --now docker, since it is launched at the post-install stage
2023-11-19 21:12:55 +04:00
lunardunno
77a411f1d7 Script_minimization_Ubuntu_fix
Script minimization.
Minimizing log information for debian and ubuntu.
Return delay to 5s for correct execution when reinstalling docker.io on Ubuntu22.
Introduction checking the status of docker.service, and corresponding error notification
2023-11-19 11:27:41 +04:00
lunardunno
4216e50e6e Improve logic of startup docker.service
Rebase install_docker.sh to dev.
Separate docker.service status check for Fedora from Debian and Centos.
2023-11-18 00:53:09 +04:00
lunardunno
b3b4adf152 changing logic startup docker.service 2023-11-15 13:43:05 +04:00
pokamest
b4694313a0 Merge pull request #426 from amnezia-vpn/ios-build
Change Qt mirror for builds
2023-11-14 09:54:54 -08:00
tiaga
abb2cae1f8 Change Qt mirror for builds
Use UC Berkeley mirror for installing Qt during a build. In addition, don't trigger builds on a tag push.
2023-11-14 23:39:15 +07:00
pokamest
b0004fd9dc Version bump 2023-11-14 12:50:52 +00:00
pokamest
19fe61ed29 Merge pull request #423 from amnezia-vpn/r2
Upload new versions to R2
2023-11-13 09:34:30 -08:00
tiaga
72de38b4fb Upload new versions to R2
A new GitHub Actions workflow for a tagged commit which uploads installers for a desktop version to Cloudflare R2.
2023-11-10 23:19:00 +07:00
pokamest
02c0f96e5e Merge pull request #418 from amnezia-vpn/feature/split-tunnel-dns-forwad
Use DNS over VPN for ForwardSites mode split tunnel
2023-11-07 06:35:43 -08:00
Mykola Baibuz
5e9f688000 Use DNS over VPN for ForwardSites mode split tunnel
This feature was in previous version of Split Tunnel
2023-11-04 15:28:59 -04:00
pokamest
6a7e346695 Merge pull request #416 from amnezia-vpn/bugfix/openvpn-exclude-route
Fix Split tunnel exclude sites mode for OpenVPN and Cloak. Windows.
2023-11-04 06:09:01 -07:00
Mykola Baibuz
071738116e Update Windows OpenVPN binary
This binary builded with ENABLE_DEBUG flag. This flag needed for ROUTE_GATEWAY varible output in log.
2023-11-03 17:29:40 -04:00
pokamest
ae4ee6431d Merge pull request #409 from useribs/patch-2
Update servercontroller.cpp, replace 2 calls (shred ; rm)  with one
2023-11-01 12:23:14 -07:00
pokamest
d1ccde2a4b Merge pull request #396 from amnezia-vpn/bugfix/server-config-sync
bugfix/server config sync
2023-11-01 07:15:10 -07:00
useribs
4848091203 Update servercontroller.cpp, replace 2 calls (shred ; rm) with one (shred -u) 2023-10-30 20:09:13 +03:00
pokamest
282f159311 Merge pull request #402 from amnezia-vpn/bugfix/description_dns
Update DNS description
2023-10-29 09:07:42 -07:00
lunardunno
4ef8c77a2d Update DNS description 2023-10-29 17:56:10 +04:00
pokamest
08c1cf2439 Merge pull request #382 from amnezia-vpn/feature/split-tunnel-mobile
Split tunnel for missed Protocol/OS
2023-10-29 06:26:07 -07:00
Mykola Baibuz
2fc33875bb Bump version 2023-10-27 15:38:24 -04:00
Mykola Baibuz
9e92e4b5ff Merge branch 'dev' into feature/split-tunnel-mobile 2023-10-27 15:37:28 -04:00
pokamest
7f2cf70bf5 Merge pull request #393 from amnezia-vpn/bugfix/return-after-installation
fixed page return after installation
2023-10-26 12:40:39 -07:00
vladimir.kuznetsov
8164026891 fixed server config update, after container config change 2023-10-26 23:37:51 +05:00
Mykola Baibuz
0e23b3a1ac Allow traffic to Amezia DNS for all OS 2023-10-25 22:19:07 +03:00
Mykola Baibuz
1739d4861e Allow acces to Amnezia DNS when used only for selected sites 2023-10-25 21:50:35 +03:00
Mykola Baibuz
a6b6e7850d Allow traffic for excluded route on Windows kill switch 2023-10-24 23:07:07 +03:00
Mykola Baibuz
3e9dea6f07 Remove some not implemented notification 2023-10-24 13:37:40 +03:00
Mykola Baibuz
1b37ca805f Cleanup debug stuff 2023-10-24 11:10:16 +03:00
Mykola Baibuz
c772f56da7 Fixes after merge 2023-10-24 11:00:40 +03:00
Mykola Baibuz
bc183e39bb Merge branch 'feature/split-tunnel-mobile' of github.com:amnezia-vpn/amnezia-client into feature/split-tunnel-mobile 2023-10-24 00:35:58 +03:00
Mykola Baibuz
306d4f70a8 Update NE Sources 2023-10-24 00:33:35 +03:00
Mykola Baibuz
a386d39495 iOS Cloak/OVPN SplitTunnel 2023-10-24 00:28:41 +03:00
Mykola Baibuz
22b14dff5f iOS AWG/WG split tunnel 2023-10-23 22:42:02 +03:00
pokamest
e749cc7578 Update amneziavpn_ru.ts
Typo fix
2023-10-23 20:32:28 +01:00
vladimir.kuznetsov
6a12cad1c9 fixed page return after installation 2023-10-23 21:33:07 +05:00
Mykola Baibuz
c15665803d Merge branch 'dev' into feature/split-tunnel-mobile 2023-10-22 15:26:20 -04:00
pokamest
97090888d5 Bump version 2023-10-22 08:11:37 -07:00
pokamest
4642308fbb Merge pull request #374 from amnezia-vpn/bugfix/split-tunneling
Bugfix/split tunneling
2023-10-22 08:02:43 -07:00
vladimir.kuznetsov
59bccb1188 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into bugfix/split-tunneling 2023-10-22 20:00:39 +05:00
pokamest
cd8fc007ac Merge pull request #392 from amnezia-vpn/bugfix/existing-awg-container
added getting awg parameters when adding an already installed awg container
2023-10-22 07:49:34 -07:00
vladimir.kuznetsov
7cfb38307e removed re-processing of server config for awg 2023-10-22 18:04:34 +05:00
vladimir.kuznetsov
994aa32745 added getting awg parameters when adding an already installed awg container 2023-10-22 17:31:13 +05:00
Mykola Baibuz
f0b872e86b Merge remote-tracking branch 'origin/bugfix/pull-awg-config' into feature/split-tunnel-mobile 2023-10-21 23:24:54 +03:00
Mykola Baibuz
0c33432436 Fix pulling exiting AWG config from server 2023-10-21 14:55:15 -04:00
pokamest
0bb4dd9442 Text and translations fixes 2023-10-21 18:32:30 +01:00
pokamest
7a54dc15da Update amneziavpn_ru.ts 2023-10-21 16:33:21 +01:00
pokamest
e16a1100d8 Update amneziavpn_ru.ts 2023-10-21 16:20:57 +01:00
pokamest
99214e22e3 Fix docs url 2023-10-21 16:05:09 +01:00
pokamest
c77d35a2ed Merge pull request #390 from amnezia-vpn/revert-370-feature/custom_drawer_component
Revert "added new drawer2type for replacing drawertype"
2023-10-21 06:21:07 -07:00
pokamest
d98fdbdc5c Revert "added new drawer2type for replacing drawertype" 2023-10-21 14:17:45 +01:00
ronoaer
4551cf0a21 Merge pull request #370 from amnezia-vpn/feature/custom_drawer_component
added new drawer2type for replacing drawertype
2023-10-21 09:34:21 +08:00
ronoaer
023c3474d2 Merge branch 'dev' into feature/custom_drawer_component 2023-10-21 09:28:41 +08:00
pokamest
2a4cefb4bf Merge pull request #387 from amnezia-vpn/bugfix/awg-mtu-len-fix
Fix MTU len for Win WG/AWG
2023-10-20 15:02:29 -07:00
Mykola Baibuz
09305724fa Fix MTU len for Win WG/AWG 2023-10-20 16:44:30 -04:00
pokamest
360fda1ba7 Merge pull request #386 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Bugfix/minor UI fixes 4 version
2023-10-20 12:23:03 -07:00
vladimir.kuznetsov
dadf0cf96e Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into dev 2023-10-20 21:51:40 +05:00
vladimir.kuznetsov
3d60ac751e removed the default protocol/server change if connected to VPN 2023-10-20 20:52:14 +05:00
pokamest
32793eef8c Merge pull request #385 from amnezia-vpn/bugfix/translated_new_source_strings_to_chinese
translated new source strings to chinese
2023-10-20 06:36:17 -07:00
ronoaer
da1cdfd6fa translated new source strings to chinese 2023-10-20 18:01:57 +08:00
vladimir.kuznetsov
58ad7dc161 removed the "remove protocol" buttons from where they shouldn't be 2023-10-20 14:10:04 +05:00
ronoaer
0a15f44193 removed states 'opened', 'closed' 2023-10-20 10:38:12 +08:00
pokamest
e1dec3c1ba Merge pull request #384 from amnezia-vpn/bugfix/startCentos7docker
Restoring autostart and enable docker for CentOS 7
2023-10-19 18:30:45 -07:00
pokamest
7834860245 Merge pull request #383 from amnezia-vpn/feature/awg-random-values
Feature/awg random values
2023-10-19 18:28:13 -07:00
pokamest
2da1025f26 Random port on install 2023-10-20 02:25:40 +01:00
Mykola Baibuz
78c83b2e21 Some logic fix 2023-10-19 17:03:24 -04:00
Mykola Baibuz
414a47e2f2 WG/AWG Desktop AllowedIP from plain WG config 2023-10-19 14:50:51 -04:00
ronoaer
6c78b4ec8f enabled drag-pagehome-drawer in tabBar 2023-10-19 23:01:03 +08:00
ronoaer
a6949bd3ae resized questiondrawer of page serverdata 2023-10-19 19:45:22 +08:00
ronoaer
f7bed04ab2 removed invalid function code 2023-10-19 19:32:15 +08:00
ronoaer
6ec773079c added hovering effect of button 2023-10-19 11:22:52 +08:00
ronoaer
366e27a321 re-adatped pagehome 2023-10-19 09:27:39 +08:00
Mykola Baibuz
32c304dc1b WG/AWG SplitTunnel for desktop 2023-10-18 17:44:28 -04:00
vladimir.kuznetsov
338499247d changed the display order of containers 2023-10-19 01:16:36 +05:00
vladimir.kuznetsov
79e1761c1f added generation of random values for awg parameters 2023-10-19 01:14:09 +05:00
Mykola Baibuz
4ea1a19572 Cleanup WG implementation 2023-10-18 13:41:58 -04:00
pokamest
e2ae341ba9 AndroidManifest fix 2023-10-18 14:01:06 +01:00
pokamest
de03435bac Merge pull request #381 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Bugfix/minor UI fixes 4 version
2023-10-18 04:05:18 -07:00
pokamest
e16c425f87 PageHome.qml fix 2023-10-18 12:04:39 +01:00
ronoaer
c461e00c5c keeping parent's cusorshape and Drawer2Type's close-animation 2023-10-18 16:17:57 +08:00
vladimir.kuznetsov
fcf6bb43b7 Merge branch 'bugfix/split-tunneling' of github.com:amnezia-vpn/amnezia-client into bugfix/split-tunneling 2023-10-18 12:18:46 +05:00
vladimir.kuznetsov
f5f72f87a6 fixed switcher status display for page split site tunneling 2023-10-18 12:17:24 +05:00
vladimir.kuznetsov
3340451245 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into bugfix/split-tunneling 2023-10-18 11:55:24 +05:00
Mykola Baibuz
c14f1b5000 Android OpenVPN/Cloak Split tunnel 2023-10-17 16:39:56 -04:00
vladimir.kuznetsov
a46e55d5c2 added a dash for drawerType 2023-10-18 01:11:41 +05:00
vladimir.kuznetsov
4b64bfaec0 fixed questionDrawer height 2023-10-18 00:37:15 +05:00
vladimir.kuznetsov
2f0c1eeecc fixed selection of default container after installing a new server 2023-10-18 00:36:40 +05:00
Mykola Baibuz
546d4c1d3d WG/AWG Android splitTunnel 2023-10-17 14:54:46 -04:00
lunardunno
160d88f002 Restoring autostart and enable docker for CentOS 7 2023-10-17 21:26:50 +04:00
ronoaer
a83cd29f72 fixed the cursorShape, and some minor issues 2023-10-17 22:00:19 +08:00
pokamest
94304b5777 Version bump 2023-10-17 14:47:31 +01:00
pokamest
61ddfe01a1 macos build script updated [no ci] 2023-10-17 06:39:49 -07:00
pokamest
00d334f704 Merge pull request #377 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
disabled the ability to change the protocol/server when a vpn connection is active
2023-10-17 05:39:51 -07:00
pokamest
f4a4979997 Merge pull request #378 from amnezia-vpn/bugfix/updated_chinese_translations
updated Chinese translations for updating source strings
2023-10-17 05:11:19 -07:00
ronoaer
03171e4743 update background color and drag-effect, moved dulicated code 2023-10-17 19:34:34 +08:00
ronoaer
5369e68267 updated Chinese translations for updating source strings 2023-10-17 14:30:59 +08:00
vladimir.kuznetsov
9eb23e38bd disabled the ability to change the protocol/server when a vpn connection is active 2023-10-16 22:57:12 +05:00
Mykola Baibuz
2a0166bb26 Merge branch 'bugfix/split-tunneling' of https://github.com/amnezia-vpn/amnezia-client into bugfix/split-tunneling 2023-10-16 12:05:50 -04:00
Mykola Baibuz
2df612ec1f Android SplitTunnel 2023-10-16 12:05:35 -04:00
pokamest
36ba3758db Translation updates 2023-10-16 15:27:26 +01:00
ronoaer
7cc0f39d3c adapted pagehome by new custom drawer type 2023-10-16 22:21:01 +08:00
vladimir.kuznetsov
9cf5590371 disabled split site tunneling for awg 2023-10-16 15:17:09 +05:00
pokamest
81f835458f Merge pull request #375 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Bugfix/minor UI fixes 4 version
2023-10-16 03:10:53 -07:00
vladimir.kuznetsov
e01b1db706 text corrections 2023-10-16 14:34:03 +05:00
vladimir.kuznetsov
cdb18de305 brought back the ability to share wireguard native format configs 2023-10-16 13:43:27 +05:00
vladimir.kuznetsov
8e0eef3316 fixed selection of default container after installing a new container 2023-10-16 13:40:43 +05:00
vladimir.kuznetsov
221d45f564 fixed pageSettingsDns width 2023-10-16 13:32:56 +05:00
vladimir.kuznetsov
2a4a01a4be removed split site tunneling page blocking when switcher is turned off 2023-10-16 13:28:37 +05:00
Mykola Baibuz
501670bdd2 Merge branch 'feature/split-tunneling-config' into bugfix/split-tunneling 2023-10-15 15:10:05 -04:00
vladimir.kuznetsov
24637a1693 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-10-15 21:08:45 +05:00
vladimir.kuznetsov
7bd1340190 fixed display of sites on page split tunneling 2023-10-15 20:41:49 +05:00
ronoaer
cb5c09d967 adapted questionDrawer 2023-10-15 21:29:01 +08:00
pokamest
a01ba5909c Version bump 2023-10-15 12:53:44 +01:00
pokamest
1c4678af95 Merge pull request #373 from amnezia-vpn/fix/update_ru_ts
Updated ru ts #2
2023-10-15 04:43:04 -07:00
pokamest
5f5435c645 Updated ru ts 2023-10-15 12:41:01 +01:00
pokamest
2f7dc2c46c Merge pull request #372 from amnezia-vpn/fix/update_ru_ts
Update ru translation
2023-10-15 04:38:29 -07:00
pokamest
9bc1c9dd03 Merge branch 'dev' into fix/update_ru_ts 2023-10-15 12:30:13 +01:00
pokamest
4c81cdb4a2 Update translation 2023-10-15 12:29:41 +01:00
pokamest
3406ffa7a2 Merge pull request #371 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Minor UI fixes 4 version
2023-10-15 02:54:27 -07:00
pokamest
6d05b6845e VPN protocol descriptions updated 2023-10-15 10:53:09 +01:00
ronoaer
29b4966119 shown ConnectionTypeSelectionDrawer on top level alway 2023-10-15 17:34:35 +08:00
ronoaer
d0f8358431 removed invalid code, and fixed top button hidden-shown 2023-10-15 17:29:22 +08:00
ronoaer
a75bd07cd8 fixed the clicked event 2023-10-15 15:54:05 +08:00
ronoaer
8c1835950b added transparent-background, for blocking clicked event 2023-10-15 15:17:04 +08:00
pokamest
c7cd8e4c80 Minor ui fixes and refactoring 2023-10-15 02:30:42 +01:00
pokamest
f65e4066e3 ui fixes 2023-10-14 23:59:46 +01:00
vladimir.kuznetsov
37c18c5d3c Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into dev 2023-10-14 21:25:09 +05:00
vladimir.kuznetsov
8885f580b2 added notification after saving backup and logs files 2023-10-14 21:18:38 +05:00
vladimir.kuznetsov
512ac74ee6 temporarily disabled the drawer close button 2023-10-14 20:59:03 +05:00
ronoaer
384ce9853b added new drawer2type for replacing drawertype 2023-10-14 23:00:31 +08:00
pokamest
b6d2030041 Ru translation 2023-10-14 15:55:52 +01:00
pokamest
3ac09181c6 Text lables fixes 2023-10-14 15:55:07 +01:00
vladimir.kuznetsov
ffc9e5823a text corrections 2023-10-14 18:21:49 +05:00
vladimir.kuznetsov
f5448fed59 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into dev 2023-10-14 16:58:14 +05:00
vladimir.kuznetsov
8163e51434 fixes on page split tunneling according to the design layout 2023-10-14 16:52:22 +05:00
pokamest
3836836c72 Change easySetupOrder 2023-10-14 02:15:49 +01:00
vladimir.kuznetsov
b78bf39767 added split tunneling to the config 2023-10-13 15:45:06 +05:00
pokamest
7c8399ce88 Fix awg description 2023-10-12 13:57:58 +01:00
pokamest
9fe2a1dd41 Merge pull request #354 from amnezia-vpn/feature/amnezia-wireguard-client-impl
AWG protocol implementation
2023-10-12 03:39:59 -07:00
Nethius
846f554157 Merge pull request #366 from amnezia-vpn/bigfix/updated_translation_for_wg
updated translations for branch feature/amnezia-wireguard-client-impl
2023-10-12 15:44:12 +07:00
ronoaer
d1f66cbf4d updated translations for branch feature/amnezia-wireguard-client-impl 2023-10-12 16:26:37 +08:00
vladimir.kuznetsov
a4624c7377 removed the close button for the app for mobile platforms 2023-10-12 10:57:13 +05:00
pokamest
10435cea69 Tiny refactoring and text fixes 2023-10-12 01:15:05 +01:00
pokamest
ce9a23e021 Merge branch 'dev' into feature/amnezia-wireguard-client-impl 2023-10-11 19:40:40 +01:00
pokamest
4b7c8f21c2 Merge pull request #364 from amnezia-vpn/bigfix/reset_topbutton_xposition
updated x position of topbutton  when resize window
2023-10-11 11:37:17 -07:00
pokamest
6ddebdbbd1 Merge pull request #365 from amnezia-vpn/bugfix/container-config-on-connect
fixed container config synchronization
2023-10-11 11:36:39 -07:00
pokamest
d92729d346 Fix install_docker.sh 2023-10-11 15:30:55 +01:00
Mykola Baibuz
fa06dbbd29 Bump Android verion 2023-10-10 08:52:36 -04:00
vladimir.kuznetsov
5d59a1a10e fixed an error when after the first connection with admin config the container model was not updated 2023-10-10 12:18:56 +03:00
vladimir.kuznetsov
222a251180 Merge branch 'feature/amnezia-wireguard-client-impl' of github.com:amnezia-vpn/amnezia-client into feature/amnezia-wireguard-client-impl 2023-10-10 14:16:02 +05:00
vladimir.kuznetsov
9d6559f0d7 fixed an error when after the first connection with admin config the container model was not updated 2023-10-10 12:50:41 +05:00
ronoaer
da02f49850 update x value of topbutton when resize window 2023-10-10 08:43:56 +08:00
Mykola Baibuz
992961c488 Update Windows WG to AWG protocol support 2023-10-09 16:32:43 -04:00
vladimir.kuznetsov
0ce30a4e81 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/amnezia-wireguard-client-impl 2023-10-09 23:19:48 +05:00
vladimir.kuznetsov
bb2d794b6f corrections to the text 2023-10-09 23:18:24 +05:00
Nethius
45dc302de4 Merge pull request #362 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Bugfix/minor UI fixes 4 version
2023-10-10 01:12:57 +07:00
vladimir.kuznetsov
4a2706a9d9 increased the application version to 4.0.8.1 2023-10-09 23:00:53 +05:00
vladimir.kuznetsov
00be3c3ccc corrections to the text 2023-10-09 22:54:33 +05:00
vladimir.kuznetsov
cb7fe50d46 added margins for picture with qr code 2023-10-09 22:40:06 +05:00
vladimir.kuznetsov
d364dbac2c now when a new container is installed, it is selected as the default container 2023-10-09 22:39:32 +05:00
vladimir.kuznetsov
042788bec3 moved add new server button to main tabbar 2023-10-09 20:19:22 +05:00
Mykola Baibuz
def261f578 Merge branch 'dev' into feature/amnezia-wireguard-client-impl 2023-10-09 11:00:37 -04:00
Mykola Baibuz
c08e23085e Fix protocol change from AWG to WG for Android 2023-10-09 10:29:42 -04:00
vladimir.kuznetsov
e01dd2bf57 added close application button in settings page 2023-10-09 19:16:06 +05:00
pokamest
61396ec82e Merge pull request #361 from amnezia-vpn/fix/android-accessibility
Disable android accessibility
2023-10-08 12:43:05 -07:00
albexk
357c283437 Disable android accessibility 2023-10-08 20:08:32 +03:00
Nethius
1b38cd6ca7 Merge pull request #360 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
Bugfix/minor UI fixes 4 version
2023-10-08 23:15:34 +07:00
Mykola Baibuz
bdfa8bfe5b AWG Android support 2023-10-07 09:01:29 -04:00
Mykola Baibuz
7f2ef65fe6 Update WG to AWG for Android 2023-10-06 17:20:41 -04:00
vladimir.kuznetsov
102d0472c7 Merge branch 'feature/amnezia-wireguard-client-impl' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-10-06 22:06:50 +05:00
vladimir.kuznetsov
445fc6efb1 renamed amneziawireguard to awg in ios controller 2023-10-06 22:05:48 +05:00
pokamest
135726f177 Merge branch 'dev' into feature/amnezia-wireguard-client-impl 2023-10-06 14:22:45 +01:00
vladimir.kuznetsov
671ca0a66f renamed amneziawireguard to awg 2023-10-06 17:26:45 +05:00
vladimir.kuznetsov
aa4a79934a renamed amenziawireguard to awg 2023-10-06 17:19:44 +05:00
vladimir.kuznetsov
16fc0617e4 renamed amneziawireguard files to awg 2023-10-06 17:02:28 +05:00
vladimir.kuznetsov
64a2f3f8bb Merge branch 'feature/amnezia-wireguard-client-impl' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-10-06 16:44:58 +05:00
vladimir.kuznetsov
b7a65343af added the ability to change awg parameters on the protocol settings page 2023-10-06 16:43:52 +05:00
Nethius
5c121ea48d Merge pull request #353 from amnezia-vpn/feature/added_i18n_for_v4
added i18n for v4
2023-10-06 11:49:17 +03:00
ronoaer
673f28ed64 retanslate donation way 2023-10-06 16:32:04 +08:00
ronoaer
3fb97d16bb updated about page 2023-10-06 15:49:48 +08:00
ronoaer
079c9176ef fixed minor issues of translation 2023-10-06 15:29:15 +08:00
ronoaer
9377a0b545 updated translated-text to connectStatusText in ConnectionController 2023-10-06 14:37:10 +08:00
ronoaer
1357c4a309 applied translation-funcation to SystemTray 2023-10-06 13:43:32 +08:00
Mykola Baibuz
d77be5a244 Update iOS network extension 2023-10-06 00:38:54 +03:00
Mykola Baibuz
08863edb52 Update AWG iOS binary again 2023-10-05 17:11:40 -04:00
Mykola Baibuz
3a77705142 Update AWG binary 2023-10-05 15:55:32 -04:00
ronoaer
1eafa9a38a updated about and tor 2023-10-05 23:47:50 +08:00
vladimir.kuznetsov
396b7aac18 fixed display of amnezia dns description on main menu 2023-10-05 13:56:00 +05:00
ronoaer
08defbbbd8 updated original string format, for adapting multi-language 2023-10-05 13:26:11 +08:00
ronoaer
79d371fb76 translated pages from english to chinese 2023-10-05 00:54:49 +08:00
vladimir.kuznetsov
9df262d502 fixed sending parameters to the awg daemon for windows 2023-10-04 19:14:27 +03:00
pokamest
6f392ce126 Crash on exit fix for Windows 2023-10-04 16:09:03 +01:00
vladimir.kuznetsov
a83ec10b61 updated description for full access sharing 2023-10-04 14:47:49 +05:00
vladimir.kuznetsov
a93f75fb5a added full version to page about 2023-10-04 14:40:17 +05:00
ronoaer
2353cc4f2c translated sub-page of Settings to Chinese 2023-10-04 15:48:35 +08:00
ronoaer
30709c66ef translated settings page 2023-10-04 09:05:29 +08:00
Nethius
70e6a3d303 Merge pull request #359 from amnezia-vpn/bugfix/minor-ui-fixes-4-version
minor ui fixes
2023-10-03 21:48:30 +03:00
Nethius
cc89939d05 Merge pull request #356 from amnezia-vpn/bugfix/buton_set_up_later_visible_logic
updated visible logic of button 'set up later'
2023-10-03 21:29:23 +03:00
vladimir.kuznetsov
7d4a01c757 minor ui fixes 2023-10-03 23:28:44 +05:00
vladimir.kuznetsov
e2d61cb518 renamed functions and variables 2023-10-03 22:38:17 +05:00
Nethius
fb1a9c9867 Merge pull request #357 from amnezia-vpn/feature/allow-android-screenshots
Added switcher "Allow app screenshots" for android
2023-10-03 20:24:10 +03:00
vladimir.kuznetsov
776ae04cbe Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-10-03 22:23:24 +05:00
Nethius
2447ab4305 Merge pull request #352 from amnezia-vpn/fix/drawerTypePositioning
Limit Drawer positioning by dragHeight and total page height
2023-10-03 19:37:58 +03:00
vladimir.kuznetsov
52124b15e8 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into fix/drawerTypePositioning 2023-10-03 19:00:58 +05:00
vladimir.kuznetsov
b1e9e8677b Merge branch 'fix/drawerTypePositioning' of github.com:amnezia-vpn/amnezia-client into fix/drawerTypePositioning 2023-10-03 18:53:16 +05:00
vladimir.kuznetsov
617e772cc1 added transitions and open/close by clicking on an item for the center menu button 2023-10-03 18:49:54 +05:00
ronoaer
27f770604b tried to translate some pages, from English to Chinese 2023-10-03 15:59:53 +08:00
Matthew Schwiebert
5bfc581ad2 add documentation, remove uneeded changes of drawertype 2023-10-02 15:40:25 -04:00
vladimir.kuznetsov
2664a52007 removed the dropdown with protocols on the share full access page 2023-10-02 22:04:18 +05:00
vladimir.kuznetsov
6dbbf1fc89 added parsing parameters for windows 2023-10-02 18:48:11 +03:00
vladimir.kuznetsov
c254f2fdc4 Merge branch 'feature/amnezia-wireguard-client-impl' of github.com:amnezia-vpn/desktop-client into feature/amnezia-wireguard-client-impl 2023-10-02 18:21:00 +03:00
vladimir.kuznetsov
cf450fa4e4 Merge remote-tracking branch 'origin/feature/amnezia-wireguard-client-impl' into HEAD 2023-10-02 20:04:40 +05:00
vladimir.kuznetsov
304f29bfac returned 'address' to awg server config and set it to 10.8.1.1/24 2023-10-02 20:03:01 +05:00
vladimir.kuznetsov
50b8b3d649 added parsing of wireguard config parameters when importing native configs 2023-10-02 18:30:32 +05:00
vladimir.kuznetsov
4e6c1094f3 minor ui fixes 2023-10-02 16:31:50 +05:00
Matthew Schwiebert
a6134ca10f fix visibility bug of collapsed state 2023-10-01 20:43:39 -04:00
Matthew Schwiebert
3d999a503c Add custom drawer behavior to pageHome, for mobile and desktop 2023-10-01 20:35:05 -04:00
vladimir.kuznetsov
39c2124a26 returned the awg setting via wg-quick 2023-10-01 21:43:30 +05:00
vladimir.kuznetsov
4e3955b39d Added switcher "Allow app screenshots" for android 2023-10-01 12:15:41 +03:00
ronoaer
784ae0da53 updated visible logic of button 'set up later' 2023-10-01 12:11:13 +08:00
ronoaer
eaede032b4 1. updated memory text when language changed,
2. updated initialize index
2023-10-01 11:12:27 +08:00
Mykola Baibuz
4ed153373f Fix Linux build, some naming changes 2023-09-30 16:05:23 -04:00
ronoaer
07d7fac490 removed invalid code 2023-09-30 17:40:26 +08:00
ronoaer
5535b6a6e3 embedded qm files into qrc file 2023-09-30 17:36:06 +08:00
Mykola Baibuz
b7fbb84a58 iOS AWG protocol Setup 2023-09-30 00:58:08 +03:00
vladimir.kuznetsov
19bd94ed02 Merge branch 'feature/amnezia-wireguard-client-impl' of github.com:amnezia-vpn/amnezia-client into feature/amnezia-wireguard-client-impl 2023-09-29 18:42:45 +05:00
vladimir.kuznetsov
54b45a36e1 test configuration using wg instead of wg-quick to configure the server 2023-09-29 18:41:00 +05:00
Nethius
ed1afa7549 Merge pull request #348 from amnezia-vpn/bugfix/changed_textfield_border_hover_color
added border hover effect for textarea
2023-09-29 16:24:28 +03:00
Mykola Baibuz
2986a18c8f iOS AWG support 2023-09-28 23:54:32 +03:00
Nethius
b2072c06b7 Merge pull request #355 from amnezia-vpn/fixbug/not_hide_topright_corner_button
Fixbug/not hide topright corner button
2023-09-28 23:39:22 +03:00
Nethius
762018883f Merge pull request #347 from amnezia-vpn/bigfix/no_container_redirecteto_wizardeasy
redirected to pagesetupwizardeasy when none containers installed
2023-09-28 21:01:55 +03:00
Nethius
0322c01c0e Merge pull request #340 from amnezia-vpn/bugfix/add_hover_in_home_page
added  hover effect for default-server in pagehome
2023-09-28 20:55:57 +03:00
Nethius
16ccfb8714 Merge pull request #349 from amnezia-vpn/bugfix/changed_cursorshape_for_cardtype
updated cursorshape of cardtype to Qt.PointingHandCursor
2023-09-28 20:55:03 +03:00
ronoaer
68095700a2 added i18n for v4 2023-09-28 23:21:13 +08:00
Matthew Schwiebert
058f8b544e Limit Drawer positioning by dragHeight and total page height 2023-09-28 10:14:01 -04:00
vladimir.kuznetsov
4cb871849b Merge remote-tracking branch 'remotes/origin/dev' into feature/amnezia-wireguard-client-impl 2023-09-28 00:26:26 +03:00
vladimir.kuznetsov
423305c35a moved the configuration of new parameters for awg to addInterface() 2023-09-28 02:14:07 +05:00
vladimir.kuznetsov
b55313527e added passing new amneziawireguard config parameters over uapi for all platforms 2023-09-27 00:45:42 +05:00
vladimir.kuznetsov
af53c456ea added passing new wireguard config parameters over uapi and configuring the amneziawireguard container 2023-09-27 00:40:01 +05:00
ronoaer
37024eb91d updated cursorshape of cardtype to Qt.PointingHandCursor 2023-09-26 17:23:35 +08:00
ronoaer
ee99565b63 1. added border-hover-interaction
2. updated textarea-focus-interaction
2023-09-26 16:38:08 +08:00
pokamest
1a8c08799f Merge pull request #346 from amnezia-vpn/bugfix/win-build
Windows. Remove unused binary from build files
2023-09-25 09:48:15 -07:00
ronoaer
8b08a5bee0 added border hover effect for textarea 2023-09-25 22:16:59 +08:00
ronoaer
51497d87e0 redirected to pagesetupwizardeasy when none containers installed 2023-09-25 07:22:11 +08:00
Mykola Baibuz
7ede1a8d83 Remove unused binary from build files 2023-09-24 22:09:30 +03:00
Mykola Baibuz
b4df5c076e Fix Linux App startup icon (#344)
* Fix Linux App startup icon
* Use project version from cmake
* Set Release date automatically
2023-09-24 16:57:59 +01:00
Mykola Baibuz
52400252dd Fix disconnect button for desktop WG (#345)
* Fix disconnect button for desktop WG
2023-09-24 12:06:52 +01:00
ronoaer
49923c4214 renamed deaultservertype, and moved to components 2023-09-24 08:21:27 +08:00
ronoaer
81b77c9688 Merge branch 'feature/new-gui' into fixbug/not_hide_topright_corner_button 2023-09-22 06:28:02 +08:00
vladimir.kuznetsov
7284bb54bc Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/amnezia-wireguard-client-impl 2023-09-22 00:39:32 +05:00
vladimir.kuznetsov
6afdd8375d added models, classes and ui files for amnezia wireguard 2023-09-22 00:37:55 +05:00
pokamest
af23d9fd14 Merge pull request #209 from amnezia-vpn/feature/new-gui
feature/new-gui
2023-09-21 12:07:22 -07:00
pokamest
e7aead292c Merge pull request #341 from amnezia-vpn/feature/icons-android-round
Android round icons
2023-09-21 11:53:09 -07:00
Mykola Baibuz
fd2678ce2f Android round icons
Icons for some older Android phones that use round icons.
2023-09-21 14:45:46 -04:00
Nethius
a6d660e708 Merge pull request #336 from amnezia-vpn/bugfix/close_drawer_easily
Bugfix/close drawer easily, short distance with dragging
2023-09-21 20:18:43 +05:00
ronoaer
de35a26285 added hover effect for default-server in pagehome 2023-09-21 23:03:12 +08:00
vladimir.kuznetsov
18bb045e9a Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-09-21 19:41:41 +05:00
pokamest
6fa9994366 Merge pull request #335 from amnezia-vpn/feature/linux-wg-rework
WireGuard rework for Linux
2023-09-21 05:43:10 -07:00
pokamest
665f2412f1 Version bump, macos/ios build fix [no ci] 2023-09-21 05:14:15 -07:00
pokamest
395099aa40 Merge pull request #338 from amnezia-vpn/bugfix/windows_signing_fix
build_windows.bat fix
2023-09-21 04:13:04 -07:00
pokamest
97a72a9ee2 build_windows.bat fix 2023-09-21 11:28:18 +01:00
pokamest
3414202b7b Merge pull request #332 from amnezia-vpn/bugfix/wireguard-config-import
added parsing of wireguard config parameters when importing native configs
2023-09-21 03:23:41 -07:00
Mykola Baibuz
52e5453d56 Upload AWG binary 2023-09-20 14:27:28 -04:00
ronoaer
dd039a612f used position-changed to closes drawer 2023-09-20 14:18:21 +08:00
Mykola Baibuz
f5ab034aeb WG routing rework for Linux 2023-09-19 17:59:04 -04:00
ronoaer
893ec2d61c researching: tried to close drawer easily 2023-09-20 00:18:10 +08:00
vladimir.kuznetsov
ff41b26e94 added parsing of wireguard config parameters when importing native configs 2023-09-19 18:45:06 +05:00
vladimir.kuznetsov
d4d6fbab88 changed the protocols for easySetup setup 2023-09-18 21:06:10 +05:00
vladimir.kuznetsov
e38fe871b2 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-09-18 20:24:15 +05:00
vladimir.kuznetsov
152d7bc3b3 added restore default settings for dns settings page 2023-09-18 17:52:41 +05:00
vladimir.kuznetsov
9e7cf3ccd9 added PageServiceDnsSettings 2023-09-18 16:39:26 +05:00
ronoaer
f7370a0280 fixed: topright-corner button not visible when drawer closed 2023-09-18 14:35:22 +08:00
Nethius
814c574f26 Merge pull request #328 from amnezia-vpn/bugfix/add_top_close_button
added close button when drawer shown in the topright corner
2023-09-18 10:48:13 +05:00
Nethius
fd9f9ee178 Merge pull request #320 from amnezia-vpn/bugfix/scroll_stuck_on_fl_textarea
fixed scroll stuck on textarea in page OpenVpnSettings
2023-09-18 10:47:58 +05:00
ronoaer
29e8f8f5fb Merge branch 'feature/new-gui' into bugfix/scroll_stuck_on_fl_textarea 2023-09-18 07:36:01 +08:00
Mykola Baibuz
279692afea WireGuard rework for Linux 2023-09-17 17:06:24 -04:00
vladimir.kuznetsov
fd09321f8e removed the 'mount sftp folder' button for mobile platforms 2023-09-18 00:16:58 +05:00
vladimir.kuznetsov
ad236baa86 fixed a typo in the variable name 2023-09-17 23:24:21 +05:00
vladimir.kuznetsov
8965b1fbba fixed the size of the drawer close button 2023-09-17 23:21:00 +05:00
vladimir.kuznetsov
9b32411659 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-09-17 17:07:28 +05:00
Nethius
32dda9b904 Merge pull request #325 from amnezia-vpn/bugfix/reconnectvpn_when_dc_changed
auto reconection when current-server's defaul container hase been cha…
2023-09-17 17:06:02 +05:00
vladimir.kuznetsov
c0cb5b96bf added reconnection to vpn after changing any protocol settings 2023-09-17 17:03:39 +05:00
Nethius
ff60030ffb Merge pull request #329 from amnezia-vpn/bugfix/text_not_saved_after_edited
fixed additional info can not be save in page OpenVpn settings
2023-09-17 15:17:28 +05:00
vladimir.kuznetsov
f40bf2d9ba limited the length of the displayed server name
- added auto-selection of the first available protocol when changing the server on the PageShare page
2023-09-17 15:01:31 +05:00
ronoaer
9eebee3ce3 fixed additional info can not be save in page OpenVpn settings 2023-09-16 16:20:19 +08:00
ronoaer
8a3bdf136b added close button when drawer shown in the topright corner 2023-09-16 08:05:43 +08:00
Mykola Baibuz
f62076d3fd Android 8 support (#321) 2023-09-15 19:42:04 +01:00
pokamest
92f4d6b392 Merge pull request #327 from amnezia-vpn/feature/android-icon
Update Android icons
2023-09-14 23:39:10 +01:00
Mykola Baibuz
96ffd7e147 Update Android icons 2023-09-14 23:44:57 +03:00
Mykola Baibuz
07c38e9b6c WireGuard rework for MacOS and Windows (#314)
WireGuard rework for MacOS and Windows
2023-09-14 17:44:17 +01:00
vladimir.kuznetsov
c0aca97083 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into HEAD 2023-09-14 21:26:13 +05:00
vladimir.kuznetsov
2fd25f53cc fixed auto-connection starting after starting the application 2023-09-14 15:35:24 +05:00
vladimir.kuznetsov
2b3383a163 removed the transition animation between tabs in the main menu
- fixed Drawer freezing when importing files from outside the application
2023-09-14 15:21:35 +05:00
pokamest
421a27ceae Merge pull request #326 from amnezia-vpn/feature/issue-template
Update issue templates
2023-09-13 17:24:32 -07:00
pokamest
10022451b4 Update issue templates 2023-09-14 01:20:38 +01:00
Nethius
3c8d923299 Merge pull request #322 from amnezia-vpn/bugfix/reconnect_server_when_changevp
reconnect to server when changed the protocol and status is connected…
2023-09-13 20:48:37 +05:00
Nethius
154044e32a Merge pull request #323 from amnezia-vpn/bugfix/linktext_cursor_sftp
the cursor changes to Qt.PointingHandCursor when hovering over links
2023-09-13 20:47:21 +05:00
ronoaer
bfc8c10f3d auto reconection when current-server's defaul container hase been changed 2023-09-13 20:49:44 +08:00
vladimir.kuznetsov
d93b5a7b5c fixed saving of configs for mobile platforms 2023-09-13 16:34:03 +05:00
vladimir.kuznetsov
4ae608ed93 added import backup file from outside for ios 2023-09-13 16:11:08 +05:00
vladimir.kuznetsov
e2aef1fc1d fixed display of installation errors on the initial installation screen 2023-09-13 11:09:29 +05:00
ronoaer
16cadfeae8 the cursor changes to Qt.PointingHandCursor when hovering over links 2023-09-13 09:39:17 +08:00
ronoaer
3c9b42b9f7 deleted unused code 2023-09-13 08:44:50 +08:00
ronoaer
9c0f27edb4 removed invalid codes 2023-09-13 08:01:14 +08:00
ronoaer
f81ee1b267 reconnect to server when changed the protocol and status is connected or connnecting 2023-09-12 21:38:36 +08:00
ronoaer
a964d955f4 fixed scroll stuck on textarea in page OpenVpnSettings 2023-09-11 23:49:50 +08:00
Nethius
f11c65c393 Merge pull request #319 from amnezia-vpn/fix_install_error_in_procotolpage
fixed the implicitWidth error in protocol installation page
2023-09-11 16:49:46 +05:00
vladimir.kuznetsov
f8e5e9f675 fixed display of cursorShape for all mouseArea 2023-09-11 16:48:56 +05:00
ronoaer
72eb36f5b3 fixed the implicitWidth error in protocol installation page 2023-09-11 18:55:50 +08:00
vladimir.kuznetsov
97c0fe1ece increased the application version to 4.0.5.1 2023-09-11 14:55:52 +05:00
vladimir.kuznetsov
844b552bf3 removed duplicate function routeMode 2023-09-11 14:45:10 +05:00
vladimir.kuznetsov
6bb85deca6 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-09-11 14:03:14 +05:00
vladimir.kuznetsov
551f7616f0 fixed the display of the protocol list in the settings when attempting to install a container that is already installed on the server 2023-09-11 13:56:49 +05:00
pokamest
285c508329 VPN mode fixes for Android and iOS 2023-09-10 17:40:18 -07:00
vladimir.kuznetsov
f751657903 fixed false triggering of swipes for the main menu drawer of PageHome 2023-09-09 22:41:36 +05:00
vladimir.kuznetsov
89096554e8 added constructor for MobileUtils.cpp 2023-09-09 18:31:04 +05:00
vladimir.kuznetsov
4bf6cce4ba fixed return type of sharedText function 2023-09-09 18:25:44 +05:00
vladimir.kuznetsov
85eae0b74a Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-09-09 15:01:03 +05:00
vladimir.kuznetsov
0a5657738e added a wait for the file dialog to close when sharing ios files 2023-09-09 15:00:34 +05:00
ronoaer
3aa0adbf39 fixed conflicts 2023-09-09 08:52:16 +08:00
Nethius
7dc21ce8a7 Merge pull request #317 from amnezia-vpn/adapt_mac_installer_wizard
adapted installer wizard to macos style
2023-09-09 01:30:45 +05:00
Nethius
6a6b200861 Merge pull request #316 from amnezia-vpn/fixed_protocol_reload_old_value
fixed: protocol reloads old value in settings page
2023-09-09 01:30:21 +05:00
vladimir.kuznetsov
1c7868312d added getting the path to the file for iOS 2023-09-09 01:29:28 +05:00
pokamest
90d1c16783 Merge pull request #315 from amnezia-vpn/installer_adapt_macos_wrap_text
updated installer-wizardstyle for adapting macos, especially text doe…
2023-09-08 12:29:31 -07:00
ronoaer
3cfca046ba adapted installer wizard to macos style 2023-09-08 21:40:55 +08:00
ronoaer
85414eb65f fixed protocol reloads old value in settings page 2023-09-08 21:31:47 +08:00
vladimir.kuznetsov
fdff57da7c fixed navigation during initial installation 2023-09-08 18:05:08 +05:00
ronoaer
7c223feef5 updated installer-wizardstyle for adapting macos, especially text does not wrapped in the page 'ready for install' 2023-09-08 16:05:24 +08:00
pokamest
3740cb2c30 Remove unnecessary qDebug() [no ci] 2023-09-07 10:56:26 -07:00
vladimir.kuznetsov
b5dd48ad7b reworking of getting the path to the file when saving/opening files 2023-09-07 22:45:01 +05:00
pokamest
e46025739a Merge pull request #312 from amnezia-vpn/dev-fixbug-cloak-protocol-config
fixed: text field can not be updated to memory, including site and port
2023-09-07 04:50:06 -07:00
ronoaer
66a3538d05 fixed: text field can not be updated to memory, including site and port 2023-09-07 07:44:51 +08:00
vladimir.kuznetsov
e1fa24c251 moved the qml filedialog opening code below the ios section 2023-09-06 22:26:37 +05:00
vladimir.kuznetsov
a76e22c021 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-09-06 22:22:01 +05:00
vladimir.kuznetsov
c166327835 filedialog for qml moved to main.qml 2023-09-06 22:20:59 +05:00
vladimir.kuznetsov
4ab006f065 added swipe up for menu on PageHome 2023-09-06 13:37:37 +05:00
Mykola Baibuz
7eaaef6e75 Connection button status change for background start 2023-09-03 23:18:08 +03:00
Mykola Baibuz
c4f94efe24 Android fileSave fixes 2023-09-02 17:04:35 -04:00
pokamest
2eb729d712 Merge pull request #311 from amnezia-vpn/bugfix/crash_on_exit_fix
Crash on exit fix
2023-09-02 12:38:31 -07:00
pokamest
0343b6cf98 Crash on exit fix 2023-09-02 19:48:43 +01:00
vladimir.kuznetsov
7fc4ea0c68 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-09-01 20:21:33 +05:00
Mykola Baibuz
195a3ab170 Save files for iOS 2023-09-01 17:29:48 +03:00
vladimir.kuznetsov
a96f485e3c added display of all protocols in the settings after installing a new container
- set the app's max height and width to 600/800
- expanded the description when removing containers
2023-09-01 17:39:23 +05:00
Mykola Baibuz
1b3a32f83f Import config from filesystem on iOS 2023-09-01 14:49:10 +03:00
Mykola Baibuz
cacf74af3c Fix iOS build 2023-09-01 01:08:44 +03:00
vladimir.kuznetsov
4e9f68acff returned the lost comma 2023-09-01 02:07:52 +05:00
vladimir.kuznetsov
b58295d1d6 added the ability to restore settings from backup on the initial screen
- fixed the display of services in the settings for mobile devices
2023-09-01 00:48:58 +05:00
vladimir.kuznetsov
cbcf187814 added missing include files 2023-08-31 21:49:36 +05:00
vladimir.kuznetsov
4baa003c0d removed old ui files 2023-08-31 16:00:41 +05:00
vladimir.kuznetsov
8cf8c3c122 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-31 15:45:29 +05:00
vladimir.kuznetsov
e3e2c0ab6a Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-31 15:44:08 +05:00
vladimir.kuznetsov
e8862a3811 removed the use of QFileDialog 2023-08-31 15:42:59 +05:00
Mykola Baibuz
1c1a82696b Fix qrDecoder for Android 2023-08-30 17:23:55 -04:00
pokamest
a2893bac7e Fixes for sudo error "host not found" 2023-08-30 20:39:14 +01:00
Mykola Baibuz
0eda42f29f Savefile for iOS 2023-08-30 01:17:14 +03:00
pokamest
810da0db61 Fixes for iOS 2023-08-28 14:14:10 -07:00
vladimir.kuznetsov
8f6aa950cd fixed conflicts after merge 2023-08-28 22:03:28 +03:00
vladimir.kuznetsov
36a2482165 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-28 14:44:47 +03:00
vladimir.kuznetsov
639c18395b fixed display of notification about successful clearing of cached profiles
- limited the input for the Port field to only numeric values, in the range 1-65535
2023-08-28 14:18:41 +03:00
vladimir.kuznetsov
fe08fd3f0a moved the connect button to the center of the screen 2023-08-28 11:06:58 +03:00
vladimir.kuznetsov
29bef052c7 minor ui fixes 2023-08-26 10:08:50 +03:00
vladimir.kuznetsov
a74736b100 Merge branch 'bugfix/macos-installer' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-25 09:24:45 +05:00
vladimir.kuznetsov
3f7e7f2601 fixed native wireguard config import if there is no port in the Endpoint field 2023-08-25 09:20:42 +05:00
vladimir.kuznetsov
259eff3fea upgraded app version 2023-08-24 16:25:51 +05:00
vladimir.kuznetsov
c271235d16 added confirmation dialog when clearing logs and notification after clearing 2023-08-24 16:22:55 +05:00
vladimir.kuznetsov
7539afa91e Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-24 14:54:22 +05:00
vladimir.kuznetsov
4c79905f5b added autostart and start minimized options
- added disabling split tunneling when selecting the wireguard protocol
- if for macos the application is minimized to tray, then now it is not displayed in the dock
2023-08-24 14:53:52 +05:00
vladimir.kuznetsov
23ad006187 removed Widgets from service part 2023-08-23 00:20:59 +05:00
vladimir.kuznetsov
f7926847ac minor ui fixes 2023-08-22 14:37:29 +05:00
vladimir.kuznetsov
420c616e9d added authResultReceiver to android.cmake 2023-08-20 13:43:27 +05:00
vladimir.kuznetsov
822009ec5f Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-20 13:38:07 +05:00
vladimir.kuznetsov
b5e1c78461 minor ui fixes 2023-08-20 13:36:54 +05:00
vladimir.kuznetsov
0060f57b63 fixed selection of connection type on PageShare when changing protocol 2023-08-19 13:12:54 +05:00
vladimir.kuznetsov
ddaa5b784d minor ui fixes 2023-08-18 14:14:45 +05:00
vladimir.kuznetsov
a40f365a54 "added display of busy server package manager on the PageSetupWizardInstalling" 2023-08-16 23:48:25 +05:00
vladimir.kuznetsov
3964bffce4 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-16 23:47:21 +05:00
vladimir.kuznetsov
a8deb3593b dropdown list fixes to match design layout 2023-08-16 22:45:05 +05:00
vladimir.kuznetsov
e0d6e0117e Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-16 13:26:41 +05:00
vladimir.kuznetsov
e157160337 added disconnection from vpn when closing application for desktop
- many small ui fixes
2023-08-16 12:11:34 +05:00
vladimir.kuznetsov
14fa0b4fd3 added qr code scanner for ios 2023-08-13 11:28:32 +05:00
vladimir.kuznetsov
c1c68cf72d fixed ability to share warguard in native format 2023-08-10 10:02:13 +05:00
vladimir.kuznetsov
591d98d8b6 moved vpnConnection to separate thread
- added tabbar blocking when installing/removing containers
2023-08-09 18:17:29 +05:00
vladimir.kuznetsov
e0d93eaa9f Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-09 10:33:34 +05:00
vladimir.kuznetsov
0c40a954fa fixed include in sitesController for android build 2023-08-08 19:39:08 +05:00
vladimir.kuznetsov
784f99a900 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-08-08 19:12:17 +05:00
vladimir.kuznetsov
90ae0b3e44 added PageSettingsSplitTunneling
- added a call to the context menu when clicking the right mouse button for textInput
2023-08-08 19:10:14 +05:00
vladimir.kuznetsov
2c429fd406 added removal of spaces when inserting ip addresses
- fixed server sharing when sharing a server available only for connection when choosing a server with full access
- removed the notification about an empty backup file when the user closes the file dialog without selecting anything
2023-08-02 21:46:02 +09:00
vladimir.kuznetsov
ebcca0c3b8 added processing of private ssh keys 2023-08-02 20:37:43 +09:00
vladimir.kuznetsov
925fd9f268 added display of installed services on the page PageSettingsServersList 2023-08-01 11:06:46 +09:00
vladimir.kuznetsov
0058edc24e added server availability check after entering credentials
- moved the protocol self-selection button to the PageSetupWizardEasy page
2023-07-31 20:38:13 +09:00
vladimir.kuznetsov
aa66133813 added 'insert' button and 'show password' button for PageSetupWizardCredentials 2023-07-31 14:29:49 +09:00
vladimir.kuznetsov
66f9a82f31 added icons for buttons in the drop-down window of connections sharing.
- corrections in texts
2023-07-31 12:54:59 +09:00
vladimir.kuznetsov
1092abe776 added output of notifications/errors after installation/import 2023-07-31 00:13:08 +09:00
vladimir.kuznetsov
0411792ca5 added qr-code decoder for android
- added color change for status and navigation bar for android
2023-07-25 16:56:10 +09:00
vladimir.kuznetsov
b9a13d3a32 changed all text to english 2023-07-24 16:33:58 +09:00
vladimir.kuznetsov
0a1359ed16 moved the platform-specific android code for the new ui 2023-07-24 16:31:04 +09:00
vladimir.kuznetsov
5b8a0881b7 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-07-18 05:36:17 +03:00
vladimir.kuznetsov
5d677a9115 added pages for sftp and tor website settings 2023-07-18 11:15:04 +09:00
vladimir.kuznetsov
75489c00c2 added button 'Reset settings and remove all data from the application' 2023-07-14 22:59:49 +09:00
vladimir.kuznetsov
3aaa7b62ef added page to display raw config 2023-07-14 13:14:50 +09:00
vladimir.kuznetsov
c13b9754eb added protocol settings pages and models for openvpn, cloak and shadowsocks 2023-07-13 11:29:26 +09:00
vladimir.kuznetsov
a97417fd38 added config export in native format openvpn and wireguard 2023-07-05 10:15:38 +09:00
vladimir.kuznetsov
43261f8469 added busy indicator component
- replaced the image of the connect button with native rendering
2023-07-04 09:58:19 +09:00
vladimir.kuznetsov
b32935dd97 Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-06-30 18:15:13 +03:00
vladimir.kuznetsov
35660ff5e7 speed optimization of ui on windows 2023-06-30 18:14:47 +03:00
vladimir.kuznetsov
9b07909ed8 added FlickableType to PageSettingsServerProtocols and PageSettingsServerServices 2023-06-30 13:45:11 +09:00
vladimir.kuznetsov
b4eb317b00 Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-06-30 05:00:20 +03:00
vladimir.kuznetsov
464d77dfb5 added functionality to change app language via settings 2023-06-30 10:40:43 +09:00
vladimir.kuznetsov
d0c9c1043c Merge remote-tracking branch 'remotes/origin/dev' into feature/new-gui 2023-06-27 13:38:06 +03:00
vladimir.kuznetsov
795405c47d added display of amnesia dns container activity on the main page 2023-06-27 19:07:42 +09:00
vladimir.kuznetsov
2ef53c6df9 added separation for read/write and readonly servers for pageSettingsServerProtocols, PageSettingsServerServices, PageSettingsServerData
- added fields validations for pageSetupWizardCredentials
2023-06-23 15:24:40 +09:00
vladimir.kuznetsov
249be451f7 moved handling of connection states from qml in connectionController
- added a check for already installed containers before installing the server/container
- added a button to scan the server for installed containers
- added separation for read/write and readonly servers for pageHome
2023-06-21 20:56:00 +09:00
vladimir.kuznetsov
3a264e6baf added a drawer to change the server name and moved the display of the exported config to a separate drawer 2023-06-20 10:25:24 +09:00
vladimir.kuznetsov
4224e8314b Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-06-16 13:49:19 +09:00
vladimir.kuznetsov
7b14ad9616 added PageSettingsAbout, PageSettingsApplication, PageSettingsBackup, PageSettingsConnection, PageSettingsDns
- added SettingsController
2023-06-16 13:43:55 +09:00
vladimir.kuznetsov
be7386f0d7 added exportController and PageShare
- added a blank PageSettingsProtocol
2023-06-13 20:03:20 +09:00
vladimir.kuznetsov
cd3263db50 made libssh::ssh_connect a non-blocking feature
- extended error handling when connecting via ssh
2023-06-10 05:25:41 +03:00
vladimir.kuznetsov
3034019d5a Merge branch 'feature/new-gui' of github.com:amnezia-vpn/amnezia-client into feature/new-gui 2023-06-07 18:28:44 +08:00
vladimir.kuznetsov
1fd48a1cf8 added protocol settings page and openvpn settings page 2023-06-07 18:28:32 +08:00
vladimir.kuznetsov
c3f39ad24d added caching of servers and containers in models 2023-06-07 13:17:48 +03:00
vladimir.kuznetsov
68d9394d9f fixed windows build errors after refactoring 2023-06-05 17:49:20 +03:00
vladimir.kuznetsov
80fca589af added ConnectionController error handling 2023-06-05 22:40:35 +08:00
vladimir.kuznetsov
420c33d3ba added PageSetupWizardViewConfig
- added a popup with a question when deleting containers/servers
- added import from code and import error handling
2023-06-05 15:49:10 +08:00
vladimir.kuznetsov
de0cd976de added page transition effects
- added functionality for buttons on PageSettingsServerData page
2023-06-01 11:25:33 +08:00
vladimir.kuznetsov
1e180489a4 added display of vpn containers and services on the settings page
- added PageSettingsData and implementation of 'remove all containers'  button
2023-05-27 22:46:41 +08:00
vladimir.kuznetsov
e00656d757 added PageSettings and PageSettingsServersList.
- replaced PageLoader with PageType with stackView property.
- added error handling when installing a server/container
2023-05-25 15:40:17 +08:00
vladimir.kuznetsov
ca6b7fbeb2 added importController 2023-05-22 22:11:20 +08:00
vladimir.kuznetsov
0479113949 moved ContainersPageHomeListView and ConnectionTypeSelectionDrawer to separate components 2023-05-22 00:10:51 +08:00
vladimir.kuznetsov
acca85b99a added installController with logic for server/container installation 2023-05-17 23:28:27 +08:00
vladimir.kuznetsov
03a0e2084a added PageLoader and pageController 2023-05-15 13:38:17 +08:00
vladimir.kuznetsov
116fa6777b added logic to the connect to vpn button 2023-05-14 21:11:19 +08:00
vladimir.kuznetsov
35d4222c7a added connectionController and ConnectionButton.qml 2023-05-12 23:54:31 +08:00
vladimir.kuznetsov
dd0de7e8be Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into origin/feature/new-gui 2023-05-12 11:54:28 +08:00
vladimir.kuznetsov
e3e7503a7c added saving the selected server and protocol to the config 2023-05-12 11:36:09 +08:00
Vladimir Kuznetsov
b66f4bf2be added display of protocols on PageHome 2023-05-11 14:50:50 +08:00
vladimir.kuznetsov
1c8dbae359 added PageHome, PageSettings, PageShare, PageStart
- renamed old PageStart to PageSetupWizardStart
- added various text types
- moved servers model to "global" scope
2023-05-06 06:52:23 +03:00
vladimir.kuznetsov
4f36349630 changed the way to create qml pages, now the page is created when you go to it
- added PageSetupWizardConfigSource, PageSetupWizardInstalling, PageSetupWizardProtocolSettings, PageSetupWizardTextKey
2023-05-03 19:06:16 +03:00
vladimir.kuznetsov
68b27451f2 Added scroll bar for DropDownType 2023-05-01 07:29:09 +03:00
vladimir.kuznetsov
c7acd63ea7 added SwitcherType and TabButtonType
- change CheckBoxType root type
- added PageTest
2023-04-29 19:09:16 +03:00
vladimir.kuznetsov
cfc17cf290 added mousearea to VerticalRadioButton 2023-04-26 18:37:56 +03:00
vladimir.kuznetsov
904e173037 added HorizontalRadioButton and VerticalRadioButton components 2023-04-26 08:30:02 +03:00
vladimir.kuznetsov
a9ebf534c6 added DropDown component 2023-04-25 08:04:20 +03:00
vladimir.kuznetsov
87f01007cc Merge branch 'dev' of github.com:amnezia-vpn/desktop-client into feature/new-gui 2023-04-18 15:47:11 +03:00
vladimir.kuznetsov
3d63d6c0f2 added PageSetupWizardCredentials and PageSetupWizardProtocols
- fixed hover and pressed effects for controls
2023-04-14 19:31:10 +03:00
vladimir.kuznetsov
905a3a30f3 added some new controls and started layout of pageStart and pageCredentials 2023-04-12 19:13:41 +03:00
vladimir.kuznetsov
ec96c1b534 added hover and pressed effects for CheckBoxType.qml 2023-04-10 06:43:36 +03:00
vladimir.kuznetsov
c74c5e0c6d added CheckBoxType
- added hover effect to LabelWithButtonType
2023-04-07 20:50:55 +03:00
vladimir.kuznetsov
167d57408d added CardType component
- added transition for BasicButtonType
2023-04-06 16:33:53 +03:00
vladimir.kuznetsov
8e61d77497 added new controls elements (BasicButtonType, ImageButtonType, LabelWithButtonType, TextFieldWithHeaderType) 2023-03-23 17:49:36 +03:00
506 changed files with 32832 additions and 16731 deletions

42
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,42 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Log files**
Attach log files to help explain your problem.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Windows 10]
- Version [e.g. 2.1.2]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Version [e.g. 2.1.2]
**Server (please complete the following information):**
- OS: [e.g. Ubuntu 22.04]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,7 +1,12 @@
name: 'Deploy workflow'
on:
push:
branches:
- '**'
on: [push]
env:
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ # https://download.qt.io/static/mirrorlist/
jobs:
Build-Linux-Ubuntu:
@@ -25,7 +30,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Get sources'
uses: actions/checkout@v3
@@ -89,7 +94,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Setup mvsc'
uses: ilammy/msvc-dev-cmd@v1
@@ -119,15 +124,14 @@ jobs:
# ------------------------------------------------------
Build-IOS:
name: 'Build-IOS'
Build-iOS:
name: 'Build-iOS'
runs-on: macos-12
env:
QT_VERSION: 6.5.2
steps:
# Just select XCode
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
@@ -143,6 +147,7 @@ jobs:
arch: 'clang_64'
dir: ${{ runner.temp }}
set-env: 'true'
extra: '--base ${{ env.QT_MIRROR }}'
- name: 'Install iOS Qt'
uses: jurplel/install-qt-action@v3
@@ -154,7 +159,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install go'
uses: actions/setup-go@v3
@@ -174,7 +179,7 @@ jobs:
- name: 'Setup ccache'
uses: hendrikmuhs/ccache-action@v1.2
- name: Install dependencies
- name: 'Install dependencies'
run: pip install jsonschema jinja2
- name: 'Build project'
@@ -232,7 +237,7 @@ jobs:
setup-python: 'true'
tools: 'tools_ifw'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Get sources'
uses: actions/checkout@v3
@@ -296,7 +301,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install android Qt'
uses: jurplel/install-qt-action@v3
@@ -309,7 +314,7 @@ jobs:
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Grant execute permission for qt-cmake'
shell: bash

64
.github/workflows/tag-upload.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: 'Upload a new version'
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
jobs:
upload:
runs-on: ubuntu-latest
name: upload
steps:
- name: Checkout CMakeLists.txt
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
sparse-checkout: |
CMakeLists.txt
sparse-checkout-cone-mode: false
- name: Verify git tag
run: |
GIT_TAG=${{ github.ref_name }}
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
else
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
exit 1
fi
- name: Download artifacts from the "${{ github.ref_name }}" tag
uses: robinraju/release-downloader@v1.8
with:
tag: ${{ github.ref_name }}
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
out-file-path: ${{ github.ref_name }}
- name: Upload beta version
uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'dev')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: beta/${{ github.ref_name }}
- name: Upload stable version
uses: jakejarvis/s3-sync-action@master
if: contains(github.event.base_ref, 'master')
with:
args: --include "AmneziaVPN*" --delete
env:
AWS_S3_BUCKET: updates
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
SOURCE_DIR: ${{ github.ref_name }}
DEST_DIR: stable/${{ github.ref_name }}

1
.gitignore vendored
View File

@@ -8,6 +8,7 @@ deploy/build/*
deploy/build_32/*
deploy/build_64/*
winbuild*.bat
.cache/
# Qt-es

6
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "client/3rd/wireguard-apple"]
path = client/3rd/wireguard-apple
url = https://github.com/WireGuard/wireguard-apple
[submodule "client/3rd/OpenVPNAdapter"]
path = client/3rd/OpenVPNAdapter
url = https://github.com/amnezia-vpn/OpenVPNAdapter.git
@@ -25,3 +22,6 @@
[submodule "client/3rd-prebuilt"]
path = client/3rd-prebuilt
url = https://github.com/amnezia-vpn/3rd-prebuilt
[submodule "client/3rd/awg-apple"]
path = client/3rd/awg-apple
url = https://github.com/amnezia-vpn/awg-apple

View File

@@ -2,11 +2,14 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 3.1.0.0
project(${PROJECT} VERSION 4.1.0.1
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
set(RELEASE_DATE "2023-08-28")
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})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")

1
client/3rd/awg-apple vendored Submodule

Submodule client/3rd/awg-apple added at 233eda6760

View File

@@ -10,30 +10,34 @@ set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "Autogen")
set(PACKAGES
Widgets Core Gui Network Xml
Core Gui Network Xml
RemoteObjects Quick Svg QuickControls2
Core5Compat Concurrent LinguistTools
)
if(IOS)
set(PACKAGES
${PACKAGES}
Multimedia
)
set(PACKAGES ${PACKAGES} Multimedia)
endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(PACKAGES ${PACKAGES} Widgets)
endif()
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
set(LIBS ${LIBS}
Qt6::Widgets Qt6::Core Qt6::Gui
Qt6::Core Qt6::Gui
Qt6::Network Qt6::Xml Qt6::RemoteObjects
Qt6::Quick Qt6::Svg Qt6::QuickControls2
Qt6::Core5Compat Qt6::Concurrent
)
if(IOS)
set(LIBS
${LIBS}
Qt6::Multimedia
)
set(LIBS ${LIBS} Qt6::Multimedia)
endif()
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(LIBS ${LIBS} Qt6::Widgets)
endif()
qt_standard_project_setup()
@@ -46,12 +50,30 @@ endif()
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
qt6_add_translations(${PROJECT} TS_FILES
# -- i18n begin
set(CMAKE_AUTORCC ON)
set(AMNEZIAVPN_TS_FILES
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_ru.ts
${CMAKE_CURRENT_LIST_DIR}/translations/amneziavpn_zh_CN.ts
)
file(GLOB_RECURSE AMNEZIAVPN_TS_SOURCES *.qrc *.cpp *.h *.ui)
qt_create_translation(AMNEZIAVPN_QM_FILES ${AMNEZIAVPN_TS_SOURCES} ${AMNEZIAVPN_TS_FILES})
set(QM_FILE_LIST "")
foreach(FILE ${AMNEZIAVPN_QM_FILES})
get_filename_component(QM_FILE_NAME ${FILE} NAME)
list(APPEND QM_FILE_LIST "<file>${QM_FILE_NAME}</file>")
endforeach()
string(REPLACE ";" "" QM_FILE_LIST ${QM_FILE_LIST})
configure_file(${CMAKE_CURRENT_LIST_DIR}/translations/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
qt6_add_resources(QRC ${I18NQRC} ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
# -- i18n end
if(IOS)
#execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/scripts/run-build-cloak.sh)
execute_process(COMMAND bash ${CMAKE_CURRENT_LIST_DIR}/ios/scripts/openvpn.sh args
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endif()
@@ -91,7 +113,6 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
${CMAKE_CURRENT_LIST_DIR}/ui/property_helper.h
${CMAKE_CURRENT_LIST_DIR}/ui/uilogic.h
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
${CMAKE_CURRENT_BINARY_DIR}/version.h
@@ -128,7 +149,6 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/servercontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/uilogic.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/core/sshclient.cpp
@@ -162,20 +182,33 @@ file(GLOB_RECURSE PAGE_LOGIC_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/
file(GLOB CONFIGURATORS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.h)
file(GLOB CONFIGURATORS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/configurators/*.cpp)
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h)
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp)
file(GLOB UI_MODELS_H CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.h
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.h
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.h
)
file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
${CMAKE_CURRENT_LIST_DIR}/ui/models/*.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/models/protocols/*.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
)
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h)
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
set(HEADERS ${HEADERS}
${COMMON_FILES_H}
${PAGE_LOGIC_H}
${CONFIGURATORS_H}
${UI_MODELS_H}
${UI_CONTROLLERS_H}
)
set(SOURCES ${SOURCES}
${COMMON_FILES_CPP}
${PAGE_LOGIC_CPP}
${CONFIGURATORS_CPP}
${UI_MODELS_CPP}
${UI_CONTROLLERS_CPP}
)
if(WIN32)
@@ -248,6 +281,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.h
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.h
)
set(SOURCES ${SOURCES}
@@ -258,6 +292,7 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
${CMAKE_CURRENT_LIST_DIR}/protocols/openvpnovercloakprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/shadowsocksvpnprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/wireguardprotocol.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/awgprotocol.cpp
)
endif()
@@ -307,16 +342,5 @@ if(NOT IOS AND NOT ANDROID)
endif()
if(WIN32)
add_custom_command(
TARGET ${PROJECT} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy,true>
$<TARGET_FILE_DIR:${PROJECT}>/../service/wireguard-service/wireguard-service.exe
$<TARGET_FILE_DIR:${PROJECT}>/wireguard/wireguard-service.exe
COMMAND_EXPAND_LISTS
)
endif()
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC})
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
qt_finalize_target(${PROJECT})

View File

@@ -3,55 +3,35 @@
#include <QClipboard>
#include <QFontDatabase>
#include <QMimeData>
#include <QQuickStyle>
#include <QResource>
#include <QStandardPaths>
#include <QTextDocument>
#include <QTimer>
#include <QTranslator>
#include <QQuickItem>
#include "core/servercontroller.h"
#include "logger.h"
#include "version.h"
#include <QQuickStyle>
#include "platforms/ios/QRCodeReaderBase.h"
#include "ui/pages.h"
#include "ui/pages_logic/AppSettingsLogic.h"
#include "ui/pages_logic/GeneralSettingsLogic.h"
#include "ui/pages_logic/NetworkSettingsLogic.h"
#include "ui/pages_logic/NewServerProtocolsLogic.h"
#include "ui/pages_logic/QrDecoderLogic.h"
#include "ui/pages_logic/ServerConfiguringProgressLogic.h"
#include "ui/pages_logic/ServerContainersLogic.h"
#include "ui/pages_logic/ServerListLogic.h"
#include "ui/pages_logic/ServerSettingsLogic.h"
#include "ui/pages_logic/ServerContainersLogic.h"
#include "ui/pages_logic/ShareConnectionLogic.h"
#include "ui/pages_logic/SitesLogic.h"
#include "ui/pages_logic/StartPageLogic.h"
#include "ui/pages_logic/VpnLogic.h"
#include "ui/pages_logic/WizardLogic.h"
#include "ui/pages_logic/protocols/CloakLogic.h"
#include "ui/pages_logic/protocols/OpenVpnLogic.h"
#include "ui/pages_logic/protocols/ShadowSocksLogic.h"
#if defined(Q_OS_ANDROID)
#include "platforms/android/android_controller.h"
#endif
#include "protocols/qml_register_protocols.h"
#if defined(Q_OS_IOS)
#include "platforms/ios/QtAppDelegate-C-Interface.h"
#include "platforms/ios/ios_controller.h"
#include "platforms/ios/ios_controller.h"
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]):
AMNEZIA_BASE_CLASS(argc, argv)
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
#else
AmneziaApplication::AmneziaApplication(int &argc, char *argv[], bool allowSecondary,
SingleApplication::Options options, int timeout, const QString &userData):
SingleApplication(argc, argv, allowSecondary, options, timeout, userData)
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);
@@ -73,49 +53,97 @@
#endif
m_settings = std::shared_ptr<Settings>(new Settings);
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this));
}
AmneziaApplication::~AmneziaApplication()
{
m_vpnConnectionThread.quit();
m_vpnConnectionThread.wait(3000);
if (m_engine) {
QObject::disconnect(m_engine, 0,0,0);
QObject::disconnect(m_engine, 0, 0, 0);
delete m_engine;
}
if (m_uiLogic) {
QObject::disconnect(m_uiLogic, 0,0,0);
delete m_uiLogic;
}
if (m_protocolProps) delete m_protocolProps;
if (m_containerProps) delete m_containerProps;
}
void AmneziaApplication::init()
{
m_engine = new QQmlApplicationEngine;
m_uiLogic = new UiLogic(m_settings, m_configurator);
const QUrl url(QStringLiteral("qrc:/ui/qml/main.qml"));
QObject::connect(m_engine, &QQmlApplicationEngine::objectCreated,
this, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
const QUrl url(QStringLiteral("qrc:/ui/qml/main2.qml"));
QObject::connect(
m_engine, &QQmlApplicationEngine::objectCreated, this,
[url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
m_uiLogic->registerPagesLogic();
#if defined(Q_OS_IOS)
setStartPageLogic(m_uiLogic->pageLogic<StartPageLogic>());
IosController::Instance()->initialize();
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this));
m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator));
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
initModels();
loadTranslator();
initControllers();
#ifdef Q_OS_ANDROID
connect(AndroidController::instance(), &AndroidController::initialized, this,
[this](bool status, bool connected, const QDateTime &connectionDate) {
if (connected) {
m_connectionController->onConnectionStateChanged(Vpn::ConnectionState::Connected);
if (m_vpnConnection)
m_vpnConnection->restoreConnection();
}
});
if (!AndroidController::instance()->initialize()) {
qCritical() << QString("Init failed");
if (m_vpnConnection)
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Error);
return;
}
connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) {
m_pageController->replaceStartPage();
m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig();
});
#endif
m_engine->load(url);
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
m_pageController->replaceStartPage();
m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig();
});
if (m_engine->rootObjects().size() > 0) {
m_uiLogic->setQmlRoot(m_engine->rootObjects().at(0));
}
connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
m_pageController->replaceStartPage();
m_pageController->goToPageSettingsBackup();
m_settingsController->importBackupFromOutside(filePath);
});
#endif
m_notificationHandler.reset(NotificationHandler::create(nullptr));
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
&NotificationHandler::setConnectionState);
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(),
&PageController::raiseMainWindow);
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
&ConnectionController::openConnection);
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
&ConnectionController::closeConnection);
connect(this, &AmneziaApplication::translationsUpdated, m_notificationHandler.get(),
&NotificationHandler::onTranslationsUpdated);
m_engine->load(url);
m_systemController->setQmlRoot(m_engine->rootObjects().value(0));
if (m_settings->isSaveLogs()) {
if (!Logger::init()) {
@@ -124,19 +152,20 @@ void AmneziaApplication::init()
}
#ifdef Q_OS_WIN
if (m_parser.isSet("a")) m_uiLogic->showOnStartup();
else emit m_uiLogic->show();
if (m_parser.isSet("a"))
m_pageController->showOnStartup();
else
emit m_pageController->raiseMainWindow();
#else
m_uiLogic->showOnStartup();
m_pageController->showOnStartup();
#endif
// TODO - fix
// TODO - fix
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (isPrimary()) {
QObject::connect(this, &SingleApplication::instanceStarted, m_uiLogic, [this](){
QObject::connect(this, &SingleApplication::instanceStarted, m_pageController.get(), [this]() {
qDebug() << "Secondary instance started, showing this window instead";
emit m_uiLogic->show();
emit m_uiLogic->raise();
emit m_pageController->raiseMainWindow();
});
}
#endif
@@ -144,7 +173,7 @@ void AmneziaApplication::init()
// Android TextField clipboard workaround
// https://bugreports.qt.io/browse/QTBUG-113461
#ifdef Q_OS_ANDROID
QObject::connect(qApp, &QApplication::applicationStateChanged, [](Qt::ApplicationState state) {
QObject::connect(qApp, &QGuiApplication::applicationStateChanged, [](Qt::ApplicationState state) {
if (state == Qt::ApplicationActive) {
if (qApp->clipboard()->mimeData()->formats().contains("text/html")) {
QTextDocument doc;
@@ -158,55 +187,64 @@ void AmneziaApplication::init()
void AmneziaApplication::registerTypes()
{
qRegisterMetaType<VpnProtocol::VpnConnectionState>("VpnProtocol::VpnConnectionState");
qRegisterMetaType<ServerCredentials>("ServerCredentials");
qRegisterMetaType<DockerContainer>("DockerContainer");
qRegisterMetaType<TransportProto>("TransportProto");
qRegisterMetaType<Proto>("Proto");
qRegisterMetaType<ServiceType>("ServiceType");
qRegisterMetaType<Page>("Page");
qRegisterMetaType<VpnProtocol::VpnConnectionState>("ConnectionState");
qRegisterMetaType<PageProtocolLogicBase *>("PageProtocolLogicBase *");
declareQmlPageEnum();
declareQmlProtocolEnum();
declareQmlContainerEnum();
qmlRegisterType<PageType>("PageType", 1, 0, "PageType");
qmlRegisterType<QRCodeReader>("QRCodeReader", 1, 0, "QRCodeReader");
m_containerProps = new ContainerProps;
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps);
m_containerProps.reset(new ContainerProps());
qmlRegisterSingletonInstance("ContainerProps", 1, 0, "ContainerProps", m_containerProps.get());
m_protocolProps = new ProtocolProps;
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps);
m_protocolProps.reset(new ProtocolProps());
qmlRegisterSingletonInstance("ProtocolProps", 1, 0, "ProtocolProps", m_protocolProps.get());
qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0,
"ContainersModelFilters");
//
Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum();
}
void AmneziaApplication::loadFonts()
{
QQuickStyle::setStyle("Basic");
QFontDatabase::addApplicationFont(":/fonts/Lato-Black.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-BlackItalic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-Bold.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-BoldItalic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-Italic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-Light.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-LightItalic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-Regular.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-Thin.ttf");
QFontDatabase::addApplicationFont(":/fonts/Lato-ThinItalic.ttf");
QFontDatabase::addApplicationFont(":/fonts/pt-root-ui_vf.ttf");
}
void AmneziaApplication::loadTranslator()
{
m_translator = new QTranslator;
if (m_translator->load(QLocale(), QString("amneziavpn"), QLatin1String("_"), QLatin1String(":/translations"))) {
installTranslator(m_translator);
auto locale = m_settings->getAppLanguage();
m_translator.reset(new QTranslator());
updateTranslator(locale);
}
void AmneziaApplication::updateTranslator(const QLocale &locale)
{
if (!m_translator->isEmpty()) {
QCoreApplication::removeTranslator(m_translator.get());
}
QString strFileName = QString(":/translations/amneziavpn") + QLatin1String("_") + locale.name() + ".qm";
if (m_translator->load(strFileName)) {
if (QCoreApplication::installTranslator(m_translator.get())) {
m_settings->setAppLanguage(locale);
}
} else {
m_settings->setAppLanguage(QLocale::English);
}
m_engine->retranslate();
emit translationsUpdated();
}
bool AmneziaApplication::parseCommands()
@@ -215,19 +253,17 @@ bool AmneziaApplication::parseCommands()
m_parser.addHelpOption();
m_parser.addVersionOption();
QCommandLineOption c_autostart {{"a", "autostart"}, "System autostart"};
QCommandLineOption c_autostart { { "a", "autostart" }, "System autostart" };
m_parser.addOption(c_autostart);
QCommandLineOption c_cleanup {{"c", "cleanup"}, "Cleanup logs"};
QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" };
m_parser.addOption(c_cleanup);
m_parser.process(*this);
if (m_parser.isSet(c_cleanup)) {
Logger::cleanUp();
QTimer::singleShot(100, this, [this]{
quit();
});
QTimer::singleShot(100, this, [this] { quit(); });
exec();
return false;
}
@@ -239,3 +275,92 @@ QQmlApplicationEngine *AmneziaApplication::qmlEngine() const
return m_engine;
}
void AmneziaApplication::initModels()
{
m_containersModel.reset(new ContainersModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
connect(m_vpnConnection.get(), &VpnConnection::newVpnConfigurationCreated, m_containersModel.get(),
&ContainersModel::updateContainersConfig);
m_serversModel.reset(new ServersModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ServersModel", m_serversModel.get());
connect(m_serversModel.get(), &ServersModel::currentlyProcessedServerIndexChanged, m_containersModel.get(),
&ContainersModel::setCurrentlyProcessedServerIndex);
connect(m_serversModel.get(), &ServersModel::defaultServerIndexChanged, m_containersModel.get(),
&ContainersModel::setCurrentlyProcessedServerIndex);
connect(m_containersModel.get(), &ContainersModel::containersModelUpdated, m_serversModel.get(),
&ServersModel::updateContainersConfig);
m_languageModel.reset(new LanguageModel(m_settings, this));
m_engine->rootContext()->setContextProperty("LanguageModel", m_languageModel.get());
connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &AmneziaApplication::updateTranslator);
connect(this, &AmneziaApplication::translationsUpdated, m_languageModel.get(), &LanguageModel::translationsUpdated);
m_sitesModel.reset(new SitesModel(m_settings, this));
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
m_openVpnConfigModel.reset(new OpenVpnConfigModel(this));
m_engine->rootContext()->setContextProperty("OpenVpnConfigModel", m_openVpnConfigModel.get());
m_shadowSocksConfigModel.reset(new ShadowSocksConfigModel(this));
m_engine->rootContext()->setContextProperty("ShadowSocksConfigModel", m_shadowSocksConfigModel.get());
m_cloakConfigModel.reset(new CloakConfigModel(this));
m_engine->rootContext()->setContextProperty("CloakConfigModel", m_cloakConfigModel.get());
m_wireGuardConfigModel.reset(new WireGuardConfigModel(this));
m_engine->rootContext()->setContextProperty("WireGuardConfigModel", m_wireGuardConfigModel.get());
m_awgConfigModel.reset(new AwgConfigModel(this));
m_engine->rootContext()->setContextProperty("AwgConfigModel", m_awgConfigModel.get());
#ifdef Q_OS_WINDOWS
m_ikev2ConfigModel.reset(new Ikev2ConfigModel(this));
m_engine->rootContext()->setContextProperty("Ikev2ConfigModel", m_ikev2ConfigModel.get());
#endif
m_sftpConfigModel.reset(new SftpConfigModel(this));
m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
}
void AmneziaApplication::initControllers()
{
m_connectionController.reset(new ConnectionController(m_serversModel, m_containersModel, m_vpnConnection));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(),
&ConnectionController::onTranslationsUpdated);
m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_settings));
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
&PageController::showPassphraseRequestDrawer);
connect(m_pageController.get(), &PageController::passphraseRequestDrawerClosed, m_installController.get(),
&InstallController::setEncryptedPassphrase);
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
&ConnectionController::onCurrentContainerUpdated);
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator));
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_settings));
m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
if (m_settingsController->isAutoStartEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
}
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
}

View File

@@ -1,27 +1,53 @@
#ifndef AMNEZIA_APPLICATION_H
#define AMNEZIA_APPLICATION_H
#include <QApplication>
#include <QGuiApplication>
#include <QCommandLineParser>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QThread>
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include <QGuiApplication>
#else
#include <QApplication>
#endif
#include "settings.h"
#include "vpnconnection.h"
#include "ui/uilogic.h"
#include "configurators/vpn_configurator.h"
#include "ui/controllers/connectionController.h"
#include "ui/controllers/exportController.h"
#include "ui/controllers/importController.h"
#include "ui/controllers/installController.h"
#include "ui/controllers/pageController.h"
#include "ui/controllers/settingsController.h"
#include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h"
#include "ui/models/containers_model.h"
#include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h"
#include "ui/notificationhandler.h"
#ifdef Q_OS_WINDOWS
#include "ui/models/protocols/ikev2ConfigModel.h"
#endif
#include "ui/models/protocols/awgConfigModel.h"
#include "ui/models/protocols/openvpnConfigModel.h"
#include "ui/models/protocols/shadowsocksConfigModel.h"
#include "ui/models/protocols/wireguardConfigModel.h"
#include "ui/models/protocols_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/services/sftpConfigModel.h"
#include "ui/models/sites_model.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#define AMNEZIA_BASE_CLASS QApplication
#define AMNEZIA_BASE_CLASS QGuiApplication
#else
#define AMNEZIA_BASE_CLASS SingleApplication
#define QAPPLICATION_CLASS QApplication
#include "singleapplication.h"
#define AMNEZIA_BASE_CLASS SingleApplication
#define QAPPLICATION_CLASS QApplication
#include "singleapplication.h"
#endif
class AmneziaApplication : public AMNEZIA_BASE_CLASS
@@ -32,7 +58,8 @@ public:
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 = {} );
SingleApplication::Options options = SingleApplication::User, int timeout = 1000,
const QString &userData = {});
#endif
virtual ~AmneziaApplication();
@@ -40,22 +67,57 @@ public:
void registerTypes();
void loadFonts();
void loadTranslator();
void updateTranslator(const QLocale &locale);
bool parseCommands();
QQmlApplicationEngine *qmlEngine() const;
signals:
void translationsUpdated();
private:
void initModels();
void initControllers();
QQmlApplicationEngine *m_engine {};
UiLogic *m_uiLogic {};
std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
ContainerProps* m_containerProps {};
ProtocolProps* m_protocolProps {};
QSharedPointer<ContainerProps> m_containerProps;
QSharedPointer<ProtocolProps> m_protocolProps;
QTranslator* m_translator;
QSharedPointer<QTranslator> m_translator;
QCommandLineParser m_parser;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel;
QSharedPointer<SitesModel> m_sitesModel;
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel;
QScopedPointer<CloakConfigModel> m_cloakConfigModel;
QScopedPointer<WireGuardConfigModel> m_wireGuardConfigModel;
QScopedPointer<AwgConfigModel> m_awgConfigModel;
#ifdef Q_OS_WINDOWS
QScopedPointer<Ikev2ConfigModel> m_ikev2ConfigModel;
#endif
QScopedPointer<SftpConfigModel> m_sftpConfigModel;
QSharedPointer<VpnConnection> m_vpnConnection;
QThread m_vpnConnectionThread;
QScopedPointer<NotificationHandler> m_notificationHandler;
QScopedPointer<ConnectionController> m_connectionController;
QScopedPointer<PageController> m_pageController;
QScopedPointer<InstallController> m_installController;
QScopedPointer<ImportController> m_importController;
QScopedPointer<ExportController> m_exportController;
QScopedPointer<SettingsController> m_settingsController;
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
};
#endif // AMNEZIA_APPLICATION_H

View File

@@ -36,7 +36,8 @@
android:requestLegacyExternalStorage="true"
android:allowNativeHeapPointerTagging="false"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:icon="@drawable/icon">
android:icon="@drawable/icon"
android:roundIcon="@drawable/icon_round">
<activity
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
@@ -44,6 +45,7 @@
android:label="-- %%INSERT_APP_NAME%% --"
android:screenOrientation="unspecified"
android:launchMode="singleInstance"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<!-- android:theme="@style/splashScreenTheme"-->

View File

@@ -138,8 +138,8 @@ android {
resConfig "en"
minSdkVersion = 24
targetSdkVersion = 34
versionCode 32 // Change to a higher number
versionName "3.0.9" // Change to a higher number
versionCode 39 // Change to a higher number
versionName "4.1.0" // Change to a higher number
javaCompileOptions.annotationProcessorOptions.arguments = [
"room.schemaLocation": "${qtAndroidDir}/schemas".toString()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -70,6 +70,15 @@ public class BadConfigException extends Exception {
EXCLUDED_APPLICATIONS("ExcludedApplications"),
INCLUDED_APPLICATIONS("IncludedApplications"),
LISTEN_PORT("ListenPort"),
JC("Jc"),
JMIN("Jmin"),
JMAX("Jmax"),
S1("S1"),
S2("S2"),
H1("H1"),
H2("H2"),
H3("H3"),
H4("H4"),
MTU("MTU"),
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
PRE_SHARED_KEY("PresharedKey"),

View File

@@ -0,0 +1,509 @@
/*
* Copyright (C) 2012-2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import androidx.annotation.NonNull;
/**
* Class that represents a range of IP addresses. This range could be a proper subnet, but that's
* not necessarily the case (see {@code getPrefix} and {@code toSubnets}).
*/
public class IPRange implements Comparable<IPRange>
{
private final byte[] mBitmask = { (byte)0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
private byte[] mFrom;
private byte[] mTo;
private Integer mPrefix;
/**
* Determine if the range is a proper subnet and, if so, what the network prefix is.
*/
private void determinePrefix()
{
boolean matching = true;
mPrefix = mFrom.length * 8;
for (int i = 0; i < mFrom.length; i++)
{
for (int bit = 0; bit < 8; bit++)
{
if (matching)
{
if ((mFrom[i] & mBitmask[bit]) != (mTo[i] & mBitmask[bit]))
{
mPrefix = (i * 8) + bit;
matching = false;
}
}
else
{
if ((mFrom[i] & mBitmask[bit]) != 0 || (mTo[i] & mBitmask[bit]) == 0)
{
mPrefix = null;
return;
}
}
}
}
}
private IPRange(byte[] from, byte[] to)
{
mFrom = from;
mTo = to;
determinePrefix();
}
public IPRange(String from, String to) throws UnknownHostException
{
this(Utils.parseInetAddress(from), Utils.parseInetAddress(to));
}
public IPRange(InetAddress from, InetAddress to)
{
initializeFromRange(from, to);
}
private void initializeFromRange(InetAddress from, InetAddress to)
{
byte[] fa = from.getAddress(), ta = to.getAddress();
if (fa.length != ta.length)
{
throw new IllegalArgumentException("Invalid range");
}
if (compareAddr(fa, ta) < 0)
{
mFrom = fa;
mTo = ta;
}
else
{
mTo = fa;
mFrom = ta;
}
determinePrefix();
}
public IPRange(String base, int prefix) throws UnknownHostException
{
this(Utils.parseInetAddress(base), prefix);
}
public IPRange(InetAddress base, int prefix)
{
this(base.getAddress(), prefix);
}
private IPRange(byte[] from, int prefix)
{
initializeFromCIDR(from, prefix);
}
private void initializeFromCIDR(byte[] from, int prefix)
{
if (from.length != 4 && from.length != 16)
{
throw new IllegalArgumentException("Invalid address");
}
if (prefix < 0 || prefix > from.length * 8)
{
throw new IllegalArgumentException("Invalid prefix");
}
byte[] to = from.clone();
byte mask = (byte)(0xff << (8 - prefix % 8));
int i = prefix / 8;
if (i < from.length)
{
from[i] = (byte)(from[i] & mask);
to[i] = (byte)(to[i] | ~mask);
Arrays.fill(from, i+1, from.length, (byte)0);
Arrays.fill(to, i+1, to.length, (byte)0xff);
}
mFrom = from;
mTo = to;
mPrefix = prefix;
}
public IPRange(String cidr) throws UnknownHostException
{
/* only verify the basic structure */
if (!cidr.matches("(?i)^(([0-9.]+)|([0-9a-f:]+))(-(([0-9.]+)|([0-9a-f:]+))|(/\\d+))?$"))
{
throw new IllegalArgumentException("Invalid CIDR or range notation");
}
if (cidr.contains("-"))
{
String[] parts = cidr.split("-");
InetAddress from = InetAddress.getByName(parts[0]);
InetAddress to = InetAddress.getByName(parts[1]);
initializeFromRange(from, to);
}
else
{
String[] parts = cidr.split("/");
InetAddress addr = InetAddress.getByName(parts[0]);
byte[] base = addr.getAddress();
int prefix = base.length * 8;
if (parts.length > 1)
{
prefix = Integer.parseInt(parts[1]);
}
initializeFromCIDR(base, prefix);
}
}
/**
* Returns the first address of the range. The network ID in case this is a proper subnet.
*/
public InetAddress getFrom()
{
try
{
return InetAddress.getByAddress(mFrom);
}
catch (UnknownHostException ignored)
{
return null;
}
}
/**
* Returns the last address of the range.
*/
public InetAddress getTo()
{
try
{
return InetAddress.getByAddress(mTo);
}
catch (UnknownHostException ignored)
{
return null;
}
}
/**
* If this range is a proper subnet returns its prefix, otherwise returns null.
*/
public Integer getPrefix()
{
return mPrefix;
}
@Override
public int compareTo(@NonNull IPRange other)
{
int cmp = compareAddr(mFrom, other.mFrom);
if (cmp == 0)
{ /* smaller ranges first */
cmp = compareAddr(mTo, other.mTo);
}
return cmp;
}
@Override
public boolean equals(Object o)
{
if (o == null || !(o instanceof IPRange))
{
return false;
}
return this == o || compareTo((IPRange)o) == 0;
}
@Override
public String toString()
{
try
{
if (mPrefix != null)
{
return InetAddress.getByAddress(mFrom).getHostAddress() + "/" + mPrefix;
}
return InetAddress.getByAddress(mFrom).getHostAddress() + "-" +
InetAddress.getByAddress(mTo).getHostAddress();
}
catch (UnknownHostException ignored)
{
return super.toString();
}
}
private int compareAddr(byte a[], byte b[])
{
if (a.length != b.length)
{
return (a.length < b.length) ? -1 : 1;
}
for (int i = 0; i < a.length; i++)
{
if (a[i] != b[i])
{
if (((int)a[i] & 0xff) < ((int)b[i] & 0xff))
{
return -1;
}
else
{
return 1;
}
}
}
return 0;
}
/**
* Check if this range fully contains the given range.
*/
public boolean contains(IPRange range)
{
return compareAddr(mFrom, range.mFrom) <= 0 && compareAddr(range.mTo, mTo) <= 0;
}
/**
* Check if this and the given range overlap.
*/
public boolean overlaps(IPRange range)
{
return !(compareAddr(mTo, range.mFrom) < 0 || compareAddr(range.mTo, mFrom) < 0);
}
private byte[] dec(byte[] addr)
{
for (int i = addr.length - 1; i >= 0; i--)
{
if (--addr[i] != (byte)0xff)
{
break;
}
}
return addr;
}
private byte[] inc(byte[] addr)
{
for (int i = addr.length - 1; i >= 0; i--)
{
if (++addr[i] != 0)
{
break;
}
}
return addr;
}
/**
* Remove the given range from the current range. Returns a list of resulting ranges (these are
* not proper subnets). At most two ranges are returned, in case the given range is contained in
* this but does not equal it, which would result in an empty list (which is also the case if
* this range is fully contained in the given range).
*/
public List<IPRange> remove(IPRange range)
{
ArrayList<IPRange> list = new ArrayList<>();
if (!overlaps(range))
{ /* | this | or | this |
* | range | | range | */
list.add(this);
}
else if (!range.contains(this))
{ /* we are not completely removed, so none of these cases applies:
* | this | or | this | or | this |
* | range | | range | | range | */
if (compareAddr(mFrom, range.mFrom) < 0 && compareAddr(range.mTo, mTo) < 0)
{ /* the removed range is completely within our boundaries:
* | this |
* | range | */
list.add(new IPRange(mFrom, dec(range.mFrom.clone())));
list.add(new IPRange(inc(range.mTo.clone()), mTo));
}
else
{ /* one end is within our boundaries the other at or outside it:
* | this | or | this | or | this | or | this |
* | range | | range | | range | | range | */
byte[] from = compareAddr(mFrom, range.mFrom) < 0 ? mFrom : inc(range.mTo.clone());
byte[] to = compareAddr(mTo, range.mTo) > 0 ? mTo : dec(range.mFrom.clone());
list.add(new IPRange(from, to));
}
}
return list;
}
private boolean adjacent(IPRange range)
{
if (compareAddr(mTo, range.mFrom) < 0)
{
byte[] to = inc(mTo.clone());
return compareAddr(to, range.mFrom) == 0;
}
byte[] from = dec(mFrom.clone());
return compareAddr(from, range.mTo) == 0;
}
/**
* Merge two adjacent or overlapping ranges, returns null if it's not possible to merge them.
*/
public IPRange merge(IPRange range)
{
if (overlaps(range))
{
if (contains(range))
{
return this;
}
else if (range.contains(this))
{
return range;
}
}
else if (!adjacent(range))
{
return null;
}
byte[] from = compareAddr(mFrom, range.mFrom) < 0 ? mFrom : range.mFrom;
byte[] to = compareAddr(mTo, range.mTo) > 0 ? mTo : range.mTo;
return new IPRange(from, to);
}
/**
* Split the given range into a sorted list of proper subnets.
*/
public List<IPRange> toSubnets()
{
ArrayList<IPRange> list = new ArrayList<>();
if (mPrefix != null)
{
list.add(this);
}
else
{
int i = 0, bit = 0, prefix, netmask, common_byte, common_bit;
int from_cur, from_prev = 0, to_cur, to_prev = 1;
boolean from_full = true, to_full = true;
byte[] from = mFrom.clone();
byte[] to = mTo.clone();
/* find a common prefix */
while (i < from.length && (from[i] & mBitmask[bit]) == (to[i] & mBitmask[bit]))
{
if (++bit == 8)
{
bit = 0;
i++;
}
}
prefix = i * 8 + bit;
/* at this point we know that the addresses are either equal, or that the
* current bits in the 'from' and 'to' addresses are 0 and 1, respectively.
* we now look at the rest of the bits as two binary trees (0=left, 1=right)
* where 'from' and 'to' are both leaf nodes. all leaf nodes between these
* nodes are addresses contained in the range. to collect them as subnets
* we follow the trees from both leaf nodes to their root node and record
* all complete subtrees (right for from, left for to) we come across as
* subnets. in that process host bits are zeroed out. if both addresses
* are equal we won't enter the loop below.
* 0_____|_____1 for the 'from' address we assume we start on a
* 0__|__ 1 0__|__1 left subtree (0) and follow the left edges until
* _|_ _|_ _|_ _|_ we reach the root of this subtree, which is
* | | | | | | | | either the root of this whole 'from'-subtree
* 0 1 0 1 0 1 0 1 (causing us to leave the loop) or the root node
* of the right subtree (1) of another node (which actually could be the
* leaf node we start from). that whole subtree gets recorded as subnet.
* next we follow the right edges to the root of that subtree which again is
* either the 'from'-root or the root node in the left subtree (0) of
* another node. the complete right subtree of that node is the next subnet
* we record. from there we assume that we are in that right subtree and
* recursively follow right edges to its root. for the 'to' address the
* procedure is exactly the same but with left and right reversed.
*/
if (++bit == 8)
{
bit = 0;
i++;
}
common_byte = i;
common_bit = bit;
netmask = from.length * 8;
for (i = from.length - 1; i >= common_byte; i--)
{
int bit_min = (i == common_byte) ? common_bit : 0;
for (bit = 7; bit >= bit_min; bit--)
{
byte mask = mBitmask[bit];
from_cur = from[i] & mask;
if (from_prev == 0 && from_cur != 0)
{ /* 0 -> 1: subnet is the whole current (right) subtree */
list.add(new IPRange(from.clone(), netmask));
from_full = false;
}
else if (from_prev != 0 && from_cur == 0)
{ /* 1 -> 0: invert bit to switch to right subtree and add it */
from[i] ^= mask;
list.add(new IPRange(from.clone(), netmask));
from_cur = 1;
}
/* clear the current bit */
from[i] &= ~mask;
from_prev = from_cur;
to_cur = to[i] & mask;
if (to_prev != 0 && to_cur == 0)
{ /* 1 -> 0: subnet is the whole current (left) subtree */
list.add(new IPRange(to.clone(), netmask));
to_full = false;
}
else if (to_prev == 0 && to_cur != 0)
{ /* 0 -> 1: invert bit to switch to left subtree and add it */
to[i] ^= mask;
list.add(new IPRange(to.clone(), netmask));
to_cur = 0;
}
/* clear the current bit */
to[i] &= ~mask;
to_prev = to_cur;
netmask--;
}
}
if (from_full && to_full)
{ /* full subnet (from=to or from=0.. and to=1.. after common prefix) - not reachable
* due to the shortcut at the top */
list.add(new IPRange(from.clone(), prefix));
}
else if (from_full)
{ /* full from subnet (from=0.. after prefix) */
list.add(new IPRange(from.clone(), prefix + 1));
}
else if (to_full)
{ /* full to subnet (to=1.. after prefix) */
list.add(new IPRange(to.clone(), prefix + 1));
}
}
Collections.sort(list);
return list;
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (C) 2012-2017 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
/**
* Class that represents a set of IP address ranges (not necessarily proper subnets) and allows
* modifying the set and enumerating the resulting subnets.
*/
public class IPRangeSet implements Iterable<IPRange>
{
private TreeSet<IPRange> mRanges = new TreeSet<>();
/**
* Parse the given string (space separated ranges in CIDR or range notation) and return the
* resulting set or {@code null} if the string was invalid. An empty set is returned if the given string
* is {@code null}.
*/
public static IPRangeSet fromString(String ranges)
{
IPRangeSet set = new IPRangeSet();
if (ranges != null)
{
for (String range : ranges.split("\\s+"))
{
try
{
set.add(new IPRange(range));
}
catch (Exception unused)
{ /* besides due to invalid strings exceptions might get thrown if the string
* contains a hostname (NetworkOnMainThreadException) */
return null;
}
}
}
return set;
}
/**
* Add a range to this set. Automatically gets merged with existing ranges.
*/
public void add(IPRange range)
{
if (mRanges.contains(range))
{
return;
}
reinsert:
while (true)
{
Iterator<IPRange> iterator = mRanges.iterator();
while (iterator.hasNext())
{
IPRange existing = iterator.next();
IPRange replacement = existing.merge(range);
if (replacement != null)
{
iterator.remove();
range = replacement;
continue reinsert;
}
}
mRanges.add(range);
break;
}
}
/**
* Add all ranges from the given set.
*/
public void add(IPRangeSet ranges)
{
if (ranges == this)
{
return;
}
for (IPRange range : ranges.mRanges)
{
add(range);
}
}
/**
* Add all ranges from the given collection to this set.
*/
public void addAll(Collection<? extends IPRange> coll)
{
for (IPRange range : coll)
{
add(range);
}
}
/**
* Remove the given range from this set. Existing ranges are automatically adjusted.
*/
public void remove(IPRange range)
{
ArrayList <IPRange> additions = new ArrayList<>();
Iterator<IPRange> iterator = mRanges.iterator();
while (iterator.hasNext())
{
IPRange existing = iterator.next();
List<IPRange> result = existing.remove(range);
if (result.size() == 0)
{
iterator.remove();
}
else if (!result.get(0).equals(existing))
{
iterator.remove();
additions.addAll(result);
}
}
mRanges.addAll(additions);
}
/**
* Remove the given ranges from ranges in this set.
*/
public void remove(IPRangeSet ranges)
{
if (ranges == this)
{
mRanges.clear();
return;
}
for (IPRange range : ranges.mRanges)
{
remove(range);
}
}
/**
* Get all the subnets derived from all the ranges in this set.
*/
public Iterable<IPRange> subnets()
{
return new Iterable<IPRange>()
{
@Override
public Iterator<IPRange> iterator()
{
return new Iterator<IPRange>()
{
private Iterator<IPRange> mIterator = mRanges.iterator();
private List<IPRange> mSubnets;
@Override
public boolean hasNext()
{
return (mSubnets != null && mSubnets.size() > 0) || mIterator.hasNext();
}
@Override
public IPRange next()
{
if (mSubnets == null || mSubnets.size() == 0)
{
IPRange range = mIterator.next();
mSubnets = range.toSubnets();
}
return mSubnets.remove(0);
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
};
}
@Override
public Iterator<IPRange> iterator()
{
return mRanges.iterator();
}
/**
* Returns the number of ranges, not subnets.
*/
public int size()
{
return mRanges.size();
}
@Override
public String toString()
{ /* we could use TextUtils, but that causes the unit tests to fail */
StringBuilder sb = new StringBuilder();
for (IPRange range : mRanges)
{
if (sb.length() > 0)
{
sb.append(" ");
}
sb.append(range.toString());
}
return sb.toString();
}
}

View File

@@ -44,6 +44,15 @@ public final class Interface {
private final KeyPair keyPair;
private final Optional<Integer> listenPort;
private final Optional<Integer> mtu;
private final Optional<Integer> jc;
private final Optional<Integer> jmin;
private final Optional<Integer> jmax;
private final Optional<Integer> s1;
private final Optional<Integer> s2;
private final Optional<Long> h1;
private final Optional<Long> h2;
private final Optional<Long> h3;
private final Optional<Long> h4;
private Interface(final Builder builder) {
// Defensively copy to ensure immutability even if the Builder is reused.
@@ -56,6 +65,15 @@ public final class Interface {
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
listenPort = builder.listenPort;
mtu = builder.mtu;
jc = builder.jc;
jmax = builder.jmax;
jmin = builder.jmin;
s1 = builder.s1;
s2 = builder.s2;
h1 = builder.h1;
h2 = builder.h2;
h3 = builder.h3;
h4 = builder.h4;
}
/**
@@ -95,6 +113,33 @@ public final class Interface {
case "privatekey":
builder.parsePrivateKey(attribute.getValue());
break;
case "jc":
builder.parseJc(attribute.getValue());
break;
case "jmin":
builder.parseJmin(attribute.getValue());
break;
case "jmax":
builder.parseJmax(attribute.getValue());
break;
case "s1":
builder.parseS1(attribute.getValue());
break;
case "s2":
builder.parseS2(attribute.getValue());
break;
case "h1":
builder.parseH1(attribute.getValue());
break;
case "h2":
builder.parseH2(attribute.getValue());
break;
case "h3":
builder.parseH3(attribute.getValue());
break;
case "h4":
builder.parseH4(attribute.getValue());
break;
default:
throw new BadConfigException(
Section.INTERFACE, Location.TOP_LEVEL, Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
@@ -111,7 +156,9 @@ public final class Interface {
return addresses.equals(other.addresses) && dnsServers.equals(other.dnsServers)
&& excludedApplications.equals(other.excludedApplications)
&& includedApplications.equals(other.includedApplications) && keyPair.equals(other.keyPair)
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu);
&& listenPort.equals(other.listenPort) && mtu.equals(other.mtu) && jc.equals(other.jc) && jmin.equals(other.jmin)
&& jmax.equals(other.jmax) && s1.equals(other.s1) && s2.equals(other.s2) && h1.equals(other.h1) && h2.equals(other.h2)
&& h3.equals(other.h3) && h4.equals(other.h4);
}
/**
@@ -180,6 +227,42 @@ public final class Interface {
public Optional<Integer> getMtu() {
return mtu;
}
public Optional<Integer> getJc() {
return jc;
}
public Optional<Integer> getJmin() {
return jmin;
}
public Optional<Integer> getJmax() {
return jmax;
}
public Optional<Integer> getS1() {
return s1;
}
public Optional<Integer> getS2() {
return s2;
}
public Optional<Long> getH1() {
return h1;
}
public Optional<Long> getH2() {
return h2;
}
public Optional<Long> getH3() {
return h3;
}
public Optional<Long> getH4() {
return h4;
}
@Override
public int hashCode() {
@@ -191,6 +274,15 @@ public final class Interface {
hash = 31 * hash + keyPair.hashCode();
hash = 31 * hash + listenPort.hashCode();
hash = 31 * hash + mtu.hashCode();
hash = 31 * hash + jc.hashCode();
hash = 31 * hash + jmin.hashCode();
hash = 31 * hash + jmax.hashCode();
hash = 31 * hash + s1.hashCode();
hash = 31 * hash + s2.hashCode();
hash = 31 * hash + h1.hashCode();
hash = 31 * hash + h2.hashCode();
hash = 31 * hash + h3.hashCode();
hash = 31 * hash + h4.hashCode();
return hash;
}
@@ -234,6 +326,19 @@ public final class Interface {
.append('\n');
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
jc.ifPresent(t_jc -> sb.append("Jc = ").append(t_jc).append('\n'));
jmin.ifPresent(t_jmin -> sb.append("Jmin = ").append(t_jmin).append('\n'));
jmax.ifPresent(t_jmax -> sb.append("Jmax = ").append(t_jmax).append('\n'));
s1.ifPresent(t_s1 -> sb.append("S1 = ").append(t_s1).append('\n'));
s2.ifPresent(t_s2 -> sb.append("S2 = ").append(t_s2).append('\n'));
h1.ifPresent(t_h1 -> sb.append("H1 = ").append(t_h1).append('\n'));
h2.ifPresent(t_h2 -> sb.append("H2 = ").append(t_h2).append('\n'));
h3.ifPresent(t_h3 -> sb.append("H3 = ").append(t_h3).append('\n'));
h4.ifPresent(t_h4 -> sb.append("H4 = ").append(t_h4).append('\n'));
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
return sb.toString();
}
@@ -248,6 +353,18 @@ public final class Interface {
final StringBuilder sb = new StringBuilder();
sb.append("private_key=").append(keyPair.getPrivateKey().toHex()).append('\n');
listenPort.ifPresent(lp -> sb.append("listen_port=").append(lp).append('\n'));
jc.ifPresent(t_jc -> sb.append("jc=").append(t_jc).append('\n'));
jmin.ifPresent(t_jmin -> sb.append("jmin=").append(t_jmin).append('\n'));
jmax.ifPresent(t_jmax -> sb.append("jmax=").append(t_jmax).append('\n'));
s1.ifPresent(t_s1 -> sb.append("s1=").append(t_s1).append('\n'));
s2.ifPresent(t_s2 -> sb.append("s2=").append(t_s2).append('\n'));
h1.ifPresent(t_h1 -> sb.append("h1=").append(t_h1).append('\n'));
h2.ifPresent(t_h2 -> sb.append("h2=").append(t_h2).append('\n'));
h3.ifPresent(t_h3 -> sb.append("h3=").append(t_h3).append('\n'));
h4.ifPresent(t_h4 -> sb.append("h4=").append(t_h4).append('\n'));
return sb.toString();
}
@@ -267,6 +384,17 @@ public final class Interface {
private Optional<Integer> listenPort = Optional.empty();
// Defaults to not present.
private Optional<Integer> mtu = Optional.empty();
private Optional<Integer> jc = Optional.empty();
private Optional<Integer> jmin = Optional.empty();
private Optional<Integer> jmax = Optional.empty();
private Optional<Integer> s1 = Optional.empty();
private Optional<Integer> s2 = Optional.empty();
private Optional<Long> h1 = Optional.empty();
private Optional<Long> h2 = Optional.empty();
private Optional<Long> h3 = Optional.empty();
private Optional<Long> h4 = Optional.empty();
public Builder addAddress(final InetNetwork address) {
addresses.add(address);
@@ -362,6 +490,78 @@ public final class Interface {
}
}
public Builder parseJc(final String jc) throws BadConfigException {
try {
return setJc(Integer.parseInt(jc));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JC, jc, e);
}
}
public Builder parseJmax(final String jmax) throws BadConfigException {
try {
return setJmax(Integer.parseInt(jmax));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JMAX, jmax, e);
}
}
public Builder parseJmin(final String jmin) throws BadConfigException {
try {
return setJmin(Integer.parseInt(jmin));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.JMIN, jmin, e);
}
}
public Builder parseS1(final String s1) throws BadConfigException {
try {
return setS1(Integer.parseInt(s1));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.S1, s1, e);
}
}
public Builder parseS2(final String s2) throws BadConfigException {
try {
return setS2(Integer.parseInt(s2));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.S2, s2, e);
}
}
public Builder parseH1(final String h1) throws BadConfigException {
try {
return setH1(Long.parseLong(h1));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H1, h1, e);
}
}
public Builder parseH2(final String h2) throws BadConfigException {
try {
return setH2(Long.parseLong(h2));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H2, h2, e);
}
}
public Builder parseH3(final String h3) throws BadConfigException {
try {
return setH3(Long.parseLong(h3));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H3, h3, e);
}
}
public Builder parseH4(final String h4) throws BadConfigException {
try {
return setH4(Long.parseLong(h4));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.H4, h4, e);
}
}
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
try {
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
@@ -386,9 +586,81 @@ public final class Interface {
public Builder setMtu(final int mtu) throws BadConfigException {
if (mtu < 0)
throw new BadConfigException(
Section.INTERFACE, Location.LISTEN_PORT, Reason.INVALID_VALUE, String.valueOf(mtu));
Section.INTERFACE, Location.MTU, Reason.INVALID_VALUE, String.valueOf(mtu));
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
return this;
}
public Builder setJc(final int jc) throws BadConfigException {
if (jc < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JC, Reason.INVALID_VALUE, String.valueOf(jc));
this.jc = Optional.of(jc);
return this;
}
public Builder setJmin(final int jmin) throws BadConfigException {
if (jmin < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JMIN, Reason.INVALID_VALUE, String.valueOf(jmin));
this.jmin = Optional.of(jmin);
return this;
}
public Builder setJmax(final int jmax) throws BadConfigException {
if (jmax < 0)
throw new BadConfigException(
Section.INTERFACE, Location.JMAX, Reason.INVALID_VALUE, String.valueOf(jmax));
this.jmax = Optional.of(jmax);
return this;
}
public Builder setS1(final int s1) throws BadConfigException {
if (s1 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.S1, Reason.INVALID_VALUE, String.valueOf(s1));
this.s1 = Optional.of(s1);
return this;
}
public Builder setS2(final int s2) throws BadConfigException {
if (s2 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.S2, Reason.INVALID_VALUE, String.valueOf(s2));
this.s2 = Optional.of(s2);
return this;
}
public Builder setH1(final long h1) throws BadConfigException {
if (h1 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H1, Reason.INVALID_VALUE, String.valueOf(h1));
this.h1 = Optional.of(h1);
return this;
}
public Builder setH2(final long h2) throws BadConfigException {
if (h2 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H2, Reason.INVALID_VALUE, String.valueOf(h2));
this.h2 = Optional.of(h2);
return this;
}
public Builder setH3(final long h3) throws BadConfigException {
if (h3 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H3, Reason.INVALID_VALUE, String.valueOf(h3));
this.h3 = Optional.of(h3);
return this;
}
public Builder setH4(final long h4) throws BadConfigException {
if (h4 < 0)
throw new BadConfigException(
Section.INTERFACE, Location.H4, Reason.INVALID_VALUE, String.valueOf(h4));
this.h4 = Optional.of(h4);
return this;
}
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2014-2019 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package com.wireguard.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Utils
{
static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
/**
* Converts the given byte array to a hexadecimal string encoding.
*
* @param bytes byte array to convert
* @return hex string
*/
public static String bytesToHex(byte[] bytes)
{
char[] hex = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; i++)
{
int value = bytes[i];
hex[i*2] = HEXDIGITS[(value & 0xf0) >> 4];
hex[i*2+1] = HEXDIGITS[ value & 0x0f];
}
return new String(hex);
}
/**
* Validate the given proposal string
*
* @param ike true for IKE, false for ESP
* @param proposal proposal string
* @return true if valid
*/
public native static boolean isProposalValid(boolean ike, String proposal);
/**
* Parse an IP address without doing a name lookup
*
* @param address IP address string
* @return address bytes if valid
*/
private native static byte[] parseInetAddressBytes(String address);
/**
* Parse an IP address without doing a name lookup (as compared to InetAddress.fromName())
*
* @param address IP address string
* @return address if valid
* @throws UnknownHostException if address is invalid
*/
public static InetAddress parseInetAddress(String address) throws UnknownHostException
{
byte[] bytes = parseInetAddressBytes(address);
if (bytes == null)
{
throw new UnknownHostException();
}
return InetAddress.getByAddress(bytes);
}
}

View File

@@ -16,6 +16,8 @@ import com.wireguard.crypto.Key
import org.json.JSONObject
import java.util.Base64
import com.wireguard.config.*
import net.openvpn.ovpn3.ClientAPI_Config
import net.openvpn.ovpn3.ClientAPI_EvalConfig
import net.openvpn.ovpn3.ClientAPI_Event
@@ -72,6 +74,8 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
val jsonVpnConfig = mService.getVpnConfig()
val ovpnConfig = jsonVpnConfig.getJSONObject("openvpn_config_data").getString("config")
val splitTunnelType = jsonVpnConfig.getInt("splitTunnelType")
val splitTunnelSites = jsonVpnConfig.getJSONArray("splitTunnelSites")
val resultingConfig = StringBuilder()
resultingConfig.append(ovpnConfig)
@@ -115,6 +119,7 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
eval_config(config)
val status = connect()
if (status.getError()) {
Log.i(tag, "connect() error: " + status.getError() + ": " + status.getMessage())
}
@@ -139,6 +144,31 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna
override fun tun_builder_establish(): Int {
Log.v(tag, "tun_builder_establish")
val jsonVpnConfig = mService.getVpnConfig()
val splitTunnelType = jsonVpnConfig.getInt("splitTunnelType")
val splitTunnelSites = jsonVpnConfig.getJSONArray("splitTunnelSites")
if (splitTunnelType == 1) {
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
val ipRange = IPRange(site)
mService.addRoute(ipRange.getFrom().getHostAddress(), ipRange.getPrefix())
}
}
if (splitTunnelType == 2) {
val ipRangeSet = IPRangeSet.fromString("0.0.0.0/0")
ipRangeSet.remove(IPRange("127.0.0.0/8"))
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
ipRangeSet.remove(IPRange(site))
}
ipRangeSet.subnets().forEach {
mService.addRoute(it.getFrom().getHostAddress(), it.getPrefix())
Thread.sleep(10)
}
mService.addRoute("2000::", 3)
}
return mService.establish()!!.detachFd()
}

View File

@@ -380,7 +380,10 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
mNetworkState.bindNetworkListener()
}
"wireguard" -> {
startWireGuard()
startWireGuard("wireguard")
}
"awg" -> {
startWireGuard("awg")
}
"shadowsocks" -> {
startShadowsocks()
@@ -457,7 +460,8 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
fun turnOff() {
Log.v(tag, "Aman: turnOff....................")
when (mProtocol) {
"wireguard" -> {
"wireguard",
"awg" -> {
GoBackend.wgTurnOff(currentTunnelHandle)
}
"cloak",
@@ -559,37 +563,76 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
}
return parseData
}
/**
* Create a Wireguard [Config] from a [json] string -
* The [json] will be created in AndroidVpnProtocol.cpp
*/
private fun buildWireguardConfig(obj: JSONObject): Config {
private fun buildWireguardConfig(obj: JSONObject, type: String): Config {
val confBuilder = Config.Builder()
val wireguardConfigData = obj.getJSONObject("wireguard_config_data")
val wireguardConfigData = obj.getJSONObject(type)
val splitTunnelType = obj.getInt("splitTunnelType")
val splitTunnelSites = obj.getJSONArray("splitTunnelSites")
val config = parseConfigData(wireguardConfigData.getString("config"))
val peerBuilder = Peer.Builder()
val peerConfig = config["Peer"]!!
peerBuilder.setPublicKey(Key.fromBase64(peerConfig["PublicKey"]))
peerConfig["PresharedKey"]?.let {
peerBuilder.setPreSharedKey(Key.fromBase64(it))
peerConfig["PresharedKey"]?.let { peerBuilder.setPreSharedKey(Key.fromBase64(it)) }
val allIpString = peerConfig["AllowedIPs"]
var allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
/* default value in template */
if (allIpString == "0.0.0.0/0, ::/0") {
allowedIPList = emptyList()
}
val allowedIPList = peerConfig["AllowedIPs"]?.split(",") ?: emptyList()
if (allowedIPList.isEmpty()) {
val internet = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internet)
if (allowedIPList.isEmpty() && (splitTunnelType == 0)) {
/* AllowedIP is empty and splitTunnel is turnoff */
/* use VPN for whole Internet */
val internetV4 = InetNetwork.parse("0.0.0.0/0") // aka The whole internet.
peerBuilder.addAllowedIp(internetV4)
val internetV6 = InetNetwork.parse("::/0") // aka The whole internet.
peerBuilder.addAllowedIp(internetV6)
} else {
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
if (!allowedIPList.isEmpty()) {
/* We have predefined AllowedIP in WG config */
/* It's have higher priority than system SplitTunnel */
allowedIPList.forEach {
val network = InetNetwork.parse(it.trim())
peerBuilder.addAllowedIp(network)
}
} else {
if (splitTunnelType == 1) {
/* Use system SplitTunnel */
/* VPN connection used only for defined IPs */
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
val internet = InetNetwork.parse(site)
peerBuilder.addAllowedIp(internet)
}
}
if (splitTunnelType == 2) {
/* Use system SplitTunnel */
/* VPN connection used for all Internet exclude defined IPs */
val ipRangeSet = IPRangeSet.fromString("0.0.0.0/0")
ipRangeSet.remove(IPRange("127.0.0.0/8"))
for (i in 0 until splitTunnelSites.length()) {
val site = splitTunnelSites.getString(i)
ipRangeSet.remove(IPRange(site))
}
val allowedIps = ipRangeSet.subnets().joinToString(", ") + ", 2000::/3"
peerBuilder.parseAllowedIPs(allowedIps)
}
}
}
val endpointConfig = peerConfig["Endpoint"]
val endpoint = InetEndpoint.parse(endpointConfig)
peerBuilder.setEndpoint(endpoint)
peerConfig["PersistentKeepalive"]?.let {
peerBuilder.setPersistentKeepalive(it.toInt())
}
peerConfig["PersistentKeepalive"]?.let { peerBuilder.setPersistentKeepalive(it.toInt()) }
confBuilder.addPeer(peerBuilder.build())
val ifaceBuilder = Interface.Builder()
@@ -599,11 +642,34 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
ifaceConfig["DNS"]!!.split(",").forEach {
ifaceBuilder.addDnsServer(InetNetwork.parse(it.trim()).address)
}
ifaceBuilder.parsePrivateKey(ifaceConfig["PrivateKey"])
if (type == "awg_config_data") {
ifaceBuilder.parseJc(ifaceConfig["Jc"])
ifaceBuilder.parseJmin(ifaceConfig["Jmin"])
ifaceBuilder.parseJmax(ifaceConfig["Jmax"])
ifaceBuilder.parseS1(ifaceConfig["S1"])
ifaceBuilder.parseS2(ifaceConfig["S2"])
ifaceBuilder.parseH1(ifaceConfig["H1"])
ifaceBuilder.parseH2(ifaceConfig["H2"])
ifaceBuilder.parseH3(ifaceConfig["H3"])
ifaceBuilder.parseH4(ifaceConfig["H4"])
} else {
ifaceBuilder.parseJc("0")
ifaceBuilder.parseJmin("0")
ifaceBuilder.parseJmax("0")
ifaceBuilder.parseS1("0")
ifaceBuilder.parseS2("0")
ifaceBuilder.parseH1("0")
ifaceBuilder.parseH2("0")
ifaceBuilder.parseH3("0")
ifaceBuilder.parseH4("0")
}
/*val jExcludedApplication = obj.getJSONArray("excludedApps")
(0 until jExcludedApplication.length()).toList().forEach {
(0 until jExcludedApplication.length()).toList().forEach {
val appName = jExcludedApplication.get(it).toString()
ifaceBuilder.excludeApplication(appName)
}*/
}*/
confBuilder.setInterface(ifaceBuilder.build())
return confBuilder.build()
@@ -716,21 +782,27 @@ class VPNService : BaseVpnService(), LocalDnsService.Interface {
}).start()
}
private fun startWireGuard() {
val wireguard_conf = buildWireguardConfig(mConfig!!)
Log.i(tag, "startWireGuard: wireguard_conf : $wireguard_conf")
private fun startWireGuard(type: String) {
val wireguard_conf = buildWireguardConfig(mConfig!!, type + "_config_data")
if (currentTunnelHandle != -1) {
Log.e(tag, "Tunnel already up")
// Turn the tunnel down because this might be a switch
GoBackend.wgTurnOff(currentTunnelHandle)
}
val wgConfig: String = wireguard_conf.toWgUserspaceString()
val builder = Builder()
setupBuilder(wireguard_conf, builder)
builder.setSession("Amnezia")
builder.establish().use { tun ->
if (tun == null) return
currentTunnelHandle = GoBackend.wgTurnOn("Amnezia", tun.detachFd(), wgConfig)
if (tun == null) return
if (type == "awg"){
currentTunnelHandle = GoBackend.wgTurnOn("awg0", tun.detachFd(), wgConfig)
} else {
currentTunnelHandle = GoBackend.wgTurnOn("amn0", tun.detachFd(), wgConfig)
}
}
if (currentTunnelHandle < 0) {
Log.e(tag, "Activation Error Code -> $currentTunnelHandle")

View File

@@ -10,6 +10,7 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
)
@@ -18,6 +19,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_notificationhandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidutils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/androidvpnactivity.cpp
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
)

View File

@@ -97,7 +97,7 @@ target_compile_options(${PROJECT} PRIVATE
-DVPN_NE_BUNDLEID=\"${BUILD_IOS_APP_IDENTIFIER}.network-extension\"
)
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/wireguard-apple/Sources)
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/awg-apple/Sources)
target_sources(${PROJECT} PRIVATE
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift

View File

@@ -0,0 +1,47 @@
#include "awg_configurator.h"
#include <QJsonDocument>
#include <QJsonObject>
#include "core/servercontroller.h"
AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: WireguardConfigurator(settings, true, parent)
{
}
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials,
DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode);
QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object();
QString awgConfig = jsonConfig.value(config_key::config).toString();
QMap<QString, QString> configMap;
auto configLines = awgConfig.split("\n");
for (auto &line : configLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
configMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
jsonConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
jsonConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
jsonConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
jsonConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
jsonConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
jsonConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
return QJsonDocument(jsonConfig).toJson();
}

View File

@@ -0,0 +1,18 @@
#ifndef AWGCONFIGURATOR_H
#define AWGCONFIGURATOR_H
#include <QObject>
#include "wireguard_configurator.h"
class AwgConfigurator : public WireguardConfigurator
{
Q_OBJECT
public:
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // AWGCONFIGURATOR_H

View File

@@ -1,28 +1,26 @@
#include "ikev2_configurator.h"
#include <QApplication>
#include <QDebug>
#include <QJsonDocument>
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
#include <QDebug>
#include <QTemporaryFile>
#include <QJsonDocument>
#include <QUuid>
#include "containers/containers_defs.h"
#include "core/server_defs.h"
#include "core/scripts_registry.h"
#include "utilities.h"
#include "core/server_defs.h"
#include "core/servercontroller.h"
#include "utilities.h"
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
}
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container, ErrorCode *errorCode)
{
Ikev2Configurator::ConnectionData connData;
connData.host = credentials.hostName;
@@ -32,26 +30,27 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
QString certFileName = "/opt/amnezia/ikev2/clients/" + connData.clientId + ".p12";
QString scriptCreateCert = QString("certutil -z <(head -c 1024 /dev/urandom) "\
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "\
"-s \"O=IKEv2 VPN,CN=%1\" "\
"-k rsa -g 3072 -v 120 "\
"-d sql:/etc/ipsec.d -t \",,\" "\
"--keyUsage digitalSignature,keyEncipherment "\
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
.arg(connData.clientId);
QString scriptCreateCert = QString("certutil -z <(head -c 1024 /dev/urandom) "
"-S -c \"IKEv2 VPN CA\" -n \"%1\" "
"-s \"O=IKEv2 VPN,CN=%1\" "
"-k rsa -g 3072 -v 120 "
"-d sql:/etc/ipsec.d -t \",,\" "
"--keyUsage digitalSignature,keyEncipherment "
"--extKeyUsage serverAuth,clientAuth -8 \"%1\"")
.arg(connData.clientId);
ServerController serverController(m_settings);
ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert);
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
.arg(connData.password)
.arg(connData.clientId)
.arg(certFileName);
.arg(connData.password)
.arg(connData.clientId)
.arg(certFileName);
e = serverController.runContainerScript(credentials, container, scriptExportCert);
connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e);
connData.caCert = serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
connData.caCert =
serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e);
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
@@ -59,8 +58,8 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
return connData;
}
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
Q_UNUSED(containerConfig)
@@ -120,4 +119,3 @@ QString Ikev2Configurator::genStrongSwanConfig(const ConnectionData &connData)
return config;
}

View File

@@ -1,82 +1,94 @@
#include "openvpn_configurator.h"
#include <QApplication>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
#include <QDebug>
#include <QTemporaryFile>
#include <QJsonObject>
#include <QJsonDocument>
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include <QGuiApplication>
#else
#include <QApplication>
#endif
#include "containers/containers_defs.h"
#include "core/scripts_registry.h"
#include "core/server_defs.h"
#include "core/servercontroller.h"
#include "core/scripts_registry.h"
#include "utilities.h"
#include "settings.h"
#include "utilities.h"
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
}
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container,
ErrorCode *errorCode)
{
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
connData.host = credentials.hostName;
if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::OpenSslFailed;
if (errorCode)
*errorCode = ErrorCode::OpenSslFailed;
return connData;
}
QString reqFileName = QString("%1/%2.req").
arg(amnezia::protocols::openvpn::clientsDirPath).
arg(connData.clientId);
QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath).arg(connData.clientId);
ServerController serverController(m_settings);
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
e = signCert(container, credentials, connData.clientId);
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
connData.caCert = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath, &e);
connData.clientCert = serverController.getTextFileFromContainer(container, credentials,
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e);
connData.caCert = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::openvpn::caCertPath, &e);
connData.clientCert = serverController.getTextFileFromContainer(
container, credentials,
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e);
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
connData.taKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath, &e);
connData.taKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::openvpn::taKeyPath, &e);
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::SshSftpFailureError;
if (errorCode)
*errorCode = ErrorCode::SshSftpFailureError;
}
return connData;
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
QString config =
serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
if (errorCode && *errorCode) {
@@ -89,8 +101,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
if (config.contains("$OPENVPN_TA_KEY")) {
config.replace("$OPENVPN_TA_KEY", connData.taKey);
}
else {
} else {
config.replace("<tls-auth>", "");
config.replace("</tls-auth>", "");
}
@@ -120,10 +131,13 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
config.append("block-ipv6\n");
}
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
// no redirect-gateway
}
if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#ifndef Q_OS_ANDROID
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
#endif
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
config.append("block-ipv6\n");
@@ -133,12 +147,11 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig)
config.replace("block-outside-dns", "");
#endif
#if (defined (MZ_MACOS) || defined(MZ_LINUX))
QString dnsConf = QString(
"\nscript-security 2\n"
"up %1/update-resolv-conf.sh\n"
"down %1/update-resolv-conf.sh\n").
arg(qApp->applicationDirPath());
#if (defined(MZ_MACOS) || defined(MZ_LINUX))
QString dnsConf = QString("\nscript-security 2\n"
"up %1/update-resolv-conf.sh\n"
"down %1/update-resolv-conf.sh\n")
.arg(qApp->applicationDirPath());
config.append(dnsConf);
#endif
@@ -168,23 +181,23 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(QString jsonConfig)
return QJsonDocument(json).toJson();
}
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
const ServerCredentials &credentials, QString clientId)
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId)
{
QString script_import = QString("sudo docker exec -i %1 bash -c \"cd /opt/amnezia/openvpn && "
"easyrsa import-req %2/%3.req %3\"")
.arg(ContainerProps::containerToString(container))
.arg(amnezia::protocols::openvpn::clientsDirPath)
.arg(clientId);
"easyrsa import-req %2/%3.req %3\"")
.arg(ContainerProps::containerToString(container))
.arg(amnezia::protocols::openvpn::clientsDirPath)
.arg(clientId);
QString script_sign = QString("sudo docker exec -i %1 bash -c \"export EASYRSA_BATCH=1; cd /opt/amnezia/openvpn && "
"easyrsa sign-req client %2\"")
.arg(ContainerProps::containerToString(container))
.arg(clientId);
"easyrsa sign-req client %2\"")
.arg(ContainerProps::containerToString(container))
.arg(clientId);
ServerController serverController(m_settings);
QStringList scriptList {script_import, script_sign};
QString script = serverController.replaceVars(scriptList.join("\n"), serverController.genVarsForScript(credentials, container));
QStringList scriptList { script_import, script_sign };
QString script = serverController.replaceVars(scriptList.join("\n"),
serverController.genVarsForScript(credentials, container));
return serverController.runScript(credentials, script);
}
@@ -194,18 +207,17 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
ConnectionData connData;
connData.clientId = Utils::getRandomString(32);
int ret = 0;
int nVersion = 1;
int ret = 0;
int nVersion = 1;
QByteArray clientIdUtf8 = connData.clientId.toUtf8();
EVP_PKEY * pKey = EVP_PKEY_new();
EVP_PKEY *pKey = EVP_PKEY_new();
q_check_ptr(pKey);
RSA * rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
RSA *rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
q_check_ptr(rsa);
EVP_PKEY_assign_RSA(pKey, rsa);
// 2. set version of x509 req
X509_REQ *x509_req = X509_REQ_new();
ret = X509_REQ_set_version(x509_req, nVersion);
@@ -219,16 +231,14 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
// 3. set subject of x509 req
X509_NAME *x509_name = X509_REQ_get_subject_name(x509_req);
X509_NAME_add_entry_by_txt(x509_name, "C", MBSTRING_ASC,
(unsigned char *)"ORG", -1, -1, 0);
X509_NAME_add_entry_by_txt(x509_name, "O", MBSTRING_ASC,
(unsigned char *)"", -1, -1, 0);
X509_NAME_add_entry_by_txt(x509_name, "C", MBSTRING_ASC, (unsigned char *)"ORG", -1, -1, 0);
X509_NAME_add_entry_by_txt(x509_name, "O", MBSTRING_ASC, (unsigned char *)"", -1, -1, 0);
X509_NAME_add_entry_by_txt(x509_name, "CN", MBSTRING_ASC,
reinterpret_cast<unsigned char const *>(clientIdUtf8.data()), clientIdUtf8.size(), -1, 0);
// 4. set public key of x509 req
ret = X509_REQ_set_pubkey(x509_req, pKey);
if (ret != 1){
if (ret != 1) {
qWarning() << "Could not set pubkey!";
X509_REQ_free(x509_req);
EVP_PKEY_free(pKey);
@@ -236,8 +246,8 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
}
// 5. set sign key of x509 req
ret = X509_REQ_sign(x509_req, pKey, EVP_sha256()); // return x509_req->signature->length
if (ret <= 0){
ret = X509_REQ_sign(x509_req, pKey, EVP_sha256()); // return x509_req->signature->length
if (ret <= 0) {
qWarning() << "Could not sign request!";
X509_REQ_free(x509_req);
EVP_PKEY_free(pKey);
@@ -245,10 +255,9 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
}
// save private key
BIO * bp_private = BIO_new(BIO_s_mem());
BIO *bp_private = BIO_new(BIO_s_mem());
q_check_ptr(bp_private);
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
{
if (PEM_write_bio_PrivateKey(bp_private, pKey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
qFatal("PEM_write_bio_PrivateKey");
EVP_PKEY_free(pKey);
BIO_free_all(bp_private);
@@ -256,7 +265,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
return connData;
}
const char * buffer = nullptr;
const char *buffer = nullptr;
size_t size = BIO_get_mem_data(bp_private, &buffer);
q_check_ptr(buffer);
connData.privKey = QByteArray(buffer, size);
@@ -270,7 +279,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
BIO_free_all(bp_private);
// save req
BIO * bio_req = BIO_new(BIO_s_mem());
BIO *bio_req = BIO_new(BIO_s_mem());
PEM_write_bio_X509_REQ(bio_req, x509_req);
BUF_MEM *bio_buf;
@@ -278,7 +287,6 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
connData.request = QByteArray(bio_buf->data, bio_buf->length);
BIO_free(bio_req);
EVP_PKEY_free(pKey); // this will also free the rsa key
return connData;

View File

@@ -1,24 +1,25 @@
#include "ssh_configurator.h"
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
#include <QDebug>
#include <QTemporaryFile>
#include <QThread>
#include <QObject>
#include <QTextEdit>
#include <QPlainTextEdit>
#include <qtimer.h>
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include <QGuiApplication>
#else
#include <QApplication>
#endif
#include "core/server_defs.h"
#include "utilities.h"
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
SshConfigurator::SshConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
}
QString SshConfigurator::convertOpenSShKey(const QString &key)
@@ -28,23 +29,30 @@ QString SshConfigurator::convertOpenSShKey(const QString &key)
p.setProcessChannelMode(QProcess::MergedChannels);
QTemporaryFile tmp;
#ifdef QT_DEBUG
#ifdef QT_DEBUG
tmp.setAutoRemove(false);
#endif
#endif
tmp.open();
tmp.write(key.toUtf8());
tmp.close();
// ssh-keygen -p -P "" -N "" -m pem -f id_ssh
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN
p.setProcessEnvironment(prepareEnv());
p.setProgram("cmd.exe");
p.setNativeArguments(QString("/C \"ssh-keygen.exe -p -P \"\" -N \"\" -m pem -f \"%1\"\"").arg(tmp.fileName()));
#else
#else
p.setProgram("ssh-keygen");
p.setArguments(QStringList() << "-p" << "-P" << "" << "-N" << "" << "-m" << "pem" << "-f" << tmp.fileName());
#endif
p.setArguments(QStringList() << "-p"
<< "-P"
<< ""
<< "-N"
<< ""
<< "-m"
<< "pem"
<< "-f" << tmp.fileName());
#endif
p.start();
p.waitForFinished();
@@ -65,22 +73,21 @@ void SshConfigurator::openSshTerminal(const ServerCredentials &credentials)
QProcess *p = new QProcess();
p->setProcessChannelMode(QProcess::SeparateChannels);
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN
p->setProcessEnvironment(prepareEnv());
p->setProgram(qApp->applicationDirPath() + "\\cygwin\\putty.exe");
if (credentials.password.contains("PRIVATE KEY")) {
if (credentials.secretData.contains("PRIVATE KEY")) {
// todo: connect by key
// p->setNativeArguments(QString("%1@%2")
// .arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
// p->setNativeArguments(QString("%1@%2")
// .arg(credentials.userName).arg(credentials.hostName).arg(credentials.secretData));
} else {
p->setNativeArguments(
QString("%1@%2 -pw %3").arg(credentials.userName).arg(credentials.hostName).arg(credentials.secretData));
}
else {
p->setNativeArguments(QString("%1@%2 -pw %3")
.arg(credentials.userName).arg(credentials.hostName).arg(credentials.password));
}
#else
#else
p->setProgram("/bin/bash");
#endif
#endif
p->startDetached();
#endif
@@ -95,11 +102,11 @@ QProcessEnvironment SshConfigurator::prepareEnv()
pathEnvVar.clear();
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\cygwin;");
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\openvpn;");
#else
#elif defined(Q_OS_MACX)
pathEnvVar.prepend(QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/Contents/MacOS");
#endif
env.insert("PATH", pathEnvVar);
//qDebug().noquote() << "ENV PATH" << pathEnvVar;
// qDebug().noquote() << "ENV PATH" << pathEnvVar;
return env;
}

View File

@@ -1,32 +1,34 @@
#include "vpn_configurator.h"
#include "openvpn_configurator.h"
#include "cloak_configurator.h"
#include "shadowsocks_configurator.h"
#include "wireguard_configurator.h"
#include "ikev2_configurator.h"
#include "openvpn_configurator.h"
#include "shadowsocks_configurator.h"
#include "ssh_configurator.h"
#include "wireguard_configurator.h"
#include "awg_configurator.h"
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonObject>
#include "containers/containers_defs.h"
#include "utilities.h"
#include "settings.h"
#include "utilities.h"
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, this));
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, this));
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, false, this));
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, this));
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
awgConfigurator = std::shared_ptr<AwgConfigurator>(new AwgConfigurator(settings, this));
}
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
{
switch (proto) {
case Proto::OpenVpn:
@@ -35,17 +37,17 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
case Proto::ShadowSocks:
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak:
return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::WireGuard:
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
case Proto::Ikev2:
return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
case Proto::Awg:
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, errorCode);
default:
return "";
case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
default: return "";
}
}
@@ -62,8 +64,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
if (dns.first.isEmpty() || !Utils::checkIPv4Format(dns.first)) {
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
dns.first = protocols::dns::amneziaDnsIp;
}
else dns.first = m_settings->primaryDns();
} else
dns.first = m_settings->primaryDns();
}
if (dns.second.isEmpty() || !Utils::checkIPv4Format(dns.second)) {
dns.second = m_settings->secondaryDns();
@@ -73,8 +75,8 @@ QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
return dns;
}
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
auto dns = getDnsForConfig(serverIndex);
@@ -84,8 +86,8 @@ QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerCo
return config;
}
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -95,8 +97,8 @@ QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, Docker
return config;
}
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container,
Proto proto, QString &config)
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
@@ -107,7 +109,7 @@ QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, Docke
}
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);

View File

@@ -13,13 +13,14 @@ class CloakConfigurator;
class WireguardConfigurator;
class Ikev2Configurator;
class SshConfigurator;
class AwgConfigurator;
// Retrieve connection settings from server
class VpnConfigurator : ConfiguratorBase
{
Q_OBJECT
public:
VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
explicit VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
@@ -40,6 +41,7 @@ public:
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
std::shared_ptr<SshConfigurator> sshConfigurator;
std::shared_ptr<AwgConfigurator> awgConfigurator;
};
#endif // VPN_CONFIGURATOR_H

View File

@@ -1,30 +1,38 @@
#include "wireguard_configurator.h"
#include <QApplication>
#include <QDebug>
#include <QJsonDocument>
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
#include <QDebug>
#include <QTemporaryFile>
#include <QJsonDocument>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "containers/containers_defs.h"
#include "core/server_defs.h"
#include "core/scripts_registry.h"
#include "utilities.h"
#include "core/server_defs.h"
#include "core/servercontroller.h"
#include "settings.h"
#include "utilities.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent)
: ConfiguratorBase(settings, parent), m_isAwg(isAwg)
{
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath
: amnezia::protocols::wireguard::serverConfigPath;
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath
: amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath
: amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template
: ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
@@ -36,37 +44,40 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
unsigned char buff[EDDSA_KEY_LENGTH];
int ret = RAND_priv_bytes(buff, EDDSA_KEY_LENGTH);
if (ret <=0) return connData;
if (ret <= 0)
return connData;
EVP_PKEY * pKey = EVP_PKEY_new();
EVP_PKEY *pKey = EVP_PKEY_new();
q_check_ptr(pKey);
pKey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, &buff[0], EDDSA_KEY_LENGTH);
size_t keySize = EDDSA_KEY_LENGTH;
// save private key
unsigned char priv[EDDSA_KEY_LENGTH];
EVP_PKEY_get_raw_private_key(pKey, priv, &keySize);
connData.clientPrivKey = QByteArray::fromRawData((char*)priv, keySize).toBase64();
connData.clientPrivKey = QByteArray::fromRawData((char *)priv, keySize).toBase64();
// save public key
unsigned char pub[EDDSA_KEY_LENGTH];
EVP_PKEY_get_raw_public_key(pKey, pub, &keySize);
connData.clientPubKey = QByteArray::fromRawData((char*)pub, keySize).toBase64();
connData.clientPubKey = QByteArray::fromRawData((char *)pub, keySize).toBase64();
return connData;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
DockerContainer container,
const QJsonObject &containerConfig,
ErrorCode *errorCode)
{
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName;
connData.port = containerConfig.value(config_key::port).toString(protocols::wireguard::defaultPort);
connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort);
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::InternalError;
if (errorCode)
*errorCode = ErrorCode::InternalError;
return connData;
}
@@ -76,7 +87,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
// Get list of already created clients (only IP addresses)
QString nextIpNumber;
{
QString script = QString("cat %1 | grep AllowedIPs").arg(amnezia::protocols::wireguard::serverConfigPath);
QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
@@ -96,22 +107,24 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
// Calc next IP address
if (ips.isEmpty()) {
nextIpNumber = "2";
}
else {
} else {
int next = ips.last().split(".").last().toInt() + 1;
if (next > 254) {
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
if (errorCode)
*errorCode = ErrorCode::AddressPoolError;
return connData;
}
nextIpNumber = QString::number(next);
}
}
QString subnetIp = containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
QString subnetIp =
containerConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
{
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
if (l.isEmpty()) {
if (errorCode) *errorCode = ErrorCode::AddressPoolError;
if (errorCode)
*errorCode = ErrorCode::AddressPoolError;
return connData;
}
l.removeLast();
@@ -121,52 +134,55 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
// Get keys
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPublicKeyPath, &e);
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, &e);
connData.serverPubKey.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::wireguard::serverPskKeyPath, &e);
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, &e);
connData.pskKey.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
// Add client to config
QString configPart = QString(
"[Peer]\n"
"PublicKey = %1\n"
"PresharedKey = %2\n"
"AllowedIPs = %3/32\n\n").
arg(connData.clientPubKey).
arg(connData.pskKey).
arg(connData.clientIP);
QString configPart = QString("[Peer]\n"
"PublicKey = %1\n"
"PresharedKey = %2\n"
"AllowedIPs = %3/32\n\n")
.arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
e = serverController.uploadTextFileToContainer(container, credentials, configPart,
protocols::wireguard::serverConfigPath, libssh::SftpOverwriteMode::SftpAppendToExisting);
e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
libssh::SftpOverwriteMode::SftpAppendToExisting);
if (e) {
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return connData;
}
e = serverController.runScript(credentials,
serverController.replaceVars("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip /opt/amnezia/wireguard/wg0.conf)'",
serverController.genVarsForScript(credentials, container)));
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
.arg(m_serverConfigPath);
e = serverController.runScript(
credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
return connData;
}
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ServerController serverController(m_settings);
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::wireguard_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
QString scriptData = amnezia::scriptData(m_configTemplate, container);
QString config = serverController.replaceVars(
scriptData, serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode && *errorCode) {

View File

@@ -6,35 +6,44 @@
#include "configurator_base.h"
#include "core/defs.h"
#include "core/scripts_registry.h"
class WireguardConfigurator : ConfiguratorBase
class WireguardConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
WireguardConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent = nullptr);
struct ConnectionData {
struct ConnectionData
{
QString clientPrivKey; // client private key
QString clientPubKey; // client public key
QString clientIP; // internal client IP address
QString serverPubKey; // tls-auth key
QString pskKey; // preshared key
QString host; // host ip
QString clientPubKey; // client public key
QString clientIP; // internal client IP address
QString serverPubKey; // tls-auth key
QString pskKey; // preshared key
QString host; // host ip
QString port;
};
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString processConfigWithLocalSettings(QString config);
QString processConfigWithExportSettings(QString config);
private:
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
ConnectionData genClientKeys();
bool m_isAwg;
QString m_serverConfigPath;
QString m_serverPublicKeyPath;
QString m_serverPskKeyPath;
amnezia::ProtocolScriptType m_configTemplate;
QString m_protocolName;
QString m_defaultPort;
};
#endif // WIREGUARD_CONFIGURATOR_H

View File

@@ -8,18 +8,23 @@ QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
return debug;
}
amnezia::DockerContainer ContainerProps::containerFromString(const QString &container){
amnezia::DockerContainer ContainerProps::containerFromString(const QString &container)
{
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
for (int i = 0; i < metaEnum.keyCount(); ++i) {
DockerContainer c = static_cast<DockerContainer>(i);
if (container == containerToString(c)) return c;
if (container == containerToString(c))
return c;
}
return DockerContainer::None;
}
QString ContainerProps::containerToString(amnezia::DockerContainer c){
if (c == DockerContainer::None) return "none";
if (c == DockerContainer::Cloak) return "amnezia-openvpn-cloak";
QString ContainerProps::containerToString(amnezia::DockerContainer c)
{
if (c == DockerContainer::None)
return "none";
if (c == DockerContainer::Cloak)
return "amnezia-openvpn-cloak";
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
@@ -27,9 +32,12 @@ QString ContainerProps::containerToString(amnezia::DockerContainer c){
return "amnezia-" + containerKey.toLower();
}
QString ContainerProps::containerTypeToString(amnezia::DockerContainer c){
if (c == DockerContainer::None) return "none";
if (c == DockerContainer::Ipsec) return "ikev2";
QString ContainerProps::containerTypeToString(amnezia::DockerContainer c)
{
if (c == DockerContainer::None)
return "none";
if (c == DockerContainer::Ipsec)
return "ikev2";
QMetaEnum metaEnum = QMetaEnum::fromType<DockerContainer>();
QString containerKey = metaEnum.valueToKey(static_cast<int>(c));
@@ -40,29 +48,21 @@ QString ContainerProps::containerTypeToString(amnezia::DockerContainer c){
QVector<amnezia::Proto> ContainerProps::protocolsForContainer(amnezia::DockerContainer container)
{
switch (container) {
case DockerContainer::None:
return { };
case DockerContainer::None: return {};
case DockerContainer::OpenVpn:
return { Proto::OpenVpn };
case DockerContainer::OpenVpn: return { Proto::OpenVpn };
case DockerContainer::ShadowSocks:
return { Proto::OpenVpn, Proto::ShadowSocks };
case DockerContainer::ShadowSocks: return { Proto::OpenVpn, Proto::ShadowSocks };
case DockerContainer::Cloak:
return { Proto::OpenVpn, Proto::ShadowSocks, Proto::Cloak };
case DockerContainer::Cloak: return { Proto::OpenVpn, Proto::ShadowSocks, Proto::Cloak };
case DockerContainer::Ipsec:
return { Proto::Ikev2 /*, Protocol::L2tp */};
case DockerContainer::Ipsec: return { Proto::Ikev2 /*, Protocol::L2tp */ };
case DockerContainer::Dns:
return { };
case DockerContainer::Dns: return {};
case DockerContainer::Sftp:
return { Proto::Sftp};
case DockerContainer::Sftp: return { Proto::Sftp };
default:
return { defaultProtocol(container) };
default: return { defaultProtocol(container) };
}
}
@@ -79,70 +79,164 @@ QList<DockerContainer> ContainerProps::allContainers()
QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
{
return {
{DockerContainer::None, "Not installed"},
{DockerContainer::OpenVpn, "OpenVPN"},
{DockerContainer::ShadowSocks, "OpenVpn over ShadowSocks"},
{DockerContainer::Cloak, "OpenVpn over Cloak"},
{DockerContainer::WireGuard, "WireGuard"},
{DockerContainer::Ipsec, QObject::tr("IPsec")},
return { { DockerContainer::None, "Not installed" },
{ DockerContainer::OpenVpn, "OpenVPN" },
{ DockerContainer::ShadowSocks, "ShadowSocks" },
{ DockerContainer::Cloak, "OpenVPN over Cloak" },
{ DockerContainer::WireGuard, "WireGuard" },
{ DockerContainer::Awg, "AmneziaWG" },
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
{DockerContainer::Dns, QObject::tr("DNS Service")},
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service")},
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service")}
};
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("Amnezia DNS") },
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service") } };
}
QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
{
return {
{DockerContainer::OpenVpn, QObject::tr("OpenVPN container")},
{DockerContainer::ShadowSocks, QObject::tr("Container with OpenVpn and ShadowSocks")},
{DockerContainer::Cloak, QObject::tr("Container with OpenVpn and ShadowSocks protocols "
"configured with traffic masking by Cloak plugin")},
{DockerContainer::WireGuard, QObject::tr("WireGuard container")},
{DockerContainer::Ipsec, QObject::tr("IPsec container")},
return { { DockerContainer::OpenVpn,
QObject::tr("OpenVPN is the most popular VPN protocol, with flexible configuration options. It uses its "
"own security protocol with SSL/TLS for key exchange.") },
{ DockerContainer::ShadowSocks,
QObject::tr("ShadowSocks - masks VPN traffic, making it similar to normal web traffic, but is "
"recognised by analysis systems in some highly censored regions.") },
{ DockerContainer::Cloak,
QObject::tr("OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against "
"active-probbing detection. Ideal for bypassing blocking in regions with the highest levels "
"of censorship.") },
{ DockerContainer::WireGuard,
QObject::tr("WireGuard - New popular VPN protocol with high performance, high speed and low power "
"consumption. Recommended for regions with low levels of censorship.") },
{ DockerContainer::Awg,
QObject::tr("AmneziaWG - Special protocol from Amnezia, based on WireGuard. It's fast like WireGuard, "
"but very resistant to blockages. "
"Recommended for regions with high levels of censorship.") },
{ DockerContainer::Ipsec,
QObject::tr("IKEv2 - Modern stable protocol, a bit faster than others, restores connection after "
"signal loss. It has native support on the latest versions of Android and iOS.") },
{DockerContainer::TorWebSite, QObject::tr("Web site in Tor network")},
{DockerContainer::Dns, QObject::tr("DNS Service")},
//{DockerContainer::FileShare, QObject::tr("SMB file sharing service - is Window file sharing protocol")},
{DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service")}
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
{ DockerContainer::Dns,
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
{ DockerContainer::Sftp,
QObject::tr("Creates a file vault on your server to securely store and transfer files.") } };
}
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
{
return {
{ DockerContainer::OpenVpn,
QObject::tr(
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"It employs its unique security protocol, "
"leveraging the strength of SSL/TLS for encryption and key exchange. "
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
"catering to a wide range of devices and operating systems. "
"Due to its open-source nature, OpenVPN benefits from extensive scrutiny by the global community, "
"which continually reinforces its security. "
"With a strong balance of performance, security, and compatibility, "
"OpenVPN remains a top choice for privacy-conscious individuals and businesses alike.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Normal power consumption on mobile devices\n"
"* Flexible customisation to suit user needs to work with different operating systems and devices\n"
"* Recognised by DPI analysis systems and therefore susceptible to blocking\n"
"* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks,
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
"* Available in the AmneziaVPN only on desktop platforms\n"
"* Normal power consumption on mobile devices\n\n"
"* Configurable encryption protocol\n"
"* Detectable by some DPI systems\n"
"* Works over TCP network protocol.") },
{ DockerContainer::Cloak,
QObject::tr("This is a combination of the OpenVPN protocol and the Cloak plugin designed specifically for "
"blocking protection.\n\n"
"OpenVPN provides a secure VPN connection by encrypting all Internet traffic between the client "
"and the server.\n\n"
"Cloak protects OpenVPN from detection and blocking. \n\n"
"Cloak can modify packet metadata so that it completely masks VPN traffic as normal web traffic, "
"and also protects the VPN from detection by Active Probing. This makes it very resistant to "
"being detected\n\n"
"Immediately after receiving the first data packet, Cloak authenticates the incoming connection. "
"If authentication fails, the plugin masks the server as a fake website and your VPN becomes "
"invisible to analysis systems.\n\n"
"If there is a extreme level of Internet censorship in your region, we advise you to use only "
"OpenVPN over Cloak from the first connection\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* High power consumption on mobile devices\n"
"* Flexible settings\n"
"* Not recognised by DPI analysis systems\n"
"* Works over TCP network protocol, 443 port.\n") },
{ DockerContainer::WireGuard,
QObject::tr("A relatively new popular VPN protocol with a simplified architecture.\n"
"Provides stable VPN connection, high performance on all devices. Uses hard-coded encryption "
"settings. WireGuard compared to OpenVPN has lower latency and better data transfer throughput.\n"
"WireGuard is very susceptible to blocking due to its distinct packet signatures. "
"Unlike some other VPN protocols that employ obfuscation techniques, "
"the consistent signature patterns of WireGuard packets can be more easily identified and "
"thus blocked by advanced Deep Packet Inspection (DPI) systems and other network monitoring tools.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Easily recognised by DPI analysis systems, susceptible to blocking\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Awg,
QObject::tr("A modern iteration of the popular VPN protocol, "
"AmneziaWG builds upon the foundation set by WireGuard, "
"retaining its simplified architecture and high-performance capabilities across devices.\n"
"While WireGuard is known for its efficiency, "
"it had issues with being easily detected due to its distinct packet signatures. "
"AmneziaWG solves this problem by using better obfuscation methods, "
"making its traffic blend in with regular internet traffic.\n"
"This means that AmneziaWG keeps the fast performance of the original "
"while adding an extra layer of stealth, "
"making it a great choice for those wanting a fast and discreet VPN connection.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Not recognised by DPI analysis systems, resistant to blocking\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Ipsec,
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
"making it particularly adaptive in dynamic network environments. \n"
"While it offers a blend of security, stability, and speed, "
"it's essential to note that IKEv2 can be easily detected and is susceptible to blocking.\n\n"
"* Available in the AmneziaVPN only on Windows\n"
"* Low power consumption, on mobile devices\n"
"* Minimal configuration\n"
"* Recognised by DPI analysis systems\n"
"* Works over UDP network protocol, ports 500 and 4500.") },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("DNS Service") },
{ DockerContainer::Sftp, QObject::tr("Sftp file sharing service - is secure FTP service") }
};
}
amnezia::ServiceType ContainerProps::containerService(DockerContainer c)
{
switch (c) {
case DockerContainer::None : return ServiceType::None;
case DockerContainer::OpenVpn : return ServiceType::Vpn;
case DockerContainer::Cloak : return ServiceType::Vpn;
case DockerContainer::ShadowSocks : return ServiceType::Vpn;
case DockerContainer::WireGuard : return ServiceType::Vpn;
case DockerContainer::Ipsec : return ServiceType::Vpn;
case DockerContainer::TorWebSite : return ServiceType::Other;
case DockerContainer::Dns : return ServiceType::Other;
//case DockerContainer::FileShare : return ServiceType::Other;
case DockerContainer::Sftp : return ServiceType::Other;
default: return ServiceType::Other;
}
return ProtocolProps::protocolService(defaultProtocol(c));
}
Proto ContainerProps::defaultProtocol(DockerContainer c)
{
switch (c) {
case DockerContainer::None : return Proto::Any;
case DockerContainer::OpenVpn : return Proto::OpenVpn;
case DockerContainer::Cloak : return Proto::Cloak;
case DockerContainer::ShadowSocks : return Proto::ShadowSocks;
case DockerContainer::WireGuard : return Proto::WireGuard;
case DockerContainer::Ipsec : return Proto::Ikev2;
case DockerContainer::None: return Proto::Any;
case DockerContainer::OpenVpn: return Proto::OpenVpn;
case DockerContainer::Cloak: return Proto::Cloak;
case DockerContainer::ShadowSocks: return Proto::ShadowSocks;
case DockerContainer::WireGuard: return Proto::WireGuard;
case DockerContainer::Awg: return Proto::Awg;
case DockerContainer::Ipsec: return Proto::Ikev2;
case DockerContainer::TorWebSite : return Proto::TorWebSite;
case DockerContainer::Dns : return Proto::Dns;
//case DockerContainer::FileShare : return Protocol::FileShare;
case DockerContainer::Sftp : return Proto::Sftp;
default: return Proto::Any;
case DockerContainer::TorWebSite: return Proto::TorWebSite;
case DockerContainer::Dns: return Proto::Dns;
case DockerContainer::Sftp: return Proto::Sftp;
default: return Proto::Any;
}
}
@@ -151,31 +245,34 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
#ifdef Q_OS_WINDOWS
return true;
#elif defined (Q_OS_IOS)
#elif defined(Q_OS_IOS)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::OpenVpn: return true;
case DockerContainer::Cloak: return true;
// case DockerContainer::ShadowSocks: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak:
return true;
// case DockerContainer::ShadowSocks: return true;
default: return false;
}
#elif defined (Q_OS_MAC)
#elif defined(Q_OS_MAC)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::Ipsec: return false;
default: return true;
}
#elif defined (Q_OS_ANDROID)
#elif defined(Q_OS_ANDROID)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::OpenVpn: return true;
case DockerContainer::ShadowSocks: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak: return true;
default: return false;
}
#elif defined (Q_OS_LINUX)
#elif defined(Q_OS_LINUX)
switch (c) {
case DockerContainer::WireGuard: return true;
case DockerContainer::Ipsec: return false;
@@ -183,14 +280,65 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
}
#else
return false;
return false;
#endif
}
QStringList ContainerProps::fixedPortsForContainer(DockerContainer c)
{
switch (c) {
case DockerContainer::Ipsec : return QStringList{"500", "4500"};
default: return {};
case DockerContainer::Ipsec: return QStringList { "500", "4500" };
default: return {};
}
}
bool ContainerProps::isEasySetupContainer(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return true;
case DockerContainer::Awg: return true;
case DockerContainer::Cloak: return true;
default: return false;
}
}
QString ContainerProps::easySetupHeader(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return tr("Low");
case DockerContainer::Awg: return tr("Medium or High");
case DockerContainer::Cloak: return tr("Extreme");
default: return "";
}
}
QString ContainerProps::easySetupDescription(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return tr("I just want to increase the level of my privacy.");
case DockerContainer::Awg: return tr("I want to bypass censorship. This option recommended in most cases.");
case DockerContainer::Cloak:
return tr("Most VPN protocols are blocked. Recommended if other options are not working.");
default: return "";
}
}
int ContainerProps::easySetupOrder(DockerContainer container)
{
switch (container) {
case DockerContainer::WireGuard: return 3;
case DockerContainer::Awg: return 2;
case DockerContainer::Cloak: return 1;
default: return 0;
}
}
bool ContainerProps::isShareable(DockerContainer container)
{
switch (container) {
case DockerContainer::TorWebSite: return false;
case DockerContainer::Dns: return false;
case DockerContainer::Sftp: return false;
default: return true;
}
}

View File

@@ -8,68 +8,72 @@
using namespace amnezia;
namespace amnezia {
namespace ContainerEnumNS {
Q_NAMESPACE
enum DockerContainer {
None = 0,
OpenVpn,
ShadowSocks,
Cloak,
WireGuard,
Ipsec,
//non-vpn
TorWebSite,
Dns,
//FileShare,
Sftp
};
Q_ENUM_NS(DockerContainer)
} // namespace ContainerEnumNS
using namespace ContainerEnumNS;
using namespace ProtocolEnumNS;
class ContainerProps : public QObject
namespace amnezia
{
Q_OBJECT
public:
Q_INVOKABLE static amnezia::DockerContainer containerFromString(const QString &container);
Q_INVOKABLE static QString containerToString(amnezia::DockerContainer container);
Q_INVOKABLE static QString containerTypeToString(amnezia::DockerContainer c);
namespace ContainerEnumNS
{
Q_NAMESPACE
enum DockerContainer {
None = 0,
Awg,
WireGuard,
OpenVpn,
Cloak,
ShadowSocks,
Ipsec,
Q_INVOKABLE static QList<amnezia::DockerContainer> allContainers();
// non-vpn
TorWebSite,
Dns,
Sftp
};
Q_ENUM_NS(DockerContainer)
} // namespace ContainerEnumNS
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerHumanNames();
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDescriptions();
using namespace ContainerEnumNS;
using namespace ProtocolEnumNS;
// these protocols will be displayed in container settings
Q_INVOKABLE static QVector<amnezia::Proto> protocolsForContainer(amnezia::DockerContainer container);
class ContainerProps : public QObject
{
Q_OBJECT
Q_INVOKABLE static amnezia::ServiceType containerService(amnezia::DockerContainer c);
public:
Q_INVOKABLE static amnezia::DockerContainer containerFromString(const QString &container);
Q_INVOKABLE static QString containerToString(amnezia::DockerContainer container);
Q_INVOKABLE static QString containerTypeToString(amnezia::DockerContainer c);
// binding between Docker container and main protocol of given container
// it may be changed fot future containers :)
Q_INVOKABLE static amnezia::Proto defaultProtocol(amnezia::DockerContainer c);
Q_INVOKABLE static QList<amnezia::DockerContainer> allContainers();
Q_INVOKABLE static bool isSupportedByCurrentPlatform(amnezia::DockerContainer c);
Q_INVOKABLE static QStringList fixedPortsForContainer(amnezia::DockerContainer c);
};
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerHumanNames();
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDescriptions();
Q_INVOKABLE static QMap<amnezia::DockerContainer, QString> containerDetailedDescriptions();
// these protocols will be displayed in container settings
Q_INVOKABLE static QVector<amnezia::Proto> protocolsForContainer(amnezia::DockerContainer container);
Q_INVOKABLE static amnezia::ServiceType containerService(amnezia::DockerContainer c);
static void declareQmlContainerEnum() {
qmlRegisterUncreatableMetaObject(
ContainerEnumNS::staticMetaObject,
"ContainerEnum",
1, 0,
"ContainerEnum",
"Error: only enums"
);
}
// binding between Docker container and main protocol of given container
// it may be changed fot future containers :)
Q_INVOKABLE static amnezia::Proto defaultProtocol(amnezia::DockerContainer c);
Q_INVOKABLE static bool isSupportedByCurrentPlatform(amnezia::DockerContainer c);
Q_INVOKABLE static QStringList fixedPortsForContainer(amnezia::DockerContainer c);
static bool isEasySetupContainer(amnezia::DockerContainer container);
static QString easySetupHeader(amnezia::DockerContainer container);
static QString easySetupDescription(amnezia::DockerContainer container);
static int easySetupOrder(amnezia::DockerContainer container);
static bool isShareable(amnezia::DockerContainer container);
};
static void declareQmlContainerEnum()
{
qmlRegisterUncreatableMetaObject(ContainerEnumNS::staticMetaObject, "ContainerEnum", 1, 0, "ContainerEnum",
"Error: only enums");
}
} // namespace amnezia

View File

@@ -12,10 +12,10 @@ struct ServerCredentials
{
QString hostName;
QString userName;
QString password;
QString secretData;
int port = 22;
bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !password.isEmpty() && port > 0; }
bool isValid() const { return !hostName.isEmpty() && !userName.isEmpty() && !secretData.isEmpty() && port > 0; }
};
enum ErrorCode
@@ -37,7 +37,7 @@ enum ErrorCode
// Ssh connection errors
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
SshPrivateKeyError, SshPrivateKeyFormatError,
SshPrivateKeyError, SshPrivateKeyFormatError, SshTimeoutError,
// Ssh sftp errors
SshSftpEofError, SshSftpNoSuchFileError, SshSftpPermissionDeniedError,
@@ -69,7 +69,10 @@ enum ErrorCode
OpenSslFailed,
OpenVpnExecutableCrashed,
ShadowSocksExecutableCrashed,
CloakExecutableCrashed
CloakExecutableCrashed,
// import and install errors
ImportInvalidConfigError
};
} // namespace amnezia

View File

@@ -24,6 +24,7 @@ QString errorString(ErrorCode code){
case(SshInternalError): return QObject::tr("Ssh internal error");
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
case(SshPrivateKeyFormatError): return QObject::tr("The selected private key format is not supported, use openssh ED25519 key types or PEM key types");
case(SshTimeoutError): return QObject::tr("Timeout connecting to server");
// Libssh sftp errors
case(SshSftpEofError): return QObject::tr("Sftp error: End-of-file encountered");
@@ -57,6 +58,8 @@ QString errorString(ErrorCode code){
case (OpenVpnTapAdapterError): return QObject::tr("Can't setup OpenVPN TAP network adapter");
case (AddressPoolError): return QObject::tr("VPN pool error: no available addresses");
case (ImportInvalidConfigError): return QObject::tr("The config does not contain any containers and credentiaks for connecting to the server");
case(InternalError):
default:
return QObject::tr("Internal error");

View File

@@ -1,8 +1,8 @@
#include "scripts_registry.h"
#include <QObject>
#include <QDebug>
#include <QFile>
#include <QObject>
QString amnezia::scriptFolder(amnezia::DockerContainer container)
{
@@ -11,11 +11,11 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
case DockerContainer::Cloak: return QLatin1String("openvpn_cloak");
case DockerContainer::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
case DockerContainer::WireGuard: return QLatin1String("wireguard");
case DockerContainer::Awg: return QLatin1String("awg");
case DockerContainer::Ipsec: return QLatin1String("ipsec");
case DockerContainer::TorWebSite: return QLatin1String("website_tor");
case DockerContainer::Dns: return QLatin1String("dns");
//case DockerContainer::FileShare: return QLatin1String("file_share");
case DockerContainer::Sftp: return QLatin1String("sftp");
default: return "";
}
@@ -45,6 +45,7 @@ QString amnezia::scriptName(ProtocolScriptType type)
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
}
}
@@ -52,7 +53,7 @@ QString amnezia::scriptData(amnezia::SharedScriptType type)
{
QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type));
QFile file(fileName);
if (! file.open(QIODevice::ReadOnly)) {
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Warning: script missing" << fileName;
return "";
}
@@ -67,7 +68,7 @@ QString amnezia::scriptData(amnezia::ProtocolScriptType type, DockerContainer co
{
QString fileName = QString(":/server_scripts/%1/%2").arg(amnezia::scriptFolder(container), amnezia::scriptName(type));
QFile file(fileName);
if (! file.open(QIODevice::ReadOnly)) {
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Warning: script missing" << fileName;
return "";
}

View File

@@ -26,7 +26,8 @@ enum ProtocolScriptType {
configure_container,
container_startup,
openvpn_template,
wireguard_template
wireguard_template,
awg_template
};

View File

@@ -2,22 +2,21 @@
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
#include <QEventLoop>
#include <QFile>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
#include <QPointer>
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
#include <QApplication>
#include <QTemporaryFile>
#include <QFileInfo>
#include <QThread>
#include <QTimer>
#include <QtConcurrent>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <chrono>
@@ -25,15 +24,14 @@
#include "containers/containers_defs.h"
#include "logger.h"
#include "scripts_registry.h"
#include "server_defs.h"
#include "settings.h"
#include "scripts_registry.h"
#include "utilities.h"
#include <configurators/vpn_configurator.h>
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) :
m_settings(settings)
ServerController::ServerController(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings)
{
}
@@ -42,10 +40,10 @@ ServerController::~ServerController()
m_sshClient.disconnectFromHost();
}
ErrorCode ServerController::runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr) {
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
{
auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) {
@@ -92,36 +90,36 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
return ErrorCode::NoError;
}
ErrorCode ServerController::runContainerScript(const ServerCredentials &credentials,
DockerContainer container, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr)
ErrorCode
ServerController::runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
{
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
if (e) return e;
if (e)
return e;
QString runner = QString("sudo docker exec -i $CONTAINER_NAME bash %1 ").arg(fileName);
e = runScript(credentials,
replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
e = runScript(credentials, replaceVars(runner, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
QString remover = QString("sudo docker exec -i $CONTAINER_NAME rm %1 ").arg(fileName);
runScript(credentials,
replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
runScript(credentials, replaceVars(remover, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
return e;
}
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
const ServerCredentials &credentials, const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode)
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode)
{
ErrorCode e = ErrorCode::NoError;
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
if (e) return e;
if (e)
return e;
QString stdOut;
auto cbReadStd = [&](const QString &data, libssh::Client &) {
@@ -130,61 +128,60 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
};
// mkdir
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"")
.arg(path);
e = runScript(credentials,
replaceVars(mkdir, genVarsForScript(credentials, container)));
if (e) return e;
QString mkdir = QString("sudo docker exec -i $CONTAINER_NAME mkdir -p \"$(dirname %1)\"").arg(path);
e = runScript(credentials, replaceVars(mkdir, genVarsForScript(credentials, container)));
if (e)
return e;
if (overwriteMode == libssh::SftpOverwriteMode::SftpOverwriteExisting) {
e = runScript(credentials,
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e) return e;
}
else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
if (e)
return e;
} else if (overwriteMode == libssh::SftpOverwriteMode::SftpAppendToExisting) {
e = runScript(credentials,
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(tmpFileName),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e) return e;
if (e)
return e;
e = runScript(credentials,
replaceVars(QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
if (e) return e;
}
else return ErrorCode::NotImplementedError;
e = runScript(
credentials,
replaceVars(
QString("sudo docker exec -i $CONTAINER_NAME sh -c \"cat %1 >> %2\"").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)),
cbReadStd, cbReadStd);
if (e)
return e;
} else
return ErrorCode::NotImplementedError;
if (stdOut.contains("Error: No such container:")) {
return ErrorCode::ServerContainerMissingError;
}
runScript(credentials,
replaceVars(QString("sudo shred %1").arg(tmpFileName),
genVarsForScript(credentials, container)));
runScript(credentials,
replaceVars(QString("sudo rm %1").arg(tmpFileName),
genVarsForScript(credentials, container)));
runScript(credentials,
replaceVars(QString("sudo shred -u %1").arg(tmpFileName), genVarsForScript(credentials, container)));
return e;
}
QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode)
QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode)
{
if (errorCode) *errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"").
arg(ContainerProps::containerToString(container)).arg(path);
if (errorCode)
*errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"")
.arg(ContainerProps::containerToString(container))
.arg(path);
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -196,8 +193,8 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
return QByteArray::fromHex(stdOut.toUtf8());
}
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::SftpOverwriteMode overwriteMode)
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode)
{
auto error = m_sshClient.connectToHost(credentials);
if (error != ErrorCode::NoError) {
@@ -209,7 +206,8 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
localFile.write(data);
localFile.close();
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(), "non_desc");
error = m_sshClient.sftpFileCopy(overwriteMode, localFile.fileName().toStdString(), remotePath.toStdString(),
"non_desc");
if (error != ErrorCode::NoError) {
return error;
}
@@ -218,15 +216,14 @@ ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credential
ErrorCode ServerController::removeAllContainers(const ServerCredentials &credentials)
{
return runScript(credentials,
amnezia::scriptData(SharedScriptType::remove_all_containers));
return runScript(credentials, amnezia::scriptData(SharedScriptType::remove_all_containers));
}
ErrorCode ServerController::removeContainer(const ServerCredentials &credentials, DockerContainer container)
{
return runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::remove_container),
genVarsForScript(credentials, container)));
replaceVars(amnezia::scriptData(SharedScriptType::remove_container),
genVarsForScript(credentials, container)));
}
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container,
@@ -236,22 +233,33 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
ErrorCode e = ErrorCode::NoError;
e = isUserInSudo(credentials, container);
if (e) return e;
if (e)
return e;
e = isServerDpkgBusy(credentials, container);
if (e) return e;
if (e)
return e;
e = installDockerWorker(credentials, container);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer installDockerWorker finished";
if (!isUpdate) {
e = isServerPortBusy(credentials, container, config);
if (e) return e;
if (e)
return e;
}
if (!isUpdate) {
e = isServerPortBusy(credentials, container, config);
if (e)
return e;
}
e = prepareHostWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer prepareHostWorker finished";
removeContainer(credentials, container);
@@ -259,15 +267,18 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
qDebug().noquote() << "buildContainerWorker start";
e = buildContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer buildContainerWorker finished";
e = runContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer runContainerWorker finished";
e = configureContainerWorker(credentials, container, config);
if (e) return e;
if (e)
return e;
qDebug().noquote() << "ServerController::setupContainer configureContainerWorker finished";
setupServerFirewall(credentials);
@@ -277,46 +288,25 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
}
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, QJsonObject &newConfig)
const QJsonObject &oldConfig, QJsonObject &newConfig)
{
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is"
<< reinstallRequired;
if (reinstallRequired) {
return setupContainer(credentials, container, newConfig, true);
}
else {
} else {
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
if (e) return e;
if (e)
return e;
return startupContainerWorker(credentials, container, newConfig);
}
}
QJsonObject ServerController::createContainerInitialConfig(DockerContainer container, int port, TransportProto tp)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject config {
{ config_key::container, ContainerProps::containerToString(container) }
};
QJsonObject protoConfig;
protoConfig.insert(config_key::port, QString::number(port));
protoConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(tp, mainProto));
if (container == DockerContainer::Sftp) {
protoConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
protoConfig.insert(config_key::password, Utils::getRandomString(10));
}
config.insert(ProtocolProps::protoToString(mainProto), protoConfig);
return config;
}
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
const QJsonObject &newConfig)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
@@ -324,25 +314,29 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
if (container == DockerContainer::OpenVpn) {
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
return true;
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto)
!= newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
return true;
}
if (container == DockerContainer::Cloak) {
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
return true;
}
if (container == DockerContainer::ShadowSocks) {
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
return true;
}
if (container == DockerContainer::Awg) {
return true;
}
return false;
@@ -364,75 +358,88 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
return ErrorCode::NoError;
};
ErrorCode error = runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
ErrorCode error =
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::install_docker), genVarsForScript(credentials)),
cbReadStdOut, cbReadStdErr);
qDebug().noquote() << "ServerController::installDockerWorker" << stdOut;
if (stdOut.contains("lock")) return ErrorCode::ServerPacketManagerError;
if (stdOut.contains("command not found")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("lock"))
return ErrorCode::ServerPacketManagerError;
if (stdOut.contains("command not found"))
return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("Docker status is not active"))
return ErrorCode::ServerDockerFailedError;
return error;
}
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
// create folder on host
return runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
genVarsForScript(credentials, container)));
return runScript(
credentials,
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host), genVarsForScript(credentials, container)));
}
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
if (e) return e;
if (e)
return e;
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
e = runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
genVarsForScript(credentials, container, config)), cbReadStdOut);
if (e) return e;
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
genVarsForScript(credentials, container, config)),
cbReadStdOut);
if (e)
return e;
return e;
}
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
ErrorCode e = runScript(credentials,
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
genVarsForScript(credentials, container, config)), cbReadStdOut);
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
genVarsForScript(credentials, container, config)),
cbReadStdOut);
if (stdOut.contains("docker: Error response from daemon")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("address already in use")) return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("is already in use by container")) return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("invalid publish")) return ErrorCode::ServerDockerFailedError;
if (stdOut.contains("address already in use"))
return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("is already in use by container"))
return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("invalid publish"))
return ErrorCode::ServerDockerFailedError;
return e;
}
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -444,19 +451,18 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
return ErrorCode::NoError;
};
ErrorCode e = runContainerScript(credentials, container,
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr);
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr);
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
return e;
}
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
@@ -465,104 +471,144 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
}
ErrorCode e = uploadTextFileToContainer(container, credentials,
replaceVars(script, genVarsForScript(credentials, container, config)),
"/opt/amnezia/start.sh");
if (e) return e;
replaceVars(script, genVarsForScript(credentials, container, config)),
"/opt/amnezia/start.sh");
if (e)
return e;
return runScript(credentials,
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
genVarsForScript(credentials, container, config)));
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && "
"/opt/amnezia/start.sh\"",
genVarsForScript(credentials, container, config)));
}
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &config)
{
const QJsonObject &openvpnConfig = config.value(ProtocolProps::protoToString(Proto::OpenVpn)).toObject();
const QJsonObject &cloakConfig = config.value(ProtocolProps::protoToString(Proto::Cloak)).toObject();
const QJsonObject &ssConfig = config.value(ProtocolProps::protoToString(Proto::ShadowSocks)).toObject();
const QJsonObject &wireguarConfig = config.value(ProtocolProps::protoToString(Proto::WireGuard)).toObject();
const QJsonObject &amneziaWireguarConfig = config.value(ProtocolProps::protoToString(Proto::Awg)).toObject();
const QJsonObject &sftpConfig = config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject();
Vars vars;
vars.append({{"$REMOTE_HOST", credentials.hostName}});
vars.append({ { "$REMOTE_HOST", credentials.hostName } });
// OpenVPN vars
vars.append({{"$OPENVPN_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) }});
vars.append({{"$OPENVPN_SUBNET_CIDR", openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) }});
vars.append({{"$OPENVPN_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) }});
vars.append(
{ { "$OPENVPN_SUBNET_IP",
openvpnConfig.value(config_key::subnet_address).toString(protocols::openvpn::defaultSubnetAddress) } });
vars.append({ { "$OPENVPN_SUBNET_CIDR",
openvpnConfig.value(config_key::subnet_cidr).toString(protocols::openvpn::defaultSubnetCidr) } });
vars.append({ { "$OPENVPN_SUBNET_MASK",
openvpnConfig.value(config_key::subnet_mask).toString(protocols::openvpn::defaultSubnetMask) } });
vars.append({{"$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) }});
vars.append({{"$OPENVPN_TRANSPORT_PROTO", openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) }});
vars.append({ { "$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) } });
vars.append(
{ { "$OPENVPN_TRANSPORT_PROTO",
openvpnConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) } });
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
vars.append({{"$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" }});
vars.append({ { "$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" } });
vars.append({{"$OPENVPN_CIPHER", openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) }});
vars.append({{"$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) }});
vars.append({ { "$OPENVPN_CIPHER",
openvpnConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher) } });
vars.append({ { "$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash) } });
bool isTlsAuth = openvpnConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
vars.append({{"$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" }});
vars.append({ { "$OPENVPN_TLS_AUTH", isTlsAuth ? protocols::openvpn::tlsAuthString : "" } });
if (!isTlsAuth) {
// erase $OPENVPN_TA_KEY, so it will not set in OpenVpnConfigurator::genOpenVpnConfig
vars.append({{"$OPENVPN_TA_KEY", "" }});
vars.append({ { "$OPENVPN_TA_KEY", "" } });
}
vars.append({{"$OPENVPN_ADDITIONAL_CLIENT_CONFIG", openvpnConfig.value(config_key::additional_client_config).
toString(protocols::openvpn::defaultAdditionalClientConfig) }});
vars.append({{"$OPENVPN_ADDITIONAL_SERVER_CONFIG", openvpnConfig.value(config_key::additional_server_config).
toString(protocols::openvpn::defaultAdditionalServerConfig) }});
vars.append({ { "$OPENVPN_ADDITIONAL_CLIENT_CONFIG",
openvpnConfig.value(config_key::additional_client_config)
.toString(protocols::openvpn::defaultAdditionalClientConfig) } });
vars.append({ { "$OPENVPN_ADDITIONAL_SERVER_CONFIG",
openvpnConfig.value(config_key::additional_server_config)
.toString(protocols::openvpn::defaultAdditionalServerConfig) } });
// ShadowSocks vars
vars.append({{"$SHADOWSOCKS_SERVER_PORT", ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) }});
vars.append({{"$SHADOWSOCKS_LOCAL_PORT", ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) }});
vars.append({{"$SHADOWSOCKS_CIPHER", ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) }});
vars.append({ { "$SHADOWSOCKS_SERVER_PORT",
ssConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort) } });
vars.append({ { "$SHADOWSOCKS_LOCAL_PORT",
ssConfig.value(config_key::local_port).toString(protocols::shadowsocks::defaultLocalProxyPort) } });
vars.append({ { "$SHADOWSOCKS_CIPHER",
ssConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher) } });
vars.append({{"$CONTAINER_NAME", ContainerProps::containerToString(container)}});
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container)}});
vars.append({ { "$CONTAINER_NAME", ContainerProps::containerToString(container) } });
vars.append({ { "$DOCKERFILE_FOLDER", "/opt/amnezia/" + ContainerProps::containerToString(container) } });
// Cloak vars
vars.append({{"$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) }});
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
vars.append({ { "$CLOAK_SERVER_PORT", cloakConfig.value(config_key::port).toString(protocols::cloak::defaultPort) } });
vars.append({ { "$FAKE_WEB_SITE_ADDRESS",
cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) } });
// Wireguard vars
vars.append({{"$WIREGUARD_SUBNET_IP", wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) }});
vars.append({{"$WIREGUARD_SUBNET_CIDR", wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) }});
vars.append({{"$WIREGUARD_SUBNET_MASK", wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) }});
vars.append(
{ { "$WIREGUARD_SUBNET_IP",
wireguarConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) } });
vars.append({ { "$WIREGUARD_SUBNET_CIDR",
wireguarConfig.value(config_key::subnet_cidr).toString(protocols::wireguard::defaultSubnetCidr) } });
vars.append({ { "$WIREGUARD_SUBNET_MASK",
wireguarConfig.value(config_key::subnet_mask).toString(protocols::wireguard::defaultSubnetMask) } });
vars.append({{"$WIREGUARD_SERVER_PORT", wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) }});
vars.append({ { "$WIREGUARD_SERVER_PORT",
wireguarConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) } });
// IPsec vars
vars.append({{"$IPSEC_VPN_L2TP_NET", "192.168.42.0/24"}});
vars.append({{"$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250"}});
vars.append({{"$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1"}});
vars.append({ { "$IPSEC_VPN_L2TP_NET", "192.168.42.0/24" } });
vars.append({ { "$IPSEC_VPN_L2TP_POOL", "192.168.42.10-192.168.42.250" } });
vars.append({ { "$IPSEC_VPN_L2TP_LOCAL", "192.168.42.1" } });
vars.append({{"$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24"}});
vars.append({{"$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250"}});
vars.append({ { "$IPSEC_VPN_XAUTH_NET", "192.168.43.0/24" } });
vars.append({ { "$IPSEC_VPN_XAUTH_POOL", "192.168.43.10-192.168.43.250" } });
vars.append({{"$IPSEC_VPN_SHA2_TRUNCBUG", "yes"}});
vars.append({ { "$IPSEC_VPN_SHA2_TRUNCBUG", "yes" } });
vars.append({{"$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes"}});
vars.append({{"$IPSEC_VPN_DISABLE_IKEV2", "no"}});
vars.append({{"$IPSEC_VPN_DISABLE_L2TP", "no"}});
vars.append({{"$IPSEC_VPN_DISABLE_XAUTH", "no"}});
vars.append({ { "$IPSEC_VPN_VPN_ANDROID_MTU_FIX", "yes" } });
vars.append({ { "$IPSEC_VPN_DISABLE_IKEV2", "no" } });
vars.append({ { "$IPSEC_VPN_DISABLE_L2TP", "no" } });
vars.append({ { "$IPSEC_VPN_DISABLE_XAUTH", "no" } });
vars.append({{"$IPSEC_VPN_C2C_TRAFFIC", "no"}});
vars.append({{"$PRIMARY_SERVER_DNS", m_settings->primaryDns()}});
vars.append({{"$SECONDARY_SERVER_DNS", m_settings->secondaryDns()}});
vars.append({ { "$IPSEC_VPN_C2C_TRAFFIC", "no" } });
vars.append({ { "$PRIMARY_SERVER_DNS", m_settings->primaryDns() } });
vars.append({ { "$SECONDARY_SERVER_DNS", m_settings->secondaryDns() } });
// Sftp vars
vars.append({{"$SFTP_PORT", sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) }});
vars.append({{"$SFTP_USER", sftpConfig.value(config_key::userName).toString() }});
vars.append({{"$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() }});
vars.append(
{ { "$SFTP_PORT",
sftpConfig.value(config_key::port).toString(QString::number(ProtocolProps::defaultPort(Proto::Sftp))) } });
vars.append({ { "$SFTP_USER", sftpConfig.value(config_key::userName).toString() } });
vars.append({ { "$SFTP_PASSWORD", sftpConfig.value(config_key::password).toString() } });
// Amnezia wireguard vars
vars.append({ { "$AWG_SERVER_PORT",
amneziaWireguarConfig.value(config_key::port).toString(protocols::awg::defaultPort) } });
vars.append({ { "$JUNK_PACKET_COUNT", amneziaWireguarConfig.value(config_key::junkPacketCount).toString() } });
vars.append({ { "$JUNK_PACKET_MIN_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMinSize).toString() } });
vars.append({ { "$JUNK_PACKET_MAX_SIZE", amneziaWireguarConfig.value(config_key::junkPacketMaxSize).toString() } });
vars.append({ { "$INIT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::initPacketJunkSize).toString() } });
vars.append({ { "$RESPONSE_PACKET_JUNK_SIZE",
amneziaWireguarConfig.value(config_key::responsePacketJunkSize).toString() } });
vars.append({ { "$INIT_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::initPacketMagicHeader).toString() } });
vars.append({ { "$RESPONSE_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::responsePacketMagicHeader).toString() } });
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER",
amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
QString serverIp = Utils::getIPAddress(credentials.hostName);
if (!serverIp.isEmpty()) {
vars.append({{"$SERVER_IP_ADDRESS", serverIp}});
}
else {
vars.append({ { "$SERVER_IP_ADDRESS", serverIp } });
} else {
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
}
@@ -581,10 +627,11 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
return ErrorCode::NoError;
};
ErrorCode e = runScript(credentials,
amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
ErrorCode e =
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
if (errorCode) *errorCode = e;
if (errorCode)
*errorCode = e;
return stdOut;
}
@@ -596,9 +643,9 @@ void ServerController::setCancelInstallation(const bool cancel)
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
{
return runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall),
genVarsForScript(credentials)));
return runScript(
credentials,
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall), genVarsForScript(credentials)));
}
QString ServerController::replaceVars(const QString &script, const Vars &vars)
@@ -610,7 +657,8 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars)
return s;
}
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
{
if (container == DockerContainer::Dns) {
return ErrorCode::NoError;
@@ -633,11 +681,15 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
QString defaultPort("%1");
QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
QString port =
containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
QString defaultTransportProto =
ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
QString script = QString("which lsof &>/dev/null || true && sudo lsof -i -P -n | grep -E ':%1 ").arg(port);
// TODO reimplement with netstat
QString script =
QString("which lsof &>/dev/null || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);
for (auto &port : fixedPorts) {
script = script.append("|:%1").arg(port);
}
@@ -647,8 +699,8 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
script = script.append(" | grep LISTEN");
}
ErrorCode errorCode = runScript(credentials,
replaceVars(script, genVarsForScript(credentials, container)), cbReadStdOut, cbReadStdErr);
ErrorCode errorCode = runScript(credentials, replaceVars(script, genVarsForScript(credentials, container)),
cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
@@ -676,9 +728,11 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
};
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
ErrorCode error =
runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
if (!stdOut.contains("sudo")) return ErrorCode::ServerUserNotInSudo;
if (!stdOut.contains("sudo"))
return ErrorCode::ServerUserNotInSudo;
return error;
}
@@ -699,27 +753,29 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
QFuture<ErrorCode> future = QtConcurrent::run([this, &stdOut, &cbReadStdOut, &cbReadStdErr, &credentials]() {
// max 100 attempts
for (int i = 0; i < 100; ++i) {
for (int i = 0; i < 30; ++i) {
if (m_cancelInstallation) {
return ErrorCode::ServerCancelInstallation;
}
stdOut.clear();
runScript(credentials,
replaceVars(amnezia::scriptData(SharedScriptType::check_server_is_busy),
genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
genVarsForScript(credentials)),
cbReadStdOut, cbReadStdErr);
// if 'fuser' is not installed, skip check
if (stdOut.contains("Not installed")) return ErrorCode::NoError;
if (stdOut.contains("Packet manager not found"))
return ErrorCode::ServerPacketManagerError;
if (stdOut.contains("fuser not installed"))
return ErrorCode::NoError;
if (stdOut.isEmpty()) {
return ErrorCode::NoError;
}
else {
#ifdef MZ_DEBUG
} else {
#ifdef MZ_DEBUG
qDebug().noquote() << stdOut;
#endif
#endif
emit serverIsBusy(true);
QThread::msleep(5000);
QThread::msleep(10000);
}
}
return ErrorCode::ServerPacketManagerError;
@@ -736,7 +792,8 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
return future.result();
}
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers)
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -767,14 +824,47 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
QString port = containerAndPortMatch.captured(2);
QString transportProto = containerAndPortMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
QJsonObject config {
{ config_key::container, name },
{ ProtocolProps::protoToString(mainProto), QJsonObject {
{ config_key::port, port },
{ config_key::transport_proto, transportProto }}
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::Awg) {
QString serverConfig = getTextFileFromContainer(container, credentials, protocols::awg::serverConfigPath, &errorCode);
QMap<QString, QString> serverConfigMap;
auto serverConfigLines = serverConfig.split("\n");
for (auto &line : serverConfigLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
containerConfig[config_key::initPacketJunkSize] = serverConfigMap.value(config_key::initPacketJunkSize);
containerConfig[config_key::responsePacketJunkSize] = serverConfigMap.value(config_key::responsePacketJunkSize);
containerConfig[config_key::initPacketMagicHeader] = serverConfigMap.value(config_key::initPacketMagicHeader);
containerConfig[config_key::responsePacketMagicHeader] = serverConfigMap.value(config_key::responsePacketMagicHeader);
containerConfig[config_key::underloadPacketMagicHeader] = serverConfigMap.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] = serverConfigMap.value(config_key::transportPacketMagicHeader);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
};
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
}
installedContainers.insert(container, config);
}
}
@@ -782,7 +872,8 @@ ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredential
return ErrorCode::NoError;
}
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback)
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
const std::function<QString()> &callback)
{
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
return error;

View File

@@ -4,8 +4,8 @@
#include <QJsonObject>
#include <QObject>
#include "defs.h"
#include "containers/containers_defs.h"
#include "defs.h"
#include "sshclient.h"
class Settings;
@@ -24,52 +24,62 @@ public:
ErrorCode removeAllContainers(const ServerCredentials &credentials);
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config, bool isUpdate = false);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config,
bool isUpdate = false);
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, QJsonObject &newConfig);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
// create initial config - generate passwords, etc
QJsonObject createContainerInitialConfig(DockerContainer container, int port, TransportProto tp);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers);
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode uploadTextFileToContainer(
DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path,
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode = nullptr);
QString replaceVars(const QString &script, const Vars &vars);
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, const QJsonObject &config = QJsonObject());
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None,
const QJsonObject &config = QJsonObject());
ErrorCode runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
ErrorCode runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode (const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
ErrorCode
runContainerScript(const ServerCredentials &credentials, DockerContainer container, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
void setCancelInstallation(const bool cancel);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, const std::function<QString()> &callback);
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
const std::function<QString()> &callback);
private:
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container,
QJsonObject &config);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config);
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig,
const QJsonObject &newConfig);
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data,
const QString &remotePath, libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath,
libssh::SftpOverwriteMode overwriteMode = libssh::SftpOverwriteMode::SftpOverwriteExisting);
ErrorCode setupServerFirewall(const ServerCredentials &credentials);

View File

@@ -10,6 +10,8 @@ const uint32_t S_IRWXU = 0644;
#endif
namespace libssh {
const QString libsshTimeoutError = "Timeout connecting to";
std::function<QString()> Client::m_passphraseCallback;
Client::Client(QObject *parent) : QObject(parent)
@@ -45,20 +47,29 @@ namespace libssh {
ssh_options_set(m_session, SSH_OPTIONS_USER, hostUsername.c_str());
ssh_options_set(m_session, SSH_OPTIONS_LOG_VERBOSITY, &logVerbosity);
int connectionResult = ssh_connect(m_session);
QFutureWatcher<int> watcher;
QFuture<int> future = QtConcurrent::run([this]() {
return ssh_connect(m_session);
});
QEventLoop wait;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
watcher.setFuture(future);
wait.exec();
int connectionResult = watcher.result();
if (connectionResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
return fromLibsshErrorCode();
}
std::string authUsername = credentials.userName.toStdString();
int authResult = SSH_ERROR;
if (credentials.password.contains("BEGIN") && credentials.password.contains("PRIVATE KEY")) {
if (credentials.secretData.contains("BEGIN") && credentials.secretData.contains("PRIVATE KEY")) {
ssh_key privateKey = nullptr;
ssh_key publicKey = nullptr;
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
authResult = ssh_pki_import_privkey_base64(credentials.secretData.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
if (authResult == SSH_OK) {
authResult = ssh_pki_export_privkey_to_pubkey(privateKey, &publicKey);
}
@@ -78,18 +89,17 @@ namespace libssh {
ssh_key_free(privateKey);
}
if (authResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
ErrorCode errorCode = fromLibsshErrorCode(ssh_get_error_code(m_session));
qCritical() << ssh_get_error(m_session);
ErrorCode errorCode = fromLibsshErrorCode();
if (errorCode == ErrorCode::NoError) {
errorCode = ErrorCode::SshPrivateKeyFormatError;
}
return errorCode;
}
} else {
authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.password.toStdString().c_str());
authResult = ssh_userauth_password(m_session, authUsername.c_str(), credentials.secretData.toStdString().c_str());
if (authResult != SSH_OK) {
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
return fromLibsshErrorCode();
}
}
}
@@ -186,16 +196,15 @@ namespace libssh {
ErrorCode Client::writeResponse(const QString &data)
{
if (m_channel == nullptr) {
qDebug() << "ssh channel not initialized";
return fromLibsshErrorCode(ssh_get_error_code(m_session));
qCritical() << "ssh channel not initialized";
return fromLibsshErrorCode();
}
int bytesWritten = ssh_channel_write(m_channel, data.toUtf8(), (uint32_t)data.size());
if (bytesWritten == data.size() && ssh_channel_write(m_channel, "\n", 1)) {
return fromLibsshErrorCode(ssh_get_error_code(m_session));
return fromLibsshErrorCode();
}
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
return fromLibsshErrorCode();
}
ErrorCode Client::closeChannel()
@@ -210,8 +219,7 @@ namespace libssh {
ssh_channel_free(m_channel);
m_channel = nullptr;
}
qDebug() << ssh_get_error(m_session);
return fromLibsshErrorCode(ssh_get_error_code(m_session));
return fromLibsshErrorCode();
}
ErrorCode Client::sftpFileCopy(const SftpOverwriteMode overwriteMode, const std::string& localPath, const std::string& remotePath, const std::string& fileDesc)
@@ -308,12 +316,21 @@ namespace libssh {
sftp_free(m_sftpSession);
m_sftpSession = nullptr;
}
qDebug() << ssh_get_error(m_session);
qCritical() << ssh_get_error(m_session);
return errorCode;
}
ErrorCode Client::fromLibsshErrorCode(int errorCode)
ErrorCode Client::fromLibsshErrorCode()
{
int errorCode = ssh_get_error_code(m_session);
if (errorCode != SSH_NO_ERROR) {
QString errorMessage = ssh_get_error(m_session);
qCritical() << errorMessage;
if (errorMessage.contains(libsshTimeoutError)) {
return ErrorCode::SshTimeoutError;
}
}
switch (errorCode) {
case(SSH_NO_ERROR): return ErrorCode::NoError;
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequsetDeniedError;
@@ -350,7 +367,7 @@ namespace libssh {
ssh_key privateKey = nullptr;
m_passphraseCallback = passphraseCallback;
authResult = ssh_pki_import_privkey_base64(credentials.password.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
authResult = ssh_pki_import_privkey_base64(credentials.secretData.toStdString().c_str(), nullptr, callback, nullptr, &privateKey);
if (authResult == SSH_OK) {
char *b64 = nullptr;

View File

@@ -40,7 +40,7 @@ namespace libssh {
private:
ErrorCode closeChannel();
ErrorCode closeSftpSession();
ErrorCode fromLibsshErrorCode(int errorCode);
ErrorCode fromLibsshErrorCode();
ErrorCode fromLibsshSftpErrorCode(int errorCode);
static int callback(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);

View File

@@ -9,6 +9,7 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QMetaEnum>
#include <QTimer>
#include "leakdetector.h"
@@ -64,9 +65,12 @@ bool Daemon::activate(const InterfaceConfig& config) {
// method calls switchServer().
//
// At the end, if the activation succeds, the `connected` signal is emitted.
// If the activation abort's for any reason `the `activationFailure` signal is
// emitted.
logger.debug() << "Activating interface";
auto emit_failure_guard = qScopeGuard([this] { emit activationFailure(); });
if (m_connections.contains(config.m_hopindex)) {
if (m_connections.contains(config.m_hopType)) {
if (supportServerSwitching(config)) {
logger.debug() << "Already connected. Server switching supported.";
@@ -85,10 +89,12 @@ bool Daemon::activate(const InterfaceConfig& config) {
bool status = run(Switch, config);
logger.debug() << "Connection status:" << status;
if (status) {
m_connections[config.m_hopindex] = ConnectionState(config);
m_connections[config.m_hopType] = ConnectionState(config);
m_handshakeTimer.start(HANDSHAKE_POLL_MSEC);
emit_failure_guard.dismiss();
return true;
}
return status;
return false;
}
logger.warning() << "Already connected. Server switching not supported.";
@@ -96,8 +102,12 @@ bool Daemon::activate(const InterfaceConfig& config) {
return false;
}
Q_ASSERT(!m_connections.contains(config.m_hopindex));
return activate(config);
Q_ASSERT(!m_connections.contains(config.m_hopType));
if (activate(config)) {
emit_failure_guard.dismiss();
return true;
}
return false;
}
prepareActivation(config);
@@ -112,13 +122,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
// Configure routing for excluded addresses.
for (const QString& i : config.m_excludedAddresses) {
QHostAddress address(i);
if (m_excludedAddrSet.contains(address)) {
m_excludedAddrSet[address]++;
continue;
}
wgutils()->addExclusionRoute(address);
m_excludedAddrSet[address] = 1;
addExclusionRoute(IPAddress(i));
}
// Add the peer to this interface.
@@ -142,7 +146,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
// set routing
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
if (!wgutils()->updateRoutePrefix(ip, config.m_hopindex)) {
if (!wgutils()->updateRoutePrefix(ip)) {
logger.debug() << "Routing configuration failed for"
<< logger.sensitive(ip.toString());
return false;
@@ -152,15 +156,21 @@ bool Daemon::activate(const InterfaceConfig& config) {
bool status = run(Up, config);
logger.debug() << "Connection status:" << status;
if (status) {
m_connections[config.m_hopindex] = ConnectionState(config);
m_connections[config.m_hopType] = ConnectionState(config);
m_handshakeTimer.start(HANDSHAKE_POLL_MSEC);
emit_failure_guard.dismiss();
return true;
}
return status;
return false;
}
bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
if ((config.m_hopindex == 0) && supportDnsUtils()) {
if (!supportDnsUtils()) {
return true;
}
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) {
QList<QHostAddress> resolvers;
resolvers.append(QHostAddress(config.m_dnsServer));
@@ -199,6 +209,28 @@ bool Daemon::parseStringList(const QJsonObject& obj, const QString& name,
return true;
}
bool Daemon::addExclusionRoute(const IPAddress& prefix) {
if (m_excludedAddrSet.contains(prefix)) {
m_excludedAddrSet[prefix]++;
return true;
}
if (!wgutils()->addExclusionRoute(prefix)) {
return false;
}
m_excludedAddrSet[prefix] = 1;
return true;
}
bool Daemon::delExclusionRoute(const IPAddress& prefix) {
Q_ASSERT(m_excludedAddrSet.contains(prefix));
if (m_excludedAddrSet[prefix] > 1) {
m_excludedAddrSet[prefix]--;
return true;
}
m_excludedAddrSet.remove(prefix);
return wgutils()->deleteExclusionRoute(prefix);
}
// static
bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
#define GETVALUE(name, where, jsontype) \
@@ -216,8 +248,8 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
GETVALUE("privateKey", config.m_privateKey, String);
GETVALUE("serverPublicKey", config.m_serverPublicKey, String);
GETVALUE("serverPort", config.m_serverPort, Double);
GETVALUE("serverPskKey", config.m_serverPskKey, String);
GETVALUE("serverPort", config.m_serverPort, Double);
config.m_deviceIpv4Address = obj.value("deviceIpv4Address").toString();
config.m_deviceIpv6Address = obj.value("deviceIpv6Address").toString();
@@ -247,15 +279,24 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
config.m_dnsServer = value.toString();
}
if (!obj.contains("hopindex")) {
config.m_hopindex = 0;
if (!obj.contains("hopType")) {
config.m_hopType = InterfaceConfig::SingleHop;
} else {
QJsonValue value = obj.value("hopindex");
if (!value.isDouble()) {
logger.error() << "hopindex is not a number";
QJsonValue value = obj.value("hopType");
if (!value.isString()) {
logger.error() << "hopType is not a string";
return false;
}
bool okay;
QByteArray vdata = value.toString().toUtf8();
QMetaEnum meta = QMetaEnum::fromType<InterfaceConfig::HopType>();
config.m_hopType =
InterfaceConfig::HopType(meta.keyToValue(vdata.constData(), &okay));
if (!okay) {
logger.error() << "hopType" << value.toString() << "is not valid";
return false;
}
config.m_hopindex = value.toInt();
}
if (!obj.contains(JSON_ALLOWEDIPADDRESSRANGES)) {
@@ -318,6 +359,23 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
return false;
}
if (!obj.value("Jc").isNull() && !obj.value("Jmin").isNull()
&& !obj.value("Jmax").isNull() && !obj.value("S1").isNull()
&& !obj.value("S2").isNull() && !obj.value("H1").isNull()
&& !obj.value("H2").isNull() && !obj.value("H3").isNull()
&& !obj.value("H4").isNull()) {
config.m_junkPacketCount = obj.value("Jc").toString();
config.m_junkPacketMinSize = obj.value("Jmin").toString();
config.m_junkPacketMaxSize = obj.value("Jmax").toString();
config.m_initPacketJunkSize = obj.value("S1").toString();
config.m_responsePacketJunkSize = obj.value("S2").toString();
config.m_initPacketMagicHeader = obj.value("H1").toString();
config.m_responsePacketMagicHeader = obj.value("H2").toString();
config.m_underloadPacketMagicHeader = obj.value("H3").toString();
config.m_transportPacketMagicHeader = obj.value("H4").toString();
}
return true;
}
@@ -325,8 +383,8 @@ bool Daemon::deactivate(bool emitSignals) {
Q_ASSERT(wgutils() != nullptr);
// Deactivate the main interface.
if (m_connections.contains(0)) {
const ConnectionState& state = m_connections.value(0);
if (!m_connections.isEmpty()) {
const ConnectionState& state = m_connections.first();
if (!run(Down, state.m_config)) {
return false;
}
@@ -349,9 +407,9 @@ bool Daemon::deactivate(bool emitSignals) {
// Cleanup peers and routing
for (const ConnectionState& state : m_connections) {
const InterfaceConfig& config = state.m_config;
logger.debug() << "Deleting routes for hop" << config.m_hopindex;
logger.debug() << "Deleting routes for" << config.m_hopType;
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
wgutils()->deleteRoutePrefix(ip, config.m_hopindex);
wgutils()->deleteRoutePrefix(ip);
}
wgutils()->deletePeer(config);
}
@@ -376,14 +434,14 @@ QString Daemon::logs() {
return {};
}
void Daemon::cleanLogs() { }
void Daemon::cleanLogs() { }
bool Daemon::supportServerSwitching(const InterfaceConfig& config) const {
if (!m_connections.contains(config.m_hopindex)) {
if (!m_connections.contains(config.m_hopType)) {
return false;
}
const InterfaceConfig& current =
m_connections.value(config.m_hopindex).m_config;
m_connections.value(config.m_hopType).m_config;
return current.m_privateKey == config.m_privateKey &&
current.m_deviceIpv4Address == config.m_deviceIpv4Address &&
@@ -395,21 +453,15 @@ bool Daemon::supportServerSwitching(const InterfaceConfig& config) const {
bool Daemon::switchServer(const InterfaceConfig& config) {
Q_ASSERT(wgutils() != nullptr);
logger.debug() << "Switching server for hop" << config.m_hopindex;
logger.debug() << "Switching server for" << config.m_hopType;
Q_ASSERT(m_connections.contains(config.m_hopindex));
Q_ASSERT(m_connections.contains(config.m_hopType));
const InterfaceConfig& lastConfig =
m_connections.value(config.m_hopindex).m_config;
m_connections.value(config.m_hopType).m_config;
// Configure routing for new excluded addresses.
for (const QString& i : config.m_excludedAddresses) {
QHostAddress address(i);
if (m_excludedAddrSet.contains(address)) {
m_excludedAddrSet[address]++;
continue;
}
wgutils()->addExclusionRoute(address);
m_excludedAddrSet[address] = 1;
addExclusionRoute(IPAddress(i));
}
// Activate the new peer and its routes.
@@ -418,7 +470,7 @@ bool Daemon::switchServer(const InterfaceConfig& config) {
return false;
}
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
if (!wgutils()->updateRoutePrefix(ip, config.m_hopindex)) {
if (!wgutils()->updateRoutePrefix(ip)) {
logger.error() << "Server switch failed to update the routing table";
break;
}
@@ -426,18 +478,11 @@ bool Daemon::switchServer(const InterfaceConfig& config) {
// Remove routing entries for the old peer.
for (const QString& i : lastConfig.m_excludedAddresses) {
QHostAddress address(i);
Q_ASSERT(m_excludedAddrSet.contains(address));
if (m_excludedAddrSet[address] > 1) {
m_excludedAddrSet[address]--;
continue;
}
wgutils()->deleteExclusionRoute(address);
m_excludedAddrSet.remove(address);
delExclusionRoute(QHostAddress(i));
}
for (const IPAddress& ip : lastConfig.m_allowedIPAddressRanges) {
if (!config.m_allowedIPAddressRanges.contains(ip)) {
wgutils()->deleteRoutePrefix(ip, config.m_hopindex);
wgutils()->deleteRoutePrefix(ip);
}
}
@@ -448,7 +493,7 @@ bool Daemon::switchServer(const InterfaceConfig& config) {
}
}
m_connections[config.m_hopindex] = ConnectionState(config);
m_connections[config.m_hopType] = ConnectionState(config);
return true;
}
@@ -457,12 +502,12 @@ QJsonObject Daemon::getStatus() {
QJsonObject json;
logger.debug() << "Status request";
if (!m_connections.contains(0) || !wgutils()->interfaceExists()) {
if (!wgutils()->interfaceExists() || m_connections.isEmpty()) {
json.insert("connected", QJsonValue(false));
return json;
}
const ConnectionState& connection = m_connections.value(0);
const ConnectionState& connection = m_connections.first();
QList<WireguardUtils::PeerStatus> peers = wgutils()->getPeerStatus();
for (const WireguardUtils::PeerStatus& status : peers) {
if (status.m_pubkey != connection.m_config.m_serverPublicKey) {
@@ -495,6 +540,7 @@ void Daemon::checkHandshake() {
if (connection.m_date.isValid()) {
continue;
}
logger.debug() << "awaiting" << config.m_serverPublicKey;
// Check if the handshake has completed.
for (const WireguardUtils::PeerStatus& status : peers) {

View File

@@ -43,11 +43,18 @@ class Daemon : public QObject {
signals:
void connected(const QString& pubkey);
/**
* Can be fired if a call to activate() was unsucessfull
* and connected systems should rollback
*/
void activationFailure();
void disconnected();
void backendFailure();
private:
bool maybeUpdateResolvers(const InterfaceConfig& config);
bool addExclusionRoute(const IPAddress& address);
bool delExclusionRoute(const IPAddress& address);
protected:
virtual bool run(Op op, const InterfaceConfig& config) {
@@ -75,8 +82,8 @@ class Daemon : public QObject {
QDateTime m_date;
InterfaceConfig m_config;
};
QMap<int, ConnectionState> m_connections;
QHash<QHostAddress, int> m_excludedAddrSet;
QMap<InterfaceConfig::HopType, ConnectionState> m_connections;
QHash<IPAddress, int> m_excludedAddrSet;
QTimer m_handshakeTimer;
};

View File

@@ -12,7 +12,7 @@
#include "leakdetector.h"
#include "logger.h"
#ifdef MZ_MACOS
#if defined(MZ_MACOS) || defined(MZ_LINUX)
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
@@ -68,7 +68,8 @@ bool DaemonLocalServer::initialize() {
QString DaemonLocalServer::daemonPath() const {
#if defined(MZ_WINDOWS)
return "\\\\.\\pipe\\amneziavpn";
#elif defined(MZ_MACOS)
#endif
#if defined(MZ_MACOS) || defined(MZ_LINUX)
QDir dir("/var/run");
if (!dir.exists()) {
logger.warning() << "/var/run doesn't exist. Fallback /tmp.";
@@ -92,7 +93,5 @@ QString DaemonLocalServer::daemonPath() const {
}
return VAR_PATH;
#else
# error Unsupported platform
#endif
}

View File

@@ -108,7 +108,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
}
if (type == "deactivate") {
Daemon::instance()->deactivate();
Daemon::instance()->deactivate(true);
return;
}

View File

@@ -0,0 +1,150 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "interfaceconfig.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QMetaEnum>
QJsonObject InterfaceConfig::toJson() const {
QJsonObject json;
QMetaEnum metaEnum = QMetaEnum::fromType<HopType>();
json.insert("hopType", QJsonValue(metaEnum.valueToKey(m_hopType)));
json.insert("privateKey", QJsonValue(m_privateKey));
json.insert("deviceIpv4Address", QJsonValue(m_deviceIpv4Address));
json.insert("deviceIpv6Address", QJsonValue(m_deviceIpv6Address));
json.insert("serverPublicKey", QJsonValue(m_serverPublicKey));
json.insert("serverPskKey", QJsonValue(m_serverPskKey));
json.insert("serverIpv4AddrIn", QJsonValue(m_serverIpv4AddrIn));
json.insert("serverIpv6AddrIn", QJsonValue(m_serverIpv6AddrIn));
json.insert("serverPort", QJsonValue((double)m_serverPort));
if ((m_hopType == InterfaceConfig::MultiHopExit) ||
(m_hopType == InterfaceConfig::SingleHop)) {
json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway));
json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway));
json.insert("dnsServer", QJsonValue(m_dnsServer));
}
QJsonArray allowedIPAddesses;
for (const IPAddress& i : m_allowedIPAddressRanges) {
QJsonObject range;
range.insert("address", QJsonValue(i.address().toString()));
range.insert("range", QJsonValue((double)i.prefixLength()));
range.insert("isIpv6",
QJsonValue(i.type() == QAbstractSocket::IPv6Protocol));
allowedIPAddesses.append(range);
};
json.insert("allowedIPAddressRanges", allowedIPAddesses);
QJsonArray jsExcludedAddresses;
for (const QString& i : m_excludedAddresses) {
jsExcludedAddresses.append(QJsonValue(i));
}
json.insert("excludedAddresses", jsExcludedAddresses);
QJsonArray disabledApps;
for (const QString& i : m_vpnDisabledApps) {
disabledApps.append(QJsonValue(i));
}
json.insert("vpnDisabledApps", disabledApps);
return json;
}
QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
#define VALIDATE(x) \
if (x.contains("\n")) return "";
VALIDATE(m_privateKey);
VALIDATE(m_deviceIpv4Address);
VALIDATE(m_deviceIpv6Address);
VALIDATE(m_serverIpv4Gateway);
VALIDATE(m_serverIpv6Gateway);
VALIDATE(m_serverPublicKey);
VALIDATE(m_serverIpv4AddrIn);
VALIDATE(m_serverIpv6AddrIn);
#undef VALIDATE
QString content;
QTextStream out(&content);
out << "[Interface]\n";
out << "PrivateKey = " << m_privateKey << "\n";
QStringList addresses;
if (!m_deviceIpv4Address.isNull()) {
addresses.append(m_deviceIpv4Address);
}
if (!m_deviceIpv6Address.isNull()) {
addresses.append(m_deviceIpv6Address);
}
if (addresses.isEmpty()) {
return "";
}
out << "Address = " << addresses.join(", ") << "\n";
if (!m_dnsServer.isNull()) {
QStringList dnsServers(m_dnsServer);
// If the DNS is not the Gateway, it's a user defined DNS
// thus, not add any other :)
if (m_dnsServer == m_serverIpv4Gateway) {
dnsServers.append(m_serverIpv6Gateway);
}
out << "DNS = " << dnsServers.join(", ") << "\n";
}
if (!m_junkPacketCount.isNull()) {
out << "Jc = " << m_junkPacketCount << "\n";
}
if (!m_junkPacketMinSize.isNull()) {
out << "JMin = " << m_junkPacketMinSize << "\n";
}
if (!m_junkPacketMaxSize.isNull()) {
out << "JMax = " << m_junkPacketMaxSize << "\n";
}
if (!m_initPacketJunkSize.isNull()) {
out << "S1 = " << m_initPacketJunkSize << "\n";
}
if (!m_responsePacketJunkSize.isNull()) {
out << "S2 = " << m_responsePacketJunkSize << "\n";
}
if (!m_initPacketMagicHeader.isNull()) {
out << "H1 = " << m_initPacketMagicHeader << "\n";
}
if (!m_responsePacketMagicHeader.isNull()) {
out << "H2 = " << m_responsePacketMagicHeader << "\n";
}
if (!m_underloadPacketMagicHeader.isNull()) {
out << "H3 = " << m_underloadPacketMagicHeader << "\n";
}
if (!m_transportPacketMagicHeader.isNull()) {
out << "H4 = " << m_transportPacketMagicHeader << "\n";
}
// If any extra config was provided, append it now.
for (const QString& key : extra.keys()) {
out << key << " = " << extra[key] << "\n";
}
out << "\n[Peer]\n";
out << "PublicKey = " << m_serverPublicKey << "\n";
out << "Endpoint = " << m_serverIpv4AddrIn.toUtf8() << ":" << m_serverPort
<< "\n";
/* In theory, we should use the ipv6 endpoint, but wireguard doesn't seem
* to be happy if there are 2 endpoints.
out << "Endpoint = [" << config.m_serverIpv6AddrIn << "]:"
<< config.m_serverPort << "\n";
*/
QStringList ranges;
for (const IPAddress& ip : m_allowedIPAddressRanges) {
ranges.append(ip.toString());
}
out << "AllowedIPs = " << ranges.join(", ") << "\n";
return content;
}

View File

@@ -10,22 +10,49 @@
#include "ipaddress.h"
struct InterfaceConfig {
int m_hopindex = 0;
class QJsonObject;
class InterfaceConfig {
Q_GADGET
public:
InterfaceConfig() {}
enum HopType { SingleHop, MultiHopEntry, MultiHopExit };
Q_ENUM(HopType)
HopType m_hopType;
QString m_privateKey;
QString m_deviceIpv4Address;
QString m_deviceIpv6Address;
QString m_serverIpv4Gateway;
QString m_serverIpv6Gateway;
QString m_serverPublicKey;
QString m_serverPskKey;
QString m_serverIpv4AddrIn;
QString m_serverPskKey;
QString m_serverIpv6AddrIn;
QString m_dnsServer;
int m_serverPort = 0;
QList<IPAddress> m_allowedIPAddressRanges;
QStringList m_excludedAddresses;
QStringList m_vpnDisabledApps;
#if defined(MZ_ANDROID) || defined(MZ_IOS)
QString m_installationId;
#endif
QString m_junkPacketCount;
QString m_junkPacketMinSize;
QString m_junkPacketMaxSize;
QString m_initPacketJunkSize;
QString m_responsePacketJunkSize;
QString m_initPacketMagicHeader;
QString m_responsePacketMagicHeader;
QString m_underloadPacketMagicHeader;
QString m_transportPacketMagicHeader;
QJsonObject toJson() const;
QString toWgConf(
const QMap<QString, QString>& extra = QMap<QString, QString>()) const;
};
#endif // INTERFACECONFIG_H

View File

@@ -5,6 +5,8 @@
#ifndef WIREGUARDUTILS_H
#define WIREGUARDUTILS_H
#define _WINSOCKAPI_
#include <QCoreApplication>
#include <QHostAddress>
#include <QObject>
@@ -12,7 +14,7 @@
#include "interfaceconfig.h"
constexpr const char* WG_INTERFACE = "moz0";
constexpr const char* WG_INTERFACE = "amn0";
constexpr uint16_t WG_KEEPALIVE_PERIOD = 60;
@@ -41,11 +43,11 @@ class WireguardUtils : public QObject {
virtual bool deletePeer(const InterfaceConfig& config) = 0;
virtual QList<PeerStatus> getPeerStatus() = 0;
virtual bool updateRoutePrefix(const IPAddress& prefix, int hopindex) = 0;
virtual bool deleteRoutePrefix(const IPAddress& prefix, int hopindex) = 0;
virtual bool updateRoutePrefix(const IPAddress& prefix) = 0;
virtual bool deleteRoutePrefix(const IPAddress& prefix) = 0;
virtual bool addExclusionRoute(const QHostAddress& address) = 0;
virtual bool deleteExclusionRoute(const QHostAddress& address) = 0;
virtual bool addExclusionRoute(const IPAddress& prefix) = 0;
virtual bool deleteExclusionRoute(const IPAddress& prefix) = 0;
};
#endif // WIREGUARDUTILS_H

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 236 KiB

View File

@@ -0,0 +1,18 @@
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_f_1379_19114)">
<circle cx="140" cy="140" r="107.5" stroke="#FBB36A"/>
</g>
<circle cx="140" cy="140" r="107" stroke="#FBB36A" stroke-width="2"/>
<circle cx="140" cy="140" r="107" stroke="url(#paint0_linear_1379_19114)" stroke-width="2"/>
<defs>
<filter id="filter0_f_1379_19114" x="2" y="2" width="276" height="276" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="15" result="effect1_foregroundBlur_1379_19114"/>
</filter>
<linearGradient id="paint0_linear_1379_19114" x1="-2.43527" y1="89.3291" x2="192.652" y2="11.9798" gradientUnits="userSpaceOnUse">
<stop stop-color="#E0AA84"/>
<stop offset="1" stop-color="#DF7D37"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 969 B

View File

@@ -0,0 +1,17 @@
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_1379_19118)">
<path d="M140 235C127.524 235 115.171 232.543 103.645 227.769C92.1191 222.994 81.6464 215.997 72.8248 207.175C64.0033 198.354 57.0056 187.881 52.2314 176.355C47.4572 164.829 45 152.476 45 140C45 127.524 47.4572 115.171 52.2314 103.645C57.0056 92.1191 64.0033 81.6464 72.8249 72.8248C81.6464 64.0033 92.1191 57.0056 103.645 52.2314C115.171 47.4572 127.524 45 140 45C152.476 45 164.829 47.4572 176.355 52.2314C187.881 57.0056 198.354 64.0033 207.175 72.8249C215.997 81.6464 222.994 92.1192 227.769 103.645C232.543 115.171 235 127.524 235 140C235 152.476 232.543 164.829 227.769 176.355C222.994 187.881 215.997 198.354 207.175 207.175C198.354 215.997 187.881 222.994 176.355 227.769C164.829 232.543 152.476 235 140 235L140 235Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round"/>
</g>
<defs>
<filter id="filter0_d_1379_19118" x="38" y="38" width="204" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19118"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19118" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,30 @@
<svg width="280" height="280" viewBox="0 0 280 280" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.1" filter="url(#filter0_d_1379_19115)">
<path d="M235 140C235 152.476 232.543 164.829 227.769 176.355C222.994 187.881 215.997 198.354 207.175 207.175C198.354 215.997 187.881 222.994 176.355 227.769C164.829 232.543 152.476 235 140 235C127.524 235 115.171 232.543 103.645 227.769C92.1191 222.994 81.6464 215.997 72.8249 207.175C64.0033 198.354 57.0056 187.881 52.2314 176.355C47.4572 164.829 45 152.476 45 140C45 127.524 47.4572 115.171 52.2314 103.645C57.0056 92.1191 64.0033 81.6464 72.8249 72.8248C81.6464 64.0033 92.1192 57.0056 103.645 52.2314C115.171 47.4572 127.524 45 140 45C152.476 45 164.829 47.4573 176.355 52.2314C187.881 57.0056 198.354 64.0033 207.175 72.8249C215.997 81.6464 222.994 92.1192 227.769 103.645C232.543 115.171 235 127.524 235 140L235 140Z" stroke="#FBB36A"/>
</g>
<g filter="url(#filter1_d_1379_19115)">
<path d="M140 235C126.016 235 112.204 231.913 99.551 225.959C86.8977 220.004 75.7151 211.33 66.8012 200.555C57.8874 189.78 51.4623 177.17 47.9846 163.626C44.5069 150.081 44.0623 135.935 46.6827 122.199C49.3031 108.462 54.9237 95.4738 63.1434 84.1604C71.363 72.847 81.979 63.4878 94.2334 56.7509C106.488 50.014 120.078 46.0655 134.035 45.1875C147.991 44.3094 161.97 46.5233 174.972 51.6712" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round"/>
</g>
<defs>
<filter id="filter0_d_1379_19115" x="38.5" y="38.5" width="203" height="203" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.984314 0 0 0 0 0.717647 0 0 0 0 0.317647 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19115"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19115" result="shape"/>
</filter>
<filter id="filter1_d_1379_19115" x="38" y="38" width="143.973" height="204" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.988235 0 0 0 0 0.301961 0 0 0 0 0.0705883 0 0 0 0.49 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1379_19115"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1379_19115" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17 10C18.6569 10 20 8.65685 20 7C20 5.34315 18.6569 4 17 4C15.3431 4 14 5.34315 14 7C14 8.65685 15.3431 10 17 10Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="4" y="4" width="6" height="6" rx="1" stroke="#D7D8DB" stroke-width="2"/>
<rect x="14" y="14" width="6" height="6" rx="1" stroke="#D7D8DB" stroke-width="2"/>
<path d="M7.18963 13.8523L10.8078 20H2.91364L7.18963 13.8523Z" stroke="#D7D8DB" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 12H5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 19L5 12L12 5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 12H19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 5L19 12L12 19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 316 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 6L9 17L4 12" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 9L12 15L18 9" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 18L15 12L9 6" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 15L12 9L6 15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 213 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 9H11C9.89543 9 9 9.89543 9 11V20C9 21.1046 9.89543 22 11 22H20C21.1046 22 22 21.1046 22 20V11C22 9.89543 21.1046 9 20 9Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 15H4C3.46957 15 2.96086 14.7893 2.58579 14.4142C2.21071 14.0391 2 13.5304 2 13V4C2 3.46957 2.21071 2.96086 2.58579 2.58579C2.96086 2.21071 3.46957 2 4 2H13C13.5304 2 14.0391 2.21071 14.4142 2.58579C14.7893 2.96086 15 3.46957 15 4V5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 649 B

View File

@@ -0,0 +1,5 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.332 5H9.33203L2.33203 12L9.33203 19H20.332C20.8625 19 21.3712 18.7893 21.7462 18.4142C22.1213 18.0391 22.332 17.5304 22.332 17V7C22.332 6.46957 22.1213 5.96086 21.7462 5.58579C21.3712 5.21071 20.8625 5 20.332 5V5Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.332 9L12.332 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.332 9L18.332 15" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 640 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 10L12 15L17 10" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 15V3" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 20H21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.5 3.49998C16.8978 3.10216 17.4374 2.87866 18 2.87866C18.2786 2.87866 18.5544 2.93353 18.8118 3.04014C19.0692 3.14674 19.303 3.303 19.5 3.49998C19.697 3.69697 19.8532 3.93082 19.9598 4.18819C20.0665 4.44556 20.1213 4.72141 20.1213 4.99998C20.1213 5.27856 20.0665 5.55441 19.9598 5.81178C19.8532 6.06915 19.697 6.303 19.5 6.49998L7 19L3 20L4 16L16.5 3.49998Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 660 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.88 9.87988C9.58526 10.1545 9.34885 10.4857 9.18488 10.8537C9.02091 11.2217 8.93274 11.619 8.92564 12.0218C8.91853 12.4246 8.99263 12.8247 9.14351 13.1983C9.2944 13.5718 9.51898 13.9112 9.80385 14.196C10.0887 14.4809 10.4281 14.7055 10.8016 14.8564C11.1752 15.0073 11.5753 15.0814 11.9781 15.0742C12.3809 15.0671 12.7782 14.979 13.1462 14.815C13.5142 14.651 13.8454 14.4146 14.12 14.1199" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.73 5.08C11.1513 5.02751 11.5754 5.00079 12 5C19 5 22 12 22 12C21.5529 12.9571 20.9922 13.8569 20.33 14.68" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.61 6.61011C4.62125 7.96473 3.02987 9.82537 2 12.0001C2 12.0001 5 19.0001 12 19.0001C13.9159 19.0052 15.7908 18.4452 17.39 17.3901" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 2L22 22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 12C2 12 5 5 12 5C19 5 22 12 22 12C22 12 19 19 12 19C5 19 2 12 2 12Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V7.5L14.5 2Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17C13.1046 17 14 16.1046 14 15C14 13.8954 13.1046 13 12 13C10.8954 13 10 13.8954 10 15C10 16.1046 10.8954 17 12 17Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12V13" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17V18" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.6 13.5L13.73 14" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.27 16L9.40002 16.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.6 16.5L13.73 16" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.27 14L9.40002 13.5" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 14L7.45 11.1C7.61696 10.7687 7.87281 10.4903 8.18893 10.296C8.50504 10.1018 8.86897 9.99927 9.24 10H20C20.3055 9.99946 20.6071 10.0689 20.8816 10.2031C21.1561 10.3372 21.3963 10.5325 21.5836 10.7739C21.7709 11.0152 21.9004 11.2963 21.9622 11.5956C22.024 11.8948 22.0164 12.2042 21.94 12.5L20.39 18.5C20.279 18.9299 20.0281 19.3106 19.6769 19.5822C19.3256 19.8538 18.894 20.0008 18.45 20H4C3.46957 20 2.96086 19.7893 2.58579 19.4142C2.21071 19.0391 2 18.5304 2 18V5C2 3.9 2.9 3 4 3H7.93C8.25941 3.0017 8.58331 3.08475 8.8729 3.24176C9.1625 3.39877 9.40882 3.62488 9.59 3.9L10.41 5.1C10.5912 5.37512 10.8375 5.60123 11.1271 5.75824C11.4167 5.91525 11.7406 5.9983 12.07 6H18C18.5304 6 19.0391 6.21071 19.4142 6.58579C19.7893 6.96086 20 7.46957 20 8V10" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 948 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 22V18C15.1392 16.7473 14.78 15.4901 14 14.5C17 14.5 20 12.5 20 9C20.08 7.75 19.73 6.52 19 5.5C19.28 4.35 19.28 3.15 19 2C19 2 18 2 16 3.5C13.36 3 10.64 3 8.00004 3.5C6.00004 2 5.00004 2 5.00004 2C4.70004 3.15 4.70004 4.35 5.00004 5.5C4.27191 6.51588 3.91851 7.75279 4.00004 9C4.00004 12.5 7.00004 14.5 10 14.5C9.61004 14.99 9.32004 15.55 9.15004 16.15C8.98004 16.75 8.93004 17.38 9.00004 18V22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 18C4.49 20 4 16 2 16" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 711 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 9L12 2L21 9V20C21 20.5304 20.7893 21.0391 20.4142 21.4142C20.0391 21.7893 19.5304 22 19 22H5C4.46957 22 3.96086 21.7893 3.58579 21.4142C3.21071 21.0391 3 20.5304 3 20V9Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 22V12H15V22" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V6C22 4.89543 21.1046 4 20 4Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22 7L13.03 12.7C12.7213 12.8934 12.3643 12.996 12 12.996C11.6357 12.996 11.2787 12.8934 10.97 12.7L2 7" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 733 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 5V19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 12H19" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 3H4C3.44772 3 3 3.44772 3 4V7C3 7.55228 3.44772 8 4 8H7C7.55228 8 8 7.55228 8 7V4C8 3.44772 7.55228 3 7 3Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 3H17C16.4477 3 16 3.44772 16 4V7C16 7.55228 16.4477 8 17 8H20C20.5523 8 21 7.55228 21 7V4C21 3.44772 20.5523 3 20 3Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 16H4C3.44772 16 3 16.4477 3 17V20C3 20.5523 3.44772 21 4 21H7C7.55228 21 8 20.5523 8 20V17C8 16.4477 7.55228 16 7 16Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 16H18C17.4696 16 16.9609 16.2107 16.5858 16.5858C16.2107 16.9609 16 17.4696 16 18V21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 21V21.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 7V10C12 10.5304 11.7893 11.0391 11.4142 11.4142C11.0391 11.7893 10.5304 12 10 12H7" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 12H3.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 3H12.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 16V16.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 12H17" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 12V12.01" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 21V20" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="23" height="23" rx="11.5" stroke="#A85809"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="23" height="23" rx="11.5" stroke="#878B91"/>
</svg>

After

Width:  |  Height:  |  Size: 177 B

View File

@@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.93006 19.0702C3.05535 17.1949 2.0022 14.6518 2.0022 12.0002C2.0022 9.34853 3.05535 6.80545 4.93006 4.93018" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.75993 16.24C7.20263 15.6818 6.76087 15.0191 6.45993 14.29C5.85157 12.8205 5.85157 11.1695 6.45993 9.7C6.76087 8.97087 7.20263 8.30823 7.75993 7.75" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.24 7.75977C16.8028 8.33271 17.2449 9.01281 17.54 9.75977C18.1483 11.2293 18.1483 12.8802 17.54 14.3498C17.2391 15.0789 16.7973 15.7415 16.24 16.2998" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.0701 4.93018C20.9448 6.80545 21.9979 9.34853 21.9979 12.0002C21.9979 14.6518 20.9448 17.1949 19.0701 19.0702" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17 21V13H7V21" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 3V8H15" stroke="#CBCBCB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 652 B

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