Compare commits

...

1700 Commits

Author SHA1 Message Date
DaanSelen
335c69f517 chore: focus dependabot 2025-09-16 15:06:22 +02:00
DaanSelen
0d118f4d32 Update dependabot.yml 2025-09-16 15:01:01 +02:00
DaanSelen
8f58a06731 testing dependabot 2025-09-16 14:55:32 +02:00
DaanSelen
4bfcc1abde Create dependabot.yml 2025-09-16 14:51:47 +02:00
Donald Zou
25f39db690 Merge pull request #886 from WGDashboard/DaanSelen-patch-2
Update docker.yml
2025-09-16 20:47:40 +08:00
DaanSelen
da5ce7da9e Update docker.yml 2025-09-16 14:46:51 +02:00
Donald Zou
e8126f3630 Merge pull request #885 from WGDashboard/DaanSelen-patch-2
Update docker.yml
2025-09-16 20:26:11 +08:00
DaanSelen
f842a7cc62 Update docker.yml 2025-09-16 14:25:40 +02:00
Donald Zou
7250422aaa Merge pull request #884 from WGDashboard/DaanSelen-patch-1
chore: add rust compiler
2025-09-16 20:00:58 +08:00
DaanSelen
9661ff0b78 chore: add rust compiler 2025-09-16 14:00:20 +02:00
Donald Zou
562201a342 Merge pull request #883 from WGDashboard/v4.3-dev
v4.3.0 Merge
2025-09-16 19:44:49 +08:00
Donald Zou
1ee9f7bc68 Delete Dockerfile-AWG-kernel 2025-09-16 19:14:40 +08:00
Donald Zou
18daa74ecd Merge branch 'main' into v4.3-dev 2025-09-16 19:13:56 +08:00
Donald Zou
eadae9373f Merge branch 'main' into v4.3-dev 2025-09-16 19:03:52 +08:00
Donald Zou
fb645dd84c Update ko-KR.json 2025-09-16 19:00:52 +08:00
Donald Zou
0cffed3037 Update README.md 2025-09-16 18:58:36 +08:00
Donald Zou
3bd5e02118 Merge pull request #880 from WGDashboard/v4.3-dev-docker
V4.3 dev docker
2025-09-16 16:59:09 +08:00
Donald Zou
c4fe81fcbf Merge pull request #878 from WGDashboard/v4.3-dev-docker-refac
refac: docker entrypoint refactoring (#743) by @AdamGH
2025-09-16 16:58:33 +08:00
Donald Zou
40976870ee Update 2025-09-16 16:49:50 +08:00
Donald Zou
d526deb826 Final testing for client side 2025-09-16 14:59:57 +08:00
Donald Zou
4ea3aa0a58 Build 2025-09-16 08:27:44 +08:00
Donald Zou
569ee8ac58 Push 2025-09-16 08:25:32 +08:00
Donald Zou
c42776a6d7 Push 2025-09-16 08:14:43 +08:00
Donald Zou
22af38579b Build 2025-09-16 08:01:50 +08:00
Donald Zou
a9ecf6c850 Build 2025-09-16 08:01:16 +08:00
Donald Zou
77112675ae Update Peer.py 2025-09-16 07:57:30 +08:00
Donald Zou
0b054ae668 Build Client 2025-09-16 07:47:29 +08:00
Donald Zou
51ba9a86fa Updated AWG 2025-09-16 07:46:25 +08:00
Donald Zou
83eeaa0d73 Push 2025-09-16 02:29:21 +08:00
Donald Zou
a2316c8641 Merge branch 'v4.3-dev' of https://github.com/donaldzou/WGDashboard into v4.3-dev 2025-09-15 22:10:13 +08:00
Donald Zou
f231e9214c Testing with 2 threads 1 worker 2025-09-15 22:09:57 +08:00
Donald Zou
3673813e6a Cleaned some code files 2025-09-15 21:48:00 +08:00
Donald Zou
feb3c38113 Merge pull request #879 from gdeeble/v4.3-dev-fix-empty-expiredate-peersharelink
fix: set date when null expiredate for peersharelink
2025-09-15 19:45:24 +08:00
Daan Selen
73a969a6bf feat: slight refactors to improve logic 2025-09-15 13:20:17 +02:00
Gary Deeble
7ac6d6c498 fix: set date on null expiredate for peersharelink 2025-09-15 06:52:34 -04:00
Adams
b2f306789c Docker entrypoint refactoring (#743)
* Add new env vars for docker

* Add email env vars for docker

* Improve sed for email vars

* Refactor entrypoint.sh file

* Add additional account docker vars

* Add comment for clear command

---------

Co-authored-by: DaanSelen <80752476+DaanSelen@users.noreply.github.com>
2025-09-15 12:09:14 +02:00
Donald Zou
1a26f757a8 Push 2025-09-15 11:41:01 +08:00
Donald Zou
1d66cda277 Push 2025-09-15 11:39:16 +08:00
Donald Zou
b52dad961b Merge pull request #872 from wdk-kr/korean
Some checks failed
Mark stale issues and pull requests / stale (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Update korean translations
2025-09-15 11:35:52 +08:00
Donald Zou
5a84136d87 Merge pull request #877 from gdeeble/v4.3-dev-fix-test-email
Fix: Test email failure
2025-09-15 11:35:30 +08:00
Gary Deeble
73d701eb08 Fix: Add subject variable to allow test email 2025-09-14 14:00:17 -04:00
Donald Zou
636ba5ebc8 Push 2025-09-15 01:28:27 +08:00
Donald Zou
627065e793 Push 2025-09-15 01:06:38 +08:00
Donald Zou
c9f395acbd Push 2025-09-15 01:04:56 +08:00
Donald Zou
919a5e9077 Merge pull request #876 from donaldzou/v4.3-dev
V4.3 dev
2025-09-14 23:50:10 +08:00
Donald Zou
b5986fde82 Merge branch 'v4.3-dev-docker' into v4.3-dev 2025-09-14 23:50:03 +08:00
Daan Selen
cf95aded77 chore: remove mariadb-dev dep 2025-09-14 17:40:53 +02:00
Daan Selen
694a06ddb6 feat: v4.3 docker compatibility 2025-09-14 17:15:41 +02:00
Donald Zou
2eb3a17775 Added "State" status for webhook session 2025-09-14 15:38:19 +08:00
Donald Zou
628464d2e1 Cleanup 2025-09-14 11:01:06 +08:00
Donald Zou
ccaaa4bd21 Build of #873 2025-09-13 23:26:23 +08:00
Donald Zou
1b285537ad Fix #873 2025-09-13 23:25:51 +08:00
Donald Zou
eab31ba5d0 Update SystemStatus.py 2025-09-13 19:05:32 +08:00
Donald Zou
acc1233b11 Update AmneziaWireguardConfiguration.py 2025-09-13 14:49:29 +08:00
Donald Zou
91a3b52a4a Update 2025-09-13 08:23:54 +08:00
Donald Zou
b2532e305e Create Dockerfile-Debian-Slim 2025-09-11 20:52:22 +08:00
Donald Zou
06f7e7f74b Update Dockerfile 2025-09-11 20:38:08 +08:00
Donald Zou
a517867cdf Update Dockerfile 2025-09-11 20:35:12 +08:00
Donald Zou
e1d3ad11cc Merge pull request #870 from donaldzou/v4.3-dev-docker
feat(docker): prepare the release's Docker deployment
2025-09-11 11:17:00 +08:00
Donald Zou
41dbdc8ccd Update dashboard.py 2025-09-11 11:14:19 +08:00
완두콩
df98ee8738 Update korean translations 2025-09-11 11:57:12 +09:00
Donald Zou
3be1cb6702 Merge pull request #871 from donaldzou/v4.3-dev
Handle backup folder error
2025-09-11 10:39:13 +08:00
Donald Zou
4644840009 Handle backup folder error 2025-09-11 10:38:30 +08:00
Daan Selen
4e75a95a73 chore(docs): add dockerignore 2025-09-10 23:59:58 +02:00
Daan Selen
92a2e26755 feat(docker): clean up remaining commands 2025-09-10 23:59:36 +02:00
Daan Selen
8ebd65cc0b feat(docker): prepare for version 4.3 2025-09-10 20:52:47 +02:00
Donald Zou
15d51735d2 Finished updating locales 2025-09-11 00:16:29 +08:00
Donald Zou
ee8afbd357 Merge pull request #868 from donaldzou/main
Keep v4.3 up to date
2025-09-08 17:37:16 +08:00
Donald Zou
b3889bb1e3 Feature for #844 2025-09-08 15:12:16 +08:00
Donald Zou
8bbb4a48f7 Update privatePublicKeyInput.vue
Added feature for #835
2025-09-07 22:20:34 +08:00
Donald Zou
2dce79bb85 Added Jinja template for subject #837 2025-09-07 22:12:22 +08:00
Donald Zou
1319c28f90 Added Reset Total Data as a valid peer job task #763 2025-09-07 21:43:49 +08:00
Donald Zou
f95c6beeba Merge pull request #867 from gdeeble/v4.3-dev-no-auth-email
Removed extra logging for email login
2025-09-07 21:11:02 +08:00
Gary Deeble
6cf1eb6140 Removed extra print statement 2025-09-07 08:25:04 -04:00
Donald Zou
4b713ab66e Added authentication option for SMTP
#893 and thank you @gdeeble!
2025-09-07 18:25:48 +08:00
Donald Zou
43d055a8b4 Update WireguardConfiguration.py
Accepted suggestion from #842
2025-09-07 17:44:16 +08:00
Donald Zou
28ce4bb1d6 Build for #525 2025-09-07 17:04:35 +08:00
Donald Zou
604d53d2f0 Added feature #525 2025-09-07 17:04:22 +08:00
Donald Zou
62d3332522 Update WireguardConfiguration.py
Resolved bug where peer is not added when mtu and keepalive is empty
2025-09-07 02:03:24 +08:00
Donald Zou
9caed31185 Added IP logging for #525 2025-09-05 17:57:50 +08:00
Donald Zou
030c1bdcba Added toggle for client side app 2025-09-05 16:39:59 +08:00
Donald Zou
44af7eba11 Finished forgot password for clients app 2025-09-05 15:48:11 +08:00
Donald Zou
41975973dc Build 2025-09-01 22:36:00 +08:00
Donald Zou
572c223854 Adjusted styles 2025-09-01 22:35:43 +08:00
Donald Zou
8191668d60 Build 2025-09-01 20:25:22 +08:00
Donald Zou
632c4f3dc7 Peer history 2025-09-01 17:16:03 +08:00
Donald Zou
caacbfae03 Added peer traffic and session 2025-08-29 16:55:33 +08:00
Donald Zou
3b3c071402 Done for #491 2025-08-28 17:58:02 +08:00
Donald Zou
85fa427134 Webhooks feature is done #669 2025-08-28 16:11:01 +08:00
Donald Zou
c3c7e50f08 Testing system status and webhook 2025-08-27 19:39:52 +08:00
Donald Zou
45524eaee5 Done #854 2025-08-27 17:48:28 +08:00
Donald Zou
48ec4c7f6f A potential fix for #854
Currently it is showing a sum of all interfaces on sent and receive... not sure if that's right
2025-08-27 11:42:06 +08:00
Donald Zou
593417a1fd Merge pull request #857 from donaldzou/donaldzou-patch-1
Some checks failed
Mark stale issues and pull requests / stale (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Fix link to WGDashboard DigitalOcean documentation
2025-08-26 14:22:40 +08:00
Donald Zou
e2c9941651 Fix link to WGDashboard DigitalOcean documentation
Updated the link for hosting WGDashboard with DigitalOcean. 

Fix #856
2025-08-26 14:14:23 +08:00
Donald Zou
f865317600 Finished most of the webhook UI 2025-08-26 00:41:37 +08:00
Donald Zou
c83a075886 Update DashboardWebHooks.py 2025-08-25 16:59:57 +08:00
Donald Zou
56d894a8d1 Update DashboardWebHooks.py 2025-08-25 16:54:02 +08:00
Donald Zou
bba7817c9b Build 2025-08-25 16:07:17 +08:00
Donald Zou
f360ef5d2f Testing webhooks 2025-08-25 16:06:41 +08:00
Donald Zou
f6e625c5f8 Webhook UI 2025-08-22 18:26:31 +08:00
Donald Zou
e26639cdc4 Adjusted settings page 2025-08-20 21:18:31 +08:00
Donald Zou
38e0a939c2 Added Webhooks Class 2025-08-20 16:47:07 +08:00
Donald Zou
2ec190ecfd Update for plugin 2025-08-20 15:26:07 +08:00
Donald Zou
549982db7f Merge branch 'v4.3-dev' of https://github.com/donaldzou/WGDashboard into v4.3-dev 2025-08-20 15:12:22 +08:00
Donald Zou
eab2c9d358 Fixed the issue where Job and Share link is not delete when peer deleted 2025-08-20 15:11:01 +08:00
Donald Zou
c5b72cb6d8 Build 2025-08-20 15:11:01 +08:00
Donald Zou
282a83829f Fixed #644 2025-08-20 15:11:01 +08:00
Donald Zou
20edd7cbcd Build 2025-08-20 15:11:01 +08:00
Donald Zou
a6311b4f63 Commit for #355 2025-08-20 15:11:01 +08:00
Donald Zou
b8792200c6 Peer groups are done... ish? 2025-08-20 15:11:01 +08:00
Donald Zou
ba85879151 For now.. 2025-08-20 15:11:01 +08:00
Donald Zou
86bb847374 Build for #843 2025-08-20 15:11:01 +08:00
Donald Zou
e61afba608 Completed feature for #843 2025-08-20 15:11:01 +08:00
Donald Zou
f418520f66 Build 2025-08-20 15:11:01 +08:00
Donald Zou
af3aebe34c Build 2025-08-20 15:11:01 +08:00
Donald Zou
8a568d787a Update client.py 2025-08-20 15:11:01 +08:00
Donald Zou
0d943cb06f Moved all dist code to one folder 2025-08-20 15:11:01 +08:00
Donald Zou
f9e9d32c52 Orignal build 2025-08-20 15:11:01 +08:00
Donald Zou
6bf38d4346 Build 2025-08-20 15:11:01 +08:00
Donald Zou
2cd59fc310 Update 2025-08-20 15:10:59 +08:00
Donald Zou
1dfa1d62e1 Build 2025-08-20 15:10:55 +08:00
Donald Zou
854b9d252f Update 2025-08-20 15:10:55 +08:00
Donald Zou
0c0cf3a378 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
b4f29e63b4 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
afbb3df571 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
01caca707b Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
8ed5826e6c Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
2c1e36e54d Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
1ed8b9f2d5 Build 2025-08-20 15:10:55 +08:00
Donald Zou
0ff8e9ed86 Update 2025-08-20 15:10:55 +08:00
Donald Zou
029081c610 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
63b9d15d34 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
7dcc3e7589 Update dashboard.py 2025-08-20 15:10:55 +08:00
Donald Zou
81e394a436 Build 2025-08-20 15:10:55 +08:00
Donald Zou
288068bf70 Up 2025-08-20 15:10:55 +08:00
Donald Zou
37546515be Update index.html 2025-08-20 15:10:55 +08:00
Donald Zou
c32787ccd3 Update index.html 2025-08-20 15:10:55 +08:00
Donald Zou
c9c7084db5 Build 2025-08-20 15:10:55 +08:00
Donald Zou
7b99441602 Build 2025-08-20 15:10:55 +08:00
Donald Zou
24940886f6 Vite build 2025-08-20 15:10:55 +08:00
Donald Zou
f777ac5f75 Update protocolBadge.vue 2025-08-20 15:10:55 +08:00
Donald Zou
a511eb21fc Completed override peer settings 2025-08-20 15:10:55 +08:00
Donald Zou
f11a3c8c3b Update 2025-08-20 15:10:55 +08:00
Donald Zou
430a6053ef Client App 2025-08-20 15:10:55 +08:00
Donald Zou
1867db5c99 Update DashboardPlugins.py 2025-08-20 15:10:55 +08:00
Donald Zou
f661cf0f83 Update AmneziaWireguardConfiguration.py 2025-08-20 15:10:55 +08:00
Donald Zou
b4814e281f Update WireguardConfiguration.py 2025-08-20 15:10:55 +08:00
Donald Zou
9d4e5d8cb5 Build 2025-08-20 15:10:55 +08:00
Donald Zou
88f40b244a Still need to work on validation 2025-08-20 15:10:55 +08:00
Donald Zou
3e3047f23e Added configuration descriptions 2025-08-20 15:10:55 +08:00
Donald Zou
ab4876e066 Added a box-shadow 2025-08-20 15:10:55 +08:00
Donald Zou
00d11880e8 Added WireguardConfigurationInfo 2025-08-20 15:10:55 +08:00
Donald Zou
c757cee988 Added Pydantic for configurations info 2025-08-20 15:10:55 +08:00
Donald Zou
ebbb681dd8 Delete DashboardPluginsManager.py 2025-08-20 15:10:55 +08:00
Donald Zou
feff6ce027 Update Plugins 2025-08-20 15:10:55 +08:00
Donald Zou
39d01015e5 Added plugins manager 2025-08-20 15:10:55 +08:00
Donald Zou
2aa2b15234 Added RRD Tool plugins 2025-08-20 15:10:55 +08:00
Donald Zou
21c6d0b8f9 Migrated configuration sorting to Pinia store
Fixed #841
2025-08-20 15:10:55 +08:00
Donald Zou
ffc9176225 Update clientAssignedPeers.vue 2025-08-20 15:10:55 +08:00
Donald Zou
d54609cc29 Update client deletion
Optimized client deletion
2025-08-20 15:10:55 +08:00
Donald Zou
0a87453961 Update availablePeersGroup.vue
Added link to each peer so is easier to set schedule jobs and other settings
2025-08-20 15:10:55 +08:00
Donald Zou
12d9058f1e Update DashboardClients.py
Added refreshing clients after signup
2025-08-20 15:10:55 +08:00
Donald Zou
f55c961e91 Finished client deletion 2025-08-20 15:10:55 +08:00
Donald Zou
fbe4e7dc4c Added router push if received 401 on client side 2025-08-20 15:10:55 +08:00
Donald Zou
53079497a1 Added client profile update 2025-08-20 15:10:55 +08:00
Donald Zou
2d08171e7c Added client profile update 2025-08-20 15:10:55 +08:00
Donald Zou
e879ceb1bc Remove deprecated file 2025-08-20 15:10:55 +08:00
Donald Zou
37e2985b9a Build 2025-08-20 15:10:55 +08:00
Donald Zou
aaca74874d Update DashboardOIDC.py
Fixed OIDC timeout
2025-08-20 15:10:55 +08:00
Donald Zou
41c5b4bd64 Optimized loading speed for peer information 2025-08-20 15:10:55 +08:00
Donald Zou
71e43eb503 Add client settings 2025-08-20 15:10:55 +08:00
Donald Zou
b52bb83c67 Adjusted OIDC template, continue working on building client side app 2025-08-20 15:10:55 +08:00
Donald Zou
7322b7cbf0 Fixed mobile css, sort by local accounts 2025-08-20 15:10:55 +08:00
Donald Zou
62ffd97808 Finished send password reset link 2025-08-20 15:10:55 +08:00
Donald Zou
a4ee56648e Added generate reset client password link 2025-08-20 15:10:55 +08:00
Donald Zou
f62e481fa0 Fixed email sender validation 2025-08-20 15:10:55 +08:00
Donald Zou
fa26fce0cc Merge pull request #820 from ikergcalvino/i18n-update
Standardize locale codes using BCP 47 to improve language support
2025-08-20 15:10:55 +08:00
Iker García Calviño
2fbee4aacc Update localizations with new strings and corrections for improved clarity and consistency 2025-08-20 15:10:54 +08:00
Iker García Calviño
530a7ef393 Add Indonesian, Portuguese, and Hungarian translations, and update supported locales 2025-08-20 15:10:50 +08:00
Iker García Calviño
99cb546b59 Changes to migrate to BCP 47 locale standard 2025-08-20 15:10:48 +08:00
Donald Zou
084bec0f07 Commit 2025-08-20 15:10:13 +08:00
Donald Zou
c199413d49 Finished peer assignment 2025-08-20 15:10:13 +08:00
Donald Zou
24eada4432 Build 2025-08-20 15:10:13 +08:00
Donald Zou
4df4aa07f4 Assign peers from client settings is done 2025-08-20 15:10:13 +08:00
Donald Zou
91fd0f0e9a Added peer selections for client 2025-08-20 15:10:13 +08:00
Donald Zou
12f6244930 Fixed MTU and KeepAlive can be empty, rewrote config builder 2025-08-20 15:10:13 +08:00
Donald Zou
327ecbe34c Build for the client manage page 2025-08-20 15:10:13 +08:00
Donald Zou
2ca62293a9 Created clients view for admin 2025-08-20 15:10:13 +08:00
Donald Zou
f3cae0b005 Build 2025-08-20 15:10:13 +08:00
Donald Zou
8f15d5dcdd Build 2025-08-20 15:10:12 +08:00
Donald Zou
c8348f7be8 Finished client assigning 2025-08-20 15:10:08 +08:00
Donald Zou
1839645360 Peer assignment to client is done 2025-08-20 15:10:04 +08:00
Donald Zou
2c73dc1df8 Update build for client and admin 2025-08-20 15:10:02 +08:00
Donald Zou
fefabe073f Updated psycopg2 to psycopg thanks @DaanSelen haha 2025-08-20 15:09:39 +08:00
Donald Zou
77b156c7f5 OIDC should be good to go 2025-08-20 15:09:39 +08:00
Donald Zou
5ac84e109d Update DashboardOIDC.py 2025-08-20 15:09:39 +08:00
Donald Zou
83d105facd Update DashboardOIDC.py 2025-08-20 15:09:39 +08:00
Donald Zou
b7af06d59d Update 2025-08-20 15:09:39 +08:00
Donald Zou
4da32690a9 Update 2025-08-20 15:09:39 +08:00
Donald Zou
a49c2a1cc0 Update DashboardOIDC.py 2025-08-20 15:09:39 +08:00
Donald Zou
f633a9654a Update 2025-08-20 15:09:39 +08:00
Donald Zou
0d58a172a9 Update 2025-08-20 15:09:39 +08:00
Donald Zou
651784b1d1 Update DashboardOIDC.py 2025-08-20 15:09:39 +08:00
Donald Zou
68abc7ec1b Update 2025-08-20 15:09:39 +08:00
Donald Zou
9745e8b034 Update DashboardOIDC.py
Testing more with OIDC
2025-08-20 15:09:39 +08:00
Donald Zou
d946c108a3 Update DashboardOIDC.py 2025-08-20 15:09:39 +08:00
Donald Zou
2b66f9a5c4 Update SSL 2025-08-20 15:09:39 +08:00
Donald Zou
4d321cf3f6 Update client.py 2025-08-20 15:09:39 +08:00
Donald Zou
299d84b16a OIDC is ready? I think? 2025-08-20 15:09:39 +08:00
Donald Zou
3d75f6bbbd Spent 4 hours working on OIDC verification 2025-08-20 15:09:39 +08:00
Donald Zou
6b194bba15 Build 2025-08-20 15:09:39 +08:00
Donald Zou
e63bccf274 Reconstruct Client App UI 2025-08-20 15:09:39 +08:00
Donald Zou
4ca79ac1c9 Fixed runJob 2025-08-20 15:09:39 +08:00
Donald Zou
aafef538f1 Build
# Conflicts:
#	src/static/app/dist/assets/configuration-cdo-S5d9.js
#	src/static/app/dist/assets/dayjs.min-C4BEB1lt.js
#	src/static/app/dist/assets/editConfiguration-UEBqsx1g.js
#	src/static/app/dist/assets/index-CPB-8sFq.js
#	src/static/app/dist/assets/index-CfPziasH.js
#	src/static/app/dist/assets/localeText-CyxQ0Kz3.js
#	src/static/app/dist/assets/message-C4Yp0lwZ.js
#	src/static/app/dist/assets/newConfiguration-ChGJ7xSk.js
#	src/static/app/dist/assets/osmap-C6nMOrBf.js
#	src/static/app/dist/assets/peerAddModal-BmoNcHxr.js
#	src/static/app/dist/assets/peerConfigurationFile-CP8FspMC.js
#	src/static/app/dist/assets/peerJobs-BLwykEew.js
#	src/static/app/dist/assets/peerJobsAllModal-DmXg9VpA.js
#	src/static/app/dist/assets/peerList-sNMkmM1X.js
#	src/static/app/dist/assets/peerSearchBar-CdEZuAVf.js
#	src/static/app/dist/assets/peerSettings-a8GW0whb.js
#	src/static/app/dist/assets/peerShareLinkModal-5XXDseK9.js
#	src/static/app/dist/assets/ping-DuPgpLex.js
#	src/static/app/dist/assets/protocolBadge-BwyLRUKo.js
#	src/static/app/dist/assets/restoreConfiguration-CPPo1_Tp.js
#	src/static/app/dist/assets/schedulePeerJob-DtVhPy4n.js
#	src/static/app/dist/assets/selectPeers-Bs51pfmN.js
#	src/static/app/dist/assets/settings-Dl9arqou.js
#	src/static/app/dist/assets/setup-BzCz1W8G.js
#	src/static/app/dist/assets/share-QVhX-X9Q.js
#	src/static/app/dist/assets/signin-BDhImFq0.js
#	src/static/app/dist/assets/storageMount.vue_vue_type_style_index_0_scoped_9509d7a0_lang-BeoP6Zsu.js
#	src/static/app/dist/assets/systemStatus-_MkxdUbb.js
#	src/static/app/dist/assets/totp-2ovufqb0.js
#	src/static/app/dist/assets/traceroute-BgNVsivF.js
#	src/static/app/dist/assets/vue-datepicker-BZlVex04.js
2025-08-20 15:09:33 +08:00
Donald Zou
68d8546383 Build 2025-08-20 15:09:13 +08:00
Donald Zou
c43b3926b8 Added update password in settings 2025-08-20 15:06:27 +08:00
Donald Zou
7e9cfc2872 Update 2025-08-20 15:06:27 +08:00
Donald Zou
e88936c05a Update 2025-08-20 15:06:27 +08:00
Donald Zou
9c1b4222d0 Adjusted styles 2025-08-20 15:06:27 +08:00
Donald Zou
69ec55b638 Update 2025-08-20 15:06:27 +08:00
Donald Zou
67a455c403 Update 2025-08-20 15:06:27 +08:00
Donald Zou
5bf4df2d27 Update 2025-08-20 15:06:27 +08:00
Donald Zou
7797cc06d0 Update 2025-08-20 15:06:27 +08:00
Donald Zou
541d89e170 Build 2025-08-20 15:06:27 +08:00
Donald Zou
d775fb69e3 Finished tweaking 2FA 2025-08-20 15:06:27 +08:00
Donald Zou
2a1a885056 Finished Index 2025-08-20 15:06:27 +08:00
Donald Zou
a334ce1527 Commit 2025-08-20 15:06:27 +08:00
Donald Zou
447cb5ccdc Update DashboardClients.py 2025-08-20 15:06:27 +08:00
Donald Zou
bca20e5b02 Update ConnectionString.py 2025-08-20 15:06:27 +08:00
Donald Zou
90675dcc2e Yay! 2025-08-20 15:06:27 +08:00
Donald Zou
e8deadaaff Sign In and TOTP is done 2025-08-20 15:06:27 +08:00
Donald Zou
ecc4cc7670 Finished SignUp and SignIn frontend and backend 2025-08-20 15:06:27 +08:00
Donald Zou
4a5de5efd4 Added ValidatePasswordStrength in Utilities.py 2025-08-20 15:06:27 +08:00
Donald Zou
bdf557fde3 Just commit 2025-08-20 15:06:27 +08:00
Donald Zou
29600cb54c Moved connection string to an individual file 2025-08-20 15:06:27 +08:00
Donald Zou
9f43fd7c92 Reconstruct notification center for client side 2025-08-20 15:06:27 +08:00
Donald Zou
6a6c1aa527 Update 2025-08-20 15:06:27 +08:00
Donald Zou
df7f9f2b14 Finished initializing client project 2025-08-20 15:06:27 +08:00
Donald Zou
568da8cc64 Update 2025-08-20 15:06:27 +08:00
Donald Zou
e16435f4fc Update 2025-08-20 15:06:27 +08:00
Donald Zou
76e9f3fd29 Update dashboard.py 2025-08-20 15:06:27 +08:00
Donald Zou
d0e46a517b Update SQLAlchemy Settings 2025-08-20 15:06:27 +08:00
Donald Zou
c94345cb2f Update 2025-08-20 15:06:27 +08:00
Donald Zou
e2882acec1 Finally moved all class to its own file 2025-08-20 15:06:27 +08:00
Donald Zou
3c2362177f Refactored DashboardConfig
Refactored this file and moved `DashboardConfig` into its own file
2025-08-20 15:06:27 +08:00
Donald Zou
5e92931108 Moved Utilities.py into src/modules for easier import 2025-08-20 15:06:27 +08:00
Donald Zou
d54e388b58 Update DashboardLogger.py
Removed the requirement of using `CONFIGURATION_PATH`
2025-08-20 15:06:27 +08:00
Donald Zou
390cfa0cdf Tested with PostgreSQL and moved PeerJobLogger into its own file 2025-08-20 15:06:27 +08:00
Donald Zou
c6fc741aa8 Update dashboard.py 2025-08-20 15:06:27 +08:00
Donald Zou
a0e15e1671 Moved PeerJobs to using SQLAlchemy, haven't test PostgreSQL yet 2025-08-20 15:06:27 +08:00
Donald Zou
8367cba259 Moved DashboardAPIKey to its own file 2025-08-20 15:06:27 +08:00
Donald Zou
f7bf709295 Moved PeerShareLink and PeerShareLinks to separate file 2025-08-20 15:06:27 +08:00
Donald Zou
ab802ea5cf Updated PeerShareLink to use SQLAlchemy 2025-08-20 15:06:27 +08:00
Donald Zou
922d8eab58 Update dashboard.py
- Updated `DashboardConfig` class to use SqlAlchemy, tested with SQLite and Postgresql
2025-08-20 15:06:20 +08:00
Donald Zou
409acc9f1a Updated both logger to use native column type 2025-08-20 15:06:05 +08:00
Donald Zou
196dc78b4f Added support to postgresql and Mysql with SqlAlchemy 2025-08-20 15:06:05 +08:00
Donald Zou
61404d9c12 Replaced both DashboardLogger and PeerJobLogger with SqlAlchemy 2025-08-20 15:06:05 +08:00
Donald Zou
ceab5ead8c Fixed the issue where Job and Share link is not delete when peer deleted 2025-08-20 14:15:03 +08:00
Donald Zou
9b60acf3db Build 2025-08-20 01:26:43 +08:00
Donald Zou
90bb321a07 Fixed #644 2025-08-19 19:11:44 +08:00
Donald Zou
e56fa24a38 Build 2025-08-19 17:58:54 +08:00
Donald Zou
574aff605f Commit for #355 2025-08-19 17:56:46 +08:00
Donald Zou
9c6d0b56c3 Peer groups are done... ish? 2025-08-19 00:40:01 +08:00
Donald Zou
e0761396b8 For now.. 2025-08-17 23:47:21 +08:00
Donald Zou
4b44eb5c80 Build for #843 2025-08-17 19:00:48 +08:00
Donald Zou
eb66a44edf Completed feature for #843 2025-08-17 18:58:28 +08:00
Donald Zou
f8708b84e6 Build 2025-08-17 17:24:56 +08:00
Donald Zou
cc29091116 Build 2025-08-17 17:24:29 +08:00
Donald Zou
2f860772d2 Update client.py 2025-08-17 16:48:31 +08:00
Donald Zou
2f5d1c0966 Moved all dist code to one folder 2025-08-17 16:33:03 +08:00
Donald Zou
39c6817e65 Orignal build 2025-08-17 16:11:03 +08:00
Donald Zou
2d63f56d64 Build 2025-08-17 16:05:04 +08:00
Donald Zou
a4a158a9e9 Update 2025-08-17 15:51:39 +08:00
Donald Zou
be78cb5321 Build 2025-08-17 15:24:53 +08:00
Donald Zou
1e483dc34d Update 2025-08-17 15:13:30 +08:00
Donald Zou
8ddf77973d Update dashboard.py 2025-08-17 15:09:17 +08:00
Donald Zou
d9a4858c4f Update dashboard.py 2025-08-17 15:06:39 +08:00
Donald Zou
c3e5406218 Update dashboard.py 2025-08-17 15:04:04 +08:00
Donald Zou
b92c345b3a Update dashboard.py 2025-08-17 14:57:20 +08:00
Donald Zou
ac9fd8f2ca Update dashboard.py 2025-08-17 02:11:19 +08:00
Donald Zou
20aae4769d Update dashboard.py 2025-08-17 01:49:08 +08:00
Donald Zou
1052c72863 Build 2025-08-16 23:31:54 +08:00
Donald Zou
4beb61c3af Update 2025-08-16 23:19:48 +08:00
Donald Zou
4b6c5db904 Update dashboard.py 2025-08-16 23:06:56 +08:00
Donald Zou
18493bb9b0 Update dashboard.py 2025-08-16 23:04:52 +08:00
Donald Zou
13a4bee725 Update dashboard.py 2025-08-16 22:57:41 +08:00
Donald Zou
7db0f7ec35 Build 2025-08-16 17:21:08 +08:00
Donald Zou
9936038603 Up 2025-08-16 17:20:44 +08:00
Donald Zou
ae9fb91c72 Update index.html 2025-08-16 17:05:39 +08:00
Donald Zou
dcf7126f51 Update index.html 2025-08-16 17:05:25 +08:00
Donald Zou
d3a512bf9e Build 2025-08-16 17:04:36 +08:00
Donald Zou
6809d97dd6 Build 2025-08-16 17:02:21 +08:00
Donald Zou
b89919546c Vite build 2025-08-16 16:54:31 +08:00
Donald Zou
cfa1c23506 Update protocolBadge.vue 2025-08-16 16:17:25 +08:00
Donald Zou
e61b5d2a3f Completed override peer settings 2025-08-16 15:40:57 +08:00
Donald Zou
9089fd37e0 Update 2025-08-16 14:04:12 +08:00
Donald Zou
4eab083a30 Client App 2025-08-16 12:27:50 +08:00
Donald Zou
11a07758aa Update DashboardPlugins.py 2025-08-16 11:19:22 +08:00
Donald Zou
ae712c1c98 Update AmneziaWireguardConfiguration.py 2025-08-16 11:17:39 +08:00
Donald Zou
9b2415f0f1 Update WireguardConfiguration.py 2025-08-16 11:12:56 +08:00
Donald Zou
f130098937 Build 2025-08-16 11:09:27 +08:00
Donald Zou
e280a2e4a9 Still need to work on validation 2025-08-16 01:51:18 +08:00
Donald Zou
60bd4bc91b Added configuration descriptions 2025-08-15 21:45:09 +08:00
Donald Zou
145c3d8f96 Added a box-shadow 2025-08-15 18:28:28 +08:00
Donald Zou
663c134e60 Added WireguardConfigurationInfo 2025-08-15 11:45:06 +08:00
Donald Zou
1e264ca4a1 Added Pydantic for configurations info 2025-08-14 22:36:14 +08:00
Donald Zou
207e9f7afd Delete DashboardPluginsManager.py 2025-08-14 17:23:48 +08:00
Donald Zou
6e4c144af6 Update Plugins 2025-08-14 17:14:52 +08:00
Donald Zou
325c97cfe6 Added plugins manager 2025-08-13 21:41:28 +08:00
Donald Zou
4d07845c7f Added RRD Tool plugins 2025-08-13 16:35:34 +08:00
Donald Zou
93baa505c7 Migrated configuration sorting to Pinia store
Fixed #841
2025-08-12 17:22:40 +08:00
Donald Zou
b81d4667b2 Update clientAssignedPeers.vue 2025-08-12 17:21:36 +08:00
Donald Zou
3dd065dd7b Update client deletion
Optimized client deletion
2025-08-12 17:21:08 +08:00
Donald Zou
0a8692dcc0 Update availablePeersGroup.vue
Added link to each peer so is easier to set schedule jobs and other settings
2025-08-12 17:20:18 +08:00
Donald Zou
26cc295167 Update DashboardClients.py
Added refreshing clients after signup
2025-08-12 17:18:31 +08:00
Donald Zou
48d9800b71 Finished client deletion 2025-08-11 17:29:15 +08:00
Donald Zou
9424ad1f13 Added router push if received 401 on client side 2025-08-11 16:32:21 +08:00
Donald Zou
5c58f548c0 Added client profile update 2025-08-11 14:35:54 +08:00
Donald Zou
f59111025b Added client profile update 2025-08-11 14:35:30 +08:00
Donald Zou
e313776982 Remove deprecated file 2025-08-11 14:35:10 +08:00
Donald Zou
faa0bc952f Merge pull request #845 from alexperreault/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Update both french translations
2025-08-11 10:37:11 +08:00
Alexandre Perreault
87f8c60e2f Update both french translations 2025-08-10 12:55:20 -04:00
Donald Zou
e551c499db Build 2025-08-09 16:46:31 +08:00
Donald Zou
9aaa1edad6 Update DashboardOIDC.py
Fixed OIDC timeout
2025-08-06 17:27:33 +08:00
Donald Zou
d96b178a9c Optimized loading speed for peer information 2025-08-06 17:27:14 +08:00
Donald Zou
1c857c0781 Add client settings 2025-08-02 21:58:09 +08:00
Donald Zou
ae160aef23 Updated ConfigParser to RawConfigParser; Updated version number
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-08-02 16:54:50 +08:00
Donald Zou
2ccce69180 Adjusted OIDC template, continue working on building client side app 2025-08-02 16:51:24 +08:00
Donald Zou
a9f618891b Fixed mobile css, sort by local accounts 2025-07-27 02:55:13 +08:00
Donald Zou
85d1cc8be4 Merge pull request #833 from DaanSelen/hinakumo-patch
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Hinakumo patch
2025-07-26 02:18:40 +08:00
Donald Zou
6315112b3b Finished send password reset link 2025-07-25 18:06:42 +08:00
Velrino
8cff8d85f6 chore: update documentation links in agentModal and helpModal (#811)
LGTM!
2025-07-24 20:41:00 +02:00
DaanSelen
d7a1007f41 Merge branch 'donaldzou:main' into hinakumo-patch 2025-07-24 20:28:20 +02:00
Daan Selen
0cd2c6864e make stale compliant 2025-07-24 20:27:54 +02:00
Daan Selen
0cb46e1444 Docker file update 2025-07-24 20:23:42 +02:00
Donald Zou
cb9dfa1321 Fixed Docker system status widget issue (#832)
* Fixed Docker system status widget issue

* Build

ref: https://github.com/donaldzou/WGDashboard/issues/798
2025-07-24 19:42:41 +02:00
Donald Zou
674fea7063 Added generate reset client password link 2025-07-24 23:12:51 +08:00
Donald Zou
722cbb6054 Fixed email sender validation 2025-07-24 23:12:21 +08:00
Donald Zou
042160e6bd Merge pull request #820 from ikergcalvino/i18n-update
Standardize locale codes using BCP 47 to improve language support
2025-07-24 15:05:33 +08:00
Iker García Calviño
06c44fe91f Update localizations with new strings and corrections for improved clarity and consistency 2025-07-24 15:05:32 +08:00
Iker García Calviño
d92c636b69 Add Indonesian, Portuguese, and Hungarian translations, and update supported locales 2025-07-24 15:05:32 +08:00
Iker García Calviño
0599503779 Changes to migrate to BCP 47 locale standard 2025-07-24 15:05:32 +08:00
Donald Zou
2cf337a606 Commit 2025-07-24 15:04:46 +08:00
Donald Zou
b0bb320fb6 Finished peer assignment 2025-07-22 03:23:58 +08:00
Donald Zou
7a2a2846e1 Build 2025-07-21 17:02:21 +08:00
Donald Zou
90c35b67bd Assign peers from client settings is done 2025-07-21 17:00:33 +08:00
Donald Zou
65287ba800 Added peer selections for client 2025-07-21 02:29:33 +08:00
Donald Zou
14af465aa3 Fixed MTU and KeepAlive can be empty, rewrote config builder 2025-07-20 20:52:37 +08:00
Donald Zou
95f0b60cac Build for the client manage page 2025-07-19 17:18:09 +08:00
Donald Zou
d69044231b Created clients view for admin 2025-07-18 21:42:39 +08:00
Donald Zou
72fde9860b Build 2025-07-18 18:50:38 +08:00
Donald Zou
481ada43d6 Build 2025-07-18 18:49:54 +08:00
Donald Zou
a9d74e834d Finished client assigning 2025-07-18 18:49:19 +08:00
Donald Zou
43fd2fff2b Merge pull request #821 from NaturGamerYT/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Update de-de.json
2025-07-17 13:49:10 +08:00
Florian
b37c64f5a5 Update de-de.json 2025-07-16 13:55:28 +02:00
hinakumo
f1aa064b2d Made CDs more direct 2025-07-14 01:26:01 +03:00
Matias G Henschel
8abadd1070 Added PT-BR language, minor ES fix. (#817)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-07-13 21:29:43 +02:00
hinakumo
3f9d9732a0 Added build packages deps to Dockerfile 2025-07-12 09:21:29 +03:00
hinakumo
b9dc3c44a8 Change AWG repos in Dockerfile 2025-07-12 09:08:10 +03:00
Donald Zou
68e757aafc Peer assignment to client is done 2025-07-10 23:39:21 +08:00
Donald Zou
af045447e6 Update build for client and admin 2025-07-08 16:32:08 +08:00
Donald Zou
db6976a06a Updated psycopg2 to psycopg thanks @DaanSelen haha 2025-07-08 16:31:03 +08:00
Donald Zou
aa66a5ffb2 OIDC should be good to go 2025-07-03 19:20:01 +08:00
Donald Zou
bf74150f62 Update DashboardOIDC.py 2025-07-02 19:01:21 +08:00
Donald Zou
2987216169 Update DashboardOIDC.py 2025-07-02 18:59:41 +08:00
Donald Zou
08a41f8f68 Update 2025-07-02 18:57:14 +08:00
Donald Zou
714a824823 Update 2025-07-02 18:56:08 +08:00
Donald Zou
2242dca27d Update DashboardOIDC.py 2025-07-02 18:52:49 +08:00
Donald Zou
681558126d Update 2025-07-02 18:51:58 +08:00
Donald Zou
927e637d88 Update 2025-07-02 18:50:47 +08:00
Donald Zou
3b97cb420d Update DashboardOIDC.py 2025-07-02 18:48:37 +08:00
Donald Zou
241fbd6be5 Update 2025-07-02 18:45:43 +08:00
Donald Zou
a619e7f571 Update DashboardOIDC.py
Testing more with OIDC
2025-07-01 13:06:16 +08:00
Donald Zou
491119d676 Update DashboardOIDC.py 2025-06-29 22:27:46 +08:00
Donald Zou
29a8c15d62 Update SSL 2025-06-29 21:18:20 +08:00
Donald Zou
26741512ea Update client.py 2025-06-29 16:14:46 +08:00
Donald Zou
a987d91ae1 OIDC is ready? I think? 2025-06-29 16:11:05 +08:00
Donald Zou
380b9a73ab Spent 4 hours working on OIDC verification 2025-06-28 18:13:26 +08:00
Donald Zou
66bd1da571 Build 2025-06-26 17:58:18 +08:00
Donald Zou
79ad3c0a84 Reconstruct Client App UI 2025-06-26 17:56:55 +08:00
Donald Zou
e69e7ff3c1 Fixed runJob 2025-06-25 23:16:51 +08:00
DaanSelen
1483ef83d9 Added except label (#806)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-06-25 10:51:23 +02:00
Donald Zou
dbed799e20 Merge pull request #805 from DaanSelen/staleenglish
English fix
2025-06-25 16:32:28 +08:00
Daan Selen
4602b68425 English fix 2025-06-25 10:27:34 +02:00
Donald Zou
2d3eaedaa7 Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-06-24 17:20:21 +08:00
Donald Zou
4d60b21a5f Update stale.yml 2025-06-24 17:09:56 +08:00
Donald Zou
50ee8374ee Update stale.yml 2025-06-24 16:36:22 +08:00
Donald Zou
65eb23e8ce Update stale.yml 2025-06-24 16:36:13 +08:00
Donald Zou
5c76b18ddd Delete .github/workflows/stale_action 2025-06-24 16:27:05 +08:00
Donald Zou
fc6f5d2535 Create stale.yml 2025-06-24 16:26:35 +08:00
Donald Zou
6a0348e9dc Create stale_action 2025-06-24 16:15:36 +08:00
Donald Zou
40d3548c82 Build 2025-06-23 16:22:05 +08:00
Donald Zou
fc7bbf89c6 Build 2025-06-20 16:01:20 +08:00
Donald Zou
6f848e3df8 Added update password in settings 2025-06-20 16:00:19 +08:00
Donald Zou
d80eb03707 Update 2025-06-19 16:51:59 +08:00
Donald Zou
85d4b8c487 Update 2025-06-19 00:41:08 +08:00
Donald Zou
90e6409b1e Update dashboard.py
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Update version number
2025-06-17 13:34:13 +08:00
Donald Zou
96b28a8e9b Update dashboard.py (#791)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Removed `getDashboardConfiguration` from API whitelist
2025-06-16 23:01:04 +02:00
Donald Zou
a818e87e96 Merge pull request #793 from DaanSelen/delpr
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
2025-06-16 22:25:16 +08:00
DaanSelen
dc715758a6 Merge branch 'donaldzou:main' into delpr 2025-06-16 14:45:53 +02:00
Daan Selen
87069329d8 Where do these come from? 2025-06-16 14:45:23 +02:00
Daan Selen
8a380a4545 Separated tasks (again) and separate builds 2025-06-16 14:42:39 +02:00
Daan Selen
a5e18cb761 del pr running 2025-06-16 14:41:02 +02:00
DaanSelen
e9da3e7b6a streamline docker (#792) 2025-06-16 14:33:16 +02:00
Daan Selen
289fa23728 streamline 2025-06-16 14:27:12 +02:00
Donald Zou
c6a44bfe09 Adjusted styles 2025-06-14 19:52:23 +08:00
Donald Zou
c6af129960 Update 2025-06-06 15:49:55 +08:00
Donald Zou
6cb30bcd7f Update 2025-06-05 17:57:24 +08:00
Donald Zou
55027fd3cd Update 2025-06-05 17:57:14 +08:00
Donald Zou
41bf9b8baa Update 2025-06-05 15:57:17 +08:00
Donald Zou
c117ee61d5 Merge pull request #780 from donaldzou/releasetagging
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Docker release management
2025-06-05 10:55:37 +08:00
Daan
7385932e52 donald 2025-06-04 19:54:40 +02:00
Daan
cb90b69b3f Looks good! 2025-06-04 19:52:44 +02:00
Donald Zou
8d0e31872a Update README.md
Testing GitHub Action
2025-06-05 00:18:22 +08:00
Donald Zou
881925fd43 Update docker.yml 2025-06-04 23:52:51 +08:00
Donald Zou
3a2f744f0a Merge pull request #779 from DaanSelen/scanfix
Add a login to the scan
2025-06-04 23:29:55 +08:00
Daan Selen
9dc9e668c5 Add a login to the scan 2025-06-04 16:53:16 +02:00
Donald Zou
39477c8de8 Merge pull request #778 from donaldzou/DaanSelen-patch-1 2025-06-04 22:44:08 +08:00
DaanSelen
1b0bb95e81 Update docker.yml
I hate this.
2025-06-04 16:41:18 +02:00
Donald Zou
cd5a4bec52 Merge pull request #776 from donaldzou/DaanSelen-patch-4 2025-06-04 22:33:26 +08:00
Daan Selen
43070ab809 Syntax fix 2025-06-04 13:14:03 +02:00
Daan Selen
532fedbb62 Adding file 2025-06-04 13:05:35 +02:00
Daan Selen
585bf37783 THIS SHOULD BE WORKING 2025-06-04 13:04:17 +02:00
DaanSelen
cad364e407 Update docker-build.yml
Pulled out the action docs this time...
2025-06-04 11:01:38 +02:00
Donald Zou
45457c5b38 Merge pull request #775 from donaldzou/DaanSelen-patch-3 2025-06-04 16:57:28 +08:00
DaanSelen
4e9142b5be Update docker-build.yml
Its becoming not fun
2025-06-04 10:56:28 +02:00
Donald Zou
207b365d40 Merge pull request #774 from donaldzou/DaanSelen-patch-2 2025-06-04 16:45:00 +08:00
DaanSelen
1ec95a0d86 Update docker-build.yml 2025-06-04 10:42:54 +02:00
Donald Zou
db4b9ccc7a Merge pull request #773 from donaldzou/DaanSelen-patch-1 2025-06-04 16:38:37 +08:00
DaanSelen
a86d0c74d3 Update docker-build.yml 2025-06-04 10:36:42 +02:00
Donald Zou
354f4e47df Merge pull request #772 from DaanSelen/workflowclarify 2025-06-04 16:32:52 +08:00
Daan Selen
84167650b8 hotfix 2025-06-04 10:27:11 +02:00
Daan Selen
15c12a81f1 Separate stages 2025-06-04 10:12:18 +02:00
DaanSelen
249ae584c3 Merge branch 'donaldzou:main' into workflowclarify 2025-06-04 10:09:57 +02:00
DaanSelen
b04f7b2d2c Separated tasks (again) and separate builds (#771)
* Separated tasks (again) and separate builds (#8)

* Update docker-build.yml

Updated `GHCR_TOKEN` to `GITHUB_TOKEN`

---------

Co-authored-by: Donald Zou <donaldzou@live.hk>
2025-06-04 10:01:01 +02:00
Donald Zou
630ce459cb Update docker-build.yml
Updated `GHCR_TOKEN` to `GITHUB_TOKEN`
2025-06-04 15:55:22 +08:00
Donald Zou
68fae3b23c Build 2025-06-03 23:38:10 +08:00
Donald Zou
3525cd1083 Finished tweaking 2FA 2025-06-03 23:37:43 +08:00
DaanSelen
a7a30fb282 Separated tasks (again) and separate builds (#8) 2025-06-03 15:19:11 +02:00
Donald Zou
e9730f24a0 Finished Index 2025-06-03 17:18:18 +08:00
Donald Zou
c35d22a82f Commit 2025-06-03 14:49:56 +08:00
Donald Zou
b76d92bfeb Update DashboardClients.py 2025-06-03 14:36:29 +08:00
Donald Zou
afa578aa34 Update ConnectionString.py 2025-06-03 12:04:08 +08:00
Donald Zou
519ccda5ed Yay! 2025-06-03 03:11:26 +08:00
Donald Zou
832513a7fc Sign In and TOTP is done 2025-06-03 03:02:06 +08:00
Donald Zou
0300c26952 Finished SignUp and SignIn frontend and backend 2025-06-02 19:23:04 +08:00
Donald Zou
243071d4cc Added ValidatePasswordStrength in Utilities.py 2025-06-02 12:26:28 +08:00
Donald Zou
c95937d08b Just commit 2025-06-02 12:04:01 +08:00
Donald Zou
58f944c72e Moved connection string to an individual file 2025-06-01 15:34:12 +08:00
Donald Zou
173cc57490 Reconstruct notification center for client side 2025-06-01 11:19:50 +08:00
Donald Zou
4c8ba6b0a8 Update 2025-05-31 22:59:46 +08:00
Donald Zou
ab5abe9bcf Merge pull request #767 from donaldzou/potential-fix-#762
Background thread terminated when iterating conf list and list changed
2025-05-31 22:52:12 +08:00
Donald Zou
be2ea8c6d5 Finished initializing client project 2025-05-31 20:52:53 +08:00
Donald Zou
7834fff541 Update dashboard.py
Potential fix for #762
2025-05-29 16:52:13 +08:00
Donald Zou
16ec9d2938 Update 2025-05-29 16:23:20 +08:00
Donald Zou
ef8849e8a9 Update README.md 2025-05-29 00:24:07 +08:00
Donald Zou
93a23671e4 Update 2025-05-27 16:46:44 +08:00
Donald Zou
8a77fbfefd Update dashboard.py 2025-05-26 16:23:06 +08:00
Donald Zou
78bedf9ad6 Update README.md 2025-05-25 12:58:18 +08:00
Donald Zou
6ec757ab66 Merge pull request #759 from donaldzou/fix-pi-os-installation-issue
Update wgd.sh
2025-05-24 20:43:18 +08:00
Donald Zou
9ffb7f54c7 Update SQLAlchemy Settings 2025-05-24 18:25:52 +08:00
Kármán Zsombor
7d71299c51 Add Hungarian language support (#747)
* feat(i18n): add Hungarian (Magyar) language support

* Update active_languages.json

chore: remove extra leading space from line

* Fix: relocate Hungarian (hu-hu) to correct alphabetical position
2025-05-22 23:52:59 +02:00
Donald Zou
bea37aee7f Update wgd.sh
Added `raspbian` into installation, thanks @DerPitter bringing this up at #749
2025-05-22 19:52:05 +08:00
Donald Zou
5323687ea5 Update README.md 2025-05-22 17:19:56 +08:00
Donald Zou
d1372a4c43 Update README.md 2025-05-22 17:05:25 +08:00
Donald Zou
c9249a164a Merge pull request #758 from DaanSelen/main 2025-05-22 10:00:47 +08:00
DaanSelen
6f105f2626 Updated Dutch translations (#7) 2025-05-21 09:59:40 +02:00
DaanSelen
e4c08896f4 Merge branch 'donaldzou:main' into main 2025-05-21 09:50:49 +02:00
Donald Zou
e85a0df9b7 Update README.md 2025-05-21 13:08:00 +08:00
Donald Zou
a5b7eabd97 Update README.md 2025-05-20 23:56:43 +08:00
Donald Zou
f3688431a3 Update README.md 2025-05-20 23:55:34 +08:00
Donald Zou
44e714352d Merge pull request #755 from donaldzou/fix-awg-qrcode
Fix AmneziaWG QR Code not workiing
2025-05-19 21:55:28 +08:00
Donald Zou
60da68c994 Build 2025-05-19 21:49:19 +08:00
Donald Zou
11288fac20 Update peerQRCode.vue 2025-05-19 21:44:16 +08:00
Donald Zou
be10a644a0 Update 2025-05-19 21:43:11 +08:00
Donald Zou
a5a64eadc7 Finally moved all class to its own file 2025-05-18 15:24:41 +08:00
Donald Zou
2cee252b14 Refactored DashboardConfig
Refactored this file and moved `DashboardConfig` into its own file
2025-05-14 09:24:29 +08:00
Donald Zou
050b4a5c9d Moved Utilities.py into src/modules for easier import 2025-05-14 09:23:48 +08:00
Donald Zou
6d4b5d4484 Update DashboardLogger.py
Removed the requirement of using `CONFIGURATION_PATH`
2025-05-14 09:22:59 +08:00
Donald Zou
964a6c2e3e Tested with PostgreSQL and moved PeerJobLogger into its own file 2025-05-13 21:36:15 +08:00
Donald Zou
fe9d373444 Delete .github/workflows/qodana_code_quality.yml 2025-05-13 20:42:29 +08:00
Donald Zou
cce31f9b0b Merge pull request #744 from donaldzou/fix-schedule-job-issue
Update dashboard.py
2025-05-11 00:14:01 +08:00
Donald Zou
ca779ed5ad Update dashboard.py
- Update Job list before every run
2025-05-11 00:09:23 +08:00
Donald Zou
14336529d9 Update dashboard.py 2025-05-11 00:04:37 +08:00
Donald Zou
2e57285120 Moved PeerJobs to using SQLAlchemy, haven't test PostgreSQL yet 2025-05-10 18:16:29 +08:00
Donald Zou
2784059a0f Moved DashboardAPIKey to its own file 2025-05-08 19:05:46 +08:00
Donald Zou
04e78f4de7 Moved PeerShareLink and PeerShareLinks to separate file 2025-05-08 19:03:26 +08:00
Donald Zou
c051ab56b4 Updated PeerShareLink to use SQLAlchemy 2025-05-08 17:27:49 +08:00
Donald Zou
eb0eaaae2e Merge pull request #733 from donaldzou/v4.2.3-dev
v4.2.3 Merge
2025-05-07 23:18:33 +08:00
Donald Zou
9631b97694 Final UI Build 2025-05-07 23:15:24 +08:00
Donald Zou
6f036876c8 Doing a final check 2025-05-07 23:14:56 +08:00
Donald Zou
bd47179ea4 Build UI for v4.2.3 2025-05-07 22:48:43 +08:00
Donald Zou
17004f704c Update dashboard.py
- Updated `DashboardConfig` class to use SqlAlchemy, tested with SQLite and Postgresql
2025-05-07 18:40:24 +08:00
dselen
418c6bd88b Merge branch 'donaldzou:main' into main 2025-05-07 08:41:49 +02:00
Donald Zou
ada4c4f816 Update dashboard.py
- Fixed #737
- Removed unnecessary code
2025-05-07 13:00:18 +08:00
Donald Zou
fc34c1fc35 Updated both logger to use native column type 2025-05-05 20:34:08 +08:00
Donald Zou
6e6cd9a7e5 Added support to postgresql and Mysql with SqlAlchemy 2025-05-05 00:40:29 +08:00
Donald Zou
16051981d7 Replaced both DashboardLogger and PeerJobLogger with SqlAlchemy 2025-05-04 17:44:54 +08:00
Donald Zou
91b499fb14 Update peerQRCode.vue 2025-05-04 17:09:45 +08:00
Donald Zou
1f73adffd6 Fixed issue #698 2025-05-04 01:54:47 +08:00
Donald Zou
82bd313e7a Taking Copilot's suggestion 2025-05-03 17:33:40 +08:00
Donald Zou
14cbfe47b9 Updated theme color 2025-05-03 16:56:20 +08:00
Donald Zou
f2d4ff6dc4 Update dashboard.py
Fixed the issue where TOTP Key is not actually reset when reset.
2025-05-03 16:13:30 +08:00
Donald Zou
bf33a70727 Updated all language file to latest language template 2025-05-02 23:34:44 +08:00
Donald Zou
e1bdcbd581 Merge pull request #708 from Jumala9163/locale/japanese
Updated Japanese translation & Added untranslated parts
2025-05-02 23:00:55 +08:00
Donald Zou
051c1e7622 Merge pull request #722 from reykim7854/locale-indonesia
add Bahasa Indonesia to localization
2025-05-02 22:56:47 +08:00
Donald Zou
3b176474ff Merge pull request #725 from sf0nt/main
add catalan translation
2025-05-02 22:55:14 +08:00
Donald Zou
15f1b33ea6 Merge pull request #727 from DaanSelen/dockerpidclean
Fix: 723 and more
2025-05-02 22:53:05 +08:00
Donald Zou
0603d4076a Merge branch 'v4.2.3-dev' into dockerpidclean 2025-05-02 22:52:52 +08:00
reykim7854
ac94f10dc3 fix deprecated locale key 2025-05-02 21:37:55 +07:00
sf0nt
bbb92490e9 order languages alphabetically 2025-05-02 16:03:08 +02:00
Donald Zou
2cb63092c0 Fixed AmneziaWG QR Code out of screen on phone 2025-05-02 21:35:27 +08:00
Donald Zou
b9bcb59592 Fixed CPU Core floating label height 2025-05-02 20:51:58 +08:00
Donald Zou
e083adc022 Merge pull request #728 from BeppeMarnell/#712-peer-delete-bug
API Peer delete bug #712 fix: fixed issue with delete endpoint return…
2025-05-02 20:33:26 +08:00
Donald Zou
c3cd38fe9f Update dashboard.py
- Fixed issue where deleting configuration will delete other configuration with similar name
2025-05-02 20:11:11 +08:00
giuseppe
a7c2db5e99 API Peer delete bug #712 fix: fixed issue with delete endpoint returning always 200 2025-05-02 11:52:39 +02:00
Daan Selen
4926ee5117 Fix https://github.com/donaldzou/WGDashboard/issues/723 and more 2025-05-02 10:02:38 +02:00
Donald Zou
e7723ac3db Build and update version number 2025-05-02 14:34:23 +08:00
Donald Zou
8dbfb93e4e Merge pull request #726 from donaldzou/fix-awg-advanced-security
Fix awg advanced security
2025-05-02 14:30:57 +08:00
Donald Zou
6096366756 Merge pull request #724 from DaanSelen/main
AmneziaWG Fix for Docker
2025-05-02 14:27:33 +08:00
sf0nt
8e4cf12512 Update active_languages.json 2025-05-02 04:42:43 +02:00
sf0nt
b61fa1f870 Rename es-ca.json to ca.json 2025-05-02 04:41:46 +02:00
sf0nt
ac3cf9e4b1 Rename es_ca.json to es-ca.json 2025-05-02 04:38:57 +02:00
sf0nt
e18463f059 Update es_ca.json 2025-05-02 04:38:19 +02:00
Donald Zou
ee54e08d18 Build and removed advanced_security from UI 2025-05-01 19:59:58 +02:00
Donald Zou
3c07df6496 Build and removed advanced_security from UI 2025-05-01 23:08:40 +08:00
Donald Zou
2117b828c8 Update dashboard.py
Removed `advanced-security` from command line send to AWG
2025-05-01 16:42:37 +02:00
Donald Zou
28d9694432 Update dashboard.py
Removed `advanced-security` from command line send to AWG
2025-05-01 22:40:53 +08:00
Daan Selen
7d977700e6 typo 2025-05-01 16:38:19 +02:00
Donald Zou
33942945d0 commit 2025-05-01 22:28:43 +08:00
Daan Selen
8d7d78db46 Not alpine, latest 2025-05-01 16:21:30 +02:00
Daan Selen
3268cc30ea Donald 2025-05-01 16:20:20 +02:00
Daan Selen
8830ebe34f AmneziaWG Fix for Docker 2025-05-01 16:15:55 +02:00
reykim7854
1d9adba6dd add Bahasa Indonesia to localization 2025-05-01 12:21:29 +07:00
sf0nt
71be73777e Update es_ca.json 2025-05-01 02:51:53 +02:00
sf0nt
7709f70ef1 Update es_ca.json 2025-05-01 02:21:21 +02:00
sf0nt
9b528b84e1 Update es_ca.json 2025-05-01 02:09:04 +02:00
sf0nt
c53a4d4861 Update es_ca.json 2025-04-30 05:23:02 +02:00
sf0nt
766173df3d Update es_ca.json 2025-04-30 05:02:43 +02:00
sf0nt
7f65cae891 Update es_ca.json 2025-04-30 04:43:41 +02:00
sf0nt
bc56ecb85c Update es_ca.json 2025-04-30 03:59:00 +02:00
sf0nt
50c3151301 Update es_ca.json 2025-04-30 03:41:49 +02:00
sf0nt
d49ec0a81e Update es_ca.json 2025-04-30 03:07:00 +02:00
sf0nt
6692028762 Update es_ca.json 2025-04-30 02:49:00 +02:00
sf0nt
b71c357958 Create es_ca.json 2025-04-30 02:40:47 +02:00
sf0nt
03b7621f3e Update active_languages.json with catalan 2025-04-30 02:40:01 +02:00
Donald Zou
2bcf24bd84 Merge pull request #710 from reloadlife/feat/route-table
feat: Supporting "table" directive in the configuration
2025-04-27 16:17:17 +08:00
Jumala9163
cc5aa05b12 Fixed where translations were not being done correctly. 2025-04-26 17:26:23 +09:00
Jumala9163
3232c5c4ce update ja-jp & Add new locations that are not yet translated 2025-04-26 16:50:31 +09:00
dselen
72a52f5cd6 Merge pull request #704 from DaanSelen/dockerdoc
Docker files cleanup
2025-04-25 14:58:35 +02:00
Daan Selen
bda48a56e0 Docker files cleanup 2025-04-25 09:27:07 +02:00
Donald Zou
09cdcf8e53 Update version number 2025-04-25 14:23:51 +08:00
Donald Zou
a4d5b41ca7 Merge pull request #703 from donaldzou/fix-#702
Fix #702 and #699
2025-04-25 14:15:33 +08:00
Donald Zou
9fa0d91d06 Update Email.py
Fixed #699
2025-04-25 14:08:45 +08:00
Donald Zou
510f60bdeb Update Email.py
Fixed to accomodate SMTP service where `username` is not an email address from #702
2025-04-25 13:39:29 +08:00
Mohammad Mahdi Afshar
30fe827253 feat: Supporting "table" directive in the configuration 2025-04-24 18:51:26 +03:30
Donald Zou
8f0f4b168b Update README.md
Added demo server
2025-04-24 19:13:34 +08:00
Donald Zou
cd11c4beb6 Merge branch 'main' of https://github.com/donaldzou/WGDashboard 2025-04-23 21:27:01 +08:00
Donald Zou
4d49cc413a Update README.md 2025-04-23 21:26:21 +08:00
Donald Zou
3d50a58a31 Merge pull request #690 from donaldzou/donaldzou-patch-2
Update README.md
2025-04-23 20:23:03 +08:00
Donald Zou
d5701230fa Pushing this for Docker 2025-04-23 20:22:26 +08:00
Donald Zou
ab945d6afe Update README.md
Changed the icon!
2025-04-23 20:06:44 +08:00
Donald Zou
b4f8a36d43 Merge pull request #689 from donaldzou/fix-#683
Fix #683
2025-04-23 19:31:50 +08:00
Donald Zou
608c1b4eb6 Update version number to v4.2.1 2025-04-23 19:30:41 +08:00
Donald Zou
edf3c42157 Update version number 2025-04-23 19:26:31 +08:00
Donald Zou
c523cec113 Fixed #683 and Re-build 2025-04-23 19:24:50 +08:00
Donald Zou
6f8b987d42 Merge pull request #688 from donaldzou/fix-welcome-session-issue
Update dashboard.py
2025-04-23 18:06:10 +08:00
Donald Zou
d0d0642bdf Update dashboard.py
Fixed issue where new user can't finish welcome session
2025-04-23 18:05:19 +08:00
Donald Zou
924d760e3b Merge pull request #687 from DaanSelen/delarmv6
Remove arm v6 because go image has not been built for it.
2025-04-23 16:29:17 +08:00
Donald Zou
f8c207ca2b Merge pull request #685 from Jorropo/fr-fr
locale: Add fr-fr language
2025-04-23 16:22:43 +08:00
Daan Selen
ada1edd0b7 Remove arm v6 because go image has not been built for it. 2025-04-23 10:08:09 +02:00
Donald Zou
c79333db61 Merge pull request #681 from DaanSelen/imagebump
Imagebump
2025-04-23 16:00:53 +08:00
Jorropo
13778bed87 locale: Add fr-fr language
This file copies most of the work from @alexp did in af5e7974 when adding fr-ca language.

There a handful of sentences being rephrased.
Typographic changes.
And few corrections that should probably be done in fr-ca too.
2025-04-23 07:33:16 +02:00
Daan
83b4d96f42 go image bump 2025-04-22 21:36:28 +02:00
Daan
6cf96de0b4 Moved Docker file around, cleaning. 2025-04-22 21:20:41 +02:00
Donald Zou
481fadc7fc Build 2025-04-23 02:15:05 +08:00
Donald Zou
44f2c59e56 Merge pull request #679 from donaldzou/v4.2-dev
V4.2 dev
2025-04-23 02:13:39 +08:00
Donald Zou
83589a912f Update README.md 2025-04-22 22:34:09 +08:00
Donald Zou
fab9f03e7d Update README.md 2025-04-22 22:33:22 +08:00
Donald Zou
928c83b13c Update README.md 2025-04-22 22:26:29 +08:00
Donald Zou
72f20bc69b Update README.md 2025-04-22 22:26:01 +08:00
Donald Zou
8293d5379d Update README.md 2025-04-22 22:23:11 +08:00
Donald Zou
1d29445a8b Merge branch 'v4.2-dev' of https://github.com/donaldzou/WGDashboard into v4.2-dev 2025-04-22 18:42:22 +08:00
Donald Zou
5c308d757f Update wgd.sh and removed SSL-TLS from Gunicorn 2025-04-22 18:42:08 +08:00
Donald Zou
5bf16004c9 Merge branch 'main' into v4.2-dev 2025-04-21 18:11:09 +08:00
Donald Zou
417fa437b7 Update 2025-04-21 17:25:12 +08:00
Donald Zou
43f893c921 Update 2025-04-21 15:59:42 +08:00
Donald Zou
8ad9af4bc2 Added Belarusian to v4.2 2025-04-20 15:47:24 +08:00
Donald Zou
b3931bdc9d Merge pull request #646 from Bardatsky/main
added Belarusian language
2025-04-20 15:46:27 +08:00
Donald Zou
7ac153848b Merge branch 'main' into main 2025-04-20 15:45:18 +08:00
Donald Zou
7689ebcac5 Update 2025-04-20 02:52:22 +08:00
Donald Zou
bf7adf9ca9 Build 2025-04-20 02:46:32 +08:00
Donald Zou
51ab8c556a Sorting language available automatically 2025-04-20 02:40:36 +08:00
Donald Zou
149a8e910d Merged latest locale from main 2025-04-20 02:37:54 +08:00
Donald Zou
310746b8cd Merge pull request #676 from donaldzou/DaanSelen-patch-1
Update active_languages.json
2025-04-19 22:26:28 +08:00
Donald Zou
6681303450 Adjusted some API endpoint
Some checks failed
Qodana / qodana (push) Has been cancelled
2025-04-19 02:54:47 +08:00
dselen
3228f37f09 Merge branch 'main' into DaanSelen-patch-1 2025-04-17 23:04:26 +02:00
dselen
421785bf6a Merge pull request #675 from mahdiMGF2/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Scan and Build / docker_build_analyze (push) Has been cancelled
Qodana / qodana (push) Has been cancelled
added Farsi language
2025-04-17 23:01:50 +02:00
Mahdi
308e8ca8c7 The Persian language was organized based on the alphabet. 2025-04-13 15:14:01 +03:30
Daan
cb068ef70e Reordering on lang_name 2025-04-13 12:02:35 +02:00
dselen
acd3ec782f Update active_languages.json
Alphabetical
2025-04-13 11:40:14 +02:00
Mahdi
12d1e5b8d0 added Farsi language 2025-04-11 09:04:02 +03:30
dselen
b165cdbd79 Merge pull request #672 from Jumala9163/jumala9163/locale/japanese
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Qodana / qodana (push) Has been cancelled
Add Japanese Language
2025-04-07 16:05:17 +02:00
Donald Zou
66f4507dee Refactored some API endpoint
Some checks failed
Qodana / qodana (push) Has been cancelled
2025-04-07 18:45:12 +08:00
Donald Zou
a724e1cb58 Update README.md 2025-04-07 17:41:12 +08:00
Donald Zou
f942809de0 Update README.md
Added DO as sponsor!
2025-04-07 15:14:07 +08:00
Donald Zou
8043f77e02 Update README.md 2025-04-06 05:32:15 +08:00
Jumala9163
1db9ba90d8 fix typo 2025-04-06 00:23:30 +09:00
Jumala9163
464fa59cb6 Add Japanese(ja-jp) Language 2025-04-06 00:12:00 +09:00
Donald Zou
a8e2cbf55b Update README.md 2025-04-05 22:38:20 +08:00
Donald Zou
fecd8dab38 Update README.md 2025-04-05 20:45:37 +08:00
Donald Zou
13a833e3ed Update README.md 2025-04-04 16:53:17 +08:00
Donald Zou
8d4784052a Build v4.2 2025-04-03 23:03:00 +08:00
Donald Zou
d9e9b41861 Build 2025-03-28 00:13:54 +08:00
Donald Zou
f0c3ef0aa1 Added Chatbot to the App! 2025-03-28 00:13:38 +08:00
Donald Zou
3888831679 Merge pull request #663 from donaldzou/DaanSelen-patch-3
Update docker-related.yaml
2025-03-26 17:11:02 +08:00
dselen
1a32fad324 Update docker-related.yaml
Added nigthly trigger.
2025-03-26 09:42:11 +01:00
Donald Zou
d842ae9540 Update docker-related.yaml 2025-03-25 15:36:53 +08:00
Donald Zou
d0177b7504 Update docker-related.yaml 2025-03-25 15:17:41 +08:00
Donald Zou
e3842b25f3 Update docker-related.yaml 2025-03-25 15:11:06 +08:00
Donald Zou
a29b59c9cd Update docker-related.yaml 2025-03-24 17:36:05 +08:00
Donald Zou
f94eb97aa4 Update docker-related.yaml 2025-03-24 12:52:28 +08:00
Donald Zou
86017b79eb Update docker-related.yaml 2025-03-24 12:50:26 +08:00
Donald Zou
bc22fa5fad Update docker-related.yaml 2025-03-24 12:42:03 +08:00
Donald Zou
d6b70028ff Merge pull request #662 from donaldzou/donaldzou-patch-1
Update docker-related.yaml
2025-03-24 05:11:36 +08:00
Donald Zou
0f7f9acd58 Update docker-related.yaml 2025-03-24 05:11:22 +08:00
Donald Zou
20633a6d1a Update docker-related.yaml 2025-03-24 05:00:45 +08:00
Donald Zou
a23856270d Merge pull request #661 from donaldzou/DaanSelen-patch-2
Update docker-related.yaml
2025-03-24 04:27:53 +08:00
dselen
55543e370e Update docker-related.yaml
Workflow fix fix
2025-03-23 21:20:40 +01:00
Donald Zou
8137a46c68 Merge pull request #660 from DaanSelen/workflow-fix
Workflow fix.
2025-03-24 04:16:34 +08:00
Daan
aeb9597c71 Workflow fix. 2025-03-23 20:41:48 +01:00
Donald Zou
5067485e94 Commit
Some checks failed
Qodana / qodana (push) Has been cancelled
2025-03-16 00:42:40 +08:00
Donald Zou
dfd456c7dc Update qodana_code_quality.yml
Some checks failed
Qodana / qodana (push) Has been cancelled
2025-03-12 01:01:42 +08:00
Donald Zou
0ccb07e683 Push 2025-03-12 00:59:32 +08:00
Donald Zou
ca67a6897f Update 2025-03-12 00:44:36 +08:00
Donald Zou
0390227641 Update qodana_code_quality.yml
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Qodana / qodana (push) Has been cancelled
2025-03-12 00:36:07 +08:00
Donald Zou
395b0982db Merge pull request #650 from donaldzou/qodana-automation-897468090
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Qodana / qodana (push) Waiting to run
Add qodana CI checks
2025-03-11 18:00:52 +08:00
Qodana Application
f096ab4da7 Add github workflow file 2025-03-11 10:00:39 +00:00
Qodana Application
d5ec9f7640 Add qodana.yaml file 2025-03-11 10:00:39 +00:00
Donald Zou
5732867407 Fixed #493 2025-03-11 17:52:53 +08:00
Егор Бардацкиий
31842f4c12 added Belarusian language 2025-03-08 03:45:26 +03:00
Donald Zou
d5168d2da6 Update dashboard.py 2025-03-07 00:52:51 +08:00
Donald Zou
cac5ec836b Update dashboard.py
- Fixing #601
2025-03-07 00:45:01 +08:00
Donald Zou
ee9569e7d4 Update dashboard.py
- Trying to fix #601
2025-03-07 00:37:01 +08:00
dselen
95df7de026 Merge pull request #639 from karorogunso/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Add Thai language
2025-02-27 11:51:53 +01:00
Karorogunso
d3a5bd374d Merge pull request #1 from karorogunso/thai
Add Thai to main brach
2025-02-27 16:44:42 +07:00
Karorogunso
43ac3dddf1 Merge branch 'donaldzou:main' into thai 2025-02-27 16:25:57 +07:00
Karorogunso
1174328de3 Update active_languages.json 2025-02-27 16:24:28 +07:00
dselen
dda54fb907 Merge pull request #625 from DaanSelen/arch-support
Arch Linux Support
2025-02-20 13:14:35 +01:00
Daan
92ea808a5d Arch Linux Support 2025-02-19 18:49:00 +01:00
dselen
2bc3a75c94 Merge pull request #621 from wdk-kr/korean
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Add Korean Language
2025-02-18 13:04:56 +01:00
완두콩
07ef97ce7c Update active_languages.json 2025-02-18 20:13:52 +09:00
완두콩
5fe3539331 Update ko.json 2025-02-18 15:52:50 +09:00
완두콩
4bc3bd5f13 Update ko.json 2025-02-18 15:51:24 +09:00
완두콩
4abce854d7 Update active_languages.json 2025-02-18 15:36:01 +09:00
완두콩
3b5c73992e Fix incorrect translations 2025-02-18 15:25:10 +09:00
완두콩
c5abea2944 Add Korean Language 2025-02-18 15:11:08 +09:00
Donald Zou
8e5cf14ebc Merge pull request #619 from akhepcat/v4.2-dev
Update wgd.sh - install pypi mirror can auto select by rtt after delay
2025-02-18 02:46:19 +08:00
Leif
7c8410ab86 Update wgd.sh
update msleep for longer timeout, and move that var to the top to make it more obvious
2025-02-17 09:41:11 -09:00
Donald Zou
369b4b92cc Update dashboard.py
- Fixed #
2025-02-17 15:25:33 +08:00
Donald Zou
c50bb70383 Build 2025-02-17 14:25:49 +08:00
Donald Zou
d84b2060f0 Added endpoint back when on list 2025-02-17 14:25:37 +08:00
Donald Zou
afcf6024e6 Update 2025-02-17 14:01:56 +08:00
Donald Zou
3542bd6668 Adjusted UI to fit list display 2025-02-17 13:47:05 +08:00
Leif Sawyer
69b9116dd5 Add auto-select based on ping response 2025-02-16 14:53:03 -09:00
Leif
a2db4f06b1 Update wgd.sh install pypi mirror auto select
add timeout value so that the install/update can run fully scripted without normal user intervention if desired
2025-02-16 11:43:47 -09:00
Donald Zou
b60b0fb511 Resolved #596 2025-02-17 00:20:36 +08:00
Donald Zou
0c1e9a6bb5 Fixed #499 2025-02-16 23:08:24 +08:00
Donald Zou
2692f92cb9 Fixed #609 2025-02-16 23:07:16 +08:00
Donald Zou
a43c8b4b00 Update dashboard.py 2025-02-16 17:43:22 +08:00
Donald Zou
6f15389411 Updated how available IP is generated 2025-02-16 17:42:32 +08:00
Donald Zou
f055241802 Build 2025-02-15 16:50:09 +08:00
Donald Zou
ac77c3a390 Fixed hardcoded issue 2025-02-15 16:49:49 +08:00
Donald Zou
5cd99f2edc Update dashboard.py
Fixed #490
2025-02-14 23:59:21 +08:00
Donald Zou
7c70fbec30 Build 2025-02-14 23:24:16 +08:00
Donald Zou
ac0dc3196f Merge pull request #612 from akhepcat/v4.2-dev
Fix version checking
2025-02-14 16:07:18 +08:00
Leif
7f4da826b1 Fix version checking
don't just check for string differences, but compare the version numbering using packaging.version
2025-02-13 23:04:27 -09:00
Donald Zou
cc2af4371f Build 2025-02-12 20:07:37 +08:00
Donald Zou
2a79a03d38 Build 2025-02-10 16:17:15 +08:00
Donald Zou
47aac7fe33 Added automatically assign keys and allowed ip when none provided
Resolve #515
2025-02-10 16:17:00 +08:00
Donald Zou
d4055884b1 Fixed #580 2025-02-08 16:40:20 +08:00
Donald Zou
61658e847a Merge branch 'v4.2-dev' of https://github.com/donaldzou/WGDashboard into v4.2-dev 2025-02-08 15:45:40 +08:00
Donald Zou
bd714223ce Update dashboard.py 2025-02-08 15:45:09 +08:00
dselen
060154cb89 Merge pull request #595 from sobhydo/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Adding Arabic Translation
2025-02-06 14:13:23 +01:00
dselen
99a1bfca9d Update active_languages.json
removed leading newline
2025-02-06 14:10:10 +01:00
dselen
4379f30628 Update active_languages.json
removed trailing enter.
2025-02-06 14:09:47 +01:00
Ahmed Sobhy
b501244577 Alphabetical order for active languages 2025-02-06 16:53:43 +04:00
Daan Selen
6f7b9815ca Hotfix for stop entrapment and addition of workdir in Dockerfile 2025-02-06 11:41:41 +01:00
dselen
227bd088f7 Merge pull request #603 from DaanSelen/4.2
Docker enhancements.
2025-02-06 10:56:32 +01:00
Daan Selen
b1d6ecb07c Tidied up compose 2025-02-06 10:55:07 +01:00
Daan Selen
41772f28bd Added a SIGTERM trap to the entrypoint script for faster stopping. 2025-02-06 10:52:14 +01:00
Daan Selen
393dac1c99 Working https://github.com/donaldzou/WGDashboard/issues/586 2025-02-05 10:32:36 +01:00
Daan
db9d0be6c7 Updated docker configuration. 2025-02-02 23:24:21 +01:00
Ahmed Sobhy
f0774ec273 Adding Arabic Translation 2025-01-27 23:41:06 +04:00
karorogunso
d4a4d28b58 Add Thai Language 2025-01-27 21:39:06 +07:00
Donald Zou
3ec97021bd Build 2025-01-26 23:51:00 +08:00
Donald Zou
56cf972373 Build 2025-01-26 23:09:09 +08:00
Donald Zou
2f3ae4c1af Pushi 2025-01-26 23:07:32 +08:00
Donald Zou
bc3dd04e12 Push 2025-01-26 23:07:19 +08:00
Donald Zou
4e8fc1b431 Commit 2025-01-26 23:03:09 +08:00
Donald Zou
cd39aa2968 Update 2025-01-25 22:15:19 +08:00
Donald Zou
87ea3fc982 Update PeerJobLogger.py 2025-01-25 22:11:50 +08:00
Donald Zou
f74a511778 Update PeerJobLogger.py 2025-01-25 22:10:29 +08:00
Donald Zou
202461fe48 Update PeerJobLogger.py 2025-01-25 21:56:29 +08:00
Donald Zou
2af6687351 Build 2025-01-24 19:19:51 +08:00
Donald Zou
e603af5f24 Refactored system status into a class. Added charts 2025-01-24 19:19:17 +08:00
Donald Zou
84069ee882 Refactor some new code 2025-01-24 00:01:29 +08:00
Donald Zou
edbb5cef92 Refactor some code 2025-01-22 15:46:04 +08:00
Donald Zou
a62c54b4ed Merge pull request #576 from petrsimunek/patch-1
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Update cs.json
2025-01-19 21:07:40 +08:00
Donald Zou
41df7c04c3 Merge pull request #585 from donaldzou/fix-#581
Ready for update
2025-01-19 21:03:38 +08:00
Donald Zou
9b783a8322 Ready for update 2025-01-19 21:03:08 +08:00
Donald Zou
57db4df618 Merge pull request #584 from donaldzou/fix-#581
Fixed Job Logger Bug, Restrict Peers with Configuration include special characters
2025-01-19 20:57:04 +08:00
Donald Zou
9d1081bd56 Update dashboard.py
- Fixed #581 issue.
2025-01-19 20:54:19 +08:00
Donald Zou
cc3773817b Refactor 2025-01-19 20:52:04 +08:00
Donald Zou
8956355e57 Update dashboard.py
Removed the need to check for each custom classes, will check if the class have `toJson`, if `True` then use it.
2025-01-19 14:04:59 +08:00
Donald Zou
645db97c14 Refactored some custom classess 2025-01-19 14:04:21 +08:00
Donald Zou
07a04dc507 Update dashboard.py 2025-01-19 13:20:04 +08:00
Donald Zou
a7317af413 Update code for #446 2025-01-16 18:36:06 +08:00
Donald Zou
ba6d6b8851 Display configuration as grid, system status process bug 2025-01-16 15:40:33 +08:00
Donald Zou
3726810108 Build with email functions 2025-01-16 00:46:38 +08:00
Donald Zou
4f92a7edf3 Finalized the email function 2025-01-16 00:44:22 +08:00
Donald Zou
5d84b61f18 Build with Email enabled 2025-01-13 16:47:15 +08:00
Donald Zou
cd1329ec67 Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-13 01:41:25 +08:00
petrsimunek
48a58b2b69 Update cs.json
Added translation for dashboard IP and port settings
2025-01-11 16:23:29 +01:00
Donald Zou
9b64aba8bf Merge pull request #575 from mahdiMGF2/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Fixed some syntax error in Peer Jobs
2025-01-09 17:21:22 +08:00
Donald Zou
cae8264d98 Update dashboard.py 2025-01-09 17:13:32 +08:00
Mahdi
95d8985336 Bug fixed
Bug Fixed deletePeerScheduleJob endpoint
2025-01-09 11:38:45 +03:30
Donald Zou
b26ae90807 Merge pull request #574 from donaldzou/v4.1.3-dev
v4.1.3 Ready
2025-01-09 14:02:19 +08:00
Donald Zou
66d171c432 v4.1.3 Ready 2025-01-09 13:42:21 +08:00
Donald Zou
40463d9831 Email functionality is done 2025-01-08 18:09:05 +08:00
Donald Zou
eb7dee013d Refactored add peers 2025-01-05 14:32:11 +08:00
dselen
1a878599b1 Merge pull request #549 from alexperreault/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
French translation
2025-01-03 08:39:41 +01:00
Donald Zou
b9e25abdd9 Refactored peer list 2025-01-03 13:45:05 +08:00
alexp
c612022717 alphabetical order 2025-01-02 20:23:52 -05:00
Donald Zou
31e7f02b8d Still trying 2025-01-02 11:38:21 +08:00
Donald Zou
75747a2979 Merge pull request #568 from donaldzou/fix-backup-folder-not-created
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Create WGDashboard_Backup when configuration initialized
2025-01-02 11:36:11 +08:00
Donald Zou
a85a8668a7 Update dashboard.py 2025-01-01 10:36:44 +08:00
Donald Zou
cca5fd859c Update dashboard.py
- Create WGDashboard_Backup
2024-12-31 11:02:52 +08:00
Donald Zou
2ed49abb1b Update dashboard.py
Minor issue
2024-12-31 10:44:27 +08:00
Donald Zou
409e6d49b2 Update dashboard.py
- Fixed `WGDashboard_Backup` not being created and caused crash
2024-12-31 10:33:28 +08:00
Donald Zou
93cfc482b8 Commit 2024-12-31 10:31:24 +08:00
Donald Zou
85be6d53d0 Merge pull request #566 from donaldzou/fix-edit-configuration
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Edited configuration not updating to dashboard
2024-12-30 20:33:10 +08:00
Donald Zou
bf6f58eb5e Remove with sqldb in SQL Select 2024-12-30 20:31:24 +08:00
Donald Zou
cd9d17ab18 Refactoring configuration list 2024-12-30 20:30:09 +08:00
Donald Zou
e0bc6a10d0 Edited configuration not updating to dashboard 2024-12-29 16:37:19 +08:00
Donald Zou
ccfc1ad166 Update dashboard.py 2024-12-29 15:57:57 +08:00
Donald Zou
812060240f Update dashboard.py 2024-12-29 13:12:40 +08:00
Donald Zou
715a266ca4 Merge pull request #563 from donaldzou/fix-#562
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Fix #562, and mysterious Jobs disappear issue
2024-12-28 23:53:35 +08:00
Donald Zou
fa4b3ece56 Log the error instead of remove the job 2024-12-28 21:01:21 +08:00
Donald Zou
aac2a002bb Delete .github/workflows/main.yml
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-28 01:34:33 +08:00
Donald Zou
8574acaf6e Create main.yml 2024-12-28 01:27:25 +08:00
Donald Zou
ddf4639354 Update README.md 2024-12-28 01:26:47 +08:00
Donald Zou
9bd394f351 Update dashboard.py 2024-12-27 03:09:27 +08:00
Donald Zou
6899d48aae Update 2024-12-26 00:06:37 +08:00
Donald Zou
514e1ca8d0 Build 2024-12-18 18:15:02 +08:00
Donald Zou
eba5be010a Update 2024-12-18 17:45:22 +08:00
Donald Zou
f578d5c1c9 Enhanced peer list rendering
- Used IntersectionObserver to better render peer list, in case of too many peers will slow down browser
2024-12-18 15:06:41 +08:00
Donald Zou
e58b1d670b Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-15 21:37:45 +08:00
Donald Zou
c2642259b4 Update gunicorn.conf.py 2024-12-12 18:31:00 +08:00
Donald Zou
c47b0c9741 Update gunicorn.conf.py 2024-12-12 18:29:11 +08:00
Donald Zou
f425156cad Sync with HTTPS build 2024-12-12 18:23:42 +08:00
Donald Zou
7d7e31120e HTTPS workflow 2024-12-12 18:20:25 +08:00
dselen
ccd247d154 Merge branch 'dev' into v4.2-dev 2024-12-12 11:07:17 +01:00
Daan
53df6849f7 Working prototype with AWG 2024-12-12 11:03:39 +01:00
Donald Zou
c2080bd1b3 Update gunicorn.conf.py 2024-12-12 16:34:45 +08:00
Donald Zou
9e93f8c2a5 HTTPS workflow 2024-12-12 16:25:54 +08:00
Donald Zou
907a142c8d Build 2024-12-09 16:13:22 +08:00
Donald Zou
d7bc8cd8e4 Update configurationList.vue 2024-12-09 16:13:06 +08:00
Daan
bb3e00a695 Thanks to @NOXCIS, added this development Ubuntu Dockerfile. 2024-12-08 14:22:02 +01:00
alexp
af5e7974c3 Added the french language 2024-12-07 21:29:59 -05:00
Donald Zou
6a88959ec4 Update dashboard.py 2024-12-07 21:59:03 +08:00
Donald Zou
7b59149f90 Build 2024-12-07 21:41:20 +08:00
Donald Zou
3e01079caf Added sorting and search to configuration list 2024-12-07 21:41:05 +08:00
Donald Zou
d92e62e40b Adjusted system status widget 2024-12-07 21:40:43 +08:00
Donald Zou
b4952dea7b Fixed message center
- Fixed message blocking element behind
- Adjusted message UI
- Allow to dismiss, will not dismiss when mouse hover on it
2024-12-07 17:48:48 +08:00
Donald Zou
00acb04329 Update dashboard.py
- Disabled `EmailSender` for now
2024-12-07 17:05:30 +08:00
Donald Zou
939dd0591e Build 2024-12-07 16:54:00 +08:00
Donald Zou
febdb2a9e0 Update deleteConfiguration.vue 2024-12-06 22:55:02 +08:00
Donald Zou
bcfd9fc1c9 Update wgd.sh 2024-12-06 22:11:34 +08:00
Donald Zou
e4964da5d4 Update wgd.sh 2024-12-06 22:05:18 +08:00
Donald Zou
a042298a4a Update wgd.sh 2024-12-06 22:03:57 +08:00
Donald Zou
908be168a9 Update wgd.sh 2024-12-06 22:01:57 +08:00
Donald Zou
d780bb3937 Added PyPI choose in wgd.sh install 2024-12-06 22:00:35 +08:00
Donald Zou
461e7e8913 build 2024-12-06 20:32:59 +08:00
Donald Zou
819e8b73c3 Added configuration editor 2024-12-06 20:27:04 +08:00
Donald Zou
627b7087a1 Build 2024-12-06 01:27:15 +08:00
Donald Zou
f23cf555e1 Added file upload to create configuration 2024-12-05 22:22:55 +08:00
Donald Zou
000978e4fb Merge pull request #538 from donaldzou/v4.2-dev-amneziawg-support
Add AmneziaWG Support
2024-12-05 01:52:35 +08:00
Donald Zou
74782483bd Build 2024-12-05 01:51:02 +08:00
Donald Zou
c5f9387b92 All AWG support work is done ;) 2024-12-05 01:50:31 +08:00
Donald Zou
57583b6747 Backup and restore for AWG is done 2024-12-04 17:50:16 +08:00
Donald Zou
434c236210 Finished adjusting Peers UI for AWG 2024-12-03 02:34:45 +08:00
Donald Zou
807bb97b6a Update some UI to handle Wireguard and AWG 2024-12-02 17:36:37 +08:00
Donald Zou
da53bd44d1 Update dashboard.py 2024-12-02 16:38:09 +08:00
Donald Zou
3b01943649 Update dashboard.py 2024-12-02 16:34:26 +08:00
Donald Zou
3340f9c6ee Update dashboard.py
- Updated WireguardConfiguration class to handle awg configuration files
- Added AmneziaWireguardConfiguration class as a subclass of WireguardConfiguration
2024-12-02 15:09:54 +08:00
Donald Zou
b21cfe8504 Updated search bar 2024-12-02 14:13:19 +08:00
Donald Zou
97ab6ec299 Build 2024-12-01 01:07:47 +08:00
Donald Zou
7fda58e5c8 New search bar design 2024-12-01 01:07:27 +08:00
Donald Zou
db6e820d1d Build 2024-11-30 00:28:12 +08:00
Donald Zou
8c2e1875ca Update peerSearch.vue 2024-11-30 00:27:59 +08:00
Donald Zou
bd95fe9af1 Build 2024-11-29 23:08:14 +08:00
Donald Zou
a517f89234 Update 2024-11-29 23:07:58 +08:00
Donald Zou
f994e7bfa8 Update dashboard.py
- Accepted proposed enhancement on #533
2024-11-29 14:42:13 +08:00
Donald Zou
28716924c9 Update dashboard.py 2024-11-28 23:36:42 +08:00
Donald Zou
b597f90f5b Update 2024-11-28 23:35:22 +08:00
Donald Zou
5912420467 Added System Status 2024-11-28 23:28:10 +08:00
Donald Zou
90f35fd680 update 2024-11-27 22:53:27 +08:00
Donald Zou
3e2d6e71b9 Update 2024-11-27 21:53:00 +08:00
Donald Zou
cbffdd829a Update 2024-11-27 18:26:13 +08:00
Donald Zou
d77e092948 Build 2024-11-27 14:27:41 +08:00
Donald Zou
1f5e10e784 Adjusted login UI 2024-11-27 14:25:38 +08:00
Donald Zou
68e3813c6c Update 2024-11-27 13:57:21 +08:00
Donald Zou
c9d78e3f67 Added tooltips to dropdown icons
#524
2024-11-26 22:43:33 +08:00
Donald Zou
b4f3fb3b30 Fixed UI 2024-11-26 21:32:08 +08:00
Donald Zou
bf7fb898f9 Update dashboard.py
- Fixed #497
2024-11-26 21:27:32 +08:00
Donald Zou
6c5e0543b4 update 2024-11-26 00:21:59 +08:00
Donald Zou
578a1db62f Refactored some of the codes 2024-11-25 22:11:51 +08:00
Donald Zou
4524a55b23 Merge pull request #527 from donaldzou/fix-#516
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Security Patch
2024-11-25 20:41:51 +08:00
Donald Zou
f942eaf1b6 Ready for release 2024-11-25 18:23:48 +08:00
Donald Zou
6a4d16fae9 Merge pull request #529 from donaldzou/fix-#522
Fixing `auth_req` is not working
2024-11-25 02:49:40 +08:00
Donald Zou
53b234252f Final build 2024-11-25 02:48:55 +08:00
Donald Zou
9287e81ef1 Build 2024-11-25 01:53:29 +08:00
Donald Zou
5462326f79 Updated dashboard.py and DashboardConfigurationStore.js
- Added `session.clear()` to clean the session specific to each login session
- Clear all cookie with the `signout` request and also clear again (just in case) in the frontend code.
2024-11-25 01:46:27 +08:00
Donald Zou
b8b3992159 commit 2024-11-24 12:10:00 +08:00
Donald Zou
8214000713 Commit 2024-11-24 00:22:33 +08:00
Donald Zou
94337a33d4 Merge pull request #521 from donaldzou/bsd-support
Replace `ifcfg` with socket to get default interface address
2024-11-23 18:25:02 +08:00
Donald Zou
8ddee03338 Merge pull request #520 from donaldzou/main
Merging latest v4.1.1 changes into v4.2.0 branch
2024-11-23 18:10:00 +08:00
Donald Zou
8e2934533b Dropping support plan to OpenBSD 2024-11-23 18:08:14 +08:00
Donald Zou
71ee784003 Update dashboard.py 2024-11-23 17:51:48 +08:00
Donald Zou
597528e9b7 Update dashboard.py 2024-11-23 17:30:34 +08:00
Donald Zou
45fbbf9218 Update dashboard.py 2024-11-23 17:30:22 +08:00
Donald Zou
c7a4a01fee Merge pull request #519 from donaldzou/main
Merge main into bsd support
2024-11-23 16:57:00 +08:00
Donald Zou
fa04ad1395 Merge pull request #518 from donaldzou/v4.1.1-dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Ready for new update
2024-11-23 15:57:28 +08:00
Donald Zou
abdd85bdd5 Ready for new update 2024-11-23 15:37:00 +08:00
Donald Zou
dba55d57e8 Merge pull request #488 from donaldzou/language-template
Added template and script to check local files
2024-11-23 15:18:14 +08:00
Donald Zou
9819c96717 Update verify_locale_files.py 2024-11-23 15:09:35 +08:00
Donald Zou
1b0885bffe Update verify_locale_files.py 2024-11-23 14:55:07 +08:00
Donald Zou
c0a8540ab8 Update tr-tr.json 2024-11-23 14:38:15 +08:00
Donald Zou
f3b95f03a1 Update active_languages.json 2024-11-23 13:46:27 +08:00
Donald Zou
5f06f3da52 Update sv-se.json 2024-11-23 13:46:20 +08:00
Donald Zou
10a7fb809b Update pl.json 2024-11-23 13:37:27 +08:00
Donald Zou
d3ea1f3da2 Update nl-nl.json
Fixed translation
2024-11-23 13:36:58 +08:00
Donald Zou
74d0471a6f Update verify_locale_files.py 2024-11-23 13:23:50 +08:00
Donald Zou
a1c1805409 Updated it-it.json 2024-11-23 13:23:47 +08:00
Donald Zou
b843145bed Update de-de.json
Fixed de-de translations
2024-11-23 13:15:03 +08:00
Donald Zou
119920b665 Update ru.json
Fixed translations
2024-11-22 19:36:11 +08:00
Donald Zou
6190e2d290 Fixed cs.json 2024-11-22 01:46:52 +08:00
Donald Zou
79de99d146 Finalized verify script 2024-11-22 01:41:11 +08:00
Donald Zou
56a9b3df0a Merge pull request #514 from MickLesk/patch-1
Update de-de.json
2024-11-22 01:32:56 +08:00
Donald Zou
4df6413dba Merge pull request #513 from oskarax/main
Added Swedish translations and updated active languages file.
2024-11-22 01:30:28 +08:00
Donald Zou
fcd0ada639 Merge branch 'language-template' into main 2024-11-22 01:30:17 +08:00
Donald Zou
6b6bd155aa Merge pull request #512 from donaldzou/main
Merging main into language template branch
2024-11-22 01:28:23 +08:00
CanbiZ
9c91b1bca5 Update de-de.json 2024-11-18 23:05:05 +01:00
Oskar Ax
1a5c0e5b24 Added Swedish translations and updated active languages file. 2024-11-18 21:08:06 +01:00
Donald Zou
981b30e4af Update check script 2024-11-17 17:20:41 +08:00
Donald Zou
30c84d8cbf Merge pull request #502 from AdimoUK/main
Merge spanish translation
2024-11-16 19:17:46 +08:00
Donald Zou
4c538c54a8 Merge pull request #501 from AdimoUK/polish-language
Merge Polish translation
2024-11-16 19:12:01 +08:00
dselen
ad7a8f1d08 Merge pull request #496 from DaanSelen/v4.1-add-qemu
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Previous PR was merged too fast 🥇
2024-11-15 12:11:18 +01:00
Daan
f02a07dab4 Name change 2024-11-15 12:08:51 +01:00
dselen
c61b0fc1e1 Merge pull request #494 from donaldzou/fix-preshared-key
Fixed #377
2024-11-15 12:06:14 +01:00
Daan
fed7dfcb73 Added arm/v6
Specified the QEMU setup. From WireGate
2024-11-15 12:05:08 +01:00
Donald Zou
0d69c811ab Merge pull request #495 from DaanSelen/v4.1-add-qemu
Added QEMU virtualization for cross-compilation
2024-11-15 18:59:48 +08:00
Daan
83274add22 Added QEMU virtualization for cross-compilation @NOXCIS 2024-11-15 11:35:45 +01:00
Donald Zou
7497d1b6d4 Fixed #377
Fixed Preshared Key is not added when adding peers
2024-11-15 13:45:14 +08:00
Donald Zou
239bc144e3 Fixed both Chinese translation 2024-11-15 12:00:31 +08:00
Donald Zou
1ece64abe1 Merge pull request #492 from DaanSelen/language-template
Proposed changes
2024-11-15 11:52:13 +08:00
Daan
915783699b Proposed changes 2024-11-14 21:36:27 +01:00
Donald Zou
43f6bd41c9 Update verify_locale_files.py 2024-11-15 02:15:40 +08:00
Adam
98c017dd56 Fix to a translation 2024-11-14 00:09:59 +00:00
Donald Zou
811ed3251b Merge pull request #464 from jpizquierdo/v4.1-dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-14 02:06:25 +08:00
Donald Zou
665b0f1484 Added template and script to check local files 2024-11-14 02:02:26 +08:00
Donald Zou
9e26d845da Update active_languages.json
Oops.. missed a comma
2024-11-14 00:59:17 +08:00
Donald Zou
6ddf20f5ce Update active_languages.json
Sorting the list based on `lang_id`
2024-11-14 00:53:26 +08:00
dselen
27ed0710cc Merge pull request #487 from donaldzou/donaldzou-patch-1
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Update README.md Discord link
2024-11-13 15:08:24 +01:00
Donald Zou
cb87c9f345 Update README.md Discord link 2024-11-13 21:12:45 +08:00
Donald Zou
e1e147c8f0 Adding support to OpenBSD 2024-11-12 18:32:53 +08:00
Donald Zou
b37d889de9 Update wgd.sh 2024-11-12 18:21:27 +08:00
Donald Zou
b61c9bfc5e Update wgd.sh 2024-11-12 18:01:59 +08:00
Donald Zou
e963788a81 Update wgd.sh 2024-11-12 17:58:51 +08:00
Donald Zou
3ef4798e09 Update wgd.sh 2024-11-12 00:12:10 +08:00
Donald Zou
21730102ae Merge pull request #474 from donaldzou/DaanSelen-lang-1
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-11 19:12:12 +08:00
Donald Zou
b1ae05152e Merge pull request #471 from kaanklky/languages-tr-tr 2024-11-11 19:05:53 +08:00
Adam
cc87f01e2f Addition of Polish Language 2024-11-10 22:07:20 +00:00
dselen
85dfa1b078 Update nl-nl.json 2024-11-10 13:53:47 +01:00
Donald Zou
fdff54e11e Merge pull request #469 from DaanSelen/main
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-10 09:02:06 +08:00
Kaan Kölköy
0894f38660 Update active languages list 2024-11-09 22:40:04 +01:00
Kaan Kölköy
f643d8ef25 Add Turkish localization 2024-11-09 22:39:51 +01:00
dselen
e437284980 Squash Docker progress: (#1)
* Version 4.1 Docker image tested.

    Fixed kinks in Docker image.
    Updated Dutch language
    Removed remaining "enable" parameter from Docker-related files
    Made the symlink system more reliable
    Improved updatability.

    Added multiplatform docker build (arm,arm64 and amd64)
    More verbose logging from the Docker image.
2024-11-09 00:18:01 +01:00
Donald Zou
f6e0d330ac update
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-09 02:17:21 +08:00
Donald Zou
890cbf0f36 Merge pull request #468 from donaldzou/issue-discord-link
Fix Discord Link Under Help
2024-11-09 00:49:46 +08:00
Donald Zou
36cf2ea2e8 Merge branch 'main' into issue-discord-link 2024-11-09 00:49:26 +08:00
Donald Zou
a8f7bd0280 Build 2024-11-09 00:48:16 +08:00
Donald Zou
aa6517046d Merge pull request #467 from donaldzou/issue-#462
Fix #462
2024-11-09 00:44:45 +08:00
Donald Zou
42e4d8c7ba build 2024-11-09 00:40:42 +08:00
Joel Pérez Izquierdo
3d1da38cbc add es-es locale file 2024-11-08 17:29:58 +01:00
Joel Pérez Izquierdo
5ae8490999 add spanish language 2024-11-08 17:28:57 +01:00
Donald Zou
715675b2f1 Merge pull request #458 from donaldzou/donaldzou-patch-1
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Update README.md
2024-11-08 16:17:28 +08:00
Donald Zou
0d7198a26c Update README.md 2024-11-08 16:17:15 +08:00
Donald Zou
d8b7ce6d9b Update README.md 2024-11-08 16:16:44 +08:00
Donald Zou
d032ca31e3 Update README.md 2024-11-08 16:15:56 +08:00
Donald Zou
67b49c0585 Merge pull request #457 from donaldzou/v4.1-dev
Final update
2024-11-08 16:14:14 +08:00
Donald Zou
c23242f18e Final update 2024-11-08 16:13:47 +08:00
Donald Zou
c23f7a3ee2 Merge pull request #440 from donaldzou/v4.1-dev
V4.1 dev
2024-11-08 16:13:22 +08:00
Donald Zou
7e3e957649 Update ru.json 2024-11-08 00:50:57 +08:00
Donald Zou
b8f304dfd3 Prepare for release 2024-11-08 00:31:19 +08:00
Donald Zou
e895ac9245 Merge branch 'main' into v4.1-dev 2024-11-08 00:29:01 +08:00
Donald Zou
77579a71e8 Match docker 2024-11-07 23:54:48 +08:00
Donald Zou
cc7e13cdbf Merge pull request #455 from DaanSelen/v4.1-dev
Added Dutch language.
2024-11-07 23:53:48 +08:00
Donald Zou
5df3886e42 Merge branch 'v4.1-dev' into v4.1-dev 2024-11-07 23:50:54 +08:00
Donald Zou
cc179a05d0 Update 2024-11-07 23:47:08 +08:00
Donald Zou
ec5f4f2778 Fixed some CSS issue on mobile 2024-11-07 23:43:14 +08:00
Donald Zou
084c95f0e5 Just fixed #455 2024-11-07 18:33:39 +08:00
Daan
3b78cfe0fd Renamed files and changed Dutch file. 2024-11-07 11:26:37 +01:00
Daan
160ce3338d Changed some file-names 2024-11-07 11:25:05 +01:00
Donald Zou
d425cfe1aa Refactor 2024-11-07 14:56:02 +08:00
Donald Zou
6ff286f9b4 Refactor 2024-11-07 14:54:42 +08:00
Donald Zou
b930461434 Refactored some files 2024-11-07 14:53:31 +08:00
Donald Zou
ee6bb24506 build test 2024-11-07 10:37:11 +08:00
Donald Zou
b69124c89f test 2024-11-07 00:15:28 +08:00
Donald Zou
f089e4a1ce update 2024-11-07 00:09:40 +08:00
Donald Zou
7dedb5c076 Test adding hash to vite build 2024-11-07 00:03:40 +08:00
Donald Zou
3276c9a84c Update 2024-11-06 23:25:20 +08:00
Donald Zou
04ef2ea3b6 Merge branch 'v4.1-dev' of https://github.com/donaldzou/WGDashboard into v4.1-dev 2024-11-06 23:22:01 +08:00
Donald Zou
04a2f27a75 Update 2024-11-06 23:21:53 +08:00
Donald Zou
d962f59884 Merge pull request #452 from jursed/v4.1-dev
Czech translation
2024-11-06 21:40:18 +08:00
Donald Zou
fd3bd4567a Update active_languages.json
Removed the `,` at the end :)
2024-11-06 21:12:55 +08:00
Donald Zou
29e7a5ecdb Fixed bulk add 2024-11-06 20:58:53 +08:00
Donald Zou
4956b0d89d Rename configuration done 2024-11-06 18:36:55 +08:00
Donald Zou
3bc54a4e16 Update wgd.sh 2024-11-05 19:46:09 +08:00
Donald Zou
29ecd602ec Added help modal 2024-11-05 19:43:47 +08:00
zire
1425dec564 Czech translation
First attempt at Czech translation. Note that some words don't have
a good and short translation, e.g. "peers", "pre-shared key" or
"persistent keepalives". In these cases, some approximate/familiar
"Czech-English" amalgamation is used.
2024-11-03 22:05:13 +01:00
Donald Zou
2bb1c0c999 Optimized build 2024-11-03 21:06:51 +08:00
Donald Zou
97f3daae70 Optimized vite build 2024-11-03 20:45:59 +08:00
Donald Zou
c53a7ef6fe Update 2024-11-03 19:09:15 +08:00
Donald Zou
b97fc16ad9 Adjusted router to dynamic import 2024-11-03 18:35:21 +08:00
Donald Zou
eaac12ddc8 Update both Chinese languague 2024-11-03 17:36:03 +08:00
Donald Zou
183be5da0e Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
testing webhooks
2024-11-03 15:58:34 +08:00
Donald Zou
ace0953c87 Update README.md 2024-11-03 15:26:33 +08:00
Donald Zou
1fd7e7833d Update README.md 2024-11-03 15:20:41 +08:00
Donald Zou
aa5801d73b Update README.md 2024-11-03 14:41:21 +08:00
Donald Zou
d1ea8081e4 Finished zh-CN 2024-11-02 18:50:15 +08:00
Donald Zou
49467c906d zh-CN Update 2024-11-02 14:26:47 +06:00
Donald Zou
79bd575aca Merge pull request #448 from donaldzou/DaanSelen-patch-1
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Hotfix.
2024-11-02 16:20:35 +08:00
Donald Zou
e533a0e405 Merge pull request #445 from knd775/patch-1
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
feat: Support Rocky Linux
2024-11-01 23:24:47 +08:00
Donald Zou
94b597d29a Adjusted some UI 2024-11-01 22:30:25 +08:00
dselen
504fefff94 Update docker-build.yaml 2024-11-01 09:19:47 +01:00
dselen
ff794a3638 Update docker-analyze.yaml
I switched them around 😭
2024-11-01 09:15:46 +01:00
Donald Zou
efb9a34cb8 Merge pull request #447 from DaanSelen/workflow-change
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-01 16:11:26 +08:00
Daan
a93291b38f Changed the workflow from every night to: on every commit in the main branch. 2024-10-31 20:16:45 +01:00
Donald Zou
dfc9eab9d3 Fixed some issue on autostart 2024-10-31 23:28:30 +08:00
Donald Zou
3c74b0b1ef Update 2024-10-31 22:13:44 +08:00
Donald Zou
9b981fcea8 Autostart feature is done 2024-10-31 22:13:00 +08:00
Ben Ayles
9d3a189d77 fix: Support Rocky Linux 2024-10-29 23:02:59 -04:00
Donald Zou
01c0175e8f Commit 2024-10-29 14:57:29 +08:00
Donald Zou
d7e5e2f381 Update wgd.sh 2024-10-26 18:09:42 +08:00
Donald Zou
c27de8b9a5 Build 2024-10-26 13:54:08 +08:00
Donald Zou
c3a55f8b69 Finished create configuration from backup 2024-10-25 23:34:07 +08:00
Donald Zou
78b65a799e Added notification to backup before delete 2024-10-25 23:33:42 +08:00
Donald Zou
6a30cee611 Adjusted some animation 2024-10-25 23:33:26 +08:00
Donald Zou
bc19e3a6ff Adjusted title 2024-10-25 23:33:07 +08:00
Donald Zou
5a8f2fa2be Adjusted some animation 2024-10-25 23:32:30 +08:00
Daan
81168c27c6 Fixed issue https://github.com/donaldzou/WGDashboard/issues/329.
Regarding being able to pass in the -y flag.
2024-10-24 23:10:36 +02:00
Donald Zou
a606626053 UI for restore configuration is done 2024-10-25 00:19:27 +08:00
Daan
adeb57864b Fixed incorrect Docker_IMAGE variable from dselen/ -> donaldzou/ 2024-10-24 10:48:14 +02:00
Daan
747f1a6fae SEC: Fixed CVE-2024-9143 presence. 2024-10-24 10:24:22 +02:00
Daan
3ac9c23573 Removed the default value: wg0 in isolate and enable.
Removed clean_up() function because persistency is done differently.
Overal tried to make readability better in entrypoint.sh
Fixed bug where local config variable causes issues.
Applied ShellCheck recommendations.
2024-10-24 10:13:33 +02:00
Daan
5ad9c0e77a Fixed issue where the wg0.conf template got obliterated.
Moved it to a safe spot.
2024-10-24 00:23:12 +02:00
Daan
ba5ba2f1d6 Removed copy step in entrypoint.sh
Tested updating, works as long as presistent files are compatible.
2024-10-24 00:09:27 +02:00
Daan
4902b5f351 Initial testing to update from version 4.0.3 to 4.0.4 have succeeded! 2024-10-23 23:47:00 +02:00
Daan
166fcda193 Minor changes to compose and Dockerfile. 2024-10-23 23:15:41 +02:00
Daan
83560bc775 Changed around Docker image building and entrypoint.
- Succeeding my tests.
2024-10-23 22:40:40 +02:00
Daan
4ffb00c9f5 Updated ensure install. 2024-10-23 16:57:51 +02:00
Daan
fbac41a774 Changed ensure install 2024-10-23 16:57:40 +02:00
Daan
c837ab8693 Complete Docker Container redo, making updates possible.
- Through symlinks.

Refactored the set env variables function.
2024-10-23 16:41:03 +02:00
Donald Zou
1cc321ddff Merge pull request #436 from donaldzou/v4.1-workflows
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
V4.1 workflows
2024-10-23 17:30:33 +08:00
dselen
7861cffb91 Merge pull request #430 from DaanSelen/main
Modified GitHub workflows
2024-10-22 08:52:52 +02:00
Donald Zou
82a472f368 Delete configuration, restore configuration 2024-10-22 12:28:51 +08:00
Daan
cfe59774e7 Changed Docker image names: dselen -> donaldzou 2024-10-21 12:09:53 +02:00
Daan
1098475473 Changed failing criteria 2024-10-21 12:07:33 +02:00
Donald Zou
4546e795ef Merge pull request #433 from reloadlife/patch-1
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Added a try/catch statement to prevent panel from crashing #432
2024-10-21 15:37:49 +08:00
Donald Zou
bb0aba586b Update dashboard.py
Instead of catching one sql statement error, I moved the catch statement to `sqlSelect` to prevent all database error
2024-10-20 16:05:32 +08:00
Mohammad Mahdi "Mamad" Afshar
204b995e6c added a try/catch statement to prevent panel from crashing #432 2024-10-19 19:25:38 +03:30
Daan
321b7b4cee Modified GitHub workflows 2024-10-17 12:52:34 +02:00
Donald Zou
413377fbb9 Backup and restore function is done
Completed with SQLDump and .conf backup
2024-10-17 00:04:26 +08:00
Donald Zou
e2e821881c Peer restore works
Still need to SQL Dump the table aswell
2024-10-16 17:44:49 +08:00
Donald Zou
51712ed2a8 Re-adjust backup & restore location 2024-10-15 23:07:49 +08:00
Donald Zou
27de7ddbf8 Still working on backup & restore 2024-10-15 00:30:20 +08:00
Donald Zou
bb700f3a3d Update selectPeers.vue 2024-10-14 17:27:34 +08:00
Donald Zou
563268558b Finished selecting peers in bulk to delete and download 2024-10-14 16:32:17 +08:00
Donald Zou
56744cec7b Commit 2024-10-06 23:09:55 +08:00
Donald Zou
87696a2e6c Fixed 2024-10-06 17:27:16 +08:00
Donald Zou
79f1c20f8a Added custom build.sh 2024-10-06 17:24:53 +08:00
Donald Zou
4e5638df36 Fixed issue #346 2024-10-06 17:13:50 +08:00
Donald Zou
71349f35e4 Fixed issue #352
Fixed issue when allowed_ips have more than 1 IP Address, allow access will crash
2024-10-06 16:59:11 +08:00
Donald Zou
2cb06bb4bb Added total peers in peers count 2024-10-05 16:10:36 +08:00
Donald Zou
5e1769b81f Updated Translation 2024-10-05 15:38:56 +08:00
Donald Zou
e344f28265 Added peer's endpoint IP back 2024-10-05 15:03:27 +08:00
Donald Zou
2297d6b85b Merge pull request #417 from donaldzou/v4.0.4-almalinux-support
Added AlmaLinux Support
2024-10-05 10:24:46 +08:00
Donald Zou
baaecdbd8c Update wgd.sh 2024-10-05 10:05:48 +08:00
Donald Zou
31d8af642d Merge pull request #363 from martin-g-it/patch-1
Update dashboard.py - sort WG configurations
2024-10-04 20:15:04 +08:00
Donald Zou
27c67ec202 Added loading bar between each routes 2024-10-04 17:48:24 +08:00
Donald Zou
4833a29e57 Adjusted some transition between routes 2024-10-04 17:27:25 +08:00
Donald Zou
4a2f3e0372 Configuration Settings done 2024-10-04 16:58:47 +08:00
Donald Zou
f3eeff4ec8 Merge pull request #415 from donaldzou/DaanSelen-patch-1
Fix README.md
2024-10-04 16:22:16 +08:00
dselen
221e03ecfa Fix README.md 2024-10-03 16:03:42 +02:00
dselen
392a9c6f53 Merge pull request #414 from DaanSelen/main
Second try. Merged Docker update.
2024-10-03 15:59:33 +02:00
Dselen
145d12b2c8 Added minor changes and deletions. 2024-10-03 08:26:30 -05:00
Dselen
0c5033ff79 fixed issues with commits 2024-10-03 08:23:17 -05:00
Donald Zou
5f46f54dfd Updated mobile UI
Using dvh and vh as fallback for mobile browsers.
2024-10-03 21:20:15 +08:00
Dselen
d4819b13eb working tests 2024-10-03 08:15:21 -05:00
Donald Zou
9dd9be3b8c Merge branch 'main' into main 2024-10-03 20:59:58 +08:00
Dselen
dd38809866 Rebase 2024-10-03 07:45:24 -05:00
Donald Zou
c414725f12 Merge pull request #406 from 3vis97/v4.1-dev-italian
Added italian language issues/#397
2024-10-03 20:13:46 +08:00
Donald Zou
d3c8a350a4 Merge branch 'v4.1-dev' into v4.1-dev-italian 2024-10-03 20:13:38 +08:00
Donald Zou
e04b748b91 Merge pull request #345 from DaanSelen/conflict-resolved
Updated Docker image
2024-10-03 20:09:31 +08:00
Donald Zou
1eee8c4725 Update 2024-10-03 20:07:50 +08:00
dselen
2b7a4b170c Merge branch 'main' into conflict-resolved 2024-10-03 12:17:18 +02:00
Donald Zou
7c0bf4f137 Fixed #357: Brought back IP Address and Port
But still manually restart WGDashboard is needed
2024-10-03 15:24:50 +08:00
Donald Zou
54bae43d2e Update osmap.vue
Added "Dark Mode" to OSM
2024-10-02 22:00:53 +08:00
Donald Zou
25be1155a6 Added testing to OSM before loading map
Prevent users in locations blocked OSM seeing an empty div
2024-10-02 21:53:57 +08:00
Donald Zou
4905d61a1a Some adjustment on map 2024-10-02 18:01:20 +08:00
Donald Zou
ff0147bebb Added OpenStreetMap for Ping and Traceroute 2024-10-02 17:09:35 +08:00
Donald Zou
7fe4889b6e Updated some languages 2024-10-02 17:09:04 +08:00
Donald Zou
3c9b1b1833 Thanks to Pixnet for providing the Russian translation :) 2024-09-27 22:07:50 +08:00
Dselen
2a46c873b8 Removed Debian container 2024-09-27 03:22:03 -05:00
Trevis97
6ed09324ad Updated Italian translations and fixed typos upstream/issues/#397 2024-09-26 22:32:43 +02:00
Mattia Trevisani
d1f9c10790 Added italian language upstream/issues/#397 2024-09-26 22:31:27 +02:00
Donald Zou
5d041b2fd3 Update README.md 2024-09-25 18:01:05 +08:00
Donald Zou
5cea0fa87b Merge pull request #401 from orangeferdi/patch-3
Create de.json
2024-09-25 00:11:05 +08:00
Donald Zou
6f140eef29 Merge pull request #400 from orangeferdi/patch-2
Update active_languages.json
2024-09-25 00:10:52 +08:00
Donald Zou
e5850adfd7 Update dashboard.py 2024-09-24 22:54:18 +08:00
orangeferdi
6921833ce2 Create de.json
Adding german language
2024-09-24 10:13:34 +02:00
orangeferdi
57b9accd97 Update active_languages.json
Adding german language
2024-09-24 10:10:16 +02:00
Donald Zou
de94f5b233 Update README.md 2024-09-24 00:40:20 +08:00
Donald Zou
b5519a73fb Merge pull request #398 from shuricksumy/v4.1-dev-uk
Add Ukrainian language
2024-09-23 16:32:00 +08:00
Oleksandr Suchkov
c5d8c2c355 Add Ukrainian language 2024-09-22 23:58:38 +01:00
Donald Zou
c5b02a426c Update README.md 2024-09-23 03:12:06 +08:00
Donald Zou
4cae910b68 Added some update :) 2024-09-23 03:07:48 +08:00
Donald Zou
b664fccce2 Finished Chinese Simplified and Traditional translation 2024-09-23 00:17:30 +08:00
Donald Zou
21672f99d1 Translating to zh-cn is done 2024-09-22 21:50:30 +08:00
Donald Zou
c269e46892 Added some new translation 2024-09-22 16:44:36 +08:00
Donald Zou
8534e8cf5b Still working on translating.... 2024-09-22 16:33:22 +08:00
Donald Zou
94bf1c2484 Finished translating most of the UI. Left with notifications 2024-09-19 22:32:15 +08:00
Donald Zou
b3b30470fc Merge branch 'main' of https://github.com/donaldzou/WGDashboard 2024-09-19 14:45:11 +08:00
Donald Zou
41d91e75fc Prepare for v4.0.4 2024-09-19 14:44:49 +08:00
Donald Zou
a97a91b844 Merge pull request #395 from donaldzou/fix-#391
Fixed issue where Preshared Key is not added when unrestricted peers
2024-09-19 14:31:41 +08:00
Donald Zou
f1c577ab76 Fixed issue mentioned in #391 2024-09-19 14:21:38 +08:00
Donald Zou
17a9fe5024 Fixed issue mentioned in #391 2024-09-17 14:42:25 +08:00
Donald Zou
d74a76dee3 Merge pull request #389 from donaldzou/v4.0.3-fix
Merge new changes to v4.1
2024-09-14 16:23:17 +08:00
Donald Zou
c01201b88e Merge branch 'v4.1-dev' into v4.0.3-fix 2024-09-14 16:23:08 +08:00
Donald Zou
833bdf878a Update dashboard.py 2024-09-14 15:49:41 +08:00
Donald Zou
891990b2f1 Merge pull request #387 from donaldzou/v4.0.3-fix
Ready for v4.0.3
2024-09-14 15:44:26 +08:00
Donald Zou
e9ab7029c9 Ready for v4.0.3 2024-09-14 15:21:10 +08:00
Donald Zou
6f681dba09 Merge pull request #386 from donaldzou/v4.0.3-fix
Update privatePublicKeyInput.vue
2024-09-14 15:14:50 +08:00
Donald Zou
b3edff947d Update privatePublicKeyInput.vue
Fixed issue mentioned in #375
2024-09-14 15:13:47 +08:00
Donald Zou
ce6d80d601 Update dashboard.py 2024-09-14 15:11:06 +08:00
Donald Zou
a80a2866de Almost done... 2024-09-13 16:32:56 +08:00
Donald Zou
02c2221970 Still working on localization 2024-09-12 15:21:42 +08:00
Donald Zou
d35bd6e75b Merge pull request #379 from donaldzou/DaanSelen-patch-1
Update README.md
2024-09-12 12:17:24 +08:00
dselen
f3a2f98864 Update README.md
Removed Docker notice, because it is no longer relevant.
2024-09-10 10:12:57 +02:00
Donald Zou
a3a312e3db Still working on translation... 2024-09-09 23:43:55 +08:00
dselen
f5cb5c4516 Merge branch 'main' into conflict-resolved 2024-09-09 09:01:07 +02:00
Donald Zou
d458a28337 Started working on localization 😏 2024-09-06 22:38:56 +08:00
Donald Zou
a102a780f8 Adjusted search functions 2024-09-06 17:15:38 +08:00
Donald Zou
4dbbc32108 Updated Bootstrap Icons 2024-09-06 16:32:05 +08:00
Donald Zou
b6aedb43ee Fixed updating WG configuration path 2024-09-06 16:31:54 +08:00
Donald Zou
ec50dcbbd9 Preshared Key switch is added for both single and bullk add peers 2024-09-05 17:10:24 +08:00
Donald Zou
bcc983f11f Update presharedKeyInput.vue
Added preshared key switch
2024-09-05 16:43:46 +08:00
Donald Zou
809651054e Update dashboard.py 2024-09-05 16:17:56 +08:00
Donald Zou
2e965ceb9e Update dashboard.py 2024-09-05 14:51:00 +08:00
Martin
e35f942964 Update dashboard.py - sort WG configurations
Sort WG configurations alphabetically
2024-09-04 14:40:04 +02:00
Dselen
40e6fce281 Fix typos 2024-08-27 02:30:01 -05:00
dselen
2139865876 Merge pull request #1 from DaanSelen/dev
Dev
2024-08-27 09:28:16 +02:00
Dselen
c3cda05d98 Move fix. 2024-08-27 02:26:19 -05:00
Dselen
548f3db33d quickfix 2024-08-26 16:16:43 -05:00
Dselen
a76e9ed98b Testing more changes for better handling of variables. 2024-08-26 16:16:09 -05:00
Dselen
c0ef41a9bb Forgot to reorder 2024-08-26 15:54:27 -05:00
Dselen
f6e5d9675a Alternative testing. 2024-08-26 15:53:53 -05:00
Dselen
ef028659d8 Testing improvement 2024-08-26 15:46:17 -05:00
Dselen
40f39e918d Finished work for now on the alpine docker image. 2024-08-26 15:28:27 -05:00
Dselen
2ec3ee2734 Fixed typo 2024-08-26 13:42:08 -05:00
Dselen
bc29b89a16 Rebased and going further 2024-08-26 13:07:42 -05:00
Donald Zou
e21853286e Did some refactor on wgd.sh 2024-08-25 16:26:36 +08:00
Donald Zou
c012b8c4a5 Merge pull request #340 from donaldzou/v4.0-alpine-linux
V4.0 alpine linux
2024-08-25 16:19:23 +08:00
Donald Zou
48f6c28556 Merge pull request #334 from NOXCIS/main
Fixed Docker Image
2024-08-25 16:18:34 +08:00
Noxcis
0c1502f801 Streamiline
+ Added Docker Install arg to wgd.sh
2024-08-25 03:01:21 -05:00
Donald Zou
fec20ed381 Reduced the time to open the config file 2024-08-25 15:59:48 +08:00
Donald Zou
252c147dcf Update dashboard.py 2024-08-25 15:15:07 +08:00
Donald Zou
453d474104 Fixed multiple IP address on a Configuration 2024-08-25 15:14:09 +08:00
Donald Zou
84cf4a9b66 Update README.md 2024-08-25 11:43:06 +08:00
Noxcis
fb016bebde Update wgd.sh 2024-08-24 20:04:07 -05:00
Noxcis
8f6a738481 Docker 2 Stage 2024-08-24 20:02:34 -05:00
Noxcis
b07f958577 Update compose.yaml 2024-08-24 06:46:06 -05:00
Noxcis
8da0fde52a + 2024-08-24 06:45:13 -05:00
Donald Zou
39be16cb63 Update README.md 2024-08-24 19:37:18 +08:00
Donald Zou
59d0c0def4 Merge pull request #337 from donaldzou/v4.0-alpine-linux
V4.0 alpine linux
2024-08-24 16:30:43 +08:00
Donald Zou
79c03db9a0 Update 2024-08-24 16:27:02 +08:00
Noxcis
0c77823020 Update main.yml 2024-08-24 03:00:51 -05:00
Noxcis
deed7e0022 Update main.yml 2024-08-24 02:56:40 -05:00
Noxcis
99db8c7335 Update main.yml 2024-08-24 02:53:30 -05:00
Noxcis
9fe2aa9ed5 Update main.yml 2024-08-24 02:49:51 -05:00
Noxcis
4c80dc256b Update main.yml 2024-08-24 02:46:43 -05:00
Noxcis
cafe9e9c11 Update main.yml 2024-08-24 02:41:57 -05:00
Noxcis
27ff4e63b6 Update main.yml 2024-08-24 02:38:10 -05:00
Noxcis
8020714e07 Update main.yml 2024-08-24 02:33:56 -05:00
Noxcis
dbd825ba4b Update main.yml 2024-08-24 02:28:35 -05:00
Noxcis
fee6cf29eb Update main.yml 2024-08-24 02:26:30 -05:00
Noxcis
56287d8e7a Update main.yml 2024-08-24 02:18:21 -05:00
Noxcis
45504eaf95 Update main.yml 2024-08-24 02:15:41 -05:00
Noxcis
b8a9b1150a Update main.yml 2024-08-24 02:13:04 -05:00
Donald Zou
8bd0e43f58 Update wgd.sh 2024-08-24 15:12:28 +08:00
Noxcis
2c83e9e83c Update main.yml 2024-08-24 02:06:57 -05:00
Noxcis
53c9ca10a7 Update main.yml 2024-08-24 02:04:46 -05:00
Noxcis
75fbdac42e Update main.yml 2024-08-24 01:40:34 -05:00
Noxcis
09d54546ca Update main.yml 2024-08-24 01:34:03 -05:00
Noxcis
b62fece3d0 Update main.yml 2024-08-24 01:29:51 -05:00
Noxcis
284a2b7f64 Update main.yml 2024-08-24 01:25:50 -05:00
Noxcis
9c873ccbbd Update main.yml 2024-08-24 01:22:37 -05:00
Noxcis
5f72f90031 Update main.yml 2024-08-24 01:18:49 -05:00
Noxcis
93cf3c69b8 Update main.yml 2024-08-24 01:04:28 -05:00
Noxcis
88f856cbc7 Create DockerScout.yml 2024-08-24 01:01:56 -05:00
Noxcis
2d5796d161 Added Auto Config Creation
Reimplemented Automatic Wireguard Configuration Generation

Setting global Env Vars via the docker image build is still insecure, better to pass to dashboard before init.
2024-08-23 16:49:54 -05:00
Dselen
1d20dc9fcb Looking like a promising end of this task. 2024-08-23 13:01:50 -05:00
Dselen
49502235b5 These needed to be added. 2024-08-23 12:48:33 -05:00
Dselen
6e9d71fcf8 Added reverted some no longer needed changes 2024-08-23 12:48:16 -05:00
Dselen
27c7e33773 added RHEL etc workings. 2024-08-23 12:27:41 -05:00
Dselen
3012619049 testing 2024-08-23 11:58:14 -05:00
dselen
d6801966c4 Merge branch 'donaldzou:main' into main 2024-08-23 16:19:58 +02:00
Dselen
518e29118c Reoganise the documents and added experimental Alpine Linux support in wgd.sh 2024-08-23 07:46:41 -05:00
Noxcis
acf4f3fbf0 Merge branch 'main' of https://github.com/NOXCIS/WGDashboard 2024-08-22 23:16:46 -05:00
Noxcis
8378030c70 Fixed Docker Vulnerability
+ Switched Base Image to Alpine
+ Simplified Docker Build
+ Added Alpine support to wgd.sh script.
+ Maintained Project Layout.
2024-08-22 23:15:39 -05:00
Donald Zou
dc7140d486 Update README.md 2024-08-23 09:24:18 +08:00
Dselen
e3771a1c53 Refined logging output a bit. 2024-08-22 16:58:29 -05:00
Dselen
2e9ac00a42 modified all and patched security vulnerability issue #333 2024-08-22 16:31:47 -05:00
Dselen
4b8b3acd39 Small readme change 2024-08-22 14:00:55 -05:00
Dselen
8703798ca0 Modified all files and have a working product, awaiting feedback! 2024-08-22 13:38:29 -05:00
dselen
47ac438844 Update README.md
Rearranged Ubuntu match other descending formats.
2024-08-22 16:24:07 +02:00
Dselen
bd3aa28523 Changed readme and compose for templating. 2024-08-20 14:48:36 -05:00
Dselen
68d0ae4002 Added context and refined code. 2024-08-20 13:54:49 -05:00
Dselen
6991039640 Working prototype. 2024-08-20 12:58:30 -05:00
Dselen
00611ef9dc Progress so far. 2024-08-20 09:58:25 -05:00
Donald Zou
3c50e4768a Merge pull request #317 from donaldzou/v4.0-fix3
Fixed recursive use of cursor
2024-08-20 00:02:46 -07:00
Donald Zou
63dc9834be Fixed recursive use of cursor 2024-08-20 00:02:00 -07:00
Donald Zou
f042e42633 Adjust version to v4.0.2 2024-08-19 21:30:47 -04:00
Donald Zou
39b80a2e7e Fixed the issue where updating is not working 2024-08-19 19:17:07 -04:00
Donald Zou
fb6e948358 Update production UI 2024-08-19 16:55:18 -04:00
Donald Zou
181b0845bf Merge pull request #313 from donaldzou/v4.0-fix2
Fixed #312, #311
2024-08-19 16:50:48 -04:00
Donald Zou
b2a82dcfe5 Fixed #312, #311
- Fixed issue in #312: The dashboard will automatically get the actual Dashboard version number.
- Fixed issue in #311: WGDashboard was not treating restricted peers correctly.
2024-08-19 16:50:00 -04:00
Noxcis
ed1c05dec9 Merge branch 'main' of https://github.com/NOXCIS/WGDashboard 2024-08-18 21:34:42 -05:00
Donald Zou
cd73aef0c9 Merge pull request #307 from donaldzou/donaldzou-patch-3
Update README.md
2024-08-17 20:34:29 -04:00
Donald Zou
ed522ec024 Update README.md 2024-08-17 20:34:20 -04:00
Donald Zou
16998d1e16 Merge pull request #306 from donaldzou/v4.0-fix1
Fixed peer status is not refreshing correctly
2024-08-17 20:25:34 -04:00
Donald Zou
11421d2d32 Try now 2024-08-17 20:19:52 -04:00
Donald Zou
1af708aaea Update 2024-08-17 01:11:48 -04:00
Donald Zou
fbb82fa759 Update README.md 2024-08-17 01:00:40 -04:00
Donald Zou
a9f977c3b4 Merge pull request #303 from donaldzou/v4
Merging the v4 branch to main.
2024-08-17 00:56:29 -04:00
Donald Zou
5669e22548 Removed all deprecated JS files 2024-08-17 00:52:38 -04:00
Donald Zou
da4bb9b83d Merge branch 'main' into v4 2024-08-17 00:46:46 -04:00
Donald Zou
c2cbaf0937 I think this is it :) 2024-08-17 00:31:46 -04:00
Donald Zou
d81dce536c Update README.md 2024-08-16 23:32:16 -04:00
Donald Zou
8e1e2c5b85 Update README.md 2024-08-16 23:24:20 -04:00
Donald Zou
959d5e6822 Update README.md 2024-08-16 23:22:55 -04:00
Donald Zou
036a0b4cb3 Update README.md 2024-08-16 23:18:28 -04:00
Donald Zou
c038f14374 Update README.md 2024-08-16 23:03:01 -04:00
Donald Zou
343cf91643 Update README.md 2024-08-16 23:02:36 -04:00
Donald Zou
4fe70a4c46 Update README.md 2024-08-16 23:01:58 -04:00
Donald Zou
59f7200512 Update README.md 2024-08-16 22:53:23 -04:00
Donald Zou
0335e709c2 Update README.md 2024-08-16 22:51:56 -04:00
Donald Zou
a7bb5ac21b Update wgd.sh 2024-08-16 17:36:22 -04:00
Donald Zou
99655cab33 Update wgd.sh 2024-08-16 17:35:38 -04:00
Donald Zou
348e574154 Update wgd.sh 2024-08-16 17:34:54 -04:00
Donald Zou
f35dee8643 Update wgd.sh 2024-08-16 17:34:03 -04:00
Donald Zou
168412c2e7 Update wgd.sh 2024-08-16 17:32:34 -04:00
Donald Zou
b9832542fb Update wgd.sh 2024-08-16 17:24:50 -04:00
Donald Zou
316545b253 Update wgd.sh 2024-08-16 17:23:16 -04:00
Donald Zou
348a57a0d8 Update wgd.sh 2024-08-16 17:22:57 -04:00
Donald Zou
a3f5654816 Update wgd.sh 2024-08-16 17:21:42 -04:00
Donald Zou
8207afe806 Update wgd.sh 2024-08-16 17:20:05 -04:00
Donald Zou
e15b8f8092 Update wgd.sh 2024-08-16 17:19:07 -04:00
Donald Zou
e6c99028d6 Update wgd.sh 2024-08-16 17:16:54 -04:00
Donald Zou
2e691d7c26 Update wgd.sh 2024-08-16 17:13:18 -04:00
Donald Zou
6c87812780 Update wgd.sh 2024-08-16 17:12:40 -04:00
Donald Zou
798a3632cf Update wgd.sh 2024-08-16 03:32:28 -04:00
Donald Zou
aa1d0aabd2 Update wgd.sh 2024-08-16 03:28:26 -04:00
Donald Zou
f348e691fa Update wgd.sh 2024-08-16 03:27:24 -04:00
Donald Zou
0dfda83e45 Update wgd.sh 2024-08-16 03:25:25 -04:00
Donald Zou
56044fa3f7 Update wgd.sh 2024-08-16 03:18:08 -04:00
Donald Zou
4c69fd4f60 Update wgd.sh 2024-08-16 03:14:03 -04:00
Donald Zou
92e3f7a6a3 Update wgd.sh 2024-08-16 03:12:29 -04:00
Donald Zou
76d0618d6e Update wgd.sh 2024-08-16 03:11:30 -04:00
Donald Zou
80c3a99eb1 Update wgd.sh 2024-08-16 03:10:26 -04:00
Donald Zou
91e3a3237b Update wgd.sh 2024-08-16 03:06:31 -04:00
Donald Zou
8c8c5a5826 Update wgd.sh 2024-08-16 03:02:45 -04:00
Donald Zou
b9370955d6 Update wgd.sh 2024-08-16 02:53:45 -04:00
Donald Zou
2761e728f7 Update wgd.sh 2024-08-16 02:50:54 -04:00
Donald Zou
f418bf4f63 Update wgd.sh 2024-08-16 02:48:31 -04:00
Donald Zou
3d046e4369 Update wgd.sh 2024-08-16 02:40:25 -04:00
Donald Zou
b6eb6f2d70 Update wgd.sh 2024-08-16 02:19:30 -04:00
Donald Zou
45ce3e26c1 Update wgd.sh 2024-08-16 02:15:10 -04:00
Donald Zou
ae91cedf76 Update wgd.sh 2024-08-16 02:07:40 -04:00
Donald Zou
b2a6b484b5 Update wgd.sh 2024-08-16 02:03:41 -04:00
Donald Zou
95c4fa56cc Update wgd.sh 2024-08-16 02:01:02 -04:00
Donald Zou
e8c56afa8e Update wgd.sh 2024-08-16 02:00:45 -04:00
Donald Zou
ddc3b1f6c2 Update wgd.sh 2024-08-16 01:58:40 -04:00
Donald Zou
d33d886574 Update wgd.sh 2024-08-16 01:55:53 -04:00
Donald Zou
0487980d2f Update wgd.sh
Selectively use a specific version of Python: 3.10, 3.11 or 3.12
2024-08-16 01:47:44 -04:00
Donald Zou
e68257d6c9 Updated some documentations 2024-08-15 23:20:29 -04:00
Donald Zou
ea0bbab680 Update api-documents.md 2024-08-15 22:50:01 -04:00
Donald Zou
5d4a8136c5 Updated some documentation 2024-08-15 22:47:44 -04:00
Donald Zou
c98d851cd2 No longer reading configuration file every few seconds
Only when the file is changed
2024-08-15 18:26:20 -04:00
Donald Zou
42fa89db7a Added to parse name in .conf file 2024-08-15 17:45:54 -04:00
Donald Zou
1a70acc6f2 Update documentation 2024-08-15 16:55:34 -04:00
Donald Zou
ee0a287112 Update README.md 2024-08-15 00:56:28 -04:00
Donald Zou
cf16a66c63 Update README.md 2024-08-15 00:53:38 -04:00
Donald Zou
4544b17c94 Update README.md 2024-08-15 00:53:23 -04:00
Donald Zou
8119c9da51 Update README.md 2024-08-15 00:49:21 -04:00
Donald Zou
baf4d75c01 Update documentations 2024-08-15 00:48:27 -04:00
Donald Zou
ac9eff0fcc Removed images 2024-08-14 23:59:50 -04:00
Donald Zou
dc57bd92ff Update README.md 2024-08-14 23:57:45 -04:00
Donald Zou
3c56a2c868 Update README.md 2024-08-14 23:55:52 -04:00
Donald Zou
2d2ab10a24 Update README.md 2024-08-14 23:54:54 -04:00
Donald Zou
ac906c9994 Update README.md 2024-08-14 23:53:28 -04:00
Donald Zou
480406d579 Update README.md 2024-08-14 23:52:14 -04:00
Donald Zou
47efb644b7 Working on some updates 2024-08-14 22:45:36 -04:00
Donald Zou
fd0e519e41 Fixed some API endpoint missed the prefix 2024-08-14 18:40:28 -04:00
Donald Zou
0c8bb990d0 Some UI adjustment 2024-08-14 14:35:49 -04:00
Donald Zou
bd7139827b Update 2024-08-14 12:31:37 -04:00
Donald Zou
4f648aff52 Updated UI for smaller screen 2024-08-14 12:07:53 -04:00
Donald Zou
3feb45dc01 Fixed for URL protocol 2024-08-14 10:59:01 -04:00
Donald Zou
0489dc7c33 Update fetch.js
Fixed for running over HTTPS
2024-08-14 10:57:41 -04:00
Donald Zou
a30843cff9 Added app prefix for URL 2024-08-14 01:17:47 -04:00
Donald Zou
3a34a0eb40 Adjusted some UI 2024-08-13 12:29:58 -04:00
Donald Zou
e3f82e136a Adjusted some UI 2024-08-12 18:04:41 -04:00
Donald Zou
8a7df4ba9f Update wgd.sh 2024-08-12 01:19:55 -04:00
Donald Zou
e86d1a4c7a Updated langugage 2024-08-12 00:34:54 -04:00
Donald Zou
5b9d0b60a1 Adjusted some UI 2024-08-11 19:20:52 -04:00
Donald Zou
7eff2f0c49 Fixed issue #250 2024-08-11 19:20:42 -04:00
Donald Zou
97236bb01d Fixed new configuration hang when error 2024-08-11 19:20:03 -04:00
Donald Zou
9c6aa12f48 Update README.md 2024-08-11 16:53:50 -04:00
Donald Zou
96ccb03eea Adjusted some code for electron version 2024-08-11 16:39:00 -04:00
Donald Zou
55f55820c5 Update wg-dashboard.service 2024-08-11 11:02:08 -04:00
Donald Zou
955839d513 I think cross server actually worked 2024-08-11 01:48:13 -04:00
Donald Zou
a650e628e5 CORS SUCCESS!!! 2024-08-10 19:23:50 -04:00
Donald Zou
54142b73fb Ohhhhh kay testing CORS :) 2024-08-10 19:03:21 -04:00
Donald Zou
55e0d2695d Update .gitignore 2024-08-10 12:58:41 -04:00
Donald Zou
2f90ab15dc Let's try ElectronJS 2024-08-10 12:58:14 -04:00
Donald Zou
fd3fc66bfc Thinking of adding Electron.js 2024-08-10 00:25:25 -04:00
Donald Zou
a352a94d8a Update .gitignore 2024-08-10 00:24:07 -04:00
Donald Zou
410b81f46f Some UI adjustment 2024-08-09 22:16:38 -04:00
Donald Zou
aa3711c5cc Adjusted search peer UI 2024-08-09 21:30:01 -04:00
Donald Zou
d6b1f97a04 Update 2024-08-09 20:46:11 -04:00
Donald Zou
b4e8e57a22 Updated UI for nav bar 2024-08-09 17:58:41 -04:00
Donald Zou
9644e6195c Finished adding data usage on configuration list 2024-08-09 17:30:44 -04:00
Donald Zou
764e0c7607 Replaced all cursor without recursive use 2024-08-09 17:29:57 -04:00
Donald Zou
97d640dd40 Update dashboard.py 2024-08-09 16:09:55 -04:00
Donald Zou
d2915b5b05 Update dashboard.py 2024-08-09 16:09:23 -04:00
Donald Zou
f274f6fd18 Fixed some bugs.. 2024-08-09 16:09:08 -04:00
Donald Zou
f507ac2569 Rewrote the add peer function 2024-08-08 23:27:13 -04:00
Donald Zou
208cbd6d89 Peer data reset function is don e 2024-08-08 20:56:14 -04:00
Donald Zou
cd2aa2902a Update README.md 2024-08-07 00:44:46 -04:00
Donald Zou
fa2d7fa3da Peer Sharing is done :) 2024-08-07 00:37:05 -04:00
Donald Zou
7463767781 Sharing peer is done, fixed #294
Fixed issue #294 with a Vue.js plugin instead of using the `datatime-local` input tag.

Still need to work on the end-user UI for sharing.
2024-08-06 19:15:00 -04:00
Donald Zou
958bc864c9 The sharing function is almost done 2024-08-06 10:17:14 -04:00
Donald Zou
4484668750 Backend for peer sharing is done 2024-08-05 19:57:17 -04:00
Donald Zou
d5dea4b87f Fixed the issue mentioned in #290 2024-08-05 17:55:58 -04:00
Donald Zou
0fdef6a0a2 fixing some Gunicorn bugs.. again.. 2024-08-05 15:39:11 -04:00
Donald Zou
bd71b6bad8 Update gunicorn.conf.py 2024-08-04 20:24:31 -04:00
Donald Zou
9b7887b279 Update gunicorn.conf.py 2024-08-04 20:23:41 -04:00
Donald Zou
3960e43872 Update gunicorn.conf.py 2024-08-04 20:22:41 -04:00
Donald Zou
201c8f9ec9 Update dashboard.py 2024-08-04 20:17:29 -04:00
Donald Zou
8c8374a08c Update wgd.sh 2024-08-04 20:16:26 -04:00
Donald Zou
467595afc9 Update wgd.sh 2024-08-04 20:15:46 -04:00
Donald Zou
acb54f098c Update gunicorn.conf.py 2024-08-04 20:13:17 -04:00
Donald Zou
5755d13460 Update gunicorn.conf.py 2024-08-04 19:45:28 -04:00
Donald Zou
2c3500315d Update gunicorn.conf.py 2024-08-04 19:36:49 -04:00
Donald Zou
47ea60c0cd Testing v4 2024-08-04 19:35:59 -04:00
Donald Zou
18b18c1396 Update wgd.sh 2024-08-04 19:33:05 -04:00
Donald Zou
ff227de5fa Update gunicorn.conf.py 2024-08-04 19:32:16 -04:00
Donald Zou
6799692811 Testing.. 2024-08-04 19:30:48 -04:00
Donald Zou
c6173f7f6f Update wgd.sh 2024-08-04 19:22:26 -04:00
Donald Zou
d0e4dabc44 Update wgd.sh 2024-08-04 19:22:06 -04:00
Donald Zou
f815dae300 Update wgd.sh 2024-08-04 19:21:38 -04:00
Donald Zou
b3bd6bb39e Update wgd.sh 2024-08-04 19:20:31 -04:00
Donald Zou
71df6409c2 Update gunicorn.conf.py 2024-08-04 19:17:41 -04:00
Donald Zou
e4f9a1e0cf Update gunicorn.conf.py 2024-08-04 19:03:30 -04:00
Donald Zou
ca6a05e393 Update gunicorn.conf.py 2024-08-04 18:59:45 -04:00
Donald Zou
c0d26164dc Update wgd.sh 2024-08-04 18:48:13 -04:00
Donald Zou
76fe2a1ba9 Update wgd.sh 2024-08-04 18:45:57 -04:00
Donald Zou
8cbdb54402 Still fixing Gunicron 2024-08-04 16:08:05 -04:00
Donald Zou
764ef80a62 Update wgd.sh 2024-08-04 15:44:55 -04:00
Donald Zou
0c37d93c01 Testing if this will fix bash exit before Gunicorn ran... 2024-08-04 15:29:07 -04:00
Donald Zou
c57a5128e5 Update wgd.sh 2024-08-04 03:20:44 -04:00
Donald Zou
6cf4eba20a Redirect when received a 401 error 2024-08-04 01:31:31 -04:00
Donald Zou
6825d728c2 Log function is completed 2024-08-03 17:03:39 -04:00
Donald Zou
6d3091b2a2 Push dockerfiles 2024-08-03 15:29:56 -04:00
Donald Zou
61473877a4 Update wgd.sh 2024-08-03 14:01:04 -04:00
Donald Zou
52989c8f5c Fixed clearInterval is not working within configuration 2024-08-03 13:26:16 -04:00
Donald Zou
b64ba2ef16 Fixed Gunicorn global variable issue 2024-08-03 13:25:57 -04:00
Donald Zou
461ae99dd8 Testing again... 2024-08-02 21:48:42 -04:00
Donald Zou
8681df6f02 Seems like Gunicorn need global 2024-08-02 21:45:55 -04:00
Donald Zou
ba081ee442 Update wgd.sh 2024-08-02 21:21:19 -04:00
Donald Zou
cf90d05115 Update wgd.sh 2024-08-02 18:30:16 -04:00
Donald Zou
658c6554af Update wgd.sh 2024-08-02 18:18:31 -04:00
Donald Zou
94d9d608f7 Update wgd.sh 2024-08-02 18:16:34 -04:00
Donald Zou
015b50be5f Doing some testing across distros 2024-08-02 17:27:28 -04:00
Donald Zou
85970f8c96 New build 2024-07-31 02:27:44 -04:00
Donald Zou
1740ab0bbe Update README.md 2024-07-31 02:23:20 -04:00
Donald Zou
9d2b5593a2 Add files via upload 2024-07-31 02:21:42 -04:00
Donald Zou
881d62d69d The UI and backend of API keys is done! 2024-07-30 18:45:05 -04:00
Donald Zou
935129f0a5 Finished the log system, now move on to something else... 2024-07-29 22:17:51 -04:00
Donald Zou
1a9bdc5e6d Merge pull request #288 from donaldzou/donaldzou-patch-3
Update README.md
2024-07-29 18:58:49 -04:00
Donald Zou
1f565bca10 Update README.md 2024-07-29 18:58:39 -04:00
Donald Zou
da089197a3 Changed the name 2024-07-29 18:56:56 -04:00
Donald Zou
2df8f41d6c Changed v4.0 preview GIF 2024-07-29 18:56:35 -04:00
Donald Zou
4e4f0d4c97 Create S1creen Recording 2024-07-29 at 5.59.53 PM.webm 2024-07-29 18:40:46 -04:00
Donald Zou
eaad22c0a1 Create proxy.js 2024-07-29 18:40:19 -04:00
Donald Zou
63e8553a09 Finished job logs :) 2024-07-29 18:40:07 -04:00
Donald Zou
b65828416f Job logs api are done, still need to build the UI to view logs 2024-07-27 18:51:43 -04:00
Donald Zou
48dc8033f5 Schedule system is finally running, still need to more testing :) 2024-07-01 00:58:02 +08:00
Donald Zou
2d838b69fd Peer schedule style is almost done
But I don't feel it quite right..
2024-06-25 23:02:13 +08:00
Donald Zou
6c529a6908 Fixed Gunicorn issue, continue on Peer Schedule Job 2024-06-19 17:09:58 +08:00
Donald Zou
9baefec541 Figuring out with Gunicorn... 2024-06-18 03:40:25 +08:00
Donald Zou
327d66bb80 Removed a tons of files :) 2024-06-18 03:16:42 +08:00
Donald Zou
760a4dfcb9 Still working on schedule.. 2024-06-16 23:32:32 +08:00
Donald Zou
ceb8cdd337 Merge pull request #281 from donaldzou/donaldzou-patch-3
Update README.md
2024-06-16 15:42:28 +08:00
Donald Zou
570c754eec Update README.md 2024-06-16 15:42:17 +08:00
Donald Zou
8ed75d1d21 Working on Job Scheduling 2024-06-16 15:40:10 +08:00
Donald Zou
54710b8221 Update .gitignore 2024-06-15 23:14:48 +08:00
Donald Zou
ff794033e1 Finished Traceroute 2024-06-13 16:56:06 +08:00
Donald Zou
f0f486da9e Adjusted some UI and finished the Ping function 2024-06-12 17:54:29 +08:00
Donald Zou
aedcfd1d24 Merge pull request #277 from DaanSelen/main
Added updated Docker functionality.
2024-06-11 22:40:38 +08:00
Daan
44e738acf5 Merge branch 'main' of https://github.com/DaanSelen/WGDashboard-dockerized 2024-06-10 20:36:13 +02:00
Daan
701b45c286 Improved (imo) the use of English. 2024-06-10 20:34:30 +02:00
dselen
72fe687d82 Update Docker-explain.md 2024-06-09 23:13:31 +02:00
dselen
632cd66b57 Update Docker-explain.md 2024-06-09 23:13:19 +02:00
Daan
20530c000e Added container documentation, and added a few new comments. 2024-06-09 23:11:22 +02:00
Daan
8824786fb4 For some reason, cloning the GitHub (which has been simplified) works from the Dockerfile directly.
But the wg0.conf file needs a re-copy on run-time. Working now.

Made code modifications and optimizations.

Please report bugs to me.
2024-06-08 13:30:24 +02:00
Daan
bdeb4a4efe Cleaned up lingering code line. 2024-06-07 14:55:16 +02:00
Daan
cf455fc19b Modified code so that the docker logging makes sense. Also fixed a bug which can happen with iptables (-s illegal option). Pushing to repo. 2024-06-07 13:25:46 +02:00
Daan
1bcddadb7a Features tested working, feeling good about a release. 2024-06-06 16:11:49 +02:00
Daan
6dc28f11e0 Working on isolated peers feature. 2024-06-06 00:12:11 +02:00
Daan
8ad601fcc0 Added features, plus explanations in about them in the compose.yaml file. Looking great! 2024-06-05 20:27:24 +02:00
Daan
f400844a3d Modified scripts 2024-06-05 09:16:29 +02:00
Daan
560096878f Persistency seems to work with this model, it has succeeded my tests. 2024-06-04 23:26:03 +02:00
Daan
0938f5ab71 Container deployed with working VPN server built-in. Missing is persistency among recreations, looking into that... 2024-06-04 22:49:17 +02:00
Daan
06193d27c0 Added dockerfile and entrypoint for basic compilation, moving to finalizing 2024-06-04 17:05:17 +02:00
Donald Zou
eb18857ecc Some UI adjustment 2024-06-03 02:16:09 +08:00
Donald Zou
9a280e99ad Finished restrict & allow access of peers 2024-06-02 23:22:43 +08:00
Donald Zou
c7ca20b45a Made some progress ;) 2024-05-20 22:28:52 +08:00
Donald Zou
60e64a3646 Merge pull request #269 from donaldzou/donaldzou-patch-2
Update README.md
2024-05-14 22:44:20 +08:00
Donald Zou
d60f89976e Update README.md 2024-05-14 22:44:09 +08:00
Donald Zou
41e05ddf9c Update dashboard_new.py
Yay adding peers in bulk is finally done ;)
2024-05-14 00:58:01 +08:00
Donald Zou
5a34f16dcf Update dashboard_new.py
Typo in `updatePeer`
2024-05-13 22:17:00 +08:00
Donald Zou
769ca4e26d Kind of finished revamping add peers
Still need to clean some of the codes but overall is good :)
2024-05-12 00:39:17 +08:00
Donald Zou
b6e62b08e4 Merge pull request #265 from donaldzou/v3.0.6.2
Update dashboard.py
2024-05-04 11:42:10 +08:00
Donald Zou
effe5b32fd Update dashboard.py 2024-05-04 11:40:32 +08:00
Donald Zou
9e38137e76 Removed DNS as a required field from peer settings 2024-05-03 10:15:00 +08:00
Donald Zou
57c2e89f00 Fixing some of the issue from users ;) 2024-04-26 00:03:42 +08:00
Donald Zou
914a0bf514 Minor updates... 2024-04-03 01:16:56 -04:00
Donald Zou
210f5eabc9 Merge pull request #261 from donaldzou/donaldzou-patch-1
Update FUNDING.yml
2024-03-31 11:20:04 -04:00
Donald Zou
5f5c91a8ff Update FUNDING.yml 2024-03-31 11:19:54 -04:00
Donald Zou
05c7121c8a Update README.md 2024-03-31 00:55:46 -04:00
Donald Zou
551a8e9588 Add files via upload 2024-03-31 00:53:00 -04:00
Donald Zou
75fbdb653a Update build 2024-03-24 22:55:19 -04:00
Donald Zou
bdfe75cff3 Finished download & QR Code 2024-03-24 22:46:32 -04:00
Donald Zou
bcd845fd59 Finished revamping peer edit 2024-03-24 18:24:01 -04:00
Donald Zou
f1e71ecb78 20240323 Commit
Finished implementing peer settings dropdown and planned how peer settings will be link
2024-03-21 02:03:08 -04:00
Donald Zou
0aa4c8af6f Continue to work on v4 ;0 2024-03-11 00:11:07 -04:00
Donald Zou
8fe5507ff8 Update README.md 2024-02-27 18:38:10 -05:00
Donald Zou
a950b80d5a v4 branch first commit! 2024-02-27 18:37:49 -05:00
Donald Zou
ed3bb6429b Finished some building blocks on the new version 2024-02-26 10:22:33 -05:00
Donald Zou
1e88491ca1 I am giving up on using ORM...
Lets go back to the good old sql query days ;)
2024-02-11 23:53:51 -05:00
Donald Zou
4aed647865 Merge pull request #254 from Upellift99/main
Enabling use of underscores in configuration name
2024-02-01 18:39:05 -05:00
John
74ab7aaa3d Enabling use of underscores in configuration name. 2024-02-01 09:53:04 +01:00
John
dcf2055851 Enabling use of underscores in configuration name. 2024-02-01 09:47:52 +01:00
Donald Zou
6b6ad05e3a The UI for New Configuration is done 2024-01-31 12:06:44 -05:00
Donald Zou
734a4b5e00 Merge pull request #252 from donaldzou/donaldzou-patch-1
Update README.md
2024-01-23 15:11:21 -05:00
Donald Zou
da70fac0b6 Update README.md 2024-01-23 15:11:02 -05:00
Donald Zou
5f4a364095 Huge update
A welcome session
Added Time based One-Time-Passcode (TOTP)
UI Update
2024-01-23 15:09:44 -05:00
Donald Zou
95a8867527 Update .gitignore 2024-01-11 13:47:35 -05:00
Donald Zou
7cb1301e80 Continue to refactor the UI and APIs :) 2024-01-11 13:46:08 -05:00
Donald Zou
e6e070d89e Continue to refactor the UI and APIs :) 2024-01-11 01:10:26 -05:00
Donald Zou
ba2bcaba07 Finally figured out SQLAlchemy and started to re-write some of the APIs. The UI will completely handle by JS with Vue. There will be no more templating from flask to minimize the resource usage ;) 2024-01-10 01:42:19 -05:00
Donald Zou
3d6ecba4f5 Update README.md 2024-01-09 14:10:08 -05:00
Donald Zou
864f82ba11 Started to refactor dashboard.py with dashboard_new.py and trying really hard to figure out sqlalchemy lol 2024-01-09 00:25:47 -05:00
Donald Zou
f671c992e1 testing something... 2024-01-08 12:23:57 -05:00
Donald Zou
86220694ce Update README.md
Added instruction to install `net-tools`. It is required for the Python package `ifcfg`. Seems like it is not pre-installed on a fresh debian based system.
2023-12-10 13:01:45 -05:00
Donald Zou
77f31177c8 Update .gitignore 2023-12-10 12:56:49 -05:00
Donald Zou
33ff91aea8 Update .gitignore 2023-12-10 12:56:02 -05:00
Noxcis
a4151800f1 Update requirements.txt 2023-12-05 04:47:40 -08:00
Noxcis
932f24c966 Update dashboard.py 2023-12-05 04:44:01 -08:00
Donald Zou
0c0bce9755 Combining Vue.js!!! How exciting!
Adding Vue.js to handle frontend changes, leaving the server only need to response json data. Ditching flask template and hope it can reduce the memory and cpu usage :)
2023-11-30 09:42:02 -05:00
Donald Zou
f07508073f A new update to the dev branch 2023-11-28 16:37:16 -05:00
Donald Zou
2c9cade70a Create SECURITY.md 2023-03-23 13:07:36 -04:00
Donald Cheng Hong Zou
e06cc1bd2d Finally finished theme switching!!!! 2022-04-23 00:34:11 -04:00
Donald Cheng Hong Zou
36e33a4c10 Adjust the dark mode theme for PWA 2022-04-22 16:21:16 -04:00
Donald Cheng Hong Zou
7f668c1653 Some changes to dark mode css 2022-04-22 00:12:22 -04:00
Donald Zou
b464fa98df Merge pull request #173 from LeoEricson/v3.1-dev
Add dark theme
2022-04-21 22:33:40 -04:00
LeoEricson
23491f1e8c Add dark theme 2022-04-21 21:30:55 +00:00
Donald Cheng Hong Zou
2b90a2eed2 Update header.html 2022-04-21 15:11:35 -04:00
Donald Cheng Hong Zou
13b9d15d8f New darkmode theme 2022-04-21 15:11:01 -04:00
Donald Cheng Hong Zou
a053504bb8 Make the dashboard more mobile friendly 2022-04-11 20:01:29 -04:00
Donald Zou
d7d7a84bd5 Update README.md 2022-04-10 09:35:50 -04:00
Donald Zou
990463fbea Update README.md 2022-04-10 09:29:07 -04:00
Donald Cheng Hong Zou
dcdd4aec85 Update Peer Data Usage Graph 2022-04-10 09:26:54 -04:00
Donald Zou
0d9a8ba6f7 Update README.md 2022-04-06 21:05:24 -04:00
Donald Cheng Hong Zou
179da2ac05 Finished peer data usage chart 2022-04-06 20:59:23 -04:00
Donald Cheng Hong Zou
4848739b6e Added dockerfile! Thanks @ikidd! 2022-04-05 21:39:47 -04:00
Donald Cheng Hong Zou
46da285831 Adjusted js 2022-03-30 14:20:08 -04:00
Donald Cheng Hong Zou
71a6a36a54 Update dashboard.css 2022-03-30 14:06:05 -04:00
Donald Cheng Hong Zou
c8ca9ef7ab Minimized some js code 2022-03-30 00:54:11 -04:00
Donald Cheng Hong Zou
5af2fff9ca IPv6 configuration IP should be working now 2022-03-29 15:11:50 -04:00
Donald Zou
edbaf3ac82 Update README.md 2022-03-29 12:27:39 -04:00
Donald Cheng Hong Zou
337c9bc01e Update dashboard.py 2022-03-28 15:33:26 -04:00
Donald Zou
cd84674ae0 Update README.md 2022-03-28 08:23:12 -04:00
Donald Cheng Hong Zou
a196dce1fa Removed flask-socketio 2022-03-28 08:09:28 -04:00
Donald Zou
f60ea43f29 Create codeql-analysis.yml 2022-03-27 21:44:49 -04:00
Donald Zou
76f547a726 Update README.md 2022-03-26 11:14:27 -04:00
Donald Zou
dffe5e0819 Update README.md 2022-03-25 14:11:39 -04:00
Donald Cheng Hong Zou
b9633bbcd6 Finished implementing add/delete config 2022-03-24 20:43:56 -04:00
Donald Cheng Hong Zou
46efe2b8dd Finished developing add config 2022-03-24 02:10:52 -04:00
Donald Zou
fb9ef0c547 Update README.md 2022-03-22 17:34:34 -04:00
Donald Cheng Hong Zou
d52cd2b17c Doing a update 2022-03-22 17:28:19 -04:00
Donald Cheng Hong Zou
cefa80f317 Fixed redirect functionality 2022-03-22 16:17:12 -04:00
Donald Cheng Hong Zou
cc1dd682e8 Add configuration and adjusted redirect functionality 2022-03-22 16:13:57 -04:00
Donald Cheng Hong Zou
bdd984a887 Brand new switch button and toast UI 2022-03-21 22:33:19 -04:00
Donald Cheng Hong Zou
2d3dffe5fc Moved refresh interval and display mode to localStorage 2022-03-07 09:29:47 -05:00
Donald Cheng Hong Zou
65f31a0b38 Gave up using WebSocket
Flask-SocketIO does not fully compatible with Gunicorn, and it limited to 1 worker, which it will takes forever to finish loading the webpage. Switched back to  using ajax.
2022-03-04 22:09:01 -05:00
Donald Cheng Hong Zou
4a1a6c5933 Testing 2022-03-04 10:06:14 -05:00
Donald Cheng Hong Zou
7e1fd99c37 Fixed chart and updated requirement.txt 2022-03-04 08:28:54 -05:00
Donald Cheng Hong Zou
8fe8209580 Added line graph using chart.js & Improving websocket.
Added line graph to show total receive & total sent changes per refresh interval, using chart.js line chart to show the changes. Switching configuration don't need to refresh anymore, by using websocket.
2022-03-03 08:46:23 -05:00
Donald Cheng Hong Zou
264a050360 Temp fix 2022-02-28 13:34:46 -05:00
Donald Cheng Hong Zou
3623104e3b Merge branch 'main' into hmm-what-about-socket 2022-02-28 13:31:06 -05:00
Donald Cheng Hong Zou
191ff1abec Merge branch 'main' of https://github.com/donaldzou/WGDashboard 2022-02-28 13:29:25 -05:00
Donald Cheng Hong Zou
3bb86493cc Minor changes 2022-02-28 13:29:17 -05:00
Donald Zou
d1d3151e1e Update README.md 2022-02-27 15:50:55 -05:00
Donald Cheng Hong Zou
f9dc9ebdb3 Removed some unnecessary comments 2022-02-11 09:35:58 -05:00
Donald Cheng Hong Zou
3b478bcc2d OneDrive gone again.... 2022-02-04 21:36:46 -05:00
Donald Cheng Hong Zou
77bb78c381 OneDrive caused my whole project folder gone.... 2022-02-04 11:44:50 -05:00
Donald Cheng Hong Zou
cafa97f502 Changed version number 2022-01-31 16:09:50 -05:00
Donald Cheng Hong Zou
0d858493d5 Update README.md 2022-01-31 09:56:38 -05:00
Donald Cheng Hong Zou
99fb07c6b3 Fixed public key error with existed private key 2022-01-31 09:38:05 -05:00
Donald Zou
eaad971c0a Update README.md 2022-01-24 22:06:38 -05:00
Donald Cheng Hong Zou
377abd87fd Commit 2022-01-24 20:11:35 -05:00
Donald Zou
af71176296 Merge pull request #133 from donaldzou/v3.0.3-pr
v3.0.3
2022-01-23 19:34:06 -05:00
Donald Cheng Hong Zou
69737177ef Changed version number to v3.0.3 2022-01-23 19:30:43 -05:00
Donald Cheng Hong Zou
efae1222c1 Update dashboard.py 2022-01-23 19:25:12 -05:00
Donald Cheng Hong Zou
3caea1a903 Update README.md 2022-01-23 19:21:43 -05:00
Donald Cheng Hong Zou
a43478d627 Fixed no init_dashboard() for debug mode the first time 2022-01-23 19:19:38 -05:00
Donald Cheng Hong Zou
ed2c3f43c7 Added tracking loading time 2022-01-19 10:43:39 -05:00
Donald Cheng Hong Zou
84c9846f7b Hmmmm... What about SocketIO? 2022-01-19 10:27:17 -05:00
Donald Cheng Hong Zou
fcfd816cec Remove pylint 2022-01-19 09:25:27 -05:00
Donald Cheng Hong Zou
2e3977e59c commit 2022-01-19 09:18:03 -05:00
Donald Cheng Hong Zou
3c68430336 Update pylint.yml 2022-01-19 09:12:57 -05:00
Donald Cheng Hong Zou
43afb86fa8 Update pylint.yml 2022-01-19 09:10:59 -05:00
Donald Cheng Hong Zou
194ccbdbb4 Update pylint.yml 2022-01-19 09:10:07 -05:00
Donald Cheng Hong Zou
7139e230cf Commit 2022-01-19 09:08:27 -05:00
Donald Zou
120d3b9f54 Update pylint.yml 2022-01-19 09:05:39 -05:00
Donald Zou
712460a040 Update pylint.yml 2022-01-19 09:03:35 -05:00
Donald Zou
be5594f1c9 Create pylint.yml 2022-01-19 09:01:35 -05:00
Donald Cheng Hong Zou
0a885117db Update README.md 2022-01-18 13:04:00 -05:00
Donald Zou
5b73654544 Update README.md 2022-01-18 12:43:37 -05:00
Donald Cheng Hong Zou
1485b78b7b Merge branch 'main' of https://github.com/donaldzou/WGDashboard 2022-01-18 12:43:20 -05:00
Donald Cheng Hong Zou
bfec57172a Update README.md 2022-01-18 12:43:11 -05:00
Donald Zou
9f8559c12d Update README.md 2022-01-18 12:34:40 -05:00
Donald Zou
83dde12ca9 Merge pull request #126 from donaldzou/Migrate-to-SQLite
Production branch for v3.0
2022-01-18 12:33:34 -05:00
Donald Cheng Hong Zou
d17888db4e Update README.md 2022-01-18 12:33:21 -05:00
Donald Cheng Hong Zou
096529af96 Experimental Functions 2022-01-18 12:16:10 -05:00
Donald Cheng Hong Zou
8a56b22635 Added manifest.json 2022-01-18 11:02:19 -05:00
Donald Cheng Hong Zou
dcdd353981 Removed unnecessary files 2022-01-18 10:49:41 -05:00
Donald Cheng Hong Zou
258564208b Finalizing everything. 2022-01-18 10:42:23 -05:00
Donald Cheng Hong Zou
e2e8222005 Upload manifest.json 2022-01-16 20:35:24 -05:00
Donald Cheng Hong Zou
75f2826805 Merge branch 'pr/93' into Migrate-to-SQLite 2022-01-13 09:44:47 -05:00
Donald Cheng Hong Zou
730af4f2ee Finishing documentation 2022-01-13 09:37:23 -05:00
Donald Zou
e5737ebd9d Merge branch 'main' into Migrate-to-SQLite 2022-01-12 21:41:41 -05:00
Donald Cheng Hong Zou
7f24904164 Bugs 2022-01-12 20:28:12 -05:00
Donald Cheng Hong Zou
9ff7198602 Still finalizing everything 2022-01-12 19:53:36 -05:00
Donald Cheng Hong Zou
6d56967a0f Getting ready for v3.0 2022-01-08 15:26:17 -05:00
Donald Cheng Hong Zou
584118805a Feature Added
Moved key generating to front-end, by using wireguard.js from WireGuard's official repository. Added "Add Peers by bulk" feature.
2022-01-06 15:17:43 -05:00
Donald Zou
68b3f01082 Merge pull request #127 from pgalonza/refactoring
Fixed misprint
2022-01-04 16:41:26 -05:00
Donald Cheng Hong Zou
77a82cb84b Finished adding available IP and related UI adjustment 2022-01-04 16:32:23 -05:00
Galonza Peter
844b19495d fixed misprint 2022-01-03 00:51:22 +03:00
Donald Cheng Hong Zou
b8b721f2bd Delete wgdashboard.db 2022-01-02 14:45:24 -05:00
Donald Cheng Hong Zou
4f93d48ac6 Successfully migrate to SQlite 2022-01-02 14:44:27 -05:00
Donald Zou
02d1bf5a2c Merge pull request #125 from pgalonza/refactoring
Refactoring
2022-01-02 14:41:24 -05:00
Galonza Peter
fb3606c2b7 Refactored
Added docstrings like sphinx style, small refactoring and added TODO
2022-01-02 16:35:39 +03:00
Galonza Peter
a5bc2cd48f wg_conf_path is global variable 2022-01-01 03:20:30 +03:00
Galonza Peter
72151ac6a3 db path is global variable 2022-01-01 02:57:59 +03:00
Donald Cheng Hong Zou
e2c8b3bf02 Removed Semaphore for configuration file 2021-12-31 13:29:37 -05:00
Donald Cheng Hong Zou
06dd641274 Minified all CSS and JS script 2021-12-30 15:21:25 -05:00
Donald Cheng Hong Zou
7d9bf01d27 Cleaned configuration.js
Removed unused functions and duplicated jQuery selector
2021-12-29 23:26:15 -05:00
Donald Cheng Hong Zou
b9553e0a05 Update dashboard.py
Finished refactoring some variable name
2021-12-29 16:15:00 -05:00
Donald Cheng Hong Zou
993dcaf235 Merge branch 'main' of https://github.com/donaldzou/WGDashboard 2021-12-29 15:30:52 -05:00
Donald Cheng Hong Zou
8d7c39bac4 Update dashboard.py
Wrapped all reading and writing to dashboard configuration into functions
2021-12-29 15:29:29 -05:00
Donald Zou
80933ab571 Merge pull request #124 from pgalonza/fix-variables
Fixed variables name
2021-12-29 14:57:53 -05:00
Donald Cheng Hong Zou
b5b30c8119 Update dashboard.py 2021-12-29 14:57:44 -05:00
Galonza Peter
bca06129d9 fixed variables name 2021-12-29 22:56:19 +03:00
Donald Zou
a136b86d81 Merge pull request #122 from pgalonza/change-path
Fixed variable name
2021-12-29 14:20:52 -05:00
Donald Zou
8d555d8ae7 Merge pull request #121 from pgalonza/refactoring
Refactoring
2021-12-29 13:57:21 -05:00
Donald Zou
c22e61add2 Merge branch 'main' into refactoring 2021-12-29 13:57:11 -05:00
Donald Zou
2c83f1ce57 Merge pull request #120 from pgalonza/fix-download
Fixed download configuration file for peer
2021-12-29 12:21:29 -05:00
Donald Cheng Hong Zou
f2750de153 Feature adding and UI adjustment
Added Preshared-Key to all configuration
2021-12-29 12:17:44 -05:00
Galonza Peter
e0934f11d6 Merge branch 'main' into fix-download 2021-12-29 02:00:36 +03:00
Galonza Peter
422924026a fixed variable name 2021-12-29 02:00:18 +03:00
Galonza Peter
332e22e534 Merge branch 'main' into refactoring
# Conflicts:
#	src/dashboard.py
2021-12-29 01:51:41 +03:00
Galonza Peter
c7bf30e18e pylint warnings 2021-12-29 00:59:10 +03:00
Galonza Peter
5ade5176c0 fixed download configuration file for peer 2021-12-28 22:55:52 +03:00
Donald Zou
f9e4fafe9f Merge pull request #96 from pgalonza/change-path
Added the ability to change the path for files to be saved
2021-12-27 21:05:34 -05:00
Donald Zou
201f2ef1f0 Merge branch 'main' into change-path 2021-12-27 21:05:25 -05:00
Donald Zou
32af4fdcca Merge pull request #119 from donaldzou/v3.0-beta
Finishing v3.0
2021-12-27 21:01:24 -05:00
Donald Cheng Hong Zou
d254b4cc39 Finishing v3.0 2021-12-27 21:01:02 -05:00
Galonza Peter
d0ad4e05bf general refactoring 2021-12-28 00:29:26 +03:00
Galonza Peter
c75854cb7b fixed after merge 2021-12-27 00:35:10 +03:00
Galonza Peter
8cc71913b3 fixed read configuration after merge 2021-12-26 23:17:19 +03:00
Galonza Peter
99abe6bcd2 Merge branch 'main' into change-path 2021-12-26 12:58:44 +03:00
Galonza Peter
f5ad7a49ce general refactoring 2021-12-26 12:57:57 +03:00
Donald Cheng Hong Zou
e42ecf3c99 Update wgd.sh 2021-12-25 17:45:47 -05:00
Donald Cheng Hong Zou
b58bf9dc17 Update wgd.sh 2021-12-25 17:40:53 -05:00
Donald Cheng Hong Zou
745c8aaf3e Update wgd.sh 2021-12-25 17:40:08 -05:00
Donald Cheng Hong Zou
0ca73bf80b Update wgd.sh 2021-12-25 17:38:13 -05:00
Donald Cheng Hong Zou
fd76cabd01 Update wgd.sh 2021-12-25 17:37:43 -05:00
Donald Cheng Hong Zou
fcf9300a49 Update wgd.sh 2021-12-25 17:35:36 -05:00
Donald Cheng Hong Zou
649b66ba1a Update wgd.sh 2021-12-25 17:20:52 -05:00
Donald Cheng Hong Zou
b5d73a0861 Delete hi.txt 2021-12-25 17:20:31 -05:00
Donald Cheng Hong Zou
1453996ccb Update wgd.sh 2021-12-25 17:16:50 -05:00
Donald Cheng Hong Zou
5bf9b97d70 Update wgd.sh 2021-12-25 17:15:33 -05:00
Donald Cheng Hong Zou
5c1e46f5a6 Update wgd.sh 2021-12-25 17:13:21 -05:00
Donald Cheng Hong Zou
c2665cbae8 Update wgd.sh 2021-12-25 17:13:08 -05:00
Donald Cheng Hong Zou
3934248a6b Update wgd.sh 2021-12-25 17:08:59 -05:00
Donald Cheng Hong Zou
7ae3bb5601 Testing update function 2021-12-25 17:07:33 -05:00
Donald Cheng Hong Zou
9890d4f3bc Removed using venv for now 2021-12-25 16:29:33 -05:00
Donald Cheng Hong Zou
5b47fc16d9 Update wgd.sh 2021-12-25 16:08:30 -05:00
Galonza Peter
344770a0a4 Merge branch 'main' into change-path
# Conflicts:
#	src/dashboard.py
2021-12-25 23:42:10 +03:00
Donald Cheng Hong Zou
fc11cacd24 Update wgd.sh 2021-12-25 15:20:56 -05:00
Donald Cheng Hong Zou
737ebdd0c6 Update wgd.sh 2021-12-25 15:20:04 -05:00
Galonza Peter
d06dddfa24 Merge branch 'main' into change-path 2021-12-25 23:17:40 +03:00
Donald Cheng Hong Zou
710d631ffe Update wgd.sh 2021-12-25 15:17:07 -05:00
Donald Cheng Hong Zou
7d9a845ca0 Update wgd.sh 2021-12-25 14:48:38 -05:00
Donald Cheng Hong Zou
cc6e5ffb97 Update wgd.sh 2021-12-25 14:46:47 -05:00
Donald Cheng Hong Zou
8d29cb7488 Testing Python venv 2021-12-25 14:44:14 -05:00
Donald Cheng Hong Zou
5c588ea01a Style adjustment
Adjusted style and the status light: Added box-shadow and border for connected peer
2021-12-24 00:20:44 -05:00
Donald Zou
dade9935da Merge pull request #117 from donaldzou/v3.0-Slow-Load-Fix
Slow Performance Fixed
2021-12-24 00:19:26 -05:00
Donald Cheng Hong Zou
34cd3aaaca Slow Performance Fixed 2021-12-23 21:26:24 -05:00
Donald Cheng Hong Zou
78d3f338fb Update dashboard.py 2021-12-22 11:36:29 -05:00
Donald Zou
d801c5911e Merge pull request #91 from pgalonza/todo-ipv6
Add IPv6
2021-12-22 11:35:17 -05:00
Galonza Peter
003743c074 Merge branch 'main' into gunicorn 2021-12-21 22:41:03 +03:00
Galonza Peter
4cef39d3b1 Merge branch 'main' into gunicorn-tmp
# Conflicts:
#	src/wgd.sh
2021-12-21 22:38:31 +03:00
Galonza Peter
83f0df32d7 added thread 2021-12-21 22:23:26 +03:00
Galonza Peter
24f269191c added Let’s Encrypt via certbot 2021-12-21 22:23:13 +03:00
Galonza Peter
94a0d5a0a4 refactored 2021-12-21 22:23:05 +03:00
Galonza Peter
c0fbf4dd0c optimized performance
# Conflicts:
#	src/gunicorn.conf.py
2021-12-21 22:22:37 +03:00
Galonza Peter
37b6161075 fixed check gunicorn process 2021-12-21 22:20:43 +03:00
Galonza Peter
c9b792c370 fixed update variable 2021-12-21 22:20:31 +03:00
Galonza Peter
2103d547a1 fixed initiation for gunicorn 2021-12-21 22:18:36 +03:00
Galonza Peter
3918e220d2 style 2021-12-21 22:17:32 +03:00
Galonza Peter
c3eaaed43b fixed stop 2021-12-21 22:17:07 +03:00
Galonza Peter
e0bf648076 added paths when command as root 2021-12-21 22:16:40 +03:00
Galonza Peter
bb298164e4 added gunicorn in requirements 2021-12-21 22:15:55 +03:00
Galonza Peter
898694b9be fixed gunicorn start and added stop 2021-12-21 22:15:41 +03:00
Galonza Peter
f0f9ac92e6 added gunicorn start 2021-12-21 22:15:23 +03:00
Galonza Peter
ea0229a8ab added wsgi for gunicorn 2021-12-21 22:15:08 +03:00
Donald Zou
66fc7cd91d Merge pull request #112 from reafian/main
Added MTU and PersistentKeepalive to QR code and download files
2021-12-21 14:12:42 -05:00
Donald Zou
c11d4f01b1 Merge pull request #114 from donaldzou/all-contributors/add-marneu
docs: add marneu as a contributor for code
2021-12-21 13:54:03 -05:00
Donald Zou
a8f498f292 Merge pull request #113 from donaldzou/marneu-main
Marneu main
2021-12-21 13:53:51 -05:00
allcontributors[bot]
6854e2275f docs: update .all-contributorsrc [skip ci] 2021-12-21 18:53:40 +00:00
allcontributors[bot]
6662e79ac5 docs: update README.md [skip ci] 2021-12-21 18:53:39 +00:00
Donald Cheng Hong Zou
9e77430634 Added Slash 2021-12-21 13:52:08 -05:00
Richard Newton
b8e070824a Update get_conf.html
Added MTU and PersistentKeepalive back into QR Code.

Update dashboard.py

Added MTU and PersistentKeepalive to downloaded file.
2021-12-21 16:48:11 +00:00
Donald Cheng Hong Zou
304d4293f3 Update wgd.sh 2021-12-20 19:54:53 -05:00
Donald Zou
a03e7f5b53 Merge pull request #111 from donaldzou/marneu-main
Marneu main
2021-12-19 18:18:50 -05:00
Donald Zou
ea57c8cad4 Merge branch 'main' into marneu-main 2021-12-19 18:18:45 -05:00
Donald Cheng Hong Zou
280802cf74 Update .gitignore 2021-12-19 18:16:45 -05:00
Donald Cheng Hong Zou
fbce01d846 Update .gitignore 2021-12-19 18:15:51 -05:00
Markus Neubauer
591b60c336 Update wgd.sh
a more automated approach to systemctl
2021-12-19 18:13:15 -05:00
Markus Neubauer
78ef870d91 Update wg-dashboard.service
A more automated approach
2021-12-19 18:13:15 -05:00
Donald Zou
bc19d82aed Merge pull request #105 from marneu/patch-1
An automated way to a systemctl unit
2021-12-19 18:07:35 -05:00
Donald Zou
79b41e1056 Update README.md 2021-12-06 14:15:22 -05:00
Markus Neubauer
805f03d231 Update .gitignore 2021-11-25 16:03:09 +01:00
Donald Zou
62acc1081f Update README.md 2021-11-19 14:48:46 -05:00
Donald Zou
257a2c2d9f Update README.md 2021-11-19 14:45:37 -05:00
Donald Zou
ed9b05cdf9 Update README.md 2021-11-19 14:44:40 -05:00
Donald Zou
2cc6fbd643 Update README.md 2021-11-10 11:40:46 -05:00
Galonza Peter
bdfc260dd2 fixed 2021-10-24 13:32:21 +03:00
Galonza Peter
7ad65956c9 fixed, if dir is exists 2021-10-24 12:45:08 +03:00
Galonza Peter
b3dc60b7ca fixed check ipv6 dns 2021-10-24 12:05:14 +03:00
Galonza Peter
bed08109fa not needed 2021-10-24 02:10:20 +03:00
Galonza Peter
06cedec090 mistake 2021-10-24 01:58:59 +03:00
Galonza Peter
1d2c468d03 fixed, when database does not create, if no directory 2021-10-24 01:51:04 +03:00
Galonza Peter
e84616f5f5 added the ability to change the path for files to be saved 2021-10-24 00:56:34 +03:00
Galonza Peter
caa9a90476 added dual-stack 2021-10-17 22:55:08 +03:00
Galonza Peter
62be683dd8 fixed search ipv6 in the string with comma 2021-10-17 21:13:18 +03:00
Galonza Peter
ffa63b3f82 completed todo. Added IPv6 2021-10-17 20:22:27 +03:00
Galonza Peter
c5a7788394 optimized pattern 2021-10-17 20:01:16 +03:00
Donald Zou
99c42ff2c1 Merge pull request #90 from pike00/pike00-update-readme
Updated README to include username/password
2021-10-14 10:14:38 -04:00
Will Pike
fd2b7bb917 Updated README to include username/password
Updated Installation instructions to include default username/password in step 6 on login. It is located in the 'Dashboard Configuration' section, however for readability/ease of setting up the server, I added the default login to the install instructions.
2021-10-14 10:10:17 -04:00
Donald Cheng Hong Zou
922a494df0 Finished 2021-09-09 12:50:38 -04:00
Donald Cheng Hong Zou
c478ec0095 Update README.md 2021-09-09 12:45:09 -04:00
Donald Cheng Hong Zou
3abbe17910 Naming changed 2021-09-09 12:43:49 -04:00
Donald Zou
349076599f Merge pull request #80 from ikidd/patch-1
Fixed service unit file spelling error
2021-09-09 12:35:44 -04:00
ikidd
92d299507f Fixed service unit file spelling error 2021-09-08 20:36:53 -06:00
Donald Cheng Hong Zou
6f2d61e918 Update README.md 2021-09-08 22:02:33 -04:00
Donald Cheng Hong Zou
ed13babf6a Merge branch 'main' of https://github.com/donaldzou/Wireguard-Dashboard into main 2021-09-08 22:01:01 -04:00
Donald Cheng Hong Zou
80db82eb93 Update dashboard.py 2021-09-08 22:00:53 -04:00
Donald Zou
8d20334d6e Update README.md 2021-09-08 21:59:15 -04:00
Donald Zou
03a95ad018 Merge pull request #79 from donaldzou/v2.3.1
Update README.md
2021-09-08 21:58:02 -04:00
Donald Cheng Hong Zou
aa59cc8af0 Update README.md 2021-09-08 21:57:50 -04:00
Donald Zou
80d63c2c89 Merge pull request #78 from donaldzou/v2.3.1
Changed dashboard naming to WGDashboard
2021-09-08 21:56:48 -04:00
Donald Cheng Hong Zou
03a4acd72b Changed dashboard naming to WGDashboard 2021-09-08 21:56:31 -04:00
Donald Cheng Hong Zou
53118cf660 Merge branch 'main' of https://github.com/donaldzou/Wireguard-Dashboard into main 2021-09-08 16:58:40 -04:00
Donald Cheng Hong Zou
16b1baf81e Update README.md 2021-09-08 16:58:36 -04:00
Donald Zou
960e0d0965 Update README.md 2021-09-08 14:50:26 -04:00
Donald Zou
8f41222e43 Merge pull request #77 from donaldzou/v2.3
Update README.md
2021-09-08 12:43:09 -04:00
Donald Cheng Hong Zou
e7bc447166 Update README.md 2021-09-08 12:42:50 -04:00
Donald Zou
1736359615 Merge pull request #76 from donaldzou/v2.3
V2.3
2021-09-08 12:42:11 -04:00
Donald Cheng Hong Zou
58784b1e22 v2.3 Final Commit 2021-09-08 12:39:25 -04:00
Donald Zou
07f2bfd279 Merge pull request #75 from donaldzou/all-contributors/add-davejlong
docs: add davejlong as a contributor for code
2021-09-08 11:24:04 -04:00
allcontributors[bot]
6d62db2890 docs: update .all-contributorsrc [skip ci] 2021-09-08 15:23:38 +00:00
allcontributors[bot]
a1b23c4aab docs: update README.md [skip ci] 2021-09-08 15:23:37 +00:00
Donald Zou
e272a096da Merge pull request #74 from donaldzou/all-contributors/add-reafian
docs: add reafian as a contributor for code
2021-09-05 16:38:57 -04:00
allcontributors[bot]
b8ca24c5bf docs: update .all-contributorsrc [skip ci] 2021-09-05 20:38:34 +00:00
allcontributors[bot]
a05d09f0de docs: update README.md [skip ci] 2021-09-05 20:38:33 +00:00
Donald Zou
1807a79c4f Create FUNDING.yml 2021-09-04 17:16:31 -04:00
Donald Cheng Hong Zou
77f6826af9 Adjusted UI and edit readme 2021-09-03 17:32:51 -04:00
Donald Cheng Hong Zou
7e39eedf35 Update wgd.sh 2021-09-03 14:40:57 -04:00
Donald Cheng Hong Zou
0b4b48ceae Update wgd.sh 2021-09-03 14:30:13 -04:00
Donald Cheng Hong Zou
dad931e898 Update wgd.sh 2021-09-03 14:26:27 -04:00
Donald Cheng Hong Zou
2e387730cb Update wgd.sh 2021-09-03 14:26:05 -04:00
Donald Cheng Hong Zou
c9b6775793 Update wgd.sh 2021-09-03 14:24:38 -04:00
Donald Cheng Hong Zou
a6eaf30c2b Update wgd.sh 2021-09-03 14:24:14 -04:00
Donald Cheng Hong Zou
6f91d199d8 Update wgd.sh 2021-09-03 14:23:08 -04:00
Donald Cheng Hong Zou
7ea486307a Update wgd.sh 2021-09-03 14:22:14 -04:00
Donald Cheng Hong Zou
37d254c827 Update wgd.sh 2021-09-03 13:55:41 -04:00
Donald Cheng Hong Zou
b4014eb317 Update wgd.sh 2021-09-03 13:55:03 -04:00
Donald Cheng Hong Zou
c7824fa184 Update wgd.sh 2021-09-03 13:52:23 -04:00
Donald Cheng Hong Zou
13c5bd45f9 Update wgd.sh 2021-09-02 22:52:22 -04:00
Donald Cheng Hong Zou
465d102bd0 Update wgd.sh 2021-09-02 22:52:01 -04:00
Donald Cheng Hong Zou
93007cd56c Update wgd.sh 2021-09-02 22:27:05 -04:00
Donald Cheng Hong Zou
8367576dc8 Update wgd.sh 2021-09-02 22:24:40 -04:00
Donald Cheng Hong Zou
dbc06145b3 Update wgd.sh 2021-09-02 22:24:07 -04:00
Donald Cheng Hong Zou
4efcf0e7c8 Update wgd.sh 2021-09-02 22:13:00 -04:00
Donald Cheng Hong Zou
0a4bbc1106 Update wgd.sh 2021-09-02 22:09:06 -04:00
Donald Cheng Hong Zou
b08c1f6699 Updated requirement.txt and wgd.sh 2021-09-02 21:56:50 -04:00
Donald Cheng Hong Zou
6828b905ef Added checking if peers removed directly from config file by not from dashboard, and fixed DNS did not get check from editing peers 2021-08-24 21:04:01 -04:00
Donald Zou
f72b405f6d Merge pull request #64 from Kofl/patch-1
Update typo3 fix
2021-08-24 20:19:22 -04:00
Donald Zou
27ae99864c Merge pull request #71 from donaldzou/v2.2.2
v2.2.2 Merge
2021-08-24 20:16:21 -04:00
Donald Cheng Hong Zou
82ba15ba5a Small fix on HTML files 2021-08-24 20:15:28 -04:00
Kofl
af01db7bc9 Update typo3 fix
TOTAL RECIEVED replaced with TOTAL RECEIVED
2021-08-18 21:46:06 +02:00
Donald Cheng Hong Zou
6ec0a65d0c Update README.md 2021-08-16 15:32:14 -04:00
Donald Zou
c32ccfc9ed Merge pull request #51 from donaldzou/v2.2.1
V2.2.1
2021-08-16 15:29:49 -04:00
Donald Cheng Hong Zou
ef818388c8 Update dashboard.py 2021-08-16 15:28:43 -04:00
Donald Cheng Hong Zou
f5aa45a3e1 Update README.md 2021-08-16 15:27:10 -04:00
Donald Cheng Hong Zou
b7a047a743 Bug fixed 2021-08-16 15:26:15 -04:00
Donald Zou
05ec985453 Update README.md 2021-08-16 12:23:56 -04:00
Donald Cheng Hong Zou
88ed9c3e79 Update README.md 2021-08-15 02:23:35 -04:00
Donald Zou
3fb03c8dfe Update README.md 2021-08-15 00:16:36 -04:00
Donald Zou
ff304027cd Merge pull request #46 from donaldzou/v2.2-beta
V2.2 pull request
2021-08-14 23:57:07 -04:00
Donald Cheng Hong Zou
3140d46c94 Finalizing the documentation 2021-08-14 23:43:30 -04:00
Donald Cheng Hong Zou
9d476af384 v2.2beta almost done!!!!! 2021-08-14 23:30:05 -04:00
Donald Cheng Hong Zou
0d380672f3 v2.2 beta 4 2021-08-14 17:13:16 -04:00
Donald Cheng Hong Zou
e2fb8dca5b Update README.md 2021-08-06 00:08:30 -04:00
Donald Cheng Hong Zou
eaba4c90c5 Edit Readme 2021-08-06 00:00:32 -04:00
Donald Cheng Hong Zou
b4ca7373f3 Update Readme 2021-08-05 23:47:18 -04:00
Donald Cheng Hong Zou
905c068ed5 v2.2-beta4
Finished testing the QR code function and finish debugging the peer file download function.
2021-08-05 23:15:50 -04:00
Donald Cheng Hong Zou
02886dd420 Remove public and private key txt 2021-08-05 01:39:32 -04:00
Donald Cheng Hong Zou
5bf7754d6c Update README.md 2021-08-05 01:21:44 -04:00
Donald Cheng Hong Zou
7a0a3055c4 Update README.md 2021-08-05 01:16:22 -04:00
Donald Cheng Hong Zou
bf73efb3b4 Update README.md 2021-08-05 01:15:17 -04:00
Donald Cheng Hong Zou
b4da212158 Update README.md 2021-08-05 01:07:10 -04:00
Donald Cheng Hong Zou
4a04d42600 v2.2-beta3
Finished QR code function and starting to test.
2021-08-05 00:45:15 -04:00
Donald Cheng Hong Zou
42bbfbe538 v2.2-beta update 2021-08-03 18:45:40 -04:00
Donald Cheng Hong Zou
31ec2430c4 Update README.md 2021-08-03 18:06:43 -04:00
Donald Cheng Hong Zou
f0b56c9f1d Update README.md 2021-08-03 18:06:22 -04:00
Donald Zou
6f9f01c991 Update README.md 2021-07-12 16:35:07 -04:00
Donald Cheng Hong Zou
b822ccb19d Update README.md 2021-07-11 13:07:27 -04:00
Donald Zou
dcb11671f3 Update README.md 2021-07-11 12:49:58 -04:00
Donald Zou
282599d36f Update README.md 2021-07-05 16:09:02 -04:00
Donald Zou
f11acdc68f Update README.md 2021-07-05 15:35:23 -04:00
Donald Zou
971e127cfd Update README.md 2021-07-03 10:30:54 -04:00
Donald Zou
9b2c59d529 Delete wg0.conf 2021-07-02 14:35:34 -04:00
Donald Zou
14dc049a66 Update README.md 2021-07-02 14:31:33 -04:00
Donald Zou
d3d0e7c615 Merge pull request #24 from donaldzou/v2.1-beta
v2.1 Merge
2021-07-02 13:28:36 -04:00
Donald Zou
89423ccb8b Merge branch 'main' into v2.1-beta 2021-07-02 13:28:29 -04:00
Donald Cheng Hong Zou
746f31f70c Update README.md 2021-07-02 13:25:35 -04:00
Donald Cheng Hong Zou
3aa9eab2bd Commit June 2 2021-07-02 13:23:04 -04:00
Donald Zou
1bcc8fed5e Update README.md 2021-07-02 12:00:12 -04:00
Donald Zou
1213a030e3 Update README.md 2021-05-13 19:54:37 -04:00
Donald Zou
3b2344b477 Delete .github/workflows directory 2021-05-13 19:51:54 -04:00
Donald Zou
c53b0fe2d4 Create main.yml 2021-05-13 19:38:22 -04:00
Donald Cheng Hong Zou
0a92269456 v2.0-beta-6 Commit 2021-05-13 18:47:59 -04:00
Donald Cheng Hong Zou
1cb8906893 v2.0-beta-6 Commit 2021-05-13 18:21:10 -04:00
Donald Cheng Hong Zou
f76579fe5e v2.0-beta-6 Commit 2021-05-13 18:00:40 -04:00
Donald Zou
db05ff5e98 Update README.md 2021-05-08 12:35:22 -04:00
Donald Zou
a05d6979ec Update README.md 2021-05-07 15:27:37 -04:00
Donald Zou
be40d17172 Update README.md 2021-05-07 15:25:23 -04:00
Donald Zou
9e11339979 Update README.md 2021-05-06 11:20:28 -04:00
Donald Zou
a56129afe0 Update README.md 2021-05-05 17:25:23 -04:00
Donald Zou
8933ea999c Update README.md 2021-05-05 15:52:13 -04:00
Donald Zou
ae3b8f6494 Merge pull request #19 from donaldzou/v2.0-beta-6
v2.0 merge to main
2021-05-05 15:29:41 -04:00
Donald Cheng Hong Zou
33487ee03f v2.0-beta-6 Commit 2021-05-05 15:16:32 -04:00
470 changed files with 54398 additions and 1659 deletions

View File

@@ -1,34 +0,0 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"contributors": [
{
"login": "antonioag95",
"name": "antonioag95",
"avatar_url": "https://avatars.githubusercontent.com/u/30556866?v=4",
"profile": "https://github.com/antonioag95",
"contributions": [
"test",
"code"
]
},
{
"login": "tonjo",
"name": "tonjo",
"avatar_url": "https://avatars.githubusercontent.com/u/4726289?v=4",
"profile": "https://github.com/tonjo",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,
"projectName": "wireguard-dashboard",
"projectOwner": "donaldzou",
"repoType": "github",
"repoHost": "https://github.com",
"skipCi": true
}

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
.git
.github
*.md
tests/
docs/

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: [donaldzou]
patreon: DonaldDonnyZou

31
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "pip"
directory: "/src"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/.github"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "daily"
- package-ecosystem: "docker-compose"
directory: "/docker"
schedule:
interval: "daily"

71
.github/workflows/codeql-analyze.yaml vendored Normal file
View File

@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '30 5 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

109
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,109 @@
name: Docker Build and Push
on:
workflow_dispatch:
push:
branches:
- 'main'
tags:
- '*'
release:
types: [ published ]
env:
DOCKERHUB_PREFIX: docker.io
GITHUB_CONTAINER_PREFIX: ghcr.io
DOCKER_IMAGE: WGDashboard
jobs:
docker_build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKERHUB_PREFIX }}
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITHUB_CONTAINER_PREFIX }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: |
- linux/amd64
- linux/arm64
- linux/arm/v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta by docs https://github.com/docker/metadata-action
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_PREFIX }}/donaldzou/${{ env.DOCKER_IMAGE }}
${{ env.GITHUB_CONTAINER_PREFIX }}/${{ github.repository_owner }}/${{ env.DOCKER_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=sha,format=short,prefix=
- name: Build and export (multi-arch)
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
docker_scan:
if: ${{ github.event_name != 'pull_request' }}
runs-on: ubuntu-latest
needs: docker_build
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKERHUB_PREFIX }}
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Docker Scout CVEs
uses: docker/scout-action@v1
with:
command: cves
image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:main
only-severities: critical,high
only-fixed: true
write-comment: true
github-token: ${{ secrets.GITHUB_TOKEN }}
exit-code: true
- name: Docker Scout Compare
uses: docker/scout-action@v1
with:
command: compare
# Set to Github for maximum compat
image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:main
to: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ env.DOCKER_IMAGE }}:latest
only-severities: critical,high
ignore-unchanged: true
github-token: ${{ secrets.GITHUB_TOKEN }}

26
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
workflow_dispatch:
schedule:
- cron: '00 08 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has not been updated for 20 days'
stale-pr-message: 'This pull request has not been updated for 20 days'
stale-issue-label: 'stale'
exempt-issue-labels: 'enhancement,ongoing'
days-before-stale: 20

54
.gitignore vendored
View File

@@ -1,12 +1,52 @@
.vscode/sftp.json
src/.vscode/sftp.json
.vscode
.DS_Store
wg.db
*.json
.idea
src/test.py
tmp
src/db
__pycache__
src/wg-dashboard.ini
src/test.py
*.db
src/wg-dashboard.ini
src/static/pic.xd
*.conf
private_key.txt
public_key.txt
venv/**
log/**
release/*
src/db/wgdashboard.db
.jshintrc
node_modules/**
*/proxy.js
src/static/app/proxy.js
.secrets
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
.vite/*

261
README.md
View File

@@ -1,192 +1,87 @@
<p align="center">
<img src="https://raw.githubusercontent.com/donaldzou/wireguard-dashboard/main/img/Group%202.png" width="128">
</p>
<h1 align="center"> Wireguard Dashboard</h1>
> [!TIP]
> 🎉 I'm excited to announce that WGDashboard is officially listed on DigitalOcean's Marketplace! For more information, please visit [Host WGDashboard & WireGuard with DigitalOcean](https://docs.wgdashboard.dev/host-wgdashboard-wireguard-with-digitalocean.html) for more information!
> [!NOTE]
> **Help Wanted 🎉**: Localizing WGDashboard to other languages! If you're willing to help, please visit https://github.com/WGDashboard/WGDashboard/issues/397. Many thanks!
![](https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Posters/Banner.png)
<p align="center">
<img src="http://ForTheBadge.com/images/badges/made-with-python.svg">
<img alt="WGDashboard" src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Logos/Logo-2-Rounded-512x512.png" width="128">
</p>
<h1 align="center">
<a href="https://wgdashboard.dev">WGDashboard</a>
</h1>
<p align="center">
<img src="https://img.shields.io/badge/Made_With-Python-blue?style=for-the-badge&logo=python&logoColor=ffffff">
<img src="https://img.shields.io/badge/Made_With-Vue.js-42b883?style=for-the-badge&logo=vuedotjs&logoColor=ffffff">
<img src="https://img.shields.io/badge/License-Apache_License_2.0-D22128?style=for-the-badge&logo=apache&logoColor=ffffff">
</p>
<p align="center">
<a href="https://github.com/WGDashboard/WGDashboard/releases/latest"><img src="https://img.shields.io/github/v/release/donaldzou/wireguard-dashboard?style=for-the-badge"></a>
<a href="https://wakatime.com/badge/github/donaldzou/WGDashboard"><img src="https://wakatime.com/badge/github/donaldzou/WGDashboard.svg?style=for-the-badge" alt="wakatime"></a>
<a href="https://hitscounter.dev"><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Fgithub.com%2Fdonaldzou%2FWGDashboard&label=Visitor&icon=github&color=%230a58ca&style=for-the-badge"></a>
<img src="https://img.shields.io/docker/pulls/donaldzou/wgdashboard?logo=docker&label=Docker%20Image%20Pulls&labelColor=ffffff&style=for-the-badge">
</p>
<p align="center"><b>This project is supported by</b></p>
<p align="center">
<a href="https://m.do.co/c/a84cb9aac585">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
</a>
</p>
<p align="center">Monitoring WireGuard is not convenient, in most case, you'll need to login to your server and type <code>wg show</code>. That's why this project is being created, to view and manage all WireGuard configurations in a easy way.</p>
<p align="center">With all these awesome features, while keeping it <b>easy to install and use</b></p>
<p align="center"><b><i>This project is not affiliate to the official WireGuard Project</i></b></p>
<h3 align="center">Looking for help or want to chat about this project?</h4>
<p align="center">
You can reach out at
</p>
<p align="center">
<a href="https://github.com/donaldzou/wireguard-dashboard/releases/latest"><img src="https://img.shields.io/github/v/release/donaldzou/wireguard-dashboard"></a>
<a align="center" href="https://discord.gg/72TwzjeuWm" target="_blank"><img src="https://img.shields.io/discord/1276818723637956628?labelColor=ffffff&style=for-the-badge&logo=discord&label=Discord"></a>
<a align="center" href="https://www.reddit.com/r/WGDashboard/" target="_blank"><img src="https://img.shields.io/badge/Reddit-r%2FWGDashboard-FF4500?style=for-the-badge&logo=reddit"></a>
<a align="center" href="https://app.element.io/#/room/#wgd:matrix.org" target="_blank"><img src="https://img.shields.io/badge/Matrix_Chatroom-%23WGD-000000?style=for-the-badge&logo=matrix"></a>
</p>
<h3 align="center">Want to support this project?</h4>
<p align="center">
You can support via <br>
</p>
<p align="center">
<a align="center" href="https://github.com/sponsors/donaldzou" target="_blank"><img src="https://img.shields.io/badge/GitHub%20Sponsor-2e9a40?style=for-the-badge&logo=github"></a>
<a align="center" href="https://buymeacoffee.com/donaldzou" target="_blank"><img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-ffdd00?style=for-the-badge&logo=buymeacoffee&logoColor=000000"></a>
<a align="center" href="https://patreon.com/c/DonaldDonnyZou/membership" target="_blank"><img src="https://img.shields.io/badge/Patreon-000000?style=for-the-badge&logo=patreon&logoColor=ffffff"></a>
</p>
<p align="center">Monitoring Wireguard is not convinient, need to login into server and type <code>wg show</code>. That's why this platform is being created, to view all configurations and manage them in a easier way.</p>
## 📣 What's New: Version 2.0
### ⚠️ **Update from v1.x.x**
1. Stop the dashboard if it is running.
2. You can use `git pull https://github.com/donaldzou/Wireguard-Dashboard.git v2.0` to get the new update inside `Wireguard-Dashboard` directory.
3. Proceed **Step 2 & 3** in the Install step down below.
<p align="center">
<b>or, visit our merch store and support us by purchasing a merch for only $USD 17.00 (Including shipping worldwide & duties)</b>
</p>
<p align="center">
<a align="center" href="https://merch.wgdashboard.dev" target="_blank"><img src="https://img.shields.io/badge/Merch%20from%20WGDashboard-926183?style=for-the-badge"></a>
</p>
<hr>
- Added login function to dashboard
- ***I'm not using the most ideal way to store the username and password, feel free to provide a better way to do this if you any good idea!***
- Added a config file to the dashboard
- Dashboard config can be change within the **Setting** tab on the side bar
- Adjusted UI
- And much more!
## 💡 Features
- Add peers for each WireGuard configuration
- Manage peer
- Delete peers
- And many more coming up! Welcome to contribute to this project!
## 📝 Requirement
- Ubuntu or Debian based OS, other might work, but haven't test yet. Tested on the following OS:
- [x] Ubuntu 18.04.1 LTS
- [ ] If you have tested on other OS and it works perfectly please provide it to me!
- ‼️ Make sure you have **Wireguard** and **Wireguard-Tools (`wg-quick`)** installed.‼️ <a href="https://www.wireguard.com/install/">How to install?</a>
- Configuration files under **/etc/wireguard**
- **Note: For peers, `PublicKey` & `AllowedIPs` is required.**
- Python 3.7+ & Pip3
```
$ sudo apt-get install python3 python3-pip
```
## 🛠 Install
1. Download Wireguard Dashboard
```
$ git clone -b v2.0 https://github.com/donaldzou/Wireguard-Dashboard.git
```
**2. Install Python Dependencies**
```
$ cd Wireguard-Dashboard/src
$ python3 -m pip install -r requirements.txt
```
**3. Install & run Wireguard Dashboard**
```
$ sudo sh wgd.sh start
```
Access your server with port `10086` ! e.g (http://your_server_ip:10086), continue to read to on how to change port and ip that dashboard is running with.
## 🪜 Usage
**1. Start/Stop/Restart Wireguard Dashboard**
```
$ cd Wireguard-Dashboard/src
$ sudo sh wgd.sh start # Start the dashboard in background
$ sudo sh wgd.sh debug # Start the dashboard in foreground (debug mode)
$ sudo sh wgd.sh stop # Stop the dashboard
$ sudo sh wgd.sh restart # Restart the dasboard
$ sudo sh wgd.sh update # Update the dashboard
```
⚠️ **For first time user please also read the next section.**
## ✂️ Dashboard Configuration
Since version 2.0, Wireguard Dashboard will be using a configuration file called `wg-dashboard.ini`, (It will generate automatically after first time running the dashboard). More options will include in future versions, and for now it included the following config:
### `[Account]`
`username` - Username (Default: `admin`)
`password` - Password, will be hash with SHA256 (Default: `admin`).
### `[Server]`
`wg_conf_path` - The path of all the Wireguard configurations (Default: `/etc/wireguard`)
`app_ip` - IP address the flask will run with (Default: `0.0.0.0`)
`app_port` - Port the flask will run with (Default: `10086`)
`auth_req` - Does the dashboard need authentication (Default: `true`)
- If `auth_req = false` , user will not be access the **Setting** tab due to security consideration. **User can only change the file directly in system**.
`version` - Dashboard Version
All these settings will be able to configure within the dashboard in **Settings** on the sidebar, without changing the actual file. **Except `version` and `auth_req` due to security consideration.**
## ❓ How to update the dashboard?
```
$ cd wireguard-dashboard
$ sudo sh wgd.sh update # Perform update
$ sudo sh wgd.sh start # Start dashboard
```
## 🔍 Screenshot
![Index Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/index.png)
<p align=center>Index Page</p>
![Signin Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/signin.png)
<p align=center>Signin Page</p>
![Configuration Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/configuration.png)
<p align=center>Configuration Page</p>
![Settings Image](https://github.com/donaldzou/Wireguard-Dashboard/raw/main/src/static/settings.png)
<p align=center>Settings Page</p>
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/antonioag95"><img src="https://avatars.githubusercontent.com/u/30556866?v=4?s=100" width="100px;" alt=""/><br /><sub><b>antonioag95</b></sub></a><br /><a href="https://github.com/donaldzou/wireguard-dashboard/commits?author=antonioag95" title="Tests">⚠️</a> <a href="https://github.com/donaldzou/wireguard-dashboard/commits?author=antonioag95" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/tonjo"><img src="https://avatars.githubusercontent.com/u/4726289?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tonjo</b></sub></a><br /><a href="https://github.com/donaldzou/wireguard-dashboard/commits?author=tonjo" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
<h4 align="center">
for more information, visit our
</h4>
<h1 align="center">
<a href="https://wgdashboard.dev">Official Website</a>
</h1>
# Screenshots
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/sign-in.png" alt=""/>
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/cross-server.png" alt=""/>
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/index.png" alt=""/>
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/new-configuration.png" alt="" />
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/settings.png" alt="" />
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/light-dark.png" alt="" />
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/configuration.png" alt=""/>
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/add-peers.png" alt="" />
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/ping.png" alt=""/>
<img src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/traceroute.png" alt=""/>

10
SECURITY.md Normal file
View File

@@ -0,0 +1,10 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |

View File

@@ -0,0 +1,76 @@
FROM golang:1.24 AS awg-go
RUN git clone https://github.com/WGDashboard/amneziawg-go /awg
WORKDIR /awg
RUN go mod download && \
go mod verify && \
go build -ldflags '-linkmode external -extldflags "-fno-PIC -static"' -v -o /usr/bin
FROM alpine:latest AS awg-tools
RUN apk update && apk add --no-cache \
make git build-base linux-headers \
&& git clone https://github.com/WGDashboard/amneziawg-tools \
&& cd amneziawg-tools/src \
&& make \
&& chmod +x wg*
FROM alpine:latest
LABEL maintainer="dselen@nerthus.nl"
RUN apk update && apk add --no-cache \
iproute2 iptables bash curl wget unzip procps sudo \
tzdata wireguard-tools python3 py3-psutil py3-bcrypt openresolv
COPY --from=awg-go /usr/bin/amneziawg-go /usr/bin/amneziawg-go
COPY --from=awg-tools /amneziawg-tools/src/wg /usr/bin/awg
COPY --from=awg-tools /amneziawg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick
# Declaring environment variables, change Peernet to an address you like, standard is a 24 bit subnet.
ARG wg_net="10.0.0.1" \
wg_port="51820"
# Following ENV variables are changable on container runtime because /entrypoint.sh handles that. See compose.yaml for more info.
ENV TZ="Europe/Amsterdam" \
global_dns="9.9.9.9" \
wgd_port="10086" \
public_ip=""
# Using WGDASH -- like wg_net functionally as a ARG command. But it is needed in entrypoint.sh so it needs to be exported as environment variable.
ENV WGDASH=/opt/wgdashboard
# Doing WireGuard Dashboard installation measures. Modify the git clone command to get the preferred version, with a specific branch for example.
RUN mkdir /data \
&& mkdir /configs \
&& mkdir -p ${WGDASH}/src \
&& mkdir -p /etc/amnezia/amneziawg
COPY ./src ${WGDASH}/src
# Generate basic WireGuard interface. Echoing the WireGuard interface config for readability, adjust if you want it for efficiency.
# Also setting the pipefail option, verbose: https://github.com/hadolint/hadolint/wiki/DL4006.
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN out_adapt=$(ip -o -4 route show to default | awk '{print $NF}') \
&& echo -e "[Interface]\n\
Address = ${wg_net}/24\n\
PrivateKey =\n\
PostUp = iptables -t nat -I POSTROUTING 1 -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE\n\
PostUp = iptables -I FORWARD -i wg0 -o wg0 -j DROP\n\
PreDown = iptables -t nat -D POSTROUTING -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE\n\
PreDown = iptables -D FORWARD -i wg0 -o wg0 -j DROP\n\
ListenPort = ${wg_port}\n\
SaveConfig = true\n\
DNS = ${global_dns}" > /configs/wg0.conf.template \
&& chmod 600 /configs/wg0.conf.template
# Defining a way for Docker to check the health of the container. In this case: checking the gunicorn process.
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD sh -c 'pgrep gunicorn > /dev/null && pgrep tail > /dev/null' || exit 1
# Copy the basic entrypoint.sh script.
COPY ./docker/entrypoint.sh /entrypoint.sh
# Exposing the default WireGuard Dashboard port for web access.
EXPOSE 10086
WORKDIR $WGDASH
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]

125
docker/Dockerfile Normal file
View File

@@ -0,0 +1,125 @@
#
# AWG GOLANG BUILDING STAGE
# Base: Alpine
#
FROM golang:1.25-alpine AS awg-go
RUN apk add --no-cache \
git \
gcc \
musl-dev
# Standard working directory for WGDashboard
RUN mkdir -p /workspace && \
git clone https://github.com/WGDashboard/amneziawg-go /workspace/awg
ENV CGO_ENABLED=1
WORKDIR /workspace/awg
RUN go mod download && \
go mod verify && \
go build -ldflags '-linkmode external -extldflags "-fno-PIC -static"' -v -o /usr/bin
#
# AWG TOOLS BUILDING STAGE
# Base: Debian
#
FROM alpine:latest AS awg-tools
RUN apk add --no-cache \
make \
git \
build-base \
linux-headers \
ca-certificates
RUN mkdir -p /workspace && \
git clone https://github.com/WGDashboard/amneziawg-tools /workspace/awg-tools
WORKDIR /workspace/awg-tools/src
RUN make && chmod +x wg*
#
# PIP DEPENDENCY BUILDING
# Base: Alpine
#
FROM python:3.13-alpine AS pip-builder
RUN apk add --no-cache \
build-base \
pkgconfig \
python3-dev \
libffi-dev \
linux-headers \
rust \
cargo \
&& mkdir -p /opt/wgdashboard/src \
&& python3 -m venv /opt/wgdashboard/src/venv
COPY ./src/requirements.txt /opt/wgdashboard/src
RUN . /opt/wgdashboard/src/venv/bin/activate && \
pip3 install --upgrade pip && \
pip3 install -r /opt/wgdashboard/src/requirements.txt
#
# WGDashboard RUNNING STAGE
# Base: Alpine
#
FROM python:3.13-alpine AS final
LABEL maintainer="dselen@nerthus.nl"
# Install only the runtime dependencies
RUN apk add --no-cache \
iproute2 iptables \
bash curl \
wget unzip \
procps sudo \
tzdata wireguard-tools \
openresolv openrc
# Copy only the final binaries from the builders
COPY --from=awg-go /usr/bin/amneziawg-go /usr/bin/amneziawg-go
COPY --from=awg-tools /workspace/awg-tools/src/wg /usr/bin/awg
COPY --from=awg-tools /workspace/awg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick
# Environment variables
ARG wg_net="10.0.0.1"
ARG wg_port="51820"
ENV TZ="Europe/Amsterdam" \
global_dns="9.9.9.9" \
wgd_port="10086" \
public_ip="" \
WGDASH=/opt/wgdashboard
# Create directories
RUN mkdir /data /configs -p ${WGDASH}/src /etc/amnezia/amneziawg
# Copy app source and prebuilt venv only (no pip cache)
COPY ./src ${WGDASH}/src
COPY --from=pip-builder /opt/wgdashboard/src/venv /opt/wgdashboard/src/venv
# WireGuard interface template
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN out_adapt=$(ip -o -4 route show to default | awk '{print $NF}') \
&& echo -e "[Interface]\n\
Address = ${wg_net}/24\n\
PrivateKey =\n\
PostUp = iptables -t nat -I POSTROUTING 1 -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE\n\
PostUp = iptables -I FORWARD -i wg0 -o wg0 -j DROP\n\
PreDown = iptables -t nat -D POSTROUTING -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE\n\
PreDown = iptables -D FORWARD -i wg0 -o wg0 -j DROP\n\
ListenPort = ${wg_port}\n\
SaveConfig = true\n\
DNS = ${global_dns}" > /configs/wg0.conf.template \
&& chmod 600 /configs/wg0.conf.template
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD sh -c 'pgrep gunicorn > /dev/null && pgrep tail > /dev/null' || exit 1
COPY ./docker/entrypoint.sh /entrypoint.sh
EXPOSE 10086
WORKDIR $WGDASH/src
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]

208
docker/README.md Normal file
View File

@@ -0,0 +1,208 @@
# WGDashboard Docker Explanation:
Author: @DaanSelen<br>
This document delves into how the WGDashboard Docker container has been built.<br>
Of course there are two stages (simply said), one before run-time and one at/after run-time.<br>
The `Dockerfile` describes how the container image is made, and the `entrypoint.sh` is executed after running the container. <br>
In this example, WireGuard is integrated into the container itself, so it should be a run-and-go(/out-of-the-box).<br>
For more details on the source-code specific to this Docker image, refer to the source files, they have lots of comments.
<br>
<img
src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Logos/Logo-2-Rounded-512x512.png"
alt="WG-Dashboard Logo"
title="WG-Dashboard Logo"
style="display: block; margin: 0 auto;"
width="150"
height="150"
/>
<br>
To get the container running you either pull the image from the repository, (docker.io)`donaldzou/wgdashboard:latest`.<br>
From there either use the environment variables describe below as parameters or use the Docker Compose file: `compose.yaml`.<br>
Be careful, the default generated WireGuard configuration file uses port 51820/udp. So use this port if you want to use it out of the box.<br>
Otherwise edit the configuration file in `/etc/wireguard/wg0.conf`.
# WGDashboard: 🐳 Docker Deployment Guide
To run the container, you can either pull the image from Docker Hub or build it yourself. The image is available at:
```
docker.io/donaldzou/wgdashboard:latest
```
> `docker.io` is in most cases automatically resolved by the Docker application.
### 🔧 Quick Docker Run Command
Here's an example to get it up and running quickly:
```bash
docker run -d \
--name wgdashboard \
--restart unless-stopped \
-p 10086:10086/tcp \
-p 51820:51820/udp \
--cap-add NET_ADMIN \
donaldzou/wgdashboard:latest
```
> ⚠️ The default WireGuard port is `51820/udp`. If you change this, update the `/etc/wireguard/wg0.conf` accordingly.
---
### 📦 Docker Compose Alternative
You can also use Docker Compose for easier configuration:
```yaml
services:
wgdashboard:
image: donaldzou/wgdashboard:latest
restart: unless-stopped
container_name: wgdashboard
environment:
# - tz=Europe/Amsterdam
# - global_dns=1.1.1.1
# - public_ip=YOUR_PUBLIC_IP
ports:
- 10086:10086/tcp
- 51820:51820/udp
volumes:
- conf:/etc/wireguard
- data:/data
cap_add:
- NET_ADMIN
volumes:
conf:
data:
```
> 📁 You can customize the **volume paths** on the host to fit your needs. The example above uses Docker volumes.
---
## 🔄 Updating the Container
Updating WGDashboard is currently in **alpha** stage. While the update process may work, it's still under testing.
---
## ⚙️ Environment Variables
| Variable | Accepted Values | Default | Example | Description |
| ------------------ | ---------------------------------------- | ----------------------- | --------------------- | ----------------------------------------------------------------------- |
| `tz` | Timezone | `Europe/Amsterdam` | `America/New_York` | Sets the container's timezone. Useful for accurate logs and scheduling. |
| `global_dns` | IPv4 and IPv6 addresses | `9.9.9.9` | `8.8.8.8`, `1.1.1.1` | Default DNS for WireGuard clients. |
| `public_ip` | Public IP address | Retrieved automatically | `253.162.134.73` | Used to generate accurate client configs. Needed if container is NATd. |
| `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. |
| `username` | Any nonempty string | `-` | `admin` | Username for the WGDashboard web interface account. |
| `password` | Any nonempty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). |
| `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTPbased twofactor authentication for the account. |
| `wg_autostart` | Wireguard interface name | `false` | `true` | Autostart the WireGuard client when the container launches. |
| `email_server` | SMTP server address | `-` | `smtp.gmail.com` | SMTP server for sending email notifications. |
| `email_port` | SMTP port number | `-` | `587` | Port for connecting to the SMTP server. |
| `email_encryption` | `TLS`, `SSL`, etc. | `-` | `TLS` | Encryption method for email communication. |
| `email_username` | Any non-empty string | `-` | `user@example.com` | Username for SMTP authentication. |
| `email_password` | Any non-empty string | `-` | `app_password` | Password for SMTP authentication. |
| `email_from` | Valid email address | `-` | `noreply@example.com` | Email address used as the sender for notifications. |
| `email_template` | Path to template file | `-` | `your-template` | Custom template for email notifications. |
---
## 🔐 Port Forwarding Note
When using multiple WireGuard interfaces, remember to **open their respective ports** on the host.
Examples:
```yaml
# Individual mapping
- 51821:51821/udp
# Or port range
- 51820-51830:51820-51830/udp
```
> 🚨 **Security Tip:** Only expose ports you actually use.
---
## 🛠️ Building the Image Yourself
To build from source:
```bash
git clone https://github.com/WGDashboard/WGDashboard.git
cd WGDashboard
docker build . -f docker/Dockerfile -t yourname/wgdashboard:latest
```
Example output:
```shell
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yourname/wgdashboard latest c96fd96ee3b3 42 minutes ago 314MB
```
---
## 🧱 Dockerfile Overview
Here's a brief overview of the Dockerfile stages used in the image build:
### 1. **Build Tools & Go Compilation**
```Dockerfile
FROM golang:1.24 AS compiler
WORKDIR /go
RUN apt-get update && apt-get install -y ...
RUN git clone ... && make
...
```
### 2. **Binary Copy to Scratch**
```Dockerfile
FROM scratch AS bins
COPY --from=compiler /go/amneziawg-go/amneziawg-go /amneziawg-go
...
```
### 3. **Final Alpine Container Setup**
```Dockerfile
FROM alpine:latest
COPY --from=bins ...
RUN apk update && apk add --no-cache ...
COPY ./src ${WGDASH}/src
COPY ./docker/entrypoint.sh /entrypoint.sh
...
EXPOSE 10086
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
```
---
## 🚀 Entrypoint Overview
### Major Functions:
- **`ensure_installation`**: Sets up the app, database, and Python environment.
- **`set_envvars`**: Writes `wg-dashboard.ini` and applies environment variables.
- **`start_core`**: Starts the main WGDashboard service.
- **`ensure_blocking`**: Tails the error log to keep the container process alive.
---
## ✅ Final Notes
- Use `docker logs wgdashboard` for troubleshooting.
- Access the web interface via `http://your-ip:10086` (or whichever port you specified in the compose).
- The first time run will auto-generate WireGuard keys and configs (configs are generated from the template).
## Closing remarks:
For feedback please submit an issue to the repository. Or message dselen@nerthus.nl.

23
docker/compose.yaml Normal file
View File

@@ -0,0 +1,23 @@
services:
wireguard-dashboard:
image: donaldzou/wgdashboard:latest
restart: unless-stopped
container_name: wgdashboard
#environment:
#- tz= # <--- Set container timezone, default: Europe/Amsterdam.
#- public_ip= # <--- Set public IP to ensure the correct one is chosen, defaulting to the IP give by ifconfig.me.
#- wgd_port= # <--- Set the port WGDashboard will use for its web-server.
ports:
- 10086:10086/tcp
- 51820:51820/udp
volumes:
- aconf:/etc/amnezia/amneziawg
- conf:/etc/wireguard
- data:/data
cap_add:
- NET_ADMIN
volumes:
aconf:
conf:
data:

224
docker/entrypoint.sh Normal file
View File

@@ -0,0 +1,224 @@
#!/bin/bash
config_file="/data/wg-dashboard.ini"
trap 'stop_service' SIGTERM
# Hash password with bcrypt
hash_password() {
python3 -c "import bcrypt; print(bcrypt.hashpw('$1'.encode(), bcrypt.gensalt(12)).decode())"
}
# Function to set or update section/key/value in the INI file
set_ini() {
local section="$1" key="$2" value="$3"
local current_value
# Add section if it doesn't exist
grep -q "^\[${section}\]" "$config_file" \
|| printf "\n[%s]\n" "${section}" >> "$config_file"
# Check current value if key exists
if grep -q "^[[:space:]]*${key}[[:space:]]*=" "$config_file"; then
current_value=$(grep "^[[:space:]]*${key}[[:space:]]*=" "$config_file" | cut -d= -f2- | xargs)
# Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then
if [ "$current_value" = "$value" ]; then
echo "- $key is already set correctly (value hidden)"
return 0
fi
sed -i "/^\[${section}\]/,/^\[/{s|^[[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|}" "$config_file"
echo "- Updated $key (value hidden)"
else
if [ "$current_value" = "$value" ]; then
echo "- $key is already set correctly ($value)"
return 0
fi
sed -i "/^\[${section}\]/,/^\[/{s|^[[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|}" "$config_file"
echo "- Updated $key to: $value"
fi
else
sed -i "/^\[${section}\]/a ${key} = ${value}" "$config_file"
# Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then
echo "- Added new setting $key (value hidden)"
else
echo "- Added new setting $key: $value"
fi
fi
}
stop_service() {
echo "[WGDashboard] Stopping WGDashboard..."
/bin/bash ./wgd.sh stop
exit 0
}
echo "------------------------- START ----------------------------"
echo "Starting the WGDashboard Docker container."
ensure_installation() {
echo "Quick-installing..."
# Make the wgd.sh script executable.
chmod +x "${WGDASH}"/src/wgd.sh
cd "${WGDASH}"/src || exit
# Github issue: https://github.com/donaldzou/WGDashboard/issues/723
echo "Checking for stale pids..."
if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then
echo "Found stale pid, removing..."
rm ${WGDASH}/src/gunicorn.pid
fi
# Removing clear shell command from the wgd.sh script to enhance docker logging.
echo "Removing clear command from wgd.sh for better Docker logging."
sed -i '/clear/d' ./wgd.sh
# Create required directories and links
if [ ! -d "/data/db" ]; then
echo "Creating database dir"
mkdir -p /data/db
fi
if [ ! -d "${WGDASH}/src/db" ]; then
ln -s /data/db "${WGDASH}/src/db"
fi
if [ ! -f "${config_file}" ]; then
echo "Creating wg-dashboard.ini file"
touch "${config_file}"
fi
if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then
ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
fi
# Create the Python virtual environment.
. "${WGDASH}/src/venv/bin/activate"
# Use the bash interpreter to install WGDashboard according to the wgd.sh script.
/bin/bash ./wgd.sh install
echo "Looks like the installation succeeded. Moving on."
# Setup WireGuard if needed
if [ ! -f "/etc/wireguard/wg0.conf" ]; then
cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf"
echo "Setting a secure private key."
local privateKey
privateKey=$(wg genkey)
sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf
echo "Done setting template."
else
echo "Existing wg0 configuration file found, using that."
fi
}
set_envvars() {
printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n"
# Check if config file is empty
if [ ! -s "${config_file}" ]; then
echo "Config file is empty. Creating initial structure."
fi
echo "Checking basic configuration:"
set_ini Peers peer_global_dns "${global_dns}"
if [ -z "${public_ip}" ]; then
public_ip=$(curl -s ifconfig.me)
echo "Automatically detected public IP: ${public_ip}"
fi
set_ini Peers remote_endpoint "${public_ip}"
set_ini Server app_port "${wgd_port}"
# Account settings - process all parameters
[[ -n "$username" ]] && echo "Configuring user account:"
# Basic account variables
[[ -n "$username" ]] && set_ini Account username "${username}"
if [[ -n "$password" ]]; then
echo "- Setting password"
set_ini Account password "$(hash_password "${password}")"
fi
# Additional account variables
[[ -n "$enable_totp" ]] && set_ini Account enable_totp "${enable_totp}"
[[ -n "$totp_verified" ]] && set_ini Account totp_verified "${totp_verified}"
[[ -n "$totp_key" ]] && set_ini Account totp_key "${totp_key}"
# Welcome session
[[ -n "$welcome_session" ]] && set_ini Other welcome_session "${welcome_session}"
# If username and password are set but welcome_session isn't, disable it
if [[ -n "$username" && -n "$password" && -z "$welcome_session" ]]; then
set_ini Other welcome_session "false"
fi
# Autostart WireGuard
if [[ -n "$wg_autostart" ]]; then
echo "Configuring WireGuard autostart:"
set_ini WireGuardConfiguration autostart "${wg_autostart}"
fi
# Email (check if any settings need to be configured)
email_vars=("email_server" "email_port" "email_encryption" "email_username" "email_password" "email_from" "email_template")
for var in "${email_vars[@]}"; do
if [ -n "${!var}" ]; then
echo "Configuring email settings:"
break
fi
done
# Email (iterate through all possible fields)
email_fields=("server:email_server" "port:email_port" "encryption:email_encryption"
"username:email_username" "email_password:email_password"
"send_from:email_from" "email_template:email_template")
for field_pair in "${email_fields[@]}"; do
IFS=: read -r field var <<< "$field_pair"
[[ -n "${!var}" ]] && set_ini Email "$field" "${!var}"
done
}
# Start service and monitor logs
start_and_monitor() {
printf "\n---------------------- STARTING CORE -----------------------\n"
# Due to some instances complaining about this, making sure its there every time.
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 600 /dev/net/tun
# Actually starting WGDashboard
echo "Activating Python venv and executing the WireGuard Dashboard service."
bash ./wgd.sh start
# Wait a second before continuing, to give the python program some time to get ready.
sleep 1
echo -e "\nEnsuring container continuation."
# Find and monitor log file
local logdir="${WGDASH}/src/log"
latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1)
# Only tail the logs if they are found
if [ -n "$latestErrLog" ]; then
tail -f "$latestErrLog" &
# Wait for the tail process to end.
wait $!
else
echo "No log files found to tail. Something went wrong, exiting..."
exit 1
fi
}
# Main execution flow
ensure_installation
set_envvars
start_and_monitor

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

1407
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

8
package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"dependencies": {
"axios": "^1.9.0",
"marked": "^15.0.7",
"openai": "^4.89.0",
"pinia-plugin-persistedstate": "^4.2.0"
}
}

6
qodana.yaml Normal file
View File

@@ -0,0 +1,6 @@
version: "1.0"
linter: jetbrains/qodana-python:2024.3
profile:
name: qodana.recommended
include:
- name: CheckDependencyLicenses

4
src/certbot.ini Normal file
View File

@@ -0,0 +1,4 @@
authenticator = standalone
noninteractive = true
agree-tos = true
rsa-key-size = 2048

232
src/client.py Normal file
View File

@@ -0,0 +1,232 @@
import datetime
from tzlocal import get_localzone
from functools import wraps
from flask import Blueprint, render_template, abort, request, Flask, current_app, session, redirect, url_for
import os
from modules.WireguardConfiguration import WireguardConfiguration
from modules.DashboardConfig import DashboardConfig
from modules.Email import EmailSender
def ResponseObject(status=True, message=None, data=None, status_code = 200) -> Flask.response_class:
response = Flask.make_response(current_app, {
"status": status,
"message": message,
"data": data
})
response.status_code = status_code
response.content_type = "application/json"
return response
from modules.DashboardClients import DashboardClients
def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration], dashboardConfig: DashboardConfig, dashboardClients: DashboardClients):
client = Blueprint('client', __name__, template_folder=os.path.abspath("./static/dist/WGDashboardClient"))
prefix = f'{dashboardConfig.GetConfig("Server", "app_prefix")[1]}/client'
def login_required(f):
@wraps(f)
def func(*args, **kwargs):
if session.get("Email") is None or session.get("TotpVerified") is None or not session.get("TotpVerified") or session.get("Role") != "client":
return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
if not dashboardClients.GetClient(session.get("ClientID")):
session.clear()
return ResponseObject(False, "Unauthorized access.", data=None, status_code=401)
return f(*args, **kwargs)
return func
@client.before_request
def clientBeforeRequest():
if not dashboardConfig.GetConfig("Clients", "enable")[1]:
abort(404)
if request.method.lower() == 'options':
return ResponseObject(True)
@client.post(f'{prefix}/api/signup')
def ClientAPI_SignUp():
data = request.get_json()
status, msg = dashboardClients.SignUp(**data)
return ResponseObject(status, msg)
@client.get(f'{prefix}/api/signin/oidc/providers')
def ClientAPI_SignIn_OIDC_GetProviders():
_, oidc = dashboardConfig.GetConfig("OIDC", "client_enable")
if not oidc:
return ResponseObject(status=False, message="OIDC is disabled")
return ResponseObject(data=dashboardClients.OIDC.GetProviders())
@client.post(f'{prefix}/api/signin/oidc')
def ClientAPI_SignIn_OIDC():
_, oidc = dashboardConfig.GetConfig("OIDC", "client_enable")
if not oidc:
return ResponseObject(status=False, message="OIDC is disabled")
data = request.get_json()
status, oidcData = dashboardClients.SignIn_OIDC(**data)
if not status:
return ResponseObject(status, oidcData)
session['Email'] = oidcData.get('email')
session['Role'] = 'client'
session['TotpVerified'] = True
return ResponseObject()
@client.post(f'{prefix}/api/signin')
def ClientAPI_SignIn():
data = request.get_json()
status, msg = dashboardClients.SignIn(**data)
if status:
session['Email'] = data.get('Email')
session['Role'] = 'client'
session['TotpVerified'] = False
return ResponseObject(status, msg)
@client.post(f'{prefix}/api/resetPassword/generateResetToken')
def ClientAPI_ResetPassword_GenerateResetToken():
date = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
emailSender = EmailSender(dashboardConfig)
if not emailSender.ready():
return ResponseObject(False, "We can't send you an email due to your Administrator has not setup email service. Please contact your administrator.")
data = request.get_json()
email = data.get('Email', None)
if not email:
return ResponseObject(False, "Please provide a valid Email")
u = dashboardClients.SignIn_UserExistence(email)
if not u:
return ResponseObject(False, "Please provide a valid Email")
token = dashboardClients.GenerateClientPasswordResetToken(u.get('ClientID'))
status, msg = emailSender.send(
email, "[WGDashboard | Client] Reset Password",
f"Hi {email}, \n\nIt looks like you're trying to reset your password at {date} \n\nEnter this 6 digits code on the Forgot Password to continue:\n\n{token}\n\nThis code will expire in 30 minutes for your security. If you didnt request a password reset, you can safely ignore this email—your current password will remain unchanged.\n\nIf you need help, feel free to contact support.\n\nBest regards,\n\nWGDashboard"
)
return ResponseObject(status, msg)
@client.post(f'{prefix}/api/resetPassword/validateResetToken')
def ClientAPI_ResetPassword_ValidateResetToken():
data = request.get_json()
email = data.get('Email', None)
token = data.get('Token', None)
if not all([email, token]):
return ResponseObject(False, "Please provide a valid Email")
u = dashboardClients.SignIn_UserExistence(email)
if not u:
return ResponseObject(False, "Please provide a valid Email")
return ResponseObject(status=dashboardClients.ValidateClientPasswordResetToken(u.get('ClientID'), token))
@client.post(f'{prefix}/api/resetPassword')
def ClientAPI_ResetPassword():
data = request.get_json()
email = data.get('Email', None)
token = data.get('Token', None)
password = data.get('Password', None)
confirmPassword = data.get('ConfirmPassword', None)
if not all([email, token, password, confirmPassword]):
return ResponseObject(False, "Please provide a valid Email")
u = dashboardClients.SignIn_UserExistence(email)
if not u:
return ResponseObject(False, "Please provide a valid Email")
if not dashboardClients.ValidateClientPasswordResetToken(u.get('ClientID'), token):
return ResponseObject(False, "Verification code is either invalid or expired")
status, msg = dashboardClients.ResetClientPassword(u.get('ClientID'), password, confirmPassword)
dashboardClients.RevokeClientPasswordResetToken(u.get('ClientID'), token)
return ResponseObject(status, msg)
@client.get(f'{prefix}/api/signout')
def ClientAPI_SignOut():
if session.get("SignInMethod") == "OIDC":
dashboardClients.SignOut_OIDC()
session.clear()
return ResponseObject(True)
@client.get(f'{prefix}/api/signin/totp')
def ClientAPI_SignIn_TOTP():
token = request.args.get('Token', None)
if not token:
return ResponseObject(False, "Please provide TOTP token")
status, msg = dashboardClients.SignIn_GetTotp(token)
return ResponseObject(status, msg)
@client.post(f'{prefix}/api/signin/totp')
def ClientAPI_SignIn_ValidateTOTP():
data = request.get_json()
token = data.get('Token', None)
userProvidedTotp = data.get('UserProvidedTOTP', None)
if not all([token, userProvidedTotp]):
return ResponseObject(False, "Please fill in all fields")
status, msg = dashboardClients.SignIn_GetTotp(token, userProvidedTotp)
if status:
if session.get('Email') is None:
return ResponseObject(False, "Sign in status is invalid", status_code=401)
session['TotpVerified'] = True
profile = dashboardClients.GetClientProfile(session.get("ClientID"))
return ResponseObject(True, data={
"Email": session.get('Email'),
"Profile": profile
})
return ResponseObject(status, msg)
@client.get(prefix)
def ClientIndex():
return render_template('client.html')
@client.get(f'{prefix}/api/serverInformation')
def ClientAPI_ServerInformation():
return ResponseObject(data={
"ServerTimezone": str(get_localzone())
})
@client.get(f'{prefix}/api/validateAuthentication')
@login_required
def ClientAPI_ValidateAuthentication():
return ResponseObject(True)
@client.get(f'{prefix}/api/configurations')
@login_required
def ClientAPI_Configurations():
return ResponseObject(True, data=dashboardClients.GetClientAssignedPeers(session['ClientID']))
@client.get(f'{prefix}/api/settings/getClientProfile')
@login_required
def ClientAPI_Settings_GetClientProfile():
return ResponseObject(data={
"Email": session.get("Email"),
"SignInMethod": session.get("SignInMethod"),
"Profile": dashboardClients.GetClientProfile(session.get("ClientID"))
})
@client.post(f'{prefix}/api/settings/updatePassword')
@login_required
def ClientAPI_Settings_UpdatePassword():
data = request.get_json()
status, message = dashboardClients.UpdateClientPassword(session['ClientID'], **data)
return ResponseObject(status, message)
return client

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
You can delete this later ;)

26
src/gunicorn.conf.py Normal file
View File

@@ -0,0 +1,26 @@
import dashboard
from datetime import datetime
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger, Dash
app_host, app_port = dashboard.gunicornConfig()
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
def post_worker_init(worker):
dashboard.startThreads()
dashboard.DashboardPlugins.startThreads()
worker_class = 'gthread'
workers = 1
threads = 2
bind = f"{app_host}:{app_port}"
daemon = True
pidfile = './gunicorn.pid'
wsgi_app = "dashboard:app"
accesslog = f"./log/access_{date}.log"
loglevel = "info"
capture_output = True
errorlog = f"./log/error_{date}.log"
pythonpath = "., ./modules"
print(f"[Gunicorn] WGDashboard w/ Gunicorn will be running on {bind}", flush=True)
print(f"[Gunicorn] Access log file is at {accesslog}", flush=True)
print(f"[Gunicorn] Error log file is at {errorlog}", flush=True)

View File

@@ -0,0 +1,92 @@
import os
import random
import re
import subprocess
import uuid
from .Peer import Peer
from .Utilities import ValidateIPAddressesWithRange, ValidateDNSAddress, GenerateWireguardPublicKey
class AmneziaWGPeer(Peer):
def __init__(self, tableData, configuration):
self.advanced_security = tableData["advanced_security"]
super().__init__(tableData, configuration)
def updatePeer(self, name: str, private_key: str,
preshared_key: str,
dns_addresses: str, allowed_ip: str, endpoint_allowed_ip: str, mtu: int,
keepalive: int, advanced_security: str) -> tuple[bool, str] or tuple[bool, None]:
if not self.configuration.getStatus():
self.configuration.toggleConfiguration()
existingAllowedIps = [item for row in list(
map(lambda x: [q.strip() for q in x.split(',')],
map(lambda y: y.allowed_ip,
list(filter(lambda k: k.id != self.id, self.configuration.getPeersList()))))) for item in row]
if allowed_ip in existingAllowedIps:
return False, "Allowed IP already taken by another peer"
if not ValidateIPAddressesWithRange(endpoint_allowed_ip):
return False, f"Endpoint Allowed IPs format is incorrect"
if len(dns_addresses) > 0 and not ValidateDNSAddress(dns_addresses):
return False, f"DNS format is incorrect"
if type(mtu) is str:
mtu = 0
if type(keepalive) is str:
keepalive = 0
if mtu < 0 or mtu > 1460:
return False, "MTU format is not correct"
if keepalive < 0:
return False, "Persistent Keepalive format is not correct"
if advanced_security != "on" and advanced_security != "off":
return False, "Advanced Security can only be on or off"
if len(private_key) > 0:
pubKey = GenerateWireguardPublicKey(private_key)
if not pubKey[0] or pubKey[1] != self.id:
return False, "Private key does not match with the public key"
try:
rd = random.Random()
uid = str(uuid.UUID(int=rd.getrandbits(128), version=4))
pskExist = len(preshared_key) > 0
if pskExist:
with open(uid, "w+") as f:
f.write(preshared_key)
newAllowedIPs = allowed_ip.replace(" ", "")
updateAllowedIp = subprocess.check_output(
f"{self.configuration.Protocol} set {self.configuration.Name} peer {self.id} allowed-ips {newAllowedIPs} {f'preshared-key {uid}' if pskExist else 'preshared-key /dev/null'}",
shell=True, stderr=subprocess.STDOUT)
if pskExist: os.remove(uid)
if len(updateAllowedIp.decode().strip("\n")) != 0:
return False, "Update peer failed when updating Allowed IPs"
saveConfig = subprocess.check_output(f"{self.configuration.Protocol}-quick save {self.configuration.Name}",
shell=True, stderr=subprocess.STDOUT)
if f"wg showconf {self.configuration.Name}" not in saveConfig.decode().strip('\n'):
return False, "Update peer failed when saving the configuration"
with self.configuration.engine.begin() as conn:
conn.execute(
self.configuration.peersTable.update().values({
"name": name,
"private_key": private_key,
"DNS": dns_addresses,
"endpoint_allowed_ip": endpoint_allowed_ip,
"mtu": mtu,
"keepalive": keepalive,
"preshared_key": preshared_key,
"advanced_security": advanced_security
}).where(
self.configuration.peersTable.c.id == self.id
)
)
self.configuration.getPeers()
return True, None
except subprocess.CalledProcessError as exc:
return False, exc.output.decode("UTF-8").strip()

View File

@@ -0,0 +1,324 @@
"""
AmneziaWG Configuration
"""
import random, sqlalchemy, os, subprocess, re, uuid
from flask import current_app
from .PeerJobs import PeerJobs
from .AmneziaWGPeer import AmneziaWGPeer
from .PeerShareLinks import PeerShareLinks
from .Utilities import RegexMatch
from .WireguardConfiguration import WireguardConfiguration
from .DashboardWebHooks import DashboardWebHooks
class AmneziaWireguardConfiguration(WireguardConfiguration):
def __init__(self, DashboardConfig,
AllPeerJobs: PeerJobs,
AllPeerShareLinks: PeerShareLinks,
DashboardWebHooks: DashboardWebHooks,
name: str = None, data: dict = None, backup: dict = None, startup: bool = False):
self.Jc = 0
self.Jmin = 0
self.Jmax = 0
self.S1 = 0
self.S2 = 0
self.H1 = 1
self.H2 = 2
self.H3 = 3
self.H4 = 4
super().__init__(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, name, data, backup, startup, wg=False)
def toJson(self):
self.Status = self.getStatus()
return {
"Status": self.Status,
"Name": self.Name,
"PrivateKey": self.PrivateKey,
"PublicKey": self.PublicKey,
"Address": self.Address,
"ListenPort": self.ListenPort,
"PreUp": self.PreUp,
"PreDown": self.PreDown,
"PostUp": self.PostUp,
"PostDown": self.PostDown,
"SaveConfig": self.SaveConfig,
"Info": self.configurationInfo.model_dump(),
"DataUsage": {
"Total": sum(list(map(lambda x: x.cumu_data + x.total_data, self.Peers))),
"Sent": sum(list(map(lambda x: x.cumu_sent + x.total_sent, self.Peers))),
"Receive": sum(list(map(lambda x: x.cumu_receive + x.total_receive, self.Peers)))
},
"ConnectedPeers": len(list(filter(lambda x: x.status == "running", self.Peers))),
"TotalPeers": len(self.Peers),
"Protocol": self.Protocol,
"Table": self.Table,
"Jc": self.Jc,
"Jmin": self.Jmin,
"Jmax": self.Jmax,
"S1": self.S1,
"S2": self.S2,
"H1": self.H1,
"H2": self.H2,
"H3": self.H3,
"H4": self.H4
}
def createDatabase(self, dbName = None):
if dbName is None:
dbName = self.Name
self.peersTable = sqlalchemy.Table(
dbName, self.metadata,
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False, primary_key=True),
sqlalchemy.Column('private_key', sqlalchemy.String(255)),
sqlalchemy.Column('DNS', sqlalchemy.Text),
sqlalchemy.Column('advanced_security', sqlalchemy.String(255)),
sqlalchemy.Column('endpoint_allowed_ip', sqlalchemy.Text),
sqlalchemy.Column('name', sqlalchemy.Text),
sqlalchemy.Column('total_receive', sqlalchemy.Float),
sqlalchemy.Column('total_sent', sqlalchemy.Float),
sqlalchemy.Column('total_data', sqlalchemy.Float),
sqlalchemy.Column('endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('status', sqlalchemy.String(255)),
sqlalchemy.Column('latest_handshake', sqlalchemy.String(255)),
sqlalchemy.Column('allowed_ip', sqlalchemy.String(255)),
sqlalchemy.Column('cumu_receive', sqlalchemy.Float),
sqlalchemy.Column('cumu_sent', sqlalchemy.Float),
sqlalchemy.Column('cumu_data', sqlalchemy.Float),
sqlalchemy.Column('mtu', sqlalchemy.Integer),
sqlalchemy.Column('keepalive', sqlalchemy.Integer),
sqlalchemy.Column('remote_endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('preshared_key', sqlalchemy.String(255)),
extend_existing=True
)
self.peersRestrictedTable = sqlalchemy.Table(
f'{dbName}_restrict_access', self.metadata,
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False, primary_key=True),
sqlalchemy.Column('private_key', sqlalchemy.String(255)),
sqlalchemy.Column('DNS', sqlalchemy.Text),
sqlalchemy.Column('advanced_security', sqlalchemy.String(255)),
sqlalchemy.Column('endpoint_allowed_ip', sqlalchemy.Text),
sqlalchemy.Column('name', sqlalchemy.Text),
sqlalchemy.Column('total_receive', sqlalchemy.Float),
sqlalchemy.Column('total_sent', sqlalchemy.Float),
sqlalchemy.Column('total_data', sqlalchemy.Float),
sqlalchemy.Column('endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('status', sqlalchemy.String(255)),
sqlalchemy.Column('latest_handshake', sqlalchemy.String(255)),
sqlalchemy.Column('allowed_ip', sqlalchemy.String(255)),
sqlalchemy.Column('cumu_receive', sqlalchemy.Float),
sqlalchemy.Column('cumu_sent', sqlalchemy.Float),
sqlalchemy.Column('cumu_data', sqlalchemy.Float),
sqlalchemy.Column('mtu', sqlalchemy.Integer),
sqlalchemy.Column('keepalive', sqlalchemy.Integer),
sqlalchemy.Column('remote_endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('preshared_key', sqlalchemy.String(255)),
extend_existing=True
)
self.peersTransferTable = sqlalchemy.Table(
f'{dbName}_transfer', self.metadata,
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('total_receive', sqlalchemy.Float),
sqlalchemy.Column('total_sent', sqlalchemy.Float),
sqlalchemy.Column('total_data', sqlalchemy.Float),
sqlalchemy.Column('cumu_receive', sqlalchemy.Float),
sqlalchemy.Column('cumu_sent', sqlalchemy.Float),
sqlalchemy.Column('cumu_data', sqlalchemy.Float),
sqlalchemy.Column('time', (sqlalchemy.DATETIME if self.DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else sqlalchemy.TIMESTAMP),
server_default=sqlalchemy.func.now()),
extend_existing=True
)
self.peersDeletedTable = sqlalchemy.Table(
f'{dbName}_deleted', self.metadata,
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('private_key', sqlalchemy.String(255)),
sqlalchemy.Column('DNS', sqlalchemy.Text),
sqlalchemy.Column('advanced_security', sqlalchemy.String(255)),
sqlalchemy.Column('endpoint_allowed_ip', sqlalchemy.Text),
sqlalchemy.Column('name', sqlalchemy.Text),
sqlalchemy.Column('total_receive', sqlalchemy.Float),
sqlalchemy.Column('total_sent', sqlalchemy.Float),
sqlalchemy.Column('total_data', sqlalchemy.Float),
sqlalchemy.Column('endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('status', sqlalchemy.String(255)),
sqlalchemy.Column('latest_handshake', sqlalchemy.String(255)),
sqlalchemy.Column('allowed_ip', sqlalchemy.String(255)),
sqlalchemy.Column('cumu_receive', sqlalchemy.Float),
sqlalchemy.Column('cumu_sent', sqlalchemy.Float),
sqlalchemy.Column('cumu_data', sqlalchemy.Float),
sqlalchemy.Column('mtu', sqlalchemy.Integer),
sqlalchemy.Column('keepalive', sqlalchemy.Integer),
sqlalchemy.Column('remote_endpoint', sqlalchemy.String(255)),
sqlalchemy.Column('preshared_key', sqlalchemy.String(255)),
extend_existing=True
)
self.infoTable = sqlalchemy.Table(
'ConfigurationsInfo', self.metadata,
sqlalchemy.Column('ID', sqlalchemy.String(255), primary_key=True),
sqlalchemy.Column('Info', sqlalchemy.Text),
extend_existing=True
)
self.peersHistoryEndpointTable = sqlalchemy.Table(
f'{dbName}_history_endpoint', self.metadata,
sqlalchemy.Column('id', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('endpoint', sqlalchemy.String(255), nullable=False),
sqlalchemy.Column('time',
(sqlalchemy.DATETIME if self.DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else sqlalchemy.TIMESTAMP)),
extend_existing=True
)
self.metadata.create_all(self.engine)
def getPeers(self):
self.Peers.clear()
current_app.logger.info(f"Refreshing {self.Name} peer list")
if self.configurationFileChanged():
with open(self.configPath, 'r') as configFile:
p = []
pCounter = -1
content = configFile.read().split('\n')
try:
if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section")
return
peerStarts = content.index("[Peer]")
content = content[peerStarts:]
for i in content:
if not RegexMatch("#(.*)", i) and not RegexMatch(";(.*)", i):
if i == "[Peer]":
pCounter += 1
p.append({})
p[pCounter]["name"] = ""
else:
if len(i) > 0:
split = re.split(r'\s*=\s*', i, 1)
if len(split) == 2:
p[pCounter][split[0]] = split[1]
if RegexMatch("#Name# = (.*)", i):
split = re.split(r'\s*=\s*', i, 1)
if len(split) == 2:
p[pCounter]["name"] = split[1]
with self.engine.begin() as conn:
for i in p:
if "PublicKey" in i.keys():
tempPeer = conn.execute(self.peersTable.select().where(
self.peersTable.columns.id == i['PublicKey']
)).mappings().fetchone()
if tempPeer is None:
tempPeer = {
"id": i['PublicKey'],
"advanced_security": i.get('AdvancedSecurity', 'off'),
"private_key": "",
"DNS": self.DashboardConfig.GetConfig("Peers", "peer_global_DNS")[1],
"endpoint_allowed_ip": self.DashboardConfig.GetConfig("Peers", "peer_endpoint_allowed_ip")[
1],
"name": i.get("name"),
"total_receive": 0,
"total_sent": 0,
"total_data": 0,
"endpoint": "N/A",
"status": "stopped",
"latest_handshake": "N/A",
"allowed_ip": i.get("AllowedIPs", "N/A"),
"cumu_receive": 0,
"cumu_sent": 0,
"cumu_data": 0,
"mtu": self.DashboardConfig.GetConfig("Peers", "peer_mtu")[1],
"keepalive": self.DashboardConfig.GetConfig("Peers", "peer_keep_alive")[1],
"remote_endpoint": self.DashboardConfig.GetConfig("Peers", "remote_endpoint")[1],
"preshared_key": i["PresharedKey"] if "PresharedKey" in i.keys() else ""
}
conn.execute(
self.peersTable.insert().values(tempPeer)
)
else:
conn.execute(
self.peersTable.update().values({
"allowed_ip": i.get("AllowedIPs", "N/A")
}).where(
self.peersTable.columns.id == i['PublicKey']
)
)
self.Peers.append(AmneziaWGPeer(tempPeer, self))
except Exception as e:
current_app.logger.error(f"{self.Name} getPeers() Error", e)
else:
with self.engine.connect() as conn:
existingPeers = conn.execute(self.peersTable.select()).mappings().fetchall()
for i in existingPeers:
self.Peers.append(AmneziaWGPeer(i, self))
def addPeers(self, peers: list) -> tuple[bool, list, str]:
result = {
"message": None,
"peers": []
}
try:
with self.engine.begin() as conn:
for i in peers:
newPeer = {
"id": i['id'],
"private_key": i['private_key'],
"DNS": i['DNS'],
"endpoint_allowed_ip": i['endpoint_allowed_ip'],
"name": i['name'],
"total_receive": 0,
"total_sent": 0,
"total_data": 0,
"endpoint": "N/A",
"status": "stopped",
"latest_handshake": "N/A",
"allowed_ip": i.get("allowed_ip", "N/A"),
"cumu_receive": 0,
"cumu_sent": 0,
"cumu_data": 0,
"mtu": i['mtu'],
"keepalive": i['keepalive'],
"remote_endpoint": self.DashboardConfig.GetConfig("Peers", "remote_endpoint")[1],
"preshared_key": i["preshared_key"],
"advanced_security": i['advanced_security']
}
conn.execute(
self.peersTable.insert().values(newPeer)
)
for p in peers:
presharedKeyExist = len(p['preshared_key']) > 0
rd = random.Random()
uid = str(uuid.UUID(int=rd.getrandbits(128), version=4))
if presharedKeyExist:
with open(uid, "w+") as f:
f.write(p['preshared_key'])
subprocess.check_output(
f"{self.Protocol} set {self.Name} peer {p['id']} allowed-ips {p['allowed_ip'].replace(' ', '')}{f' preshared-key {uid}' if presharedKeyExist else ''}",
shell=True, stderr=subprocess.STDOUT)
if presharedKeyExist:
os.remove(uid)
subprocess.check_output(
f"{self.Protocol}-quick save {self.Name}", shell=True, stderr=subprocess.STDOUT)
self.getPeers()
for p in peers:
p = self.searchPeer(p['id'])
if p[0]:
result['peers'].append(p[1])
self.DashboardWebHooks.RunWebHook("peer_created", {
"configuration": self.Name,
"peers": list(map(lambda k : k['id'], peers))
})
except Exception as e:
current_app.logger.error("Add peers error", e)
return False, [], str(e)
return True, result['peers'], ""
def getRestrictedPeers(self):
self.RestrictedPeers = []
with self.engine.connect() as conn:
restricted = conn.execute(self.peersRestrictedTable.select()).mappings().fetchall()
for i in restricted:
self.RestrictedPeers.append(AmneziaWGPeer(i, self))

View File

@@ -0,0 +1,25 @@
import configparser
import os
from sqlalchemy_utils import database_exists, create_database
from flask import current_app
def ConnectionString(database) -> str:
parser = configparser.ConfigParser(strict=False)
parser.read_file(open('wg-dashboard.ini', "r+"))
sqlitePath = os.path.join("db")
if not os.path.isdir(sqlitePath):
os.mkdir(sqlitePath)
if parser.get("Database", "type") == "postgresql":
cn = f'postgresql+psycopg://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}'
elif parser.get("Database", "type") == "mysql":
cn = f'mysql+pymysql://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}'
else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}'
try:
if not database_exists(cn):
create_database(cn)
except Exception as e:
current_app.logger.error("Database error. Terminating...", e)
exit(1)
return cn

View File

@@ -0,0 +1,11 @@
"""
Dashboard API Key
"""
class DashboardAPIKey:
def __init__(self, Key: str, CreatedAt: str, ExpiredAt: str):
self.Key = Key
self.CreatedAt = CreatedAt
self.ExpiredAt = ExpiredAt
def toJson(self):
return self.__dict__

View File

@@ -0,0 +1,498 @@
import datetime
import hashlib
import random
import uuid
import bcrypt
import pyotp
import sqlalchemy as db
import requests
from .ConnectionString import ConnectionString
from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment
from .DashboardClientsTOTP import DashboardClientsTOTP
from .DashboardOIDC import DashboardOIDC
from .Utilities import ValidatePasswordStrength
from .DashboardLogger import DashboardLogger
from flask import session
class DashboardClients:
def __init__(self, wireguardConfigurations):
self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.OIDC = DashboardOIDC("Client")
self.dashboardClientsTable = db.Table(
'DashboardClients', self.metadata,
db.Column('ClientID', db.String(255), nullable=False, primary_key=True),
db.Column('Email', db.String(255), nullable=False, index=True),
db.Column('Password', db.String(500)),
db.Column('TotpKey', db.String(500)),
db.Column('TotpKeyVerified', db.Integer),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
extend_existing=True,
)
self.dashboardOIDCClientsTable = db.Table(
'DashboardOIDCClients', self.metadata,
db.Column('ClientID', db.String(255), nullable=False, primary_key=True),
db.Column('Email', db.String(255), nullable=False, index=True),
db.Column('ProviderIssuer', db.String(500), nullable=False, index=True),
db.Column('ProviderSubject', db.String(500), nullable=False, index=True),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
extend_existing=True,
)
self.dashboardClientsInfoTable = db.Table(
'DashboardClientsInfo', self.metadata,
db.Column('ClientID', db.String(255), nullable=False, primary_key=True),
db.Column('Name', db.String(500)),
extend_existing=True,
)
self.dashboardClientsPasswordResetLinkTable = db.Table(
'DashboardClientsPasswordResetLinks', self.metadata,
db.Column('ResetToken', db.String(255), nullable=False, primary_key=True),
db.Column('ClientID', db.String(255), nullable=False),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('ExpiryDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
extend_existing=True
)
self.metadata.create_all(self.engine)
self.Clients = {}
self.ClientsRaw = []
self.__getClients()
self.DashboardClientsTOTP = DashboardClientsTOTP()
self.DashboardClientsPeerAssignment = DashboardClientsPeerAssignment(wireguardConfigurations)
def __getClients(self):
with self.engine.connect() as conn:
localClients = db.select(
self.dashboardClientsTable.c.ClientID,
self.dashboardClientsTable.c.Email,
db.literal_column("'Local'").label("ClientGroup")
).where(
self.dashboardClientsTable.c.DeletedDate.is_(None)
)
oidcClients = db.select(
self.dashboardOIDCClientsTable.c.ClientID,
self.dashboardOIDCClientsTable.c.Email,
self.dashboardOIDCClientsTable.c.ProviderIssuer.label("ClientGroup"),
).where(
self.dashboardOIDCClientsTable.c.DeletedDate.is_(None)
)
union = db.union(localClients, oidcClients).alias("U")
self.ClientsRaw = conn.execute(
db.select(
union,
self.dashboardClientsInfoTable.c.Name
).outerjoin(self.dashboardClientsInfoTable,
union.c.ClientID == self.dashboardClientsInfoTable.c.ClientID)
).mappings().fetchall()
groups = set(map(lambda c: c.get('ClientGroup'), self.ClientsRaw))
gr = {}
for g in groups:
gr[(g if g == 'Local' else self.OIDC.GetProviderNameByIssuer(g))] = [
dict(x) for x in list(
filter(lambda c: c.get('ClientGroup') == g, self.ClientsRaw)
)
]
self.Clients = gr
def GetAllClients(self):
self.__getClients()
return self.Clients
def GetAllClientsRaw(self):
self.__getClients()
return self.ClientsRaw
def GetClient(self, ClientID) -> dict[str, str] | None:
c = filter(lambda x: x['ClientID'] == ClientID, self.ClientsRaw)
client = next((dict(client) for client in c), None)
if client is not None:
client['ClientGroup'] = self.OIDC.GetProviderNameByIssuer(client['ClientGroup'])
return client
def GetClientProfile(self, ClientID):
with self.engine.connect() as conn:
return dict(conn.execute(
db.select(
*[c for c in self.dashboardClientsInfoTable.c if c.name != 'ClientID']
).where(
self.dashboardClientsInfoTable.c.ClientID == ClientID
)
).mappings().fetchone())
def SignIn_ValidatePassword(self, Email, Password) -> bool:
if not all([Email, Password]):
return False
existingClient = self.SignIn_UserExistence(Email)
if existingClient:
return bcrypt.checkpw(Password.encode("utf-8"), existingClient.get("Password").encode("utf-8"))
return False
def SignIn_UserExistence(self, Email):
with self.engine.connect() as conn:
existingClient = conn.execute(
self.dashboardClientsTable.select().where(
self.dashboardClientsTable.c.Email == Email
)
).mappings().fetchone()
return existingClient
def SignIn_OIDC_UserExistence(self, data: dict[str, str]):
with self.engine.connect() as conn:
existingClient = conn.execute(
self.dashboardOIDCClientsTable.select().where(
db.and_(
self.dashboardOIDCClientsTable.c.ProviderIssuer == data.get('iss'),
self.dashboardOIDCClientsTable.c.ProviderSubject == data.get('sub'),
)
)
).mappings().fetchone()
return existingClient
def SignUp_OIDC(self, data: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]:
if not self.SignIn_OIDC_UserExistence(data):
with self.engine.begin() as conn:
newClientUUID = str(uuid.uuid4())
conn.execute(
self.dashboardOIDCClientsTable.insert().values({
"ClientID": newClientUUID,
"Email": data.get('email', ''),
"ProviderIssuer": data.get('iss', ''),
"ProviderSubject": data.get('sub', '')
})
)
conn.execute(
self.dashboardClientsInfoTable.insert().values({
"ClientID": newClientUUID,
"Name": data.get("name")
})
)
self.logger.log(Message=f"User {data.get('email', '')} from {data.get('iss', '')} signed up")
self.__getClients()
return True, newClientUUID
return False, "User already signed up"
def SignOut_OIDC(self):
sessionPayload = session.get('OIDCPayload')
status, oidc_config = self.OIDC.GetProviderConfiguration(session.get('SignInPayload').get("Provider"))
signOut = requests.get(
oidc_config.get("end_session_endpoint"),
params={
'id_token_hint': session.get('SignInPayload').get("Payload").get('sid')
}
)
return True
def SignIn_OIDC(self, **kwargs):
status, data = self.OIDC.VerifyToken(**kwargs)
if not status:
return False, "Sign in failed. Reason: " + data
existingClient = self.SignIn_OIDC_UserExistence(data)
if not existingClient:
status, newClientUUID = self.SignUp_OIDC(data)
session['ClientID'] = newClientUUID
else:
session['ClientID'] = existingClient.get("ClientID")
session['SignInMethod'] = 'OIDC'
session['SignInPayload'] = {
"Provider": kwargs.get('provider'),
"Payload": data
}
return True, data
def SignIn(self, Email, Password) -> tuple[bool, str]:
if not all([Email, Password]):
return False, "Please fill in all fields"
existingClient = self.SignIn_UserExistence(Email)
if existingClient:
checkPwd = self.SignIn_ValidatePassword(Email, Password)
if checkPwd:
session['SignInMethod'] = 'local'
session['Email'] = Email
session['ClientID'] = existingClient.get("ClientID")
return True, self.DashboardClientsTOTP.GenerateToken(existingClient.get("ClientID"))
return False, "Email or Password is incorrect"
def SignIn_GetTotp(self, Token: str, UserProvidedTotp: str = None) -> tuple[bool, str] or tuple[bool, None, str]:
status, data = self.DashboardClientsTOTP.GetTotp(Token)
if not status:
return False, "TOTP Token is invalid"
if UserProvidedTotp is None:
if data.get('TotpKeyVerified') is None:
return True, pyotp.totp.TOTP(data.get('TotpKey')).provisioning_uri(name=data.get('Email'),
issuer_name="WGDashboard Client")
else:
totpMatched = pyotp.totp.TOTP(data.get('TotpKey')).verify(UserProvidedTotp)
if not totpMatched:
return False, "TOTP is does not match"
else:
self.DashboardClientsTOTP.RevokeToken(Token)
if data.get('TotpKeyVerified') is None:
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsTable.update().values({
'TotpKeyVerified': 1
}).where(
self.dashboardClientsTable.c.ClientID == data.get('ClientID')
)
)
return True, None
def SignUp(self, Email, Password, ConfirmPassword) -> tuple[bool, str] or tuple[bool, None]:
try:
if not all([Email, Password, ConfirmPassword]):
return False, "Please fill in all fields"
if Password != ConfirmPassword:
return False, "Passwords does not match"
existingClient = self.SignIn_UserExistence(Email)
if existingClient:
return False, "Email already signed up"
pwStrength, msg = ValidatePasswordStrength(Password)
if not pwStrength:
return pwStrength, msg
with self.engine.begin() as conn:
newClientUUID = str(uuid.uuid4())
totpKey = pyotp.random_base32()
encodePassword = Password.encode('utf-8')
conn.execute(
self.dashboardClientsTable.insert().values({
"ClientID": newClientUUID,
"Email": Email,
"Password": bcrypt.hashpw(encodePassword, bcrypt.gensalt()).decode("utf-8"),
"TotpKey": totpKey
})
)
conn.execute(
self.dashboardClientsInfoTable.insert().values({
"ClientID": newClientUUID
})
)
self.logger.log(Message=f"User {Email} signed up")
self.__getClients()
except Exception as e:
self.logger.log(Status="false", Message=f"Signed up failed, reason: {str(e)}")
return False, "Signe up failed."
return True, None
def GetClientAssignedPeers(self, ClientID):
return self.DashboardClientsPeerAssignment.GetAssignedPeers(ClientID)
def ResetClientPassword(self, ClientID, NewPassword, ConfirmNewPassword) -> tuple[bool, str] | tuple[bool, None]:
c = self.GetClient(ClientID)
if c is None:
return False, "Client does not exist"
if NewPassword != ConfirmNewPassword:
return False, "New passwords does not match"
pwStrength, msg = ValidatePasswordStrength(NewPassword)
if not pwStrength:
return pwStrength, msg
try:
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsTable.update().values({
"TotpKeyVerified": None,
"TotpKey": pyotp.random_base32(),
"Password": bcrypt.hashpw(NewPassword.encode('utf-8'), bcrypt.gensalt()).decode("utf-8"),
}).where(
self.dashboardClientsTable.c.ClientID == ClientID
)
)
self.logger.log(Message=f"User {ClientID} reset password and TOTP")
except Exception as e:
self.logger.log(Status="false", Message=f"User {ClientID} reset password failed, reason: {str(e)}")
return False, "Reset password failed."
return True, None
def UpdateClientPassword(self, ClientID, CurrentPassword, NewPassword, ConfirmNewPassword) -> tuple[bool, str] | tuple[bool, None]:
c = self.GetClient(ClientID)
if c is None:
return False, "Client does not exist"
if not all([CurrentPassword, NewPassword, ConfirmNewPassword]):
return False, "Please fill in all fields"
if not self.SignIn_ValidatePassword(c.get('Email'), CurrentPassword):
return False, "Current password does not match"
if NewPassword != ConfirmNewPassword:
return False, "New passwords does not match"
pwStrength, msg = ValidatePasswordStrength(NewPassword)
if not pwStrength:
return pwStrength, msg
try:
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsTable.update().values({
"Password": bcrypt.hashpw(NewPassword.encode('utf-8'), bcrypt.gensalt()).decode("utf-8"),
}).where(
self.dashboardClientsTable.c.ClientID == ClientID
)
)
self.logger.log(Message=f"User {ClientID} updated password")
except Exception as e:
self.logger.log(Status="false", Message=f"User {ClientID} update password failed, reason: {str(e)}")
return False, "Update password failed."
return True, None
def UpdateClientProfile(self, ClientID, Name):
try:
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsInfoTable.update().values({
"Name": Name
}).where(
self.dashboardClientsInfoTable.c.ClientID == ClientID
)
)
self.logger.log(Message=f"User {ClientID} updated name to {Name}")
except Exception as e:
self.logger.log(Status="false", Message=f"User {ClientID} updated name to {Name} failed")
return False
return True
def DeleteClient(self, ClientID):
try:
with self.engine.begin() as conn:
client = self.GetClient(ClientID)
if client.get("ClientGroup") == "Local":
conn.execute(
self.dashboardClientsTable.delete().where(
self.dashboardClientsTable.c.ClientID == ClientID
)
)
else:
conn.execute(
self.dashboardOIDCClientsTable.delete().where(
self.dashboardOIDCClientsTable.c.ClientID == ClientID
)
)
conn.execute(
self.dashboardClientsInfoTable.delete().where(
self.dashboardClientsInfoTable.c.ClientID == ClientID
)
)
self.DashboardClientsPeerAssignment.UnassignPeers(ClientID)
self.__getClients()
except Exception as e:
self.logger.log(Status="false", Message=f"Failed to delete {ClientID}")
return False
return True
'''
For WGDashboard Admin to Manage Clients
'''
def GenerateClientPasswordResetToken(self, ClientID) -> bool | str:
c = self.GetClient(ClientID)
if c is None:
return False
newToken = str(random.randint(0, 999999)).zfill(6)
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsPasswordResetLinkTable.update().values({
"ExpiryDate": datetime.datetime.now()
}).where(
db.and_(
self.dashboardClientsPasswordResetLinkTable.c.ClientID == ClientID,
self.dashboardClientsPasswordResetLinkTable.c.ExpiryDate > db.func.now()
)
)
)
conn.execute(
self.dashboardClientsPasswordResetLinkTable.insert().values({
"ResetToken": newToken,
"ClientID": ClientID,
"CreatedDate": datetime.datetime.now(),
"ExpiryDate": datetime.datetime.now() + datetime.timedelta(minutes=30)
})
)
return newToken
def ValidateClientPasswordResetToken(self, ClientID, Token):
c = self.GetClient(ClientID)
if c is None:
return False
with self.engine.connect() as conn:
t = conn.execute(
self.dashboardClientsPasswordResetLinkTable.select().where(
db.and_(self.dashboardClientsPasswordResetLinkTable.c.ClientID == ClientID,
self.dashboardClientsPasswordResetLinkTable.c.ResetToken == Token,
self.dashboardClientsPasswordResetLinkTable.c.ExpiryDate > datetime.datetime.now())
)
).mappings().fetchone()
return t is not None
def RevokeClientPasswordResetToken(self, ClientID, Token):
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsPasswordResetLinkTable.update().values({
"ExpiryDate": datetime.datetime.now()
}).where(
db.and_(self.dashboardClientsPasswordResetLinkTable.c.ClientID == ClientID,
self.dashboardClientsPasswordResetLinkTable.c.ResetToken == Token)
)
)
return True
def GetAssignedPeerClients(self, ConfigurationName, PeerID):
c = self.DashboardClientsPeerAssignment.GetAssignedClients(ConfigurationName, PeerID)
for a in c:
client = self.GetClient(a.ClientID)
if client is not None:
a.Client = self.GetClient(a.ClientID)
return c
def GetClientAssignedPeersGrouped(self, ClientID):
client = self.GetClient(ClientID)
if client is not None:
p = self.DashboardClientsPeerAssignment.GetAssignedPeers(ClientID)
configs = set(map(lambda x : x['configuration_name'], p))
d = {}
for i in configs:
d[i] = list(filter(lambda x : x['configuration_name'] == i, p))
return d
return None
def AssignClient(self, ConfigurationName, PeerID, ClientID) -> tuple[bool, dict[str, str]] | tuple[bool, None]:
return self.DashboardClientsPeerAssignment.AssignClient(ClientID, ConfigurationName, PeerID)
def UnassignClient(self, AssignmentID):
return self.DashboardClientsPeerAssignment.UnassignClients(AssignmentID)

View File

@@ -0,0 +1,159 @@
import datetime
import uuid
from .ConnectionString import ConnectionString
from .DashboardLogger import DashboardLogger
import sqlalchemy as db
from .WireguardConfiguration import WireguardConfiguration
class Assignment:
def __init__(self, **kwargs):
self.AssignmentID: str = kwargs.get('AssignmentID')
self.ClientID: str = kwargs.get('ClientID')
self.ConfigurationName: str = kwargs.get('ConfigurationName')
self.PeerID: str = kwargs.get('PeerID')
self.AssignedDate: datetime.datetime = kwargs.get('AssignedDate')
self.UnassignedDate: datetime.datetime = kwargs.get('UnassignedDate')
self.Client: dict = {
"ClientID": self.ClientID
}
def toJson(self):
return {
"AssignmentID": self.AssignmentID,
"Client": self.Client,
"ConfigurationName": self.ConfigurationName,
"PeerID": self.PeerID,
"AssignedDate": self.AssignedDate.strftime("%Y-%m-%d %H:%M:%S"),
"UnassignedDate": self.UnassignedDate.strftime("%Y-%m-%d %H:%M:%S") if self.UnassignedDate is not None else self.UnassignedDate
}
class DashboardClientsPeerAssignment:
def __init__(self, wireguardConfigurations: dict[str, WireguardConfiguration]):
self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.wireguardConfigurations = wireguardConfigurations
self.dashboardClientsPeerAssignmentTable = db.Table(
'DashboardClientsPeerAssignment', self.metadata,
db.Column('AssignmentID', db.String(255), nullable=False, primary_key=True),
db.Column('ClientID', db.String(255), nullable=False, index=True),
db.Column('ConfigurationName', db.String(255)),
db.Column('PeerID', db.String(500)),
db.Column('AssignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('UnassignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
extend_existing=True
)
self.metadata.create_all(self.engine)
self.assignments: list[Assignment] = []
self.__getAssignments()
def __getAssignments(self):
with self.engine.connect() as conn:
assignments = []
get = conn.execute(
self.dashboardClientsPeerAssignmentTable.select().where(
self.dashboardClientsPeerAssignmentTable.c.UnassignedDate.is_(None)
)
).mappings().fetchall()
for a in get:
assignments.append(Assignment(**a))
self.assignments = assignments
def AssignClient(self, ClientID, ConfigurationName, PeerID):
existing = list(
filter(lambda e:
e.ClientID == ClientID and
e.ConfigurationName == ConfigurationName and
e.PeerID == PeerID, self.assignments)
)
if len(existing) == 0:
if ConfigurationName in self.wireguardConfigurations.keys():
config = self.wireguardConfigurations.get(ConfigurationName)
peer = list(filter(lambda x : x.id == PeerID, config.Peers))
if len(peer) == 1:
with self.engine.begin() as conn:
data = {
"AssignmentID": str(uuid.uuid4()),
"ClientID": ClientID,
"ConfigurationName": ConfigurationName,
"PeerID": PeerID
}
conn.execute(
self.dashboardClientsPeerAssignmentTable.insert().values(data)
)
self.__getAssignments()
return True, data
return False, None
def UnassignClients(self, AssignmentID):
existing = list(
filter(lambda e:
e.AssignmentID == AssignmentID, self.assignments)
)
if not existing:
return False
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsPeerAssignmentTable.update().values({
"UnassignedDate": datetime.datetime.now()
}).where(
self.dashboardClientsPeerAssignmentTable.c.AssignmentID == AssignmentID
)
)
self.__getAssignments()
return True
def UnassignPeers(self, ClientID):
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsPeerAssignmentTable.update().values({
"UnassignedDate": datetime.datetime.now()
}).where(
db.and_(
self.dashboardClientsPeerAssignmentTable.c.ClientID == ClientID,
self.dashboardClientsPeerAssignmentTable.c.UnassignedDate.is_(db.null())
)
)
)
self.__getAssignments()
return True
def GetAssignedClients(self, ConfigurationName, PeerID) -> list[Assignment]:
self.__getAssignments()
return list(filter(
lambda c : c.ConfigurationName == ConfigurationName and
c.PeerID == PeerID, self.assignments))
def GetAssignedPeers(self, ClientID):
self.__getAssignments()
peers = []
assigned = filter(lambda e:
e.ClientID == ClientID, self.assignments)
for a in assigned:
peer = filter(lambda e : e.id == a.PeerID,
self.wireguardConfigurations[a.ConfigurationName].Peers)
for p in peer:
peers.append({
'assignment_id': a.AssignmentID,
'protocol': self.wireguardConfigurations[a.ConfigurationName].Protocol,
'id': p.id,
'private_key': p.private_key,
'name': p.name,
'received_data': p.total_receive + p.cumu_receive,
'sent_data': p.total_sent + p.cumu_sent,
'data': p.total_data + p.cumu_data,
'status': p.status,
'latest_handshake': p.latest_handshake,
'allowed_ip': p.allowed_ip,
'jobs': p.jobs,
'configuration_name': a.ConfigurationName,
'peer_configuration_data': p.downloadPeer()
})
return peers

View File

@@ -0,0 +1,82 @@
import datetime
import hashlib
import uuid
import sqlalchemy as db
from .ConnectionString import ConnectionString
class DashboardClientsTOTP:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.dashboardClientsTOTPTable = db.Table(
'DashboardClientsTOTPTokens', self.metadata,
db.Column("Token", db.String(500), primary_key=True, index=True),
db.Column("ClientID", db.String(500), index=True),
db.Column(
"ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)
)
)
self.metadata.create_all(self.engine)
self.metadata.reflect(self.engine)
self.dashboardClientsTable = self.metadata.tables['DashboardClients']
def GenerateToken(self, ClientID) -> str:
token = hashlib.sha512(f"{ClientID}_{datetime.datetime.now()}_{uuid.uuid4()}".encode()).hexdigest()
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsTOTPTable.update().values({
"ExpireTime": datetime.datetime.now()
}).where(
db.and_(self.dashboardClientsTOTPTable.c.ClientID == ClientID, self.dashboardClientsTOTPTable.c.ExpireTime > datetime.datetime.now())
)
)
conn.execute(
self.dashboardClientsTOTPTable.insert().values({
"Token": token,
"ClientID": ClientID,
"ExpireTime": datetime.datetime.now() + datetime.timedelta(minutes=10)
})
)
return token
def RevokeToken(self, Token) -> bool:
try:
with self.engine.begin() as conn:
conn.execute(
self.dashboardClientsTOTPTable.update().values({
"ExpireTime": datetime.datetime.now()
}).where(
self.dashboardClientsTOTPTable.c.Token == Token
)
)
except Exception as e:
return False
return True
def GetTotp(self, token: str) -> tuple[bool, dict] or tuple[bool, None]:
with self.engine.connect() as conn:
totp = conn.execute(
db.select(
self.dashboardClientsTable.c.ClientID,
self.dashboardClientsTable.c.Email,
self.dashboardClientsTable.c.TotpKey,
self.dashboardClientsTable.c.TotpKeyVerified,
).select_from(
self.dashboardClientsTOTPTable
).where(
db.and_(
self.dashboardClientsTOTPTable.c.Token == token,
self.dashboardClientsTOTPTable.c.ExpireTime > datetime.datetime.now()
)
).join(
self.dashboardClientsTable,
self.dashboardClientsTOTPTable.c.ClientID == self.dashboardClientsTable.c.ClientID
)
).mappings().fetchone()
if totp:
return True, dict(totp)
return False, None

View File

@@ -0,0 +1,285 @@
"""
Dashboard Configuration
"""
import configparser, secrets, os, pyotp, ipaddress, bcrypt
from sqlalchemy_utils import database_exists, create_database
import sqlalchemy as db
from datetime import datetime
from typing import Any
from flask import current_app
from .ConnectionString import ConnectionString
from .Utilities import (
GetRemoteEndpoint, ValidateDNSAddress
)
from .DashboardAPIKey import DashboardAPIKey
class DashboardConfig:
DashboardVersion = 'v4.3'
ConfigurationPath = os.getenv('CONFIGURATION_PATH', '.')
ConfigurationFilePath = os.path.join(ConfigurationPath, 'wg-dashboard.ini')
def __init__(self):
if not os.path.exists(DashboardConfig.ConfigurationFilePath):
open(DashboardConfig.ConfigurationFilePath, "x")
self.__config = configparser.RawConfigParser(strict=False)
self.__config.read_file(open(DashboardConfig.ConfigurationFilePath, "r+"))
self.hiddenAttribute = ["totp_key", "auth_req"]
self.__default = {
"Account": {
"username": "admin",
"password": "admin",
"enable_totp": "false",
"totp_verified": "false",
"totp_key": pyotp.random_base32()
},
"Server": {
"wg_conf_path": "/etc/wireguard",
"awg_conf_path": "/etc/amnezia/amneziawg",
"app_prefix": "",
"app_ip": "0.0.0.0",
"app_port": "10086",
"auth_req": "true",
"version": DashboardConfig.DashboardVersion,
"dashboard_refresh_interval": "60000",
"dashboard_peer_list_display": "grid",
"dashboard_sort": "status",
"dashboard_theme": "dark",
"dashboard_api_key": "false",
"dashboard_language": "en-US"
},
"Peers": {
"peer_global_DNS": "1.1.1.1",
"peer_endpoint_allowed_ip": "0.0.0.0/0",
"peer_display_mode": "grid",
"remote_endpoint": GetRemoteEndpoint(),
"peer_MTU": "1420",
"peer_keep_alive": "21"
},
"Other": {
"welcome_session": "true"
},
"Database":{
"type": "sqlite",
"host": "",
"port": "",
"username": "",
"password": ""
},
"Email":{
"server": "",
"port": "",
"encryption": "",
"username": "",
"email_password": "",
"authentication_required": "true",
"send_from": "",
"email_template": ""
},
"OIDC": {
"admin_enable": "false",
"client_enable": "false"
},
"Clients": {
"enable": "true",
},
"WireGuardConfiguration": {
"autostart": ""
}
}
for section, keys in self.__default.items():
for key, value in keys.items():
exist, currentData = self.GetConfig(section, key)
if not exist:
self.SetConfig(section, key, value, True)
self.engine = db.create_engine(ConnectionString('wgdashboard'))
self.dbMetadata = db.MetaData()
self.__createAPIKeyTable()
self.DashboardAPIKeys = self.__getAPIKeys()
self.APIAccessed = False
self.SetConfig("Server", "version", DashboardConfig.DashboardVersion)
def getConnectionString(self, database) -> str or None:
sqlitePath = os.path.join(DashboardConfig.ConfigurationPath, "db")
if not os.path.isdir(sqlitePath):
os.mkdir(sqlitePath)
if self.GetConfig("Database", "type")[1] == "postgresql":
cn = f'postgresql+psycopg2://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
elif self.GetConfig("Database", "type")[1] == "mysql":
cn = f'mysql+mysqldb://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}'
if not database_exists(cn):
create_database(cn)
return cn
def __createAPIKeyTable(self):
self.apiKeyTable = db.Table('DashboardAPIKeys', self.dbMetadata,
db.Column("Key", db.String(255), nullable=False, primary_key=True),
db.Column("CreatedAt",
(db.DATETIME if self.GetConfig('Database', 'type')[1] == 'sqlite' else db.TIMESTAMP),
server_default=db.func.now()
),
db.Column("ExpiredAt",
(db.DATETIME if self.GetConfig('Database', 'type')[1] == 'sqlite' else db.TIMESTAMP)
)
)
self.dbMetadata.create_all(self.engine)
def __getAPIKeys(self) -> list[DashboardAPIKey]:
try:
with self.engine.connect() as conn:
keys = conn.execute(self.apiKeyTable.select().where(
db.or_(self.apiKeyTable.columns.ExpiredAt.is_(None), self.apiKeyTable.columns.ExpiredAt > datetime.now())
)).fetchall()
fKeys = []
for k in keys:
fKeys.append(DashboardAPIKey(k[0], k[1].strftime("%Y-%m-%d %H:%M:%S"), (k[2].strftime("%Y-%m-%d %H:%M:%S") if k[2] else None)))
return fKeys
except Exception as e:
current_app.logger.error("API Keys error", e)
return []
def createAPIKeys(self, ExpiredAt = None):
newKey = secrets.token_urlsafe(32)
with self.engine.begin() as conn:
conn.execute(
self.apiKeyTable.insert().values({
"Key": newKey,
"ExpiredAt": ExpiredAt
})
)
self.DashboardAPIKeys = self.__getAPIKeys()
def deleteAPIKey(self, key):
with self.engine.begin() as conn:
conn.execute(
self.apiKeyTable.update().values({
"ExpiredAt": datetime.now(),
}).where(self.apiKeyTable.columns.Key == key)
)
self.DashboardAPIKeys = self.__getAPIKeys()
def __configValidation(self, section : str, key: str, value: Any) -> tuple[bool, str]:
if (type(value) is str and len(value) == 0
and section not in ['Email', 'WireGuardConfiguration'] and
(section == 'Peer' and key == 'peer_global_dns')):
return False, "Field cannot be empty!"
if section == "Peers" and key == "peer_global_dns" and len(value) > 0:
return ValidateDNSAddress(value)
if section == "Peers" and key == "peer_endpoint_allowed_ip":
value = value.split(",")
for i in value:
i = i.strip()
try:
ipaddress.ip_network(i, strict=False)
except Exception as e:
return False, str(e)
if section == "Server" and key == "wg_conf_path":
if not os.path.exists(value):
return False, f"{value} is not a valid path"
if section == "Account" and key == "password":
if self.GetConfig("Account", "password")[0]:
if not self.__checkPassword(
value["currentPassword"], self.GetConfig("Account", "password")[1].encode("utf-8")):
return False, "Current password does not match."
if value["newPassword"] != value["repeatNewPassword"]:
return False, "New passwords does not match"
return True, ""
def generatePassword(self, plainTextPassword: str):
return bcrypt.hashpw(plainTextPassword.encode("utf-8"), bcrypt.gensalt())
def __checkPassword(self, plainTextPassword: str, hashedPassword: bytes):
return bcrypt.checkpw(plainTextPassword.encode("utf-8"), hashedPassword)
def SetConfig(self, section: str, key: str, value: str | bool | list[str] | dict[str, str], init: bool = False) -> tuple[bool, str] | tuple[bool, None]:
if key in self.hiddenAttribute and not init:
return False, None
if not init:
valid, msg = self.__configValidation(section, key, value)
if not valid:
return False, msg
if section == "Account" and key == "password":
if not init:
value = self.generatePassword(value["newPassword"]).decode("utf-8")
else:
value = self.generatePassword(value).decode("utf-8")
if section == "Email" and key == "email_template":
value = value.encode('unicode_escape').decode('utf-8')
if section == "Server" and key == "wg_conf_path":
if not os.path.exists(value):
return False, "Path does not exist"
if section not in self.__config:
if init:
self.__config[section] = {}
else:
return False, "Section does not exist"
if ((key not in self.__config[section].keys() and init) or
(key in self.__config[section].keys())):
if type(value) is bool:
if value:
self.__config[section][key] = "true"
else:
self.__config[section][key] = "false"
elif type(value) in [int, float]:
self.__config[section][key] = str(value)
elif type(value) is list:
self.__config[section][key] = "||".join(value).strip("||")
else:
self.__config[section][key] = fr"{value}"
return self.SaveConfig(), ""
else:
return False, f"{key} does not exist under {section}"
def SaveConfig(self) -> bool:
try:
with open(DashboardConfig.ConfigurationFilePath, "w+", encoding='utf-8') as configFile:
self.__config.write(configFile)
return True
except Exception as e:
return False
def GetConfig(self, section, key) ->tuple[bool, bool] | tuple[bool, str] | tuple[bool, list[str]] | tuple[bool, None]:
if section not in self.__config:
return False, None
if key not in self.__config[section]:
return False, None
if section == "Email" and key == "email_template":
return True, self.__config[section][key].encode('utf-8').decode('unicode_escape')
if section == "WireGuardConfiguration" and key == "autostart":
return True, list(filter(lambda x: len(x) > 0, self.__config[section][key].split("||")))
if self.__config[section][key] in ["1", "yes", "true", "on"]:
return True, True
if self.__config[section][key] in ["0", "no", "false", "off"]:
return True, False
return True, self.__config[section][key]
def toJson(self) -> dict[str, dict[Any, Any]]:
the_dict = {}
for section in self.__config.sections():
the_dict[section] = {}
for key, val in self.__config.items(section):
if key not in self.hiddenAttribute:
the_dict[section][key] = self.GetConfig(section, key)[1]
return the_dict

View File

@@ -0,0 +1,44 @@
"""
Dashboard Logger Class
"""
import uuid
import sqlalchemy as db
from flask import current_app
from .ConnectionString import ConnectionString
class DashboardLogger:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard_log"))
self.metadata = db.MetaData()
self.dashboardLoggerTable = db.Table('DashboardLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True),
db.Column('LogDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('URL', db.String(255)),
db.Column('IP', db.String(255)),
db.Column('Status', db.String(255), nullable=False),
db.Column('Message', db.Text), extend_existing=True,
)
self.metadata.create_all(self.engine)
self.log(Message="WGDashboard started")
def log(self, URL: str = "", IP: str = "", Status: str = "true", Message: str = "") -> bool:
try:
with self.engine.begin() as conn:
conn.execute(
self.dashboardLoggerTable.insert().values(
LogID=str(uuid.uuid4()),
URL=URL,
IP=IP,
Status=Status,
Message=Message
)
)
return True
except Exception as e:
current_app.logger.error(f"Access Log Error", e)
return False

View File

@@ -0,0 +1,142 @@
import os
import json
import requests
from jose import jwt
import certifi
from flask import current_app
class DashboardOIDC:
ConfigurationPath = os.getenv('CONFIGURATION_PATH', '.')
ConfigurationFilePath = os.path.join(ConfigurationPath, 'wg-dashboard-oidc-providers.json')
def __init__(self, mode):
self.mode = mode
self.providers: dict[str, dict] = {}
self.provider_secret: dict[str, str] = {}
self.__default = {
"Admin": {
'Provider': {
'client_id': '',
'client_secret': '',
'issuer': '',
},
},
"Client": {
'Provider': {
'client_id': '',
'client_secret': '',
'issuer': '',
},
}
}
if not os.path.exists(DashboardOIDC.ConfigurationFilePath):
with open(DashboardOIDC.ConfigurationFilePath, "w+") as f:
encoder = json.JSONEncoder(indent=4)
f.write(encoder.encode(self.__default))
self.ReadFile()
def GetProviders(self):
return self.providers
def GetProviderNameByIssuer(self, issuer):
for (key, val) in self.providers.items():
if val.get('openid_configuration').get('issuer') == issuer:
return key
return issuer
def VerifyToken(self, provider, code, redirect_uri):
try:
if not all([provider, code, redirect_uri]):
return False, "Please provide all parameters"
if provider not in self.providers.keys():
return False, "Provider does not exist"
secrete = self.provider_secret.get(provider)
oidc_config_status, oidc_config = self.GetProviderConfiguration(provider)
provider_info = self.providers.get(provider)
data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirect_uri,
"client_id": provider_info.get('client_id'),
"client_secret": secrete
}
try:
tokens = requests.post(oidc_config.get('token_endpoint'), data=data).json()
if not all([tokens.get('access_token'), tokens.get('id_token')]):
return False, tokens.get('error_description', None)
except Exception as e:
current_app.logger.error("Verify token failed", e)
return False, str(e)
access_token = tokens.get('access_token')
id_token = tokens.get('id_token')
jwks_uri = oidc_config.get("jwks_uri")
issuer = oidc_config.get("issuer")
jwks = requests.get(jwks_uri, verify=certifi.where()).json()
headers = jwt.get_unverified_header(id_token)
kid = headers["kid"]
key = next(k for k in jwks["keys"] if k["kid"] == kid)
payload = jwt.decode(
id_token,
key,
algorithms=[key["alg"]],
audience=provider_info.get('client_id'),
issuer=issuer,
access_token=access_token
)
print(payload)
return True, payload
except Exception as e:
current_app.logger.error('Read OIDC file failed. Reason: ' + str(e), provider, code, redirect_uri)
return False, str(e)
def GetProviderConfiguration(self, provider_name):
if not all([provider_name]):
return False, None
provider = self.providers.get(provider_name)
try:
oidc_config = requests.get(
f"{provider.get('issuer').strip('/')}/.well-known/openid-configuration",
verify=certifi.where()
).json()
except Exception as e:
current_app.logger.error("Failed to get OpenID Configuration of " + provider.get('issuer'), exc_info=e)
return False, None
return True, oidc_config
def ReadFile(self):
decoder = json.JSONDecoder()
try:
providers = decoder.decode(
open(DashboardOIDC.ConfigurationFilePath, 'r').read()
)
providers = providers[self.mode]
for k in providers.keys():
if all([providers[k]['client_id'], providers[k]['client_secret'], providers[k]['issuer']]):
try:
oidc_config = requests.get(
f"{providers[k]['issuer'].strip('/')}/.well-known/openid-configuration",
timeout=3,
verify=certifi.where()
).json()
self.providers[k] = {
'client_id': providers[k]['client_id'],
'issuer': providers[k]['issuer'].strip('/'),
'openid_configuration': oidc_config
}
self.provider_secret[k] = providers[k]['client_secret']
current_app.logger.info(f"Registered OIDC Provider: {k}")
except Exception as e:
current_app.logger.error(f"Failed to register OIDC config for {k}", exc_info=e)
except Exception as e:
current_app.logger.error('Read OIDC file failed. Reason: ' + str(e))
return False

View File

@@ -0,0 +1,117 @@
import os
import sys
import importlib.util
from pathlib import Path
from typing import Dict, Callable, List, Optional
import threading
class DashboardPlugins:
def __init__(self, app, WireguardConfigurations, directory: str = 'plugins'):
self.directory = Path('plugins')
self.loadedPlugins: dict[str, Callable] = {}
self.errorPlugins: List[str] = []
self.logger = app.logger
self.WireguardConfigurations = WireguardConfigurations
def startThreads(self):
self.loadAllPlugins()
self.executeAllPlugins()
def preparePlugins(self) -> list[Path]:
readyPlugins = []
if not self.directory.exists():
os.mkdir(self.directory)
return []
for plugin in self.directory.iterdir():
if plugin.is_dir():
codeFile = plugin / "main.py"
if codeFile.exists():
self.logger.info(f"Prepared plugin: {plugin.name}")
readyPlugins.append(plugin)
return readyPlugins
def loadPlugin(self, path: Path) -> Optional[Callable]:
pluginName = path.name
codeFile = path / "main.py"
try:
spec = importlib.util.spec_from_file_location(
f"WGDashboardPlugin_{pluginName}",
codeFile
)
if spec is None or spec.loader is None:
raise ImportError(f"Failed to create spec for {pluginName}")
module = importlib.util.module_from_spec(spec)
plugin_dir_str = str(path)
if plugin_dir_str not in sys.path:
sys.path.insert(0, plugin_dir_str)
try:
spec.loader.exec_module(module)
finally:
if plugin_dir_str in sys.path:
sys.path.remove(plugin_dir_str)
if hasattr(module, 'main'):
main_func = getattr(module, 'main')
if callable(main_func):
self.logger.info(f"Successfully loaded plugin [{pluginName}]")
return main_func
else:
raise AttributeError(f"'main' in {pluginName} is not callable")
else:
raise AttributeError(f"Plugin {pluginName} does not have a 'main' function")
except Exception as e:
self.logger.error(f"Failed to load the plugin [{pluginName}]. Reason: {str(e)}")
self.errorPlugins.append(pluginName)
return None
def loadAllPlugins(self):
self.loadedPlugins.clear()
self.errorPlugins.clear()
preparedPlugins = self.preparePlugins()
for plugin in preparedPlugins:
pluginName = plugin.name
mainFunction = self.loadPlugin(plugin)
if mainFunction:
self.loadedPlugins[pluginName] = mainFunction
if self.errorPlugins:
self.logger.warning(f"Failed to load {len(self.errorPlugins)} plugin(s): {self.errorPlugins}")
def executePlugin(self, pluginName: str):
if pluginName not in self.loadedPlugins.keys():
self.logger.error(f"Failed to execute plugin [{pluginName}]. Reason: Not loaded")
return False
plugin = self.loadedPlugins.get(pluginName)
try:
t = threading.Thread(target=plugin, args=(self.WireguardConfigurations,), daemon=True)
t.name = f'WGDashboardPlugin_{pluginName}'
t.start()
if t.is_alive():
self.logger.info(f"Execute plugin [{pluginName}] success. PID: {t.native_id}")
except Exception as e:
self.logger.error(f"Failed to execute plugin [{pluginName}]. Reason: {str(e)}")
return False
return True
def executeAllPlugins(self):
for plugin in self.loadedPlugins.keys():
self.executePlugin(plugin)

View File

@@ -0,0 +1,287 @@
import json
import threading
import time
import urllib.parse
import uuid
from datetime import datetime, timedelta
import requests
from pydantic import BaseModel, field_serializer
import sqlalchemy as db
from .ConnectionString import ConnectionString
from flask import current_app
WebHookActions = ['peer_created', 'peer_deleted', 'peer_updated']
class WebHook(BaseModel):
WebHookID: str = ''
PayloadURL: str = ''
ContentType: str = 'application/json'
Headers: dict[str, dict[str, str]] = {}
VerifySSL: bool = True
SubscribedActions: list[str] = WebHookActions
IsActive: bool = True
CreationDate: datetime = ''
Notes: str = ''
class WebHookSessionLog(BaseModel):
LogTime: datetime
Status: int
Message: str = ''
@field_serializer('LogTime')
def logTimeSerializer(self, LogTime: datetime):
return LogTime.strftime("%Y-%m-%d %H:%M:%S")
class WebHookSessionLogs(BaseModel):
Logs: list[WebHookSessionLog] = []
def addLog(self, status: int, message: str):
self.Logs.append(WebHookSessionLog(LogTime=datetime.now(), Status=status, Message=message))
class DashboardWebHooks:
def __init__(self, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.webHooksTable = db.Table(
'DashboardWebHooks', self.metadata,
db.Column('WebHookID', db.String(255), nullable=False, primary_key=True),
db.Column('PayloadURL', db.Text, nullable=False),
db.Column('ContentType', db.String(255), nullable=False),
db.Column('Headers', db.JSON),
db.Column('VerifySSL', db.Boolean, nullable=False),
db.Column('SubscribedActions', db.JSON),
db.Column('IsActive', db.Boolean, nullable=False),
db.Column('CreationDate',
(db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
server_default=db.func.now(),
nullable=False),
db.Column('Notes', db.Text),
extend_existing=True
)
self.webHookSessionsTable = db.Table(
'DashboardWebHookSessions', self.metadata,
db.Column('WebHookSessionID', db.String(255), nullable=False, primary_key=True),
db.Column('WebHookID', db.String(255), nullable=False),
db.Column('StartDate',
(db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
server_default=db.func.now(),
nullable=False
),
db.Column('EndDate',
(db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
),
db.Column('Data', db.JSON),
db.Column('Status', db.INTEGER),
db.Column('Logs', db.JSON)
)
self.metadata.create_all(self.engine)
self.WebHooks: list[WebHook] = []
with self.engine.begin() as conn:
conn.execute(
self.webHookSessionsTable.update().values({
"EndDate": datetime.now(),
"Status": 2
}).where(
self.webHookSessionsTable.c.Status == -1
)
)
self.__getWebHooks()
def __getWebHooks(self):
with self.engine.connect() as conn:
webhooks = conn.execute(
self.webHooksTable.select().order_by(
self.webHooksTable.c.CreationDate
)
).mappings().fetchall()
self.WebHooks.clear()
self.WebHooks = [WebHook(**webhook) for webhook in webhooks]
def GetWebHooks(self):
self.__getWebHooks()
return list(map(lambda x : x.model_dump(), self.WebHooks))
def GetWebHookSessions(self, webHook: WebHook):
with self.engine.connect() as conn:
sessions = conn.execute(
self.webHookSessionsTable.select().where(
self.webHookSessionsTable.c.WebHookID == webHook.WebHookID
).order_by(
db.desc(self.webHookSessionsTable.c.StartDate)
)
).mappings().fetchall()
return sessions
def CreateWebHook(self) -> WebHook:
return WebHook(WebHookID=str(uuid.uuid4()))
def SearchWebHook(self, webHook: WebHook) -> WebHook | None:
try:
first = next(filter(lambda x : x.WebHookID == webHook.WebHookID, self.WebHooks))
except StopIteration:
return None
return first
def SearchWebHookByID(self, webHookID: str) -> WebHook | None:
try:
first = next(filter(lambda x : x.WebHookID == webHookID, self.WebHooks))
except StopIteration:
return None
return first
def UpdateWebHook(self, webHook: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]:
try:
webHook = WebHook(**webHook)
if len(webHook.PayloadURL) == 0:
return False, "Payload URL cannot be empty"
if len(webHook.ContentType) == 0 or webHook.ContentType not in [
'application/json', 'application/x-www-form-urlencoded'
]:
return False, "Content Type is invalid"
with self.engine.begin() as conn:
if self.SearchWebHook(webHook):
conn.execute(
self.webHooksTable.update().values(
webHook.model_dump(exclude={'WebHookID'})
).where(
self.webHooksTable.c.WebHookID == webHook.WebHookID
)
)
else:
webHook.CreationDate = datetime.now()
conn.execute(
self.webHooksTable.insert().values(
webHook.model_dump()
)
)
self.__getWebHooks()
except Exception as e:
return False, str(e)
return True, None
def DeleteWebHook(self, webHook) -> tuple[bool, str] | tuple[bool, None]:
try:
webHook = WebHook(**webHook)
with self.engine.begin() as conn:
conn.execute(
self.webHooksTable.delete().where(
self.webHooksTable.c.WebHookID == webHook.WebHookID
)
)
self.__getWebHooks()
except Exception as e:
return False, str(e)
return True, None
def RunWebHook(self, action: str, data):
try:
if action not in WebHookActions:
return False
self.__getWebHooks()
subscribedWebHooks = filter(lambda webhook: action in webhook.SubscribedActions and webhook.IsActive,
self.WebHooks)
data['action'] = action
for i in subscribedWebHooks:
try:
ws = WebHookSession(i, data)
t = threading.Thread(target=ws.Execute, daemon=True)
t.start()
current_app.logger.info(f"Requesting {i.PayloadURL}")
except Exception as e:
current_app.logger.error(f"Requesting {i.PayloadURL} error", e)
except Exception as e:
current_app.logger.error("Error when running WebHook")
class WebHookSession:
def __init__(self, webHook: WebHook, data: dict[str, str]):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.webHookSessionsTable = db.Table('DashboardWebHookSessions', self.metadata, autoload_with=self.engine)
self.webHook = webHook
self.sessionID = str(uuid.uuid4())
self.webHookSessionLogs: WebHookSessionLogs = WebHookSessionLogs()
self.time = datetime.now()
data['time'] = self.time.strftime("%Y-%m-%d %H:%M:%S")
data['webhook_id'] = webHook.WebHookID
data['webhook_session'] = self.sessionID
self.data = data
self.Prepare()
def Prepare(self):
with self.engine.begin() as conn:
conn.execute(
self.webHookSessionsTable.insert().values({
"WebHookSessionID": self.sessionID,
"WebHookID": self.webHook.WebHookID,
"Data": self.data,
"StartDate": self.time,
"Status": -1,
"Logs": self.webHookSessionLogs.model_dump()
})
)
self.UpdateSessionLog(-1, "Preparing webhook session")
def UpdateSessionLog(self, status, message):
self.webHookSessionLogs.addLog(status, message)
with self.engine.begin() as conn:
conn.execute(
self.webHookSessionsTable.update().values({
"Logs": self.webHookSessionLogs.model_dump()
}).where(
self.webHookSessionsTable.c.WebHookSessionID == self.sessionID
)
)
def UpdateStatus(self, status: int):
with self.engine.begin() as conn:
conn.execute(
self.webHookSessionsTable.update().values({
"Status": status,
"EndDate": datetime.now()
}).where(
self.webHookSessionsTable.c.WebHookSessionID == self.sessionID
)
)
def Execute(self):
success = False
for i in range(5):
headerDictionary = {
'Content-Type': self.webHook.ContentType
}
for header in self.webHook.Headers.values():
if header['key'] not in ['Content-Type']:
headerDictionary[header['key']] = header['value']
if self.webHook.ContentType == "application/json":
reqData = json.dumps(self.data)
else:
for (key, val) in self.data.items():
if type(self.data[key]) not in [str, int]:
self.data[key] = json.dumps(self.data[key])
reqData = urllib.parse.urlencode(self.data)
try:
req = requests.post(
self.webHook.PayloadURL, headers=headerDictionary, timeout=10, data=reqData, verify=self.webHook.VerifySSL
)
req.raise_for_status()
success = True
self.UpdateSessionLog(0, "Webhook request finished")
self.UpdateSessionLog(0, json.dumps({"returned_data": req.text}))
self.UpdateStatus(0)
break
except requests.exceptions.RequestException as e:
self.UpdateSessionLog(1, f"Attempt #{i + 1}/5. Request errored. Reason: " + str(e))
time.sleep(10)
if not success:
self.UpdateSessionLog(1, "Webhook request failed & terminated.")
self.UpdateStatus(1)

76
src/modules/Email.py Normal file
View File

@@ -0,0 +1,76 @@
import os.path
import smtplib
from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr
class EmailSender:
def __init__(self, DashboardConfig):
self.smtp = None
self.DashboardConfig = DashboardConfig
if not os.path.exists('./attachments'):
os.mkdir('./attachments')
def Server(self):
return self.DashboardConfig.GetConfig("Email", "server")[1]
def Port(self):
return self.DashboardConfig.GetConfig("Email", "port")[1]
def Encryption(self):
return self.DashboardConfig.GetConfig("Email", "encryption")[1]
def Username(self):
return self.DashboardConfig.GetConfig("Email", "username")[1]
def Password(self):
return self.DashboardConfig.GetConfig("Email", "email_password")[1]
def SendFrom(self):
return self.DashboardConfig.GetConfig("Email", "send_from")[1]
# Thank you, @gdeeble from GitHub
def AuthenticationRequired(self):
return self.DashboardConfig.GetConfig("Email", "authentication_required")[1]
def ready(self):
if self.AuthenticationRequired():
return all([self.Server(), self.Port(), self.Encryption(), self.Username(), self.Password(), self.SendFrom()])
return all([self.Server(), self.Port(), self.Encryption(), self.SendFrom()])
def send(self, receiver, subject, body, includeAttachment = False, attachmentName = "") -> tuple[bool, str] | tuple[bool, None]:
if self.ready():
try:
self.smtp = smtplib.SMTP(self.Server(), port=int(self.Port()))
self.smtp.ehlo()
if self.Encryption() == "STARTTLS":
self.smtp.starttls()
if self.AuthenticationRequired():
self.smtp.login(self.Username(), self.Password())
message = MIMEMultipart()
message['Subject'] = subject
message['From'] = self.SendFrom()
message["To"] = receiver
message.attach(MIMEText(body, "plain"))
if includeAttachment and len(attachmentName) > 0:
attachmentPath = os.path.join('./attachments', attachmentName)
if os.path.exists(attachmentPath):
attachment = MIMEBase("application", "octet-stream")
with open(os.path.join('./attachments', attachmentName), 'rb') as f:
attachment.set_payload(f.read())
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", f"attachment; filename= {attachmentName}",)
message.attach(attachment)
else:
self.smtp.close()
return False, "Attachment does not exist"
self.smtp.sendmail(self.SendFrom(), receiver, message.as_string())
self.smtp.close()
return True, None
except Exception as e:
return False, f"Send failed | Reason: {e}"
return False, "SMTP not configured"

22
src/modules/Log.py Normal file
View File

@@ -0,0 +1,22 @@
"""
Log Class
"""
class Log:
def __init__(self, LogID: str, JobID: str, LogDate: str, Status: str, Message: str):
self.LogID = LogID
self.JobID = JobID
self.LogDate = LogDate
self.Status = Status
self.Message = Message
def toJson(self):
return {
"LogID": self.LogID,
"JobID": self.JobID,
"LogDate": self.LogDate,
"Status": self.Status,
"Message": self.Message
}
def __dict__(self):
return self.toJson()

View File

@@ -0,0 +1,88 @@
import uuid
from pydantic import BaseModel, field_serializer
import sqlalchemy as db
from .ConnectionString import ConnectionString
class NewConfigurationTemplate(BaseModel):
TemplateID: str = ''
Subnet: str = ''
ListenPortStart: int = 0
ListenPortEnd: int = 0
Notes: str = ""
class NewConfigurationTemplates:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.templatesTable = db.Table(
'NewConfigurationTemplates', self.metadata,
db.Column('TemplateID', db.String(255), primary_key=True),
db.Column('Subnet', db.String(255)),
db.Column('ListenPortStart', db.Integer),
db.Column('ListenPortEnd', db.Integer),
db.Column('Notes', db.Text),
)
self.metadata.create_all(self.engine)
self.Templates: list[NewConfigurationTemplate] = []
self.__getTemplates()
def GetTemplates(self):
self.__getTemplates()
return list(map(lambda x : x.model_dump(), self.Templates))
def __getTemplates(self):
with self.engine.connect() as conn:
templates = conn.execute(
self.templatesTable.select()
).mappings().fetchall()
self.Templates.clear()
self.Templates = [NewConfigurationTemplate(**template) for template in templates]
def CreateTemplate(self) -> NewConfigurationTemplate:
return NewConfigurationTemplate(TemplateID=str(uuid.uuid4()))
def SearchTemplate(self, template: NewConfigurationTemplate):
try:
first = next(filter(lambda x : x.TemplateID == template.TemplateID, self.Templates))
except StopIteration:
return None
return first
def UpdateTemplate(self, template: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]:
try:
template = NewConfigurationTemplate(**template)
with self.engine.begin() as conn:
if self.SearchTemplate(template):
conn.execute(
self.templatesTable.update().values(
template.model_dump(exclude={'TemplateID'})
).where(
self.templatesTable.c.TemplateID == template.TemplateID
)
)
else:
conn.execute(
self.templatesTable.insert().values(
template.model_dump()
)
)
self.__getTemplates()
except Exception as e:
return False, str(e)
return True, None
def DeleteTemplate(self, template: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]:
try:
template = NewConfigurationTemplate(**template)
with self.engine.begin() as conn:
conn.execute(
self.templatesTable.delete().where(
self.templatesTable.c.TemplateID == template.TemplateID
)
)
self.__getTemplates()
except Exception as e:
return False, str(e)
return True, None

350
src/modules/Peer.py Normal file
View File

@@ -0,0 +1,350 @@
"""
Peer
"""
import base64
import datetime
import json
import os, subprocess, uuid, random, re
from datetime import timedelta
import jinja2
import sqlalchemy as db
from .PeerJob import PeerJob
from .PeerShareLink import PeerShareLink
from .Utilities import GenerateWireguardPublicKey, ValidateIPAddressesWithRange, ValidateDNSAddress
class Peer:
def __init__(self, tableData, configuration):
self.configuration = configuration
self.id = tableData["id"]
self.private_key = tableData["private_key"]
self.DNS = tableData["DNS"]
self.endpoint_allowed_ip = tableData["endpoint_allowed_ip"]
self.name = tableData["name"]
self.total_receive = tableData["total_receive"]
self.total_sent = tableData["total_sent"]
self.total_data = tableData["total_data"]
self.endpoint = tableData["endpoint"]
self.status = tableData["status"]
self.latest_handshake = tableData["latest_handshake"]
self.allowed_ip = tableData["allowed_ip"]
self.cumu_receive = tableData["cumu_receive"]
self.cumu_sent = tableData["cumu_sent"]
self.cumu_data = tableData["cumu_data"]
self.mtu = tableData["mtu"]
self.keepalive = tableData["keepalive"]
self.remote_endpoint = tableData["remote_endpoint"]
self.preshared_key = tableData["preshared_key"]
self.jobs: list[PeerJob] = []
self.ShareLink: list[PeerShareLink] = []
self.getJobs()
self.getShareLink()
def toJson(self):
# self.getJobs()
# self.getShareLink()
return self.__dict__
def __repr__(self):
return str(self.toJson())
def updatePeer(self, name: str, private_key: str,
preshared_key: str,
dns_addresses: str, allowed_ip: str, endpoint_allowed_ip: str, mtu: int,
keepalive: int) -> tuple[bool, str] or tuple[bool, None]:
if not self.configuration.getStatus():
self.configuration.toggleConfiguration()
existingAllowedIps = [item for row in list(
map(lambda x: [q.strip() for q in x.split(',')],
map(lambda y: y.allowed_ip,
list(filter(lambda k: k.id != self.id, self.configuration.getPeersList()))))) for item in row]
if allowed_ip in existingAllowedIps:
return False, "Allowed IP already taken by another peer"
if not ValidateIPAddressesWithRange(endpoint_allowed_ip):
return False, f"Endpoint Allowed IPs format is incorrect"
if len(dns_addresses) > 0 and not ValidateDNSAddress(dns_addresses):
return False, f"DNS format is incorrect"
if type(mtu) is str or mtu is None:
mtu = 0
if mtu < 0 or mtu > 1460:
return False, "MTU format is not correct"
if type(keepalive) is str or keepalive is None:
keepalive = 0
if keepalive < 0:
return False, "Persistent Keepalive format is not correct"
if len(private_key) > 0:
pubKey = GenerateWireguardPublicKey(private_key)
if not pubKey[0] or pubKey[1] != self.id:
return False, "Private key does not match with the public key"
try:
rd = random.Random()
uid = str(uuid.UUID(int=rd.getrandbits(128), version=4))
pskExist = len(preshared_key) > 0
if pskExist:
with open(uid, "w+") as f:
f.write(preshared_key)
newAllowedIPs = allowed_ip.replace(" ", "")
updateAllowedIp = subprocess.check_output(
f"{self.configuration.Protocol} set {self.configuration.Name} peer {self.id} allowed-ips {newAllowedIPs} {f'preshared-key {uid}' if pskExist else 'preshared-key /dev/null'}",
shell=True, stderr=subprocess.STDOUT)
if pskExist: os.remove(uid)
if len(updateAllowedIp.decode().strip("\n")) != 0:
return False, "Update peer failed when updating Allowed IPs"
saveConfig = subprocess.check_output(f"{self.configuration.Protocol}-quick save {self.configuration.Name}",
shell=True, stderr=subprocess.STDOUT)
if f"wg showconf {self.configuration.Name}" not in saveConfig.decode().strip('\n'):
return False, "Update peer failed when saving the configuration"
with self.configuration.engine.begin() as conn:
conn.execute(
self.configuration.peersTable.update().values({
"name": name,
"private_key": private_key,
"DNS": dns_addresses,
"endpoint_allowed_ip": endpoint_allowed_ip,
"mtu": mtu,
"keepalive": keepalive,
"preshared_key": preshared_key
}).where(
self.configuration.peersTable.c.id == self.id
)
)
return True, None
except subprocess.CalledProcessError as exc:
return False, exc.output.decode("UTF-8").strip()
def downloadPeer(self) -> dict[str, str]:
final = {
"fileName": "",
"file": ""
}
filename = self.name
if len(filename) == 0:
filename = "UntitledPeer"
filename = "".join(filename.split(' '))
filename = f"{filename}"
illegal_filename = [".", ",", "/", "?", "<", ">", "\\", ":", "*", '|' '\"', "com1", "com2", "com3",
"com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4",
"lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "con", "nul", "prn"]
for i in illegal_filename:
filename = filename.replace(i, "")
for i in filename:
if re.match("^[a-zA-Z0-9_=+.-]$", i):
final["fileName"] += i
interfaceSection = {
"PrivateKey": self.private_key,
"Address": self.allowed_ip,
"MTU": (
self.configuration.configurationInfo.OverridePeerSettings.MTU
if self.configuration.configurationInfo.OverridePeerSettings.MTU else self.mtu
),
"DNS": (
self.configuration.configurationInfo.OverridePeerSettings.DNS
if self.configuration.configurationInfo.OverridePeerSettings.DNS else self.DNS
)
}
if self.configuration.Protocol == "awg":
interfaceSection.update({
"Jc": self.configuration.Jc,
"Jmin": self.configuration.Jmin,
"Jmax": self.configuration.Jmax,
"S1": self.configuration.S1,
"S2": self.configuration.S2,
"H1": self.configuration.H1,
"H2": self.configuration.H2,
"H3": self.configuration.H3,
"H4": self.configuration.H4
})
peerSection = {
"PublicKey": self.configuration.PublicKey,
"AllowedIPs": (
self.configuration.configurationInfo.OverridePeerSettings.EndpointAllowedIPs
if self.configuration.configurationInfo.OverridePeerSettings.EndpointAllowedIPs else self.endpoint_allowed_ip
),
"Endpoint": f'{(self.configuration.configurationInfo.OverridePeerSettings.PeerRemoteEndpoint if self.configuration.configurationInfo.OverridePeerSettings.PeerRemoteEndpoint else self.configuration.DashboardConfig.GetConfig("Peers", "remote_endpoint")[1])}:{(self.configuration.configurationInfo.OverridePeerSettings.ListenPort if self.configuration.configurationInfo.OverridePeerSettings.ListenPort else self.configuration.ListenPort)}',
"PersistentKeepalive": (
self.configuration.configurationInfo.OverridePeerSettings.PersistentKeepalive
if self.configuration.configurationInfo.OverridePeerSettings.PersistentKeepalive
else self.keepalive
),
"PresharedKey": self.preshared_key
}
combine = [interfaceSection.items(), peerSection.items()]
for s in range(len(combine)):
if s == 0:
final["file"] += "[Interface]\n"
else:
final["file"] += "\n[Peer]\n"
for (key, val) in combine[s]:
if val is not None and ((type(val) is str and len(val) > 0) or (type(val) is int and val > 0)):
final["file"] += f"{key} = {val}\n"
if self.configuration.Protocol == "awg":
final["amneziaVPN"] = json.dumps({
"containers": [{
"awg": {
"isThirdPartyConfig": True,
"last_config": final['file'],
"port": self.configuration.ListenPort,
"transport_proto": "udp"
},
"container": "amnezia-awg"
}],
"defaultContainer": "amnezia-awg",
"description": self.name,
"hostName": (
self.configuration.configurationInfo.OverridePeerSettings.PeerRemoteEndpoint
if self.configuration.configurationInfo.OverridePeerSettings.PeerRemoteEndpoint
else self.configuration.DashboardConfig.GetConfig("Peers", "remote_endpoint")[1])
})
return final
def getJobs(self):
self.jobs = self.configuration.AllPeerJobs.searchJob(self.configuration.Name, self.id)
def getShareLink(self):
self.ShareLink = self.configuration.AllPeerShareLinks.getLink(self.configuration.Name, self.id)
def resetDataUsage(self, mode: str):
try:
with self.configuration.engine.begin() as conn:
if mode == "total":
conn.execute(
self.configuration.peersTable.update().values({
"total_data": 0,
"cumu_data": 0,
"total_receive": 0,
"cumu_receive": 0,
"total_sent": 0,
"cumu_sent": 0
}).where(
self.configuration.peersTable.c.id == self.id
)
)
self.total_data = 0
self.total_receive = 0
self.total_sent = 0
self.cumu_data = 0
self.cumu_sent = 0
self.cumu_receive = 0
elif mode == "receive":
conn.execute(
self.configuration.peersTable.update().values({
"total_receive": 0,
"cumu_receive": 0,
}).where(
self.configuration.peersTable.c.id == self.id
)
)
self.cumu_receive = 0
self.total_receive = 0
elif mode == "sent":
conn.execute(
self.configuration.peersTable.update().values({
"total_sent": 0,
"cumu_sent": 0
}).where(
self.configuration.peersTable.c.id == self.id
)
)
self.cumu_sent = 0
self.total_sent = 0
else:
return False
except Exception as e:
print(e)
return False
return True
def getEndpoints(self):
result = []
with self.configuration.engine.connect() as conn:
result = conn.execute(
db.select(
self.configuration.peersHistoryEndpointTable.c.endpoint
).group_by(
self.configuration.peersHistoryEndpointTable.c.endpoint
).where(
self.configuration.peersHistoryEndpointTable.c.id == self.id
)
).mappings().fetchall()
return list(result)
def getTraffics(self, interval: int = 30, startDate: datetime.datetime = None, endDate: datetime.datetime = None):
if startDate is None and endDate is None:
endDate = datetime.datetime.now()
startDate = endDate - timedelta(minutes=interval)
else:
endDate = endDate.replace(hour=23, minute=59, second=59, microsecond=999999)
startDate = startDate.replace(hour=0, minute=0, second=0, microsecond=0)
with self.configuration.engine.connect() as conn:
result = conn.execute(
db.select(
self.configuration.peersTransferTable.c.cumu_data,
self.configuration.peersTransferTable.c.total_data,
self.configuration.peersTransferTable.c.cumu_receive,
self.configuration.peersTransferTable.c.total_receive,
self.configuration.peersTransferTable.c.cumu_sent,
self.configuration.peersTransferTable.c.total_sent,
self.configuration.peersTransferTable.c.time
).where(
db.and_(
self.configuration.peersTransferTable.c.id == self.id,
self.configuration.peersTransferTable.c.time <= endDate,
self.configuration.peersTransferTable.c.time >= startDate,
)
).order_by(
self.configuration.peersTransferTable.c.time
)
).mappings().fetchall()
return list(result)
def getSessions(self, startDate: datetime.datetime = None, endDate: datetime.datetime = None):
if endDate is None:
endDate = datetime.datetime.now()
if startDate is None:
startDate = endDate
endDate = endDate.replace(hour=23, minute=59, second=59, microsecond=999999)
startDate = startDate.replace(hour=0, minute=0, second=0, microsecond=0)
with self.configuration.engine.connect() as conn:
result = conn.execute(
db.select(
self.configuration.peersTransferTable.c.time
).where(
db.and_(
self.configuration.peersTransferTable.c.id == self.id,
self.configuration.peersTransferTable.c.time <= endDate,
self.configuration.peersTransferTable.c.time >= startDate,
)
).order_by(
self.configuration.peersTransferTable.c.time
)
).fetchall()
time = list(map(lambda x : x[0], result))
return time
def __duration(self, t1: datetime.datetime, t2: datetime.datetime):
delta = t1 - t2
hours, remainder = divmod(delta.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}"

32
src/modules/PeerJob.py Normal file
View File

@@ -0,0 +1,32 @@
"""
Peer Job
"""
from datetime import datetime
class PeerJob:
def __init__(self, JobID: str, Configuration: str, Peer: str,
Field: str, Operator: str, Value: str, CreationDate: datetime, ExpireDate: datetime, Action: str):
self.Action = Action
self.ExpireDate = ExpireDate
self.CreationDate = CreationDate
self.Value = Value
self.Operator = Operator
self.Field = Field
self.Configuration = Configuration
self.Peer = Peer
self.JobID = JobID
def toJson(self):
return {
"JobID": self.JobID,
"Configuration": self.Configuration,
"Peer": self.Peer,
"Field": self.Field,
"Operator": self.Operator,
"Value": self.Value,
"CreationDate": self.CreationDate.strftime("%Y-%m-%d %H:%M:%S"),
"ExpireDate": (self.ExpireDate.strftime("%Y-%m-%d %H:%M:%S") if self.ExpireDate is not None else None),
"Action": self.Action
}
def __dict__(self):
return self.toJson()

View File

@@ -0,0 +1,59 @@
"""
Peer Job Logger
"""
import uuid
import sqlalchemy as db
from flask import current_app
from .ConnectionString import ConnectionString
from .Log import Log
class PeerJobLogger:
def __init__(self, AllPeerJobs, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard_log"))
self.metadata = db.MetaData()
self.jobLogTable = db.Table('JobLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True),
db.Column('JobID', db.String(255), nullable=False),
db.Column('LogDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('Status', db.String(255), nullable=False),
db.Column('Message', db.Text)
)
self.logs: list[Log] = []
self.metadata.create_all(self.engine)
self.AllPeerJobs = AllPeerJobs
def log(self, JobID: str, Status: bool = True, Message: str = "") -> bool:
try:
with self.engine.begin() as conn:
conn.execute(
self.jobLogTable.insert().values(
{
"LogID": str(uuid.uuid4()),
"JobID": JobID,
"Status": Status,
"Message": Message
}
)
)
except Exception as e:
current_app.logger.error(f"Peer Job Log Error", e)
return False
return True
def getLogs(self, configName = None) -> list[Log]:
logs: list[Log] = []
try:
allJobs = self.AllPeerJobs.getAllJobs(configName)
allJobsID = [x.JobID for x in allJobs]
stmt = self.jobLogTable.select().where(self.jobLogTable.columns.JobID.in_(
allJobsID
))
with self.engine.connect() as conn:
table = conn.execute(stmt).fetchall()
for l in table:
logs.append(
Log(l.LogID, l.JobID, l.LogDate.strftime("%Y-%m-%d %H:%M:%S"), l.Status, l.Message))
except Exception as e:
current_app.logger.error(f"Getting Peer Job Log Error", e)
return logs
return logs

202
src/modules/PeerJobs.py Normal file
View File

@@ -0,0 +1,202 @@
"""
Peer Jobs
"""
from .ConnectionString import ConnectionString
from .PeerJob import PeerJob
from .PeerJobLogger import PeerJobLogger
import sqlalchemy as db
from datetime import datetime
from flask import current_app
class PeerJobs:
def __init__(self, DashboardConfig, WireguardConfigurations):
self.Jobs: list[PeerJob] = []
self.engine = db.create_engine(ConnectionString('wgdashboard_job'))
self.metadata = db.MetaData()
self.peerJobTable = db.Table('PeerJobs', self.metadata,
db.Column('JobID', db.String(255), nullable=False, primary_key=True),
db.Column('Configuration', db.String(255), nullable=False),
db.Column('Peer', db.String(255), nullable=False),
db.Column('Field', db.String(255), nullable=False),
db.Column('Operator', db.String(255), nullable=False),
db.Column('Value', db.String(255), nullable=False),
db.Column('CreationDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP), nullable=False),
db.Column('ExpireDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP)),
db.Column('Action', db.String(255), nullable=False),
)
self.metadata.create_all(self.engine)
self.__getJobs()
self.JobLogger: PeerJobLogger = PeerJobLogger(self, DashboardConfig)
self.WireguardConfigurations = WireguardConfigurations
def __getJobs(self):
self.Jobs.clear()
with self.engine.connect() as conn:
jobs = conn.execute(self.peerJobTable.select().where(
self.peerJobTable.columns.ExpireDate.is_(None)
)).mappings().fetchall()
for job in jobs:
self.Jobs.append(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
def getAllJobs(self, configuration: str = None):
if configuration is not None:
with self.engine.connect() as conn:
jobs = conn.execute(self.peerJobTable.select().where(
self.peerJobTable.columns.Configuration == configuration
)).mappings().fetchall()
j = []
for job in jobs:
j.append(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
return j
return []
def toJson(self):
return [x.toJson() for x in self.Jobs]
def searchJob(self, Configuration: str, Peer: str):
return list(filter(lambda x: x.Configuration == Configuration and x.Peer == Peer, self.Jobs))
def searchJobById(self, JobID):
return list(filter(lambda x: x.JobID == JobID, self.Jobs))
def saveJob(self, Job: PeerJob) -> tuple[bool, list] | tuple[bool, str]:
import traceback
try:
with self.engine.begin() as conn:
currentJob = self.searchJobById(Job.JobID)
if len(currentJob) == 0:
conn.execute(
self.peerJobTable.insert().values(
{
"JobID": Job.JobID,
"Configuration": Job.Configuration,
"Peer": Job.Peer,
"Field": Job.Field,
"Operator": Job.Operator,
"Value": Job.Value,
"CreationDate": datetime.now(),
"ExpireDate": None,
"Action": Job.Action
}
)
)
self.JobLogger.log(Job.JobID, Message=f"Job is created if {Job.Field} {Job.Operator} {Job.Value} then {Job.Action}")
else:
conn.execute(
self.peerJobTable.update().values({
"Field": Job.Field,
"Operator": Job.Operator,
"Value": Job.Value,
"Action": Job.Action
}).where(self.peerJobTable.columns.JobID == Job.JobID)
)
self.JobLogger.log(Job.JobID, Message=f"Job is updated from if {currentJob[0].Field} {currentJob[0].Operator} {currentJob[0].Value} then {currentJob[0].Action}; to if {Job.Field} {Job.Operator} {Job.Value} then {Job.Action}")
self.__getJobs()
self.WireguardConfigurations.get(Job.Configuration).searchPeer(Job.Peer)[1].getJobs()
return True, list(
filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID,
self.Jobs))
except Exception as e:
traceback.print_exc()
return False, str(e)
def deleteJob(self, Job: PeerJob) -> tuple[bool, None] | tuple[bool, str]:
try:
if len(self.searchJobById(Job.JobID)) == 0:
return False, "Job does not exist"
with self.engine.begin() as conn:
conn.execute(
self.peerJobTable.update().values(
{
"ExpireDate": datetime.now()
}
).where(self.peerJobTable.columns.JobID == Job.JobID)
)
self.JobLogger.log(Job.JobID, Message=f"Job is removed due to being deleted or finshed.")
self.__getJobs()
self.WireguardConfigurations.get(Job.Configuration).searchPeer(Job.Peer)[1].getJobs()
return True, None
except Exception as e:
return False, str(e)
def updateJobConfigurationName(self, ConfigurationName: str, NewConfigurationName: str) -> tuple[bool, str] | tuple[bool, None]:
try:
with self.engine.begin() as conn:
conn.execute(
self.peerJobTable.update().values({
"Configuration": NewConfigurationName
}).where(self.peerJobTable.columns.Configuration == ConfigurationName)
)
self.__getJobs()
return True, None
except Exception as e:
return False, str(e)
def getPeerJobLogs(self, configurationName):
return self.JobLogger.getLogs(configurationName)
def runJob(self):
current_app.logger.info("Running scheduled jobs")
needToDelete = []
self.__getJobs()
for job in self.Jobs:
c = self.WireguardConfigurations.get(job.Configuration)
if c is not None:
f, fp = c.searchPeer(job.Peer)
if f:
if job.Field in ["total_receive", "total_sent", "total_data"]:
s = job.Field.split("_")[1]
x: float = getattr(fp, f"total_{s}") + getattr(fp, f"cumu_{s}")
y: float = float(job.Value)
else:
x: datetime = datetime.now()
y: datetime = datetime.strptime(job.Value, "%Y-%m-%d %H:%M:%S")
runAction: bool = self.__runJob_Compare(x, y, job.Operator)
if runAction:
s = False
if job.Action == "restrict":
s, msg = c.restrictPeers([fp.id])
elif job.Action == "delete":
s, msg = c.deletePeers([fp.id])
elif job.Action == "reset_total_data_usage":
s = fp.resetDataUsage("total")
c.restrictPeers([fp.id])
c.allowAccessPeers([fp.id])
if s is True:
self.JobLogger.log(job.JobID, s,
f"Peer {fp.id} from {c.Name} is successfully {job.Action}ed."
)
current_app.logger.info(f"Peer {fp.id} from {c.Name} is successfully {job.Action}ed.")
needToDelete.append(job)
else:
current_app.logger.info(f"Peer {fp.id} from {c.Name} is failed {job.Action}ed.")
self.JobLogger.log(job.JobID, s,
f"Peer {fp.id} from {c.Name} failed {job.Action}ed."
)
else:
current_app.logger.warning(f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed.")
self.JobLogger.log(job.JobID, False,
f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed."
)
else:
current_app.logger.warning(f"Somehow can't find this peer {job.Peer} from {c.Name} failed {job.Action}ed.")
self.JobLogger.log(job.JobID, False,
f"Somehow can't find this peer {job.Peer} from {job.Configuration} failed {job.Action}ed."
)
for j in needToDelete:
self.deleteJob(j)
def __runJob_Compare(self, x: float | datetime, y: float | datetime, operator: str):
if operator == "eq":
return x == y
if operator == "neq":
return x != y
if operator == "lgt":
return x > y
if operator == "lst":
return x < y

View File

@@ -0,0 +1,22 @@
from datetime import datetime
"""
Peer Share Link
"""
class PeerShareLink:
def __init__(self, ShareID:str, Configuration: str, Peer: str, ExpireDate: datetime, SharedDate: datetime):
self.ShareID = ShareID
self.Peer = Peer
self.Configuration = Configuration
self.SharedDate = SharedDate
self.ExpireDate = ExpireDate
if not self.ExpireDate:
self.ExpireDate = datetime.strptime("2199-12-31","%Y-%m-%d")
def toJson(self):
return {
"ShareID": self.ShareID,
"Peer": self.Peer,
"Configuration": self.Configuration,
"ExpireDate": self.ExpireDate.strftime("%Y-%m-%d %H:%M:%S"),
"SharedDate": self.SharedDate.strftime("%Y-%m-%d %H:%M:%S"),
}

View File

@@ -0,0 +1,89 @@
from .ConnectionString import ConnectionString
from .PeerShareLink import PeerShareLink
import sqlalchemy as db
from datetime import datetime
import uuid
"""
Peer Share Links
"""
class PeerShareLinks:
def __init__(self, DashboardConfig, WireguardConfigurations):
self.Links: list[PeerShareLink] = []
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.metadata = db.MetaData()
self.peerShareLinksTable = db.Table(
'PeerShareLinks', self.metadata,
db.Column('ShareID', db.String(255), nullable=False, primary_key=True),
db.Column('Configuration', db.String(255), nullable=False),
db.Column('Peer', db.String(255), nullable=False),
db.Column('ExpireDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP)),
db.Column('SharedDate', (db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
server_default=db.func.now()),
)
self.metadata.create_all(self.engine)
self.__getSharedLinks()
self.wireguardConfigurations = WireguardConfigurations
def __getSharedLinks(self):
self.Links.clear()
with self.engine.connect() as conn:
allLinks = conn.execute(
self.peerShareLinksTable.select().where(
db.or_(self.peerShareLinksTable.columns.ExpireDate.is_(None), self.peerShareLinksTable.columns.ExpireDate > datetime.now())
)
).mappings().fetchall()
for link in allLinks:
self.Links.append(PeerShareLink(**link))
def getLink(self, Configuration: str, Peer: str) -> list[PeerShareLink]:
self.__getSharedLinks()
return list(filter(lambda x : x.Configuration == Configuration and x.Peer == Peer, self.Links))
def getLinkByID(self, ShareID: str) -> list[PeerShareLink]:
self.__getSharedLinks()
return list(filter(lambda x : x.ShareID == ShareID, self.Links))
def addLink(self, Configuration: str, Peer: str, ExpireDate: datetime = None) -> tuple[bool, str]:
try:
newShareID = str(uuid.uuid4())
with self.engine.begin() as conn:
if len(self.getLink(Configuration, Peer)) > 0:
conn.execute(
self.peerShareLinksTable.update().values(
{
"ExpireDate": datetime.now()
}
).where(db.and_(self.peerShareLinksTable.columns.Configuration == Configuration, self.peerShareLinksTable.columns.Peer == Peer))
)
conn.execute(
self.peerShareLinksTable.insert().values(
{
"ShareID": newShareID,
"Configuration": Configuration,
"Peer": Peer,
"ExpireDate": ExpireDate
}
)
)
self.__getSharedLinks()
self.wireguardConfigurations.get(Configuration).searchPeer(Peer)[1].getShareLink()
except Exception as e:
return False, str(e)
return True, newShareID
def updateLinkExpireDate(self, ShareID, ExpireDate: datetime = None) -> tuple[bool, str]:
with self.engine.begin() as conn:
updated = conn.execute(
self.peerShareLinksTable.update().values(
{
"ExpireDate": ExpireDate
}
).returning(self.peerShareLinksTable.c.Configuration, self.peerShareLinksTable.c.Peer)
.where(self.peerShareLinksTable.columns.ShareID == ShareID)
).mappings().fetchone()
self.__getSharedLinks()
self.wireguardConfigurations.get(updated.Configuration).searchPeer(updated.Peer)[1].getShareLink()
return True, ""

181
src/modules/SystemStatus.py Normal file
View File

@@ -0,0 +1,181 @@
import shutil, subprocess, time, threading, psutil
from flask import current_app
class SystemStatus:
def __init__(self):
self.CPU = CPU()
self.MemoryVirtual = Memory('virtual')
self.MemorySwap = Memory('swap')
self.Disks = Disks()
self.NetworkInterfaces = NetworkInterfaces()
self.Processes = Processes()
def toJson(self):
process = [
threading.Thread(target=self.CPU.getCPUPercent),
threading.Thread(target=self.CPU.getPerCPUPercent),
threading.Thread(target=self.NetworkInterfaces.getData)
]
for p in process:
p.start()
for p in process:
p.join()
return {
"CPU": self.CPU,
"Memory": {
"VirtualMemory": self.MemoryVirtual,
"SwapMemory": self.MemorySwap
},
"Disks": self.Disks,
"NetworkInterfaces": self.NetworkInterfaces,
"NetworkInterfacesPriority": self.NetworkInterfaces.getInterfacePriorities(),
"Processes": self.Processes
}
class CPU:
def __init__(self):
self.cpu_percent: float = 0
self.cpu_percent_per_cpu: list[float] = []
def getCPUPercent(self):
try:
self.cpu_percent = psutil.cpu_percent(interval=1)
except Exception as e:
current_app.logger.error("Get CPU Percent error", e)
def getPerCPUPercent(self):
try:
self.cpu_percent_per_cpu = psutil.cpu_percent(interval=1, percpu=True)
except Exception as e:
current_app.logger.error("Get Per CPU Percent error", e)
def toJson(self):
return self.__dict__
class Memory:
def __init__(self, memoryType: str):
self.__memoryType__ = memoryType
self.total = 0
self.available = 0
self.percent = 0
def getData(self):
try:
if self.__memoryType__ == "virtual":
memory = psutil.virtual_memory()
self.available = memory.available
else:
memory = psutil.swap_memory()
self.available = memory.free
self.total = memory.total
self.percent = memory.percent
except Exception as e:
current_app.logger.error("Get Memory percent error", e)
def toJson(self):
self.getData()
return self.__dict__
class Disks:
def __init__(self):
self.disks : list[Disk] = []
def getData(self):
try:
self.disks = list(map(lambda x : Disk(x.mountpoint), psutil.disk_partitions()))
except Exception as e:
current_app.logger.error("Get Disk percent error", e)
def toJson(self):
self.getData()
return self.disks
class Disk:
def __init__(self, mountPoint: str):
self.total = 0
self.used = 0
self.free = 0
self.percent = 0
self.mountPoint = mountPoint
def getData(self):
try:
disk = psutil.disk_usage(self.mountPoint)
self.total = disk.total
self.free = disk.free
self.used = disk.used
self.percent = disk.percent
except Exception as e:
current_app.logger.error("Get Disk percent error", e)
def toJson(self):
self.getData()
return self.__dict__
class NetworkInterfaces:
def __init__(self):
self.interfaces = {}
def getInterfacePriorities(self):
if shutil.which("ip"):
result = subprocess.check_output(["ip", "route", "show"]).decode()
priorities = {}
for line in result.splitlines():
if "metric" in line and "dev" in line:
parts = line.split()
dev = parts[parts.index("dev")+1]
metric = int(parts[parts.index("metric")+1])
if dev not in priorities:
priorities[dev] = metric
return priorities
return {}
def getData(self):
self.interfaces.clear()
try:
network = psutil.net_io_counters(pernic=True, nowrap=True)
for i in network.keys():
self.interfaces[i] = network[i]._asdict()
time.sleep(1)
network = psutil.net_io_counters(pernic=True, nowrap=True)
for i in network.keys():
self.interfaces[i]['realtime'] = {
'sent': round((network[i].bytes_sent - self.interfaces[i]['bytes_sent']) / 1024 / 1024, 4),
'recv': round((network[i].bytes_recv - self.interfaces[i]['bytes_recv']) / 1024 / 1024, 4)
}
except Exception as e:
current_app.logger.error("Get network error", e)
def toJson(self):
return self.interfaces
class Process:
def __init__(self, name, command, pid, percent):
self.name = name
self.command = command
self.pid = pid
self.percent = percent
def toJson(self):
return self.__dict__
class Processes:
def __init__(self):
self.CPU_Top_10_Processes: list[Process] = []
self.Memory_Top_10_Processes: list[Process] = []
def getData(self):
while True:
try:
processes = list(psutil.process_iter())
self.CPU_Top_10_Processes = sorted(
list(map(lambda x : Process(x.name(), " ".join(x.cmdline()), x.pid, x.cpu_percent()), processes)),
key=lambda x : x.percent, reverse=True)[:20]
self.Memory_Top_10_Processes = sorted(
list(map(lambda x : Process(x.name(), " ".join(x.cmdline()), x.pid, x.memory_percent()), processes)),
key=lambda x : x.percent, reverse=True)[:20]
break
except Exception as e:
current_app.logger.error("Get processes error", e)
def toJson(self):
self.getData()
return {
"cpu_top_10": self.CPU_Top_10_Processes,
"memory_top_10": self.Memory_Top_10_Processes
}

104
src/modules/Utilities.py Normal file
View File

@@ -0,0 +1,104 @@
import re, ipaddress
import subprocess
def RegexMatch(regex, text) -> bool:
"""
Regex Match
@param regex: Regex patter
@param text: Text to match
@return: Boolean indicate if the text match the regex pattern
"""
pattern = re.compile(regex)
return pattern.search(text) is not None
def GetRemoteEndpoint() -> str:
"""
Using socket to determine default interface IP address. Thanks, @NOXICS
@return:
"""
import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("1.1.1.1", 80)) # Connecting to a public IP
wgd_remote_endpoint = s.getsockname()[0]
return str(wgd_remote_endpoint)
def StringToBoolean(value: str):
"""
Convert string boolean to boolean
@param value: Boolean value in string came from Configuration file
@return: Boolean value
"""
return (value.strip().replace(" ", "").lower() in
("yes", "true", "t", "1", 1))
def ValidateIPAddressesWithRange(ips: str) -> bool:
s = ips.replace(" ", "").split(",")
for ip in s:
try:
ipaddress.ip_network(ip)
except ValueError as e:
return False
return True
def ValidateIPAddresses(ips) -> bool:
s = ips.replace(" ", "").split(",")
for ip in s:
try:
ipaddress.ip_address(ip)
except ValueError as e:
return False
return True
def ValidateDNSAddress(addresses) -> tuple[bool, str]:
s = addresses.replace(" ", "").split(",")
for address in s:
if not ValidateIPAddresses(address) and not RegexMatch(
r"(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z]{0,61}[a-z]", address):
return False, f"{address} does not appear to be an valid DNS address"
return True, ""
def ValidateEndpointAllowedIPs(IPs) -> tuple[bool, str] | tuple[bool, None]:
ips = IPs.replace(" ", "").split(",")
for ip in ips:
try:
ipaddress.ip_network(ip, strict=False)
except ValueError as e:
return False, str(e)
return True, None
def GenerateWireguardPublicKey(privateKey: str) -> tuple[bool, str] | tuple[bool, None]:
try:
publicKey = subprocess.check_output(f"wg pubkey", input=privateKey.encode(), shell=True,
stderr=subprocess.STDOUT)
return True, publicKey.decode().strip('\n')
except subprocess.CalledProcessError:
return False, None
def GenerateWireguardPrivateKey() -> tuple[bool, str] | tuple[bool, None]:
try:
publicKey = subprocess.check_output(f"wg genkey", shell=True,
stderr=subprocess.STDOUT)
return True, publicKey.decode().strip('\n')
except subprocess.CalledProcessError:
return False, None
def ValidatePasswordStrength(password: str) -> tuple[bool, str] | tuple[bool, None]:
# Rules:
# - Must be over 8 characters & numbers
# - Must contain at least 1 Uppercase & Lowercase letters
# - Must contain at least 1 Numbers (0-9)
# - Must contain at least 1 special characters from $&+,:;=?@#|'<>.-^*()%!~_-
if len(password) < 8:
return False, "Password must be 8 characters or more"
if not re.search(r'[a-z]', password):
return False, "Password must contain at least 1 lowercase character"
if not re.search(r'[A-Z]', password):
return False, "Password must contain at least 1 uppercase character"
if not re.search(r'\d', password):
return False, "Password must contain at least 1 number"
if not re.search(r'[$&+,:;=?@#|\'<>.\-^*()%!~_-]', password):
return False, "Password must contain at least 1 special character from $&+,:;=?@#|'<>.-^*()%!~_-"
return True, None

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
from pydantic import BaseModel
class OverridePeerSettingsClass(BaseModel):
DNS: str = ''
EndpointAllowedIPs: str = ''
MTU: str | int = ''
PersistentKeepalive: int | str = ''
PeerRemoteEndpoint: str = ''
ListenPort: int | str = ''
class PeerGroupsClass(BaseModel):
GroupName: str = ''
Description: str = ''
BackgroundColor: str = ''
Icon: str = ''
Peers: list[str] = []
class WireguardConfigurationInfo(BaseModel):
Description: str = ''
OverridePeerSettings: OverridePeerSettingsClass = OverridePeerSettingsClass(**{})
PeerGroups: dict[str, PeerGroupsClass] = {}

View File

@@ -1,3 +1,17 @@
Flask==1.1.2
tinydb==4.3.0
ifcfg==0.21
bcrypt
ifcfg
psutil
pyotp
Flask
flask-cors
icmplib
gunicorn
requests
tcconfig
sqlalchemy
sqlalchemy_utils
psycopg
PyMySQL
tzlocal
python-jose
pydantic

BIN
src/static/.DS_Store vendored

Binary file not shown.

30
src/static/app/.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
.vite/*

27
src/static/app/build.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
echo "Running vite build..."
if vite build; then
echo "Vite build successful."
else
echo "Vite build failed. Exiting."
exit 1
fi
echo "Checking for changes to commit..."
if git diff-index --quiet HEAD --; then
if git commit -a; then
echo "Git commit successful."
else
echo "Git commit failed. Exiting."
exit 1
fi
else
echo "No changes to commit. Skipping commit."
fi
echo "Pushing changes to remote..."
if git push; then
echo "Git push successful."
else
echo "Git push failed. Exiting."
exit 1
fi

19
src/static/app/index.html Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="WGDashboard">
<meta name="apple-mobile-web-app-title" content="WGDashboard">
<link rel="manifest" href="/json/manifest.json">
<link rel="icon" href="/img/Logo-2-512x512.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WGDashboard</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,8 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

9174
src/static/app/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
{
"name": "app",
"version": "4.3.0",
"private": true,
"type": "module",
"module": "es2022",
"scripts": {
"dev": "vite",
"build": "vite build --emptyOutDir",
"buildcommitpush": "./build.sh",
"build electron": "vite build --emptyOutDir && vite build --mode electron && cd ../../../../WGDashboard-Desktop && /opt/homebrew/bin/npm run \"electron dist\"",
"preview": "vite preview"
},
"dependencies": {
"@volar/language-server": "2.4.23",
"@vue/language-server": "3.0.5",
"@vuepic/vue-datepicker": "^11.0.2",
"@vueuse/core": "^13.5.0",
"@vueuse/shared": "^13.5.0",
"animate.css": "^4.1.1",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.3",
"cidr-tools": "^11.0.3",
"css-color-converter": "^2.0.0",
"dayjs": "^1.11.12",
"electron-builder": "^26.0.12",
"fuse.js": "^7.0.0",
"i": "^0.3.7",
"is-cidr": "^5.0.3",
"npm": "^10.5.0",
"ol": "^10.2.1",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0",
"qrcode": "^1.5.3",
"qrcodejs": "^1.0.0",
"simple-code-editor": "^2.0.9",
"uuid": "^11.1.0",
"vue": "^3.5.17",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.0",
"vite": "^7.0.5"
}
}

1
src/static/app/proxy.js Normal file
View File

@@ -0,0 +1 @@
export const proxy = "http://wg.local:10086/"

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -0,0 +1,48 @@
{
"theme_color": "#343a40",
"background_color": "#343a40",
"display": "fullscreen",
"scope": "/",
"start_url": "/",
"name": "WGDashboard",
"short_name": "WGDashboard",
"screenshots": [
{
"src": "https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/sign-in.png",
"sizes": "2880x1826",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Documentation%20Images/index.png",
"sizes": "2880x1826",
"type": "image/png"
}
],
"icons": [
{
"src": "../img/Logo-2-Rounded-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "any"
},
{
"src": "../img/Logo-2-Rounded-256x256.png",
"sizes": "256x256",
"type": "image/png",
"purpose": "any"
},
{
"src": "../img/Logo-2-Rounded-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "any"
},
{
"src": "../img/Logo-2-Rounded-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
}
]
}

View File

@@ -0,0 +1,75 @@
<script setup async>
import {RouterView, useRoute} from 'vue-router'
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import {computed, watch} from "vue";
const store = DashboardConfigurationStore();
import "@/utilities/wireguard.js"
import {fetchGet} from "@/utilities/fetch.js";
store.initCrossServerConfiguration();
if (window.IS_WGDASHBOARD_DESKTOP){
store.IsElectronApp = true;
store.CrossServerConfiguration.Enable = true;
if (store.ActiveServerConfiguration){
fetchGet("/api/locale", {}, (res) => {
store.Locale = res.data
})
}
}else{
fetchGet("/api/locale", {}, (res) => {
store.Locale = res.data
})
}
watch(store.CrossServerConfiguration, () => {
store.syncCrossServerConfiguration()
}, {
deep: true
});
const route = useRoute()
</script>
<template>
<div class="h-100 bg-body" :data-bs-theme="store.Configuration?.Server.dashboard_theme">
<div style="z-index: 9999; height: 5px" class="position-absolute loadingBar top-0 start-0"></div>
<nav class="navbar bg-dark sticky-top" data-bs-theme="dark" v-if="!route.meta.hideTopNav">
<div class="container-fluid d-flex text-body align-items-center">
<RouterLink to="/" class="navbar-brand mb-0 h1">
<img src="/img/Logo-2-Rounded-512x512.png" alt="WGDashboard Logo" style="width: 32px">
</RouterLink>
<a role="button" class="navbarBtn text-body"
@click="store.ShowNavBar = !store.ShowNavBar"
style="line-height: 0; font-size: 2rem">
<Transition name="fade2" mode="out-in">
<i class="bi bi-list" v-if="!store.ShowNavBar"></i>
<i class="bi bi-x-lg" v-else></i>
</Transition>
</a>
</div>
</nav>
<Suspense>
<RouterView v-slot="{ Component }">
<Transition name="app" mode="out-in" type="transition" appear>
<Component :is="Component"></Component>
</Transition>
</RouterView>
</Suspense>
</div>
</template>
<style scoped>
.app-enter-active,
.app-leave-active {
transition: all 0.7s cubic-bezier(0.82, 0.58, 0.17, 1);
}
.app-enter-from,
.app-leave-to{
opacity: 0;
transform: scale(1.05);
filter: blur(8px);
}
@media screen and (min-width: 768px) {
.navbar{
display: none;
}
}
</style>

View File

@@ -0,0 +1,96 @@
<script setup lang="ts">
import {computed, ref} from "vue";
import {DashboardClientAssignmentStore} from "@/stores/DashboardClientAssignmentStore.js";
import LocaleText from "@/components/text/localeText.vue";
const props = defineProps(['configuration', 'peers', 'clientAssignedPeers', 'availablePeerSearchString'])
const emits = defineEmits(['assign', 'unassign'])
const assignmentStore = DashboardClientAssignmentStore()
const available = computed(() => {
if (props.clientAssignedPeers){
if (Object.keys(props.clientAssignedPeers).includes(props.configuration)){
return props.peers.filter(
x => {
return !props.clientAssignedPeers[props.configuration].map(
x => x.id
).includes(x.id) &&
(!props.availablePeerSearchString ||
(props.availablePeerSearchString &&
(x.id.includes(props.availablePeerSearchString) || x.name.includes(props.availablePeerSearchString))))
}
)
}
}
return props.availablePeerSearchString ? props.peers.filter(
x => x.id.includes(props.availablePeerSearchString) || x.name.includes(props.availablePeerSearchString)
) : props.peers
})
const confirmDelete = ref(false)
const collapse = ref(false)
</script>
<template>
<div class="card rounded-0 border-0">
<div
@click="collapse = !collapse"
role="button"
class="card-header rounded-0 sticky-top z-5 bg-body-secondary border-0 border-bottom text-white d-flex">
<small><samp>{{ configuration }}</samp></small>
<a role="button" class="ms-auto text-white" >
<i class="bi bi-chevron-compact-down" v-if="collapse"></i>
<i class="bi bi-chevron-compact-up" v-else></i>
</a>
</div>
<div class="card-body p-0" v-if="!collapse">
<div class="list-group list-group-flush" >
<div
class="list-group-item d-flex border-bottom list-group-item-action d-flex align-items-center gap-3"
:key="peer.id"
v-for="peer in available" >
<div v-if="!confirmDelete">
<small class="text-body">
<RouterLink
class="text-decoration-none"
target="_blank"
:to="'/configuration/' + configuration +'/peers?id=' + encodeURIComponent(peer.id)">
<samp>{{ peer.id }}</samp>
</RouterLink>
</small><br>
<small class="text-muted">
{{ peer.name ? peer.name : 'Untitled Peer'}}
</small>
</div>
<div v-else>
<small class="text-body">
<LocaleText t="Are you sure to remove this peer?"></LocaleText>
</small><br>
<small class="text-muted">
<samp>{{ peer.id }}</samp>
</small>
</div>
<template v-if="clientAssignedPeers">
<button
@click="emits('assign', peer.id)"
:class="{disabled: assignmentStore.assigning}"
class="btn bg-success-subtle text-success-emphasis ms-auto">
<i class="bi bi-plus-circle-fill" ></i>
</button>
</template>
<button
v-else
@click="emits('unassign', peer.assignment_id)"
:class="{disabled: assignmentStore.unassigning}"
aria-label="Delete Assignment"
class="btn bg-danger-subtle text-danger-emphasis ms-auto">
<i class="bi bi-trash-fill"></i>
</button>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,109 @@
<script setup lang="ts" async>
import {onMounted, ref, watch, watchEffect} from "vue";
import { fetchGet } from "@/utilities/fetch.js"
import {DashboardClientAssignmentStore} from "@/stores/DashboardClientAssignmentStore.js";
import AvailablePeersGroup from "@/components/clientComponents/availablePeersGroup.vue";
import LocaleText from "@/components/text/localeText.vue";
const props = defineProps(['client', 'clientAssignedPeers'])
const loading = ref(false)
const assignmentStore = DashboardClientAssignmentStore()
const manage = ref(false)
const emits = defineEmits(['refresh'])
const assign = async (ConfigurationName, Peer, ClientID) => {
await assignmentStore.assignClient(ConfigurationName, Peer, ClientID, false)
emits('refresh')
}
const unassign = async (AssignmentID) => {
await assignmentStore.unassignClient(undefined, undefined, AssignmentID)
emits('refresh')
}
const availablePeerSearchString = ref("")
</script>
<template>
<div>
<div class="d-flex rounded-0 border-0 flex-column d-flex flex-column border-bottom pb-1" v-if="!loading">
<div class="d-flex flex-column p-3 gap-3">
<div class="d-flex align-items-center">
<h6 class="mb-0">
<LocaleText t="Assigned Peers"></LocaleText>
<span class="text-bg-primary badge ms-2">
{{ Object.keys(clientAssignedPeers).length }} <LocaleText :t="Object.keys(clientAssignedPeers).length > 1 ? 'Configurations' : 'Configuration'"></LocaleText>
</span>
<span class="text-bg-info badge ms-2">
{{ Object.values(clientAssignedPeers).flat().length }} <LocaleText :t="Object.values(clientAssignedPeers).flat().length > 1 ? 'Peers' : 'Peer'"></LocaleText>
</span>
</h6>
<button class="btn btn-sm bg-primary-subtle text-primary-emphasis rounded-3 ms-auto"
@click="manage = !manage">
<template v-if="!manage">
<i class="bi bi-list-check me-2"></i>
<LocaleText t="Manage"></LocaleText>
</template>
<template v-else>
<i class="bi bi-check me-2"></i>
<LocaleText t="Done"></LocaleText>
</template>
</button>
</div>
<div class="rounded-3 availablePeers border h-100 overflow-scroll flex-grow-1 d-flex flex-column">
<AvailablePeersGroup
:configuration="configuration"
:peers="peers"
@unassign="async (id) => await unassign(id)"
v-for="(peers, configuration) in clientAssignedPeers">
</AvailablePeersGroup>
<h6 class="text-muted m-auto p-3" v-if="Object.keys(clientAssignedPeers).length === 0">
<LocaleText t="No peer assigned to this client"></LocaleText>
</h6>
</div>
</div>
<div style="height: 500px" class="d-flex flex-column p-3" v-if="manage">
<div class="availablePeers border h-100 card rounded-3">
<div class="card-header sticky-top p-3">
<h6 class="mb-0 d-flex align-items-center">
<LocaleText t="Available Peers"></LocaleText>
</h6>
</div>
<div class="card-body p-0 overflow-scroll">
<AvailablePeersGroup
:availablePeerSearchString="availablePeerSearchString"
:configuration="configuration"
:clientAssignedPeers="clientAssignedPeers"
:peers="peers"
:key="configuration"
@assign="async (id) => await assign(configuration, id, props.client.ClientID)"
v-for="(peers, configuration) in assignmentStore.allConfigurationsPeers">
</AvailablePeersGroup>
<h6 class="text-muted m-auto" v-if="Object.keys(assignmentStore.allConfigurationsPeers).length === 0">
<LocaleText t="No peer is available to assign"></LocaleText>
</h6>
</div>
<div class="card-footer d-flex gap-2 p-3 align-items-center justify-content-end">
<label for="availablePeerSearchString">
<i class="bi bi-search me-2"></i>
</label>
<input
id="availablePeerSearchString"
v-model="availablePeerSearchString"
class="form-control form-control-sm rounded-3 w-auto" type="text">
</div>
</div>
</div>
</div>
<div v-else>
<div class="p-3 placeholder-glow border-bottom">
<h6 class="placeholder w-100 rounded-3"></h6>
<div class="placeholder w-100 rounded-3" style="height: 400px"></div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import LocaleText from "@/components/text/localeText.vue";
import { fetchPost } from "@/utilities/fetch"
import {ref} from "vue";
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore.js"
const props = defineProps(['client'])
const deleting = ref(false)
const confirmDelete = ref(false)
const emits = defineEmits(['refresh'])
const dashboardConfigurationStore = DashboardConfigurationStore()
const deleteClient = async () => {
deleting.value = true
await fetchPost("/api/clients/deleteClient", {
ClientID: props.client.ClientID
}, (res) => {
deleting.value = false
if (res.status){
emits("deleteSuccess")
dashboardConfigurationStore.newMessage("Server", "Delete client successfully", "success")
}else {
dashboardConfigurationStore.newMessage("Server", "Failed to delete client", "danger")
}
})
}
</script>
<template>
<div class="p-3 d-flex gap-3 flex-column border-bottom">
<div class="d-flex align-items-center gap-2">
<h6 class="mb-0">
<LocaleText t="Delete Client" v-if="!confirmDelete"></LocaleText>
<LocaleText t="Are you sure to delete this client?" v-else></LocaleText>
</h6>
<button class="btn btn-sm bg-danger-subtle text-danger-emphasis rounded-3 ms-auto"
v-if="!confirmDelete"
@click="confirmDelete = true"
>
<i class="bi bi-trash-fill me-2"></i>
<LocaleText t="Delete"></LocaleText>
</button>
<template v-if="confirmDelete">
<button
@click="deleteClient"
class="btn btn-sm bg-danger-subtle text-danger-emphasis rounded-3 ms-auto">
<i class="bi bi-trash-fill me-2"></i>
<LocaleText t="Yes"></LocaleText>
</button>
<button class="btn btn-sm bg-secondary-subtle text-secondary-emphasis rounded-3"
v-if="confirmDelete" @click="confirmDelete = false">
<i class="bi bi-x-lg me-2"></i>
<LocaleText t="No"></LocaleText>
</button>
</template>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
import {computed, onMounted} from "vue";
import LocaleText from "@/components/text/localeText.vue";
import {useRoute} from "vue-router";
const props = defineProps(['groupName', 'clients', 'searchString'])
const getClients = computed(() => {
const s = props.searchString.toLowerCase()
if (!props.searchString){
return props.clients
}
return props.clients.filter(
x =>
(x.ClientID && x.ClientID.toLowerCase().includes(s)) ||
(x.Email && x.Email.toLowerCase().includes(s) ||
(x.Name && x.Name.toLowerCase().includes(s)))
)
})
const route = useRoute()
onMounted(() => {
document.querySelector(".clientList .active")?.scrollIntoView()
})
</script>
<template>
<div class="card rounded-0 border-0">
<div class="card-header d-flex align-items-center rounded-0">
<h6 class="my-2">{{ groupName }}</h6>
<span class="badge text-bg-primary ms-auto">
<LocaleText :t="getClients.length + ' Client' + (getClients.length > 1 ? 's': '')"></LocaleText>
</span>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush clientList">
<RouterLink
:key="client.ClientID"
:id="'client_' + client.ClientID"
active-class="active"
:to="{ name: 'Client Viewer', params: { id: client.ClientID } }"
class="list-group-item d-flex flex-column border-bottom list-group-item-action client"
v-for="client in getClients" >
<small class="text-body">
{{ client.Email }}
</small>
<small class="text-muted">
{{ client.Name ? client.Name : 'No Name'}}
</small>
</RouterLink>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,96 @@
<script setup lang="ts">
import LocaleText from "@/components/text/localeText.vue";
import { fetchGet, fetchPost } from "@/utilities/fetch.js"
import {ref} from "vue";
import {DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore.js"
import {useRouter} from "vue-router";
const props = defineProps(['client'])
const alert = ref(false)
const alertStatus = ref(false)
const alertMessage = ref(false)
const resetting = ref(false)
const store = DashboardConfigurationStore();
const router = useRouter()
const getUrl = (token) => {
const crossServer = store.getActiveCrossServer();
if(crossServer){
return new URL('/client/#/reset_password?token=' + token, crossServer.host).href
}
return new URL('/client/#/reset_password?token=' + token, window.location.href).href
}
const sendResetLink = async () => {
resetting.value = true
let smtpReady = false;
let token = undefined;
await fetchPost('/api/clients/generatePasswordResetLink', {
ClientID: props.client.ClientID
},async (res) => {
if (res.status){
token = res.data
alertStatus.value = true
await fetchGet('/api/email/ready', {}, (res) => {
smtpReady = res.status
});
if (smtpReady){
let body = {
"Receiver": props.client.Email,
"Subject": "[WGDashboard | Client] Reset Password",
"Body":
`Hi${props.client.Name ? ' ' + props.client.Name: ''},\n\nWe received a request to reset the password for your account. You can reset your password by visiting the link below:\n\n${getUrl(token)}\n\nThis link will expire in 30 minutes for your security. If you didnt request a password reset, you can safely ignore this email—your current password will remain unchanged.\n\nIf you need help, feel free to contact support.\n\nBest regards,\nWGDashboard`
}
await fetchPost('/api/email/send', body, (res) => {
if (res.status){
alertMessage.value = `Send email success.`
alert.value = true;
}else{
alertMessage.value = `Send email failed.`
alertStatus.value = false;
alert.value = true;
}
});
}else{
alertMessage.value = `Please share this URL to your client to reset the password: ${getUrl(token)}`
alert.value = true;
}
}else{
alertStatus.value = false
alertMessage.value = res.message
alert.value = true
}
})
resetting.value = false;
}
</script>
<template>
<div class="p-3 d-flex gap-3 flex-column border-bottom">
<div class="d-flex align-items-center">
<h6 class="mb-0">
<LocaleText t="Reset Password"></LocaleText>
</h6>
<button class="btn btn-sm bg-primary-subtle text-primary-emphasis rounded-3 ms-auto"
@click="sendResetLink()"
:class="{disabled: resetting}"
>
<i class="bi bi-send me-2"></i>
<LocaleText t="Send Password Reset Link" v-if="!resetting"></LocaleText>
<LocaleText t="Sending..." v-else></LocaleText>
</button>
</div>
<div class="alert rounded-3 mb-0"
:class="[alertStatus ? 'alert-success' : 'alert-danger']"
v-if="alert">
{{ alertMessage }}
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,63 @@
<script setup lang="ts">
import {ref} from "vue"
import LocaleText from "@/components/text/localeText.vue";
import { fetchGet } from "@/utilities/fetch.js"
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore"
const props = defineProps(['mode'])
const dashboardConfigurationStore = DashboardConfigurationStore()
const oidcStatus = ref(false)
const oidcStatusLoading = ref(false)
const getStatus = async () => {
await fetchGet("/api/oidc/status", {
mode: props.mode
}, (res) => {
oidcStatus.value = res.data
oidcStatusLoading.value = false
})
}
await getStatus()
const toggle = async () => {
oidcStatusLoading.value = true
await fetchGet('/api/oidc/toggle', {
mode: props.mode
}, (res) => {
if (!res.status){
oidcStatus.value = !oidcStatus.value
dashboardConfigurationStore.newMessage("Server", res.message, "danger")
}
oidcStatusLoading.value = false
})
}
</script>
<template>
<div class="d-flex flex-column gap-2">
<div class="d-flex align-items-center">
<h6 class="mb-0">
<LocaleText t="OpenID Connect (OIDC)"></LocaleText>
</h6>
<div class="form-check form-switch ms-auto">
<label class="form-check-label" for="oidc_switch">
<LocaleText :t="oidcStatus ? 'Enabled':'Disabled'"></LocaleText>
</label>
<input
:disabled="oidcStatusLoading"
v-model="oidcStatus"
@change="toggle()"
class="form-check-input" type="checkbox" role="switch" id="oidc_switch">
</div>
</div>
<!-- <div>-->
<!-- <div class="alert alert-dark rounded-3 mb-0">-->
<!-- <LocaleText t="Due to security reason, in order to edit OIDC configuration, you will need to edit "></LocaleText>-->
<!-- <code>wg-dashboard-oidc-providers.json</code> <LocaleText t="directly, then restart WGDashboard to apply the latest settings."></LocaleText>-->
<!-- </div>-->
<!-- </div>-->
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
import { ref, reactive } from "vue"
import LocaleText from "@/components/text/localeText.vue";
import OidcSettings from "@/components/clientComponents/clientSettingComponents/oidcSettings.vue";
import { fetchGet } from "@/utilities/fetch.js"
const emits = defineEmits(['close'])
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore"
const dashboardConfigurationStore = DashboardConfigurationStore()
const loading = ref(false)
const values = reactive({
enableClients: dashboardConfigurationStore.Configuration.Clients.enable
})
const toggling = ref(false)
const toggleClientSideApp = async () => {
toggling.value = true
await fetchGet("/api/clients/toggleStatus", {}, (res) => {
values.enableClients = res.data
})
toggling.value = false
}
</script>
<template>
<div class="position-absolute w-100 h-100 top-0 start-0 z-1 rounded-3 d-flex p-2" style="background-color: #00000070; z-index: 9999">
<div class="card m-auto rounded-3" style="width: 700px">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0">
<LocaleText t="Clients Settings"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="emits('close')"></button>
</div>
<div class="card-body px-4 d-flex gap-3 flex-column">
<div class="d-flex align-items-center">
<h6 class="mb-0">
<LocaleText t="Client Side App"></LocaleText>
</h6>
<div class="form-check form-switch ms-auto">
<label class="form-check-label" for="oidc_switch">
<LocaleText :t="values.enableClients ? 'Enabled':'Disabled'"></LocaleText>
</label>
<input
:disabled="oidcStatusLoading"
v-model="values.enableClients"
@change="toggleClientSideApp()"
class="form-check-input" type="checkbox" role="switch" id="oidc_switch">
</div>
</div>
<OidcSettings mode="Client"></OidcSettings>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,143 @@
<script setup lang="ts" async>
import {useRoute, useRouter} from "vue-router";
import { fetchGet, fetchPost } from "@/utilities/fetch.js"
import {DashboardClientAssignmentStore} from "@/stores/DashboardClientAssignmentStore.js";
import { DashboardConfigurationStore } from "@/stores/DashboardConfigurationStore.js"
import {computed, reactive, ref, watch} from "vue";
import LocaleText from "@/components/text/localeText.vue";
import ClientAssignedPeers from "@/components/clientComponents/clientAssignedPeers.vue";
import ClientResetPassword from "@/components/clientComponents/clientResetPassword.vue";
import ClientDelete from "@/components/clientComponents/clientDelete.vue";
const assignmentStore = DashboardClientAssignmentStore()
const dashboardConfigurationStore = DashboardConfigurationStore()
const route = useRoute()
const router = useRouter()
const client = computed(() => {
return assignmentStore.getClientById(route.params.id)
})
const clientAssignedPeers = ref({})
const getAssignedPeers = async () => {
await fetchGet('/api/clients/assignedPeers', {
ClientID: client.value.ClientID
}, (res) => {
clientAssignedPeers.value = res.data;
})
}
const emits = defineEmits(['deleteSuccess'])
const clientProfile = reactive({
Name: undefined
})
if (client.value){
watch(() => client.value.ClientID, async () => {
clientProfile.Name = client.value.Name;
await getAssignedPeers()
})
await getAssignedPeers()
clientProfile.Name = client.value.Name
}else{
router.push('/clients')
dashboardConfigurationStore.newMessage("WGDashboard", "Client does not exist", "danger")
}
const updatingProfile = ref(false)
const updateProfile = async () => {
updatingProfile.value = true
await fetchPost("/api/clients/updateProfileName", {
ClientID: client.value.ClientID,
Name: clientProfile.Name
}, (res) => {
if (res.status){
client.value.Name = clientProfile.Name;
dashboardConfigurationStore.newMessage("Server", "Client name update success", "success")
}else{
clientProfile.Name = client.value.Name;
dashboardConfigurationStore.newMessage("Server", "Client name update failed", "danger")
}
updatingProfile.value = false
})
}
const deleteSuccess = async () => {
await router.push('/clients')
await assignmentStore.getClients()
}
</script>
<template>
<div class="text-body d-flex flex-column overflow-y-scroll h-100" v-if="client" :key="client.ClientID">
<div class="p-4 border-bottom bg-body-tertiary z-0">
<div class="mb-3 backLink">
<RouterLink to="/clients" class="text-body text-decoration-none">
<i class="bi bi-arrow-left me-2"></i>
Back</RouterLink>
</div>
<small class="text-muted">
<LocaleText t="Email"></LocaleText>
</small>
<h1>
{{ client.Email }}
</h1>
<div class="d-flex flex-column gap-2">
<div class="d-flex align-items-center">
<small class="text-muted">
<LocaleText t="Client ID"></LocaleText>
</small>
<small class="ms-auto">
<samp>{{ client.ClientID }}</samp>
</small>
</div>
<div class="d-flex align-items-center gap-2">
<small class="text-muted">
<LocaleText t="Client Name"></LocaleText>
</small>
<input class="form-control form-control-sm rounded-3 ms-auto"
style="width: 300px"
type="text" v-model="clientProfile.Name">
<button
@click="updateProfile()"
aria-label="Save Client Name"
class="btn btn-sm rounded-3 bg-success-subtle border-success-subtle text-success-emphasis">
<i class="bi bi-save-fill"></i>
</button>
</div>
</div>
</div>
<div style="flex: 1 0 0; overflow-y: scroll;">
<ClientAssignedPeers
@refresh="getAssignedPeers()"
:clientAssignedPeers="clientAssignedPeers"
:client="client"></ClientAssignedPeers>
<!-- <ClientResetPassword-->
<!-- :client="client" v-if="client.ClientGroup === 'Local'"></ClientResetPassword>-->
<ClientDelete
@deleteSuccess="deleteSuccess()"
:client="client"></ClientDelete>
</div>
</div>
<div v-else class="d-flex w-100 h-100 text-muted">
<div class="m-auto text-center">
<h1>
<i class="bi bi-person-x"></i>
</h1>
<p>
<LocaleText t="Client does not exist"></LocaleText>
</p>
</div>
</div>
</template>
<style scoped>
@media screen and (min-width: 576px) {
.backLink{
display: none;
}
}
</style>

View File

@@ -0,0 +1,191 @@
<script setup>
import dayjs from "dayjs";
import {computed, ref} from "vue";
import {fetchGet, fetchPost, getUrl} from "@/utilities/fetch.js";
import {useRoute} from "vue-router";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
const props = defineProps(["b", "delay"])
const deleteConfirmation = ref(false)
const restoreConfirmation = ref(false)
const route = useRoute()
const emit = defineEmits(["refresh", "refreshPeersList"])
const store = DashboardConfigurationStore()
const loading = ref(false);
const deleteBackup = () => {
loading.value = true;
fetchPost("/api/deleteWireguardConfigurationBackup", {
ConfigurationName: route.params.id,
BackupFileName: props.b.filename
}, (res) => {
loading.value = false;
if (res.status){
emit("refresh")
store.newMessage("Server", "Backup deleted", "success")
}else{
store.newMessage("Server", "Backup failed to delete", "danger")
}
})
}
const restoreBackup = () => {
loading.value = true;
fetchPost("/api/restoreWireguardConfigurationBackup", {
ConfigurationName: route.params.id,
BackupFileName: props.b.filename
}, (res) => {
loading.value = false;
restoreConfirmation.value = false;
if (res.status){
emit("refreshPeersList")
store.newMessage("Server", "Backup restored with " + props.b.filename, "success")
}else{
store.newMessage("Server", "Backup failed to restore", "danger")
}
})
}
const downloadBackup = () => {
fetchGet("/api/downloadWireguardConfigurationBackup", {
configurationName: route.params.id,
backupFileName: props.b.filename
}, (res) => {
if (res.status){
window.open(getUrl(`/fileDownload?file=${res.data}`), '_blank')
}
})
}
const delaySeconds = computed(() => {
return props.delay + 's'
})
const showContent = ref(false);
</script>
<template>
<div class="card my-0 rounded-3">
<div class="card-body position-relative">
<Transition name="zoomReversed">
<div
v-if="deleteConfirmation"
class="position-absolute w-100 h-100 confirmationContainer start-0 top-0 rounded-3 d-flex p-2">
<div class="m-auto">
<h5>
<LocaleText t="Are you sure to delete this backup?"></LocaleText>
</h5>
<div class="d-flex gap-2 align-items-center justify-content-center">
<button class="btn btn-danger rounded-3"
:disabled="loading"
@click='deleteBackup()'>
<LocaleText t="Yes"></LocaleText>
</button>
<button
@click="deleteConfirmation = false"
:disabled="loading"
class="btn bg-secondary-subtle text-secondary-emphasis border-secondary-subtle rounded-3">
<LocaleText t="No"></LocaleText>
</button>
</div>
</div>
</div>
</Transition>
<Transition name="zoomReversed">
<div
v-if="restoreConfirmation"
class="position-absolute w-100 h-100 confirmationContainer start-0 top-0 rounded-3 d-flex p-2">
<div class="m-auto">
<h5>
<LocaleText t="Are you sure to restore this backup?"></LocaleText>
</h5>
<div class="d-flex gap-2 align-items-center justify-content-center">
<button
:disabled="loading"
@click="restoreBackup()"
class="btn btn-success rounded-3">
<LocaleText t="Yes"></LocaleText>
</button>
<button
@click="restoreConfirmation = false"
:disabled="loading"
class="btn bg-secondary-subtle text-secondary-emphasis border-secondary-subtle rounded-3">
<LocaleText t="No"></LocaleText>
</button>
</div>
</div>
</div>
</Transition>
<div class="d-flex gap-3">
<div class="d-flex flex-column">
<small class="text-muted">
<LocaleText t="Backup"></LocaleText>
</small>
<samp>{{b.filename}}</samp>
</div>
<div class="d-flex flex-column">
<small class="text-muted">
<LocaleText t="Backup Date"></LocaleText>
</small>
{{dayjs(b.backupDate, "YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss")}}
</div>
<div class="d-flex gap-2 align-items-center ms-auto">
<button
@click="downloadBackup()"
class="btn bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-3 btn-sm">
<i class="bi bi-download"></i>
</button>
<button
@click="restoreConfirmation = true"
class="btn bg-warning-subtle text-warning-emphasis border-warning-subtle rounded-3 btn-sm">
<i class="bi bi-clock-history"></i>
</button>
<button
@click="deleteConfirmation = true"
class="btn bg-danger-subtle text-danger-emphasis border-danger-subtle rounded-3 btn-sm">
<i class="bi bi-trash-fill"></i>
</button>
</div>
</div>
<hr>
<div class="card rounded-3">
<a role="button" class="card-header d-flex text-decoration-none align-items-center"
:class="{'border-bottom-0': !showContent}"
style="cursor: pointer" @click="showContent = !showContent">
<small>.conf <LocaleText t="File"></LocaleText>
</small>
<i class="bi bi-chevron-down ms-auto"></i>
</a>
<div class="card-body" v-if="showContent">
<textarea class="form-control rounded-3" :value="b.content"
disabled
style="height: 300px; font-family: var(--bs-font-monospace),sans-serif !important;"></textarea>
</div>
</div>
<hr>
<div class="d-flex">
<span>
<i class="bi bi-database me-1"></i>
<LocaleText t="Database File"></LocaleText>
</span>
<i class="bi ms-auto"
:class="[b.database ? 'text-success bi-check-circle-fill' : 'text-danger bi-x-circle-fill']"
></i>
</div>
</div>
</div>
</template>
<style scoped>
.confirmationContainer{
background-color: rgba(0, 0, 0, 0.53);
z-index: 9999;
backdrop-filter: blur(1px);
-webkit-backdrop-filter: blur(1px);
}
.list1-enter-active{
transition-delay: v-bind(delaySeconds) !important;
}
</style>

View File

@@ -0,0 +1,123 @@
<script setup>
import {onBeforeUnmount, onMounted, reactive, ref} from "vue";
import {fetchGet} from "@/utilities/fetch.js";
import {useRoute} from "vue-router";
import dayjs from "dayjs";
import LocaleText from "@/components/text/localeText.vue";
import Backup from "@/components/configurationComponents/backupRestoreComponents/backup.vue";
const route = useRoute()
const backups = ref([])
const loading = ref(true)
const emit = defineEmits(["close", "refreshPeersList"])
onMounted(() => {
loadBackup();
})
const loadBackup = () => {
loading.value = true
fetchGet("/api/getWireguardConfigurationBackup", {
configurationName: route.params.id
}, (res) => {
backups.value = res.data;
loading.value = false;
})
}
const createBackup = () => {
fetchGet("/api/createWireguardConfigurationBackup", {
configurationName: route.params.id
}, (res) => {
backups.value = res.data;
loading.value = false;
})
}
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll" ref="editConfigurationContainer">
<div class="d-flex h-100 w-100">
<div class="modal-dialog-centered dashboardModal w-100 h-100 overflow-x-scroll flex-column gap-3 mx-3">
<div class="my-5 d-flex gap-3 flex-column position-relative">
<div class="title">
<div class="d-flex mb-3">
<h4 class="mb-0">
<LocaleText t="Backup & Restore"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="$emit('close')"></button>
</div>
<button
@click="createBackup()"
class="btn bg-primary-subtle text-primary-emphasis border-primary-subtle rounded-3 w-100">
<i class="bi bi-plus-circle-fill me-2"></i>
<LocaleText t="Create Backup"></LocaleText>
</button>
</div>
<div class="position-relative d-flex flex-column gap-3">
<TransitionGroup name="list1" >
<div class="text-center title"
key="spinner"
v-if="loading && backups.length === 0">
<div class="spinner-border"></div>
</div>
<div class="card my-0 rounded-3"
v-else-if="!loading && backups.length === 0"
key="noBackups"
>
<div class="card-body text-center text-muted">
<i class="bi bi-x-circle-fill me-2"></i>
<LocaleText t="No backup yet, click the button above to create backup."></LocaleText>
</div>
</div>
<Backup
@refresh="loadBackup()"
@refreshPeersList="emit('refreshPeersList')"
:b="b" v-for="b in backups"
:key="b.filename"
></Backup>
</TransitionGroup>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.card, .title{
width: 100%;
}
@media screen and (min-width: 700px) {
.card, .title{
width: 700px;
}
}
.animate__fadeInUp{
animation-timing-function: cubic-bezier(0.42, 0, 0.22, 1.0)
}
.list1-move, /* apply transition to moving elements */
.list1-enter-active,
.list1-leave-active {
transition: all 0.5s cubic-bezier(0.42, 0, 0.22, 1.0);
}
.list1-enter-from,
.list1-leave-to {
opacity: 0;
transform: translateY(30px);
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.list1-leave-active {
width: 100%;
position: absolute;
}
</style>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
import {ref} from "vue";
import { fetchPost } from "@/utilities/fetch.js"
const props = defineProps(['configuration'])
const description = ref(props.configuration.Info.Description)
const showStatus = ref(false)
const status = ref(false)
const updateDescription = async () => {
await fetchPost("/api/updateWireguardConfigurationInfo", {
Name: props.configuration.Name,
Key: "Description",
Value: description.value
}, (res) => {
status.value = res.status
toggleStatus()
})
}
const toggleSuccess = () => {
status.value = true
toggleStatus()
}
const toggleFail = () => {
status.value = false
toggleStatus()
}
const toggleStatus = () => {
showStatus.value = true
setTimeout(() => {
showStatus.value = false
}, 3000)
}
</script>
<template>
<div class="d-flex gap-1 flex-column">
<label for="configurationDescription">
<small style="white-space: nowrap" class="text-muted">
<i class="bi bi-pencil-fill me-2"></i>Notes
</small>
</label>
<input type="text"
:class="[showStatus ? [status ? 'is-valid':'is-invalid'] : undefined]"
id="configurationDescription"
v-model="description"
@change="updateDescription()"
class="form-control rounded-3 bg-transparent form-control-sm">
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,122 @@
<script setup>
import LocaleText from "@/components/text/localeText.vue";
import {useRoute, useRouter} from "vue-router";
import {onMounted, ref, useTemplateRef} from "vue";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
const route = useRoute()
const configurationName = route.params.id;
const input = ref("")
const router = useRouter()
const store = DashboardConfigurationStore()
const deleting = ref(false)
const deleteConfiguration = () => {
clearInterval(store.Peers.RefreshInterval)
deleting.value = true;
fetchPost("/api/deleteWireguardConfiguration", {
ConfigurationName: configurationName
}, (res) => {
if (res.status){
router.push('/')
store.newMessage("Server", "Configuration deleted", "success")
}else{
deleting.value = false;
}
})
}
const loading = ref(true)
const backups = ref([])
const getBackup = () => {
loading.value = true;
fetchGet("/api/getWireguardConfigurationBackup", {
configurationName: configurationName
}, (res) => {
backups.value = res.data;
loading.value = false;
})
}
onMounted(() => {
getBackup()
})
const emits = defineEmits(["backup", "close"])
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal" style="width: 700px">
<div class="card rounded-3 shadow flex-grow-1 bg-danger-subtle border-danger-subtle" id="deleteConfigurationContainer">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h5 class="mb-0">
<LocaleText t="Are you sure to delete this configuration?"></LocaleText>
</h5>
<button type="button" class="btn-close ms-auto" @click="emits('close')"></button>
</div>
<div class="card-body px-4 text-muted">
<p class="mb-0">
<LocaleText t="Once you deleted this configuration:"></LocaleText>
</p>
<ul>
<li>
<LocaleText t="All connected peers will get disconnected"></LocaleText>
</li>
<li>
<LocaleText t="Both configuration file (.conf) and database table related to this configuration will get deleted"></LocaleText>
</li>
</ul>
<div class="alert"
:class="[loading ? 'alert-secondary' : (backups.length > 0 ? 'alert-success' : 'alert-danger')]">
<div v-if="loading">
<i class="bi bi-search me-2"></i>
<LocaleText t="Checking backups..."></LocaleText>
</div>
<div v-else-if="backups.length > 0">
<i class="bi bi-check-circle-fill me-2"></i>
<LocaleText :t="'This configuration have ' + backups.length + ' backups'"></LocaleText>
</div>
<div v-else class="d-flex align-items-center gap-2">
<i class="bi bi-x-circle-fill me-2"></i>
<LocaleText t="This configuration have no backup"></LocaleText>
<a role="button"
@click="emits('backup')"
class="ms-auto btn btn-sm btn-primary rounded-3">
<i class="bi bi-clock-history me-2"></i>
<LocaleText t="Backup"></LocaleText>
</a>
<a role="button"
@click="getBackup()"
class="btn btn-sm btn-primary rounded-3">
<i class="bi bi-arrow-clockwise"></i>
</a>
</div>
</div>
<hr>
<p>
<LocaleText t="If you're sure, please type in the configuration name below and click Delete"></LocaleText>
</p>
<input class="form-control rounded-3 mb-3"
:placeholder="configurationName"
v-model="input"
type="text">
<button class="btn btn-danger w-100"
@click="deleteConfiguration()"
:disabled="input !== configurationName || deleting">
<i class="bi bi-trash-fill me-2 rounded-3"></i>
<LocaleText t="Delete" v-if="!deleting"></LocaleText>
<LocaleText t="Deleting..." v-else></LocaleText>
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,270 @@
<script setup>
import LocaleText from "@/components/text/localeText.vue";
import {reactive, ref, watch} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {fetchPost} from "@/utilities/fetch.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import UpdateConfigurationName
from "@/components/configurationComponents/editConfigurationComponents/updateConfigurationName.vue";
import EditRawConfigurationFile
from "@/components/configurationComponents/editConfigurationComponents/editRawConfigurationFile.vue";
import DeleteConfiguration from "@/components/configurationComponents/deleteConfiguration.vue";
import ConfigurationBackupRestore from "@/components/configurationComponents/configurationBackupRestore.vue";
import EditPeerSettingsOverride
from "@/components/configurationComponents/editConfigurationComponents/editPeerSettingsOverride.vue";
const props = defineProps({
configurationInfo: Object
})
const wgStore = WireguardConfigurationsStore()
const store = DashboardConfigurationStore()
const saving = ref(false)
const data = reactive(JSON.parse(JSON.stringify(props.configurationInfo)))
const editPrivateKey = ref(false)
const dataChanged = ref(false)
const reqField = reactive({
PrivateKey: true,
IPAddress: true,
ListenPort: true
})
const genKey = () => {
if (wgStore.checkWGKeyLength(data.PrivateKey)){
reqField.PrivateKey = true;
data.PublicKey = window.wireguard.generatePublicKey(data.PrivateKey)
}else{
reqField.PrivateKey = false;
}
}
const resetForm = () => {
dataChanged.value = false;
Object.assign(data, JSON.parse(JSON.stringify(props.configurationInfo)))
}
const emit = defineEmits(["changed", "close", "refresh", "dataChanged"])
const saveForm = () => {
saving.value = true
fetchPost("/api/updateWireguardConfiguration", data, (res) => {
saving.value = false
if (res.status){
store.newMessage("Server", "Configuration saved", "success")
dataChanged.value = false
emit("dataChanged", res.data)
}else{
store.newMessage("Server", res.message, "danger")
}
})
}
const updateConfigurationName = ref(false)
watch(data, () => {
dataChanged.value = JSON.stringify(data) !== JSON.stringify(props.configurationInfo);
}, {
deep: true
})
const editRawConfigurationFileModal = ref(false)
const backupRestoreModal = ref(false)
const deleteConfigurationModal = ref(false)
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0" ref="editConfigurationContainer">
<div class="w-100 h-100 overflow-y-scroll">
<TransitionGroup name="zoom">
<EditRawConfigurationFile
name="EditRawConfigurationFile"
v-if="editRawConfigurationFileModal"
@close="editRawConfigurationFileModal = false">
</EditRawConfigurationFile>
<DeleteConfiguration
key="DeleteConfiguration"
@backup="backupRestoreModal = true"
@close="deleteConfigurationModal = false"
v-if="deleteConfigurationModal">
</DeleteConfiguration>
<ConfigurationBackupRestore
@close="backupRestoreModal = false"
@refreshPeersList="emit('refresh')"
v-if="backupRestoreModal">
</ConfigurationBackupRestore>
</TransitionGroup>
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal" style="width: 700px">
<div class="card rounded-3 shadow flex-grow-1">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4">
<h4 class="mb-0">
<LocaleText t="Configuration Settings"></LocaleText>
</h4>
<button type="button" class="btn-close ms-auto" @click="$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4">
<div class="d-flex gap-2 flex-column">
<div class="d-flex align-items-center gap-3" v-if="!updateConfigurationName">
<small class="text-muted">
<LocaleText t="Name"></LocaleText>
</small>
<small>{{data.Name}}</small>
<button
@click="updateConfigurationName = true"
class="btn btn-sm bg-danger-subtle border-danger-subtle text-danger-emphasis rounded-3 ms-auto">
<LocaleText t="Update Name"></LocaleText>
</button>
</div>
<UpdateConfigurationName
@close="updateConfigurationName = false"
:configuration-name="data.Name"
v-if="updateConfigurationName"></UpdateConfigurationName>
<template v-else>
<hr>
<div class="d-flex align-items-center gap-3">
<small class="text-muted" style="word-break: keep-all">
<LocaleText t="Public Key"></LocaleText>
</small>
<small class="ms-auto" style="word-break: break-all">
{{data.PublicKey}}
</small>
</div>
<hr>
<div>
<div class="d-flex">
<label for="configuration_private_key" class="form-label">
<small class="text-muted d-block">
<LocaleText t="Private Key"></LocaleText>
</small>
</label>
<div class="form-check form-switch ms-auto">
<input class="form-check-input"
type="checkbox" role="switch" id="editPrivateKeySwitch"
v-model="editPrivateKey"
>
<label class="form-check-label" for="editPrivateKeySwitch">
<small>Edit</small>
</label>
</div>
</div>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving || !editPrivateKey"
:class="{'is-invalid': !reqField.PrivateKey}"
@keyup="genKey()"
v-model="data.PrivateKey"
id="configuration_private_key">
</div>
<div>
<label for="configuration_ipaddress_cidr" class="form-label">
<small class="text-muted">
<LocaleText t="IP Address/CIDR"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="data.Address"
id="configuration_ipaddress_cidr">
</div>
<div>
<label for="configuration_listen_port" class="form-label">
<small class="text-muted">
<LocaleText t="Listen Port"></LocaleText>
</small>
</label>
<input type="number" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="data.ListenPort"
id="configuration_listen_port">
</div>
<div class="accordion mt-2" id="editConfigurationOptionalAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed px-3 py-2" type="button" data-bs-toggle="collapse" data-bs-target="#editOptionalAccordionCollapse">
<small class="text-muted">
<LocaleText t="Optional Settings"></LocaleText>
</small>
</button>
</h2>
<div id="editOptionalAccordionCollapse"
class="accordion-collapse collapse" data-bs-parent="#editConfigurationOptionalAccordion">
<div class="accordion-body d-flex flex-column gap-3">
<div v-for="key in ['Table', 'PreUp', 'PreDown', 'PostUp', 'PostDown']">
<label :for="'configuration_' + key" class="form-label">
<small class="text-muted">
<LocaleText :t="key"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="data[key]"
:id="'configuration_' + key">
</div>
<div v-for="key in ['Jc', 'Jmin', 'Jmax', 'S1', 'S2', 'H1', 'H2', 'H3', 'H4']"
v-if="configurationInfo.Protocol === 'awg'">
<label :for="'configuration_' + key" class="form-label">
<small class="text-muted">
<LocaleText :t="key"></LocaleText>
</small>
</label>
<input type="number" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="data[key]"
:id="'configuration_' + key">
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-items-center gap-2 mt-1">
<button class="btn btn-sm bg-secondary-subtle border-secondary-subtle text-secondary-emphasis rounded-3 shadow ms-auto"
@click="resetForm()"
:disabled="!dataChanged || saving">
<i class="bi bi-arrow-clockwise me-2"></i>
<LocaleText t="Reset"></LocaleText>
</button>
<button class="btn btn-sm bg-primary-subtle border-primary-subtle text-primary-emphasis rounded-3 shadow"
:disabled="!dataChanged || saving"
@click="saveForm()"
>
<i class="bi bi-save-fill me-2"></i>
<LocaleText t="Save"></LocaleText>
</button>
</div>
<hr>
<EditPeerSettingsOverride :configuration="configurationInfo"></EditPeerSettingsOverride>
<hr>
<h5 class="mb-3">
<LocaleText t="Danger Zone"></LocaleText>
</h5>
<div class="d-flex gap-2 flex-column">
<button
@click="backupRestoreModal = true"
class="btn bg-warning-subtle border-warning-subtle text-warning-emphasis rounded-3 text-start d-flex">
<i class="bi bi-copy me-auto"></i>
<LocaleText t="Backup & Restore"></LocaleText>
</button>
<button
@click="editRawConfigurationFileModal = true"
class="btn bg-warning-subtle border-warning-subtle text-warning-emphasis rounded-3 d-flex">
<i class="bi bi-pen me-auto"></i>
<LocaleText t="Edit Raw Configuration File"></LocaleText>
</button>
<button
@click="deleteConfigurationModal = true"
class="btn bg-danger-subtle border-danger-subtle text-danger-emphasis rounded-3 d-flex mt-4">
<i class="bi bi-trash-fill me-auto"></i>
<LocaleText t="Delete Configuration"></LocaleText>
</button>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,152 @@
<script setup lang="ts">
import LocaleText from "@/components/text/localeText.vue";
import { fetchPost } from "@/utilities/fetch.js"
import {onMounted, reactive, ref} from "vue";
const props = defineProps(['configuration'])
const saving = ref(false)
const overridePeerSettings = ref({...props.configuration.Info.OverridePeerSettings})
const edited = ref(false)
const errorMsg = ref("")
onMounted(() => {
document.querySelectorAll("#editPeerSettingsOverride input").forEach(
x => x.addEventListener("change", () => {
edited.value = true
})
)
})
const resetForm = () => {
overridePeerSettings.value = props.configuration.Info.OverridePeerSettings
edited.value = false
}
const submitForm = async () => {
document.querySelectorAll("#editPeerSettingsOverride input").forEach(
x => x.classList.remove("is-invalid", "is-valid")
)
await fetchPost("/api/updateWireguardConfigurationInfo", {
Name: props.configuration.Name,
Key: "OverridePeerSettings",
Value: overridePeerSettings.value
}, (res) => {
if (res.status){
edited.value = false
props.configuration.Info.OverridePeerSettings = overridePeerSettings.value
document.querySelectorAll("#editPeerSettingsOverride input").forEach(
x => x.classList.add("is-valid")
)
}else{
errorMsg.value = res.message
document.querySelector(`#override_${res.data}`).classList.add("is-invalid")
}
})
}
</script>
<template>
<div id="editPeerSettingsOverride">
<h5 class="mb-0">
<LocaleText t="Override Peer Settings"></LocaleText>
</h5>
<h6 class="mb-3 text-muted">
<small>
<LocaleText t="Only apply to peers in this configuration"></LocaleText>
</small>
</h6>
<div class="d-flex gap-2 flex-column">
<div>
<label for="override_DNS" class="form-label">
<small class="text-muted">
<LocaleText t="DNS"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.DNS"
id="override_DNS">
<div class="invalid-feedback">{{ errorMsg }}</div>
</div>
<div>
<label for="override_EndpointAllowedIPs" class="form-label">
<small class="text-muted">
<LocaleText t="Endpoint Allowed IPs"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.EndpointAllowedIPs"
id="override_EndpointAllowedIPs">
<div class="invalid-feedback">{{ errorMsg }}</div>
</div>
<div>
<label for="override_ListenPort" class="form-label">
<small class="text-muted">
<LocaleText t="Listen Port"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.ListenPort"
id="override_ListenPort">
<div class="invalid-feedback">{{ errorMsg }}</div>
</div>
<div>
<label for="override_MTU" class="form-label">
<small class="text-muted">
<LocaleText t="MTU"></LocaleText>
</small>
</label>
<input type="text"
class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.MTU"
id="override_MTU">
<div class="invalid-feedback">{{ errorMsg }}</div>
</div>
<div>
<label for="override_PeerRemoteEndpoint" class="form-label">
<small class="text-muted">
<LocaleText t="Peer Remote Endpoint"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.PeerRemoteEndpoint"
id="override_PeerRemoteEndpoint">
</div>
<div>
<label for="override_persistent_keepalive" class="form-label">
<small class="text-muted">
<LocaleText t="Persistent Keepalive"></LocaleText>
</small>
</label>
<input type="text" class="form-control form-control-sm rounded-3"
:disabled="saving"
v-model="overridePeerSettings.PersistentKeepalive"
id="override_PersistentKeepalive">
<div class="invalid-feedback">{{ errorMsg }}</div>
</div>
<div class="d-flex mt-1 gap-2">
<button
:class="{disabled: !edited}"
@click="resetForm()"
class="btn btn-sm bg-secondary-subtle border-secondary-subtle text-secondary-emphasis rounded-3 shadow ms-auto">
<i class="bi bi-arrow-clockwise me-2"></i>
<LocaleText t="Reset"></LocaleText>
</button>
<button
:class="{disabled: !edited}"
@click="submitForm()"
class="btn btn-sm bg-primary-subtle border-primary-subtle text-primary-emphasis rounded-3 shadow">
<i class="bi bi-save-fill me-2"></i>
<LocaleText t="Save"></LocaleText>
</button>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,103 @@
<script setup>
import LocaleText from "@/components/text/localeText.vue";
import CodeEditor from "@/utilities/simple-code-editor/CodeEditor.vue";
import {fetchGet, fetchPost} from "@/utilities/fetch.js";
import {useRoute} from "vue-router";
import {ref} from "vue";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
const emits = defineEmits(['close'])
const route = useRoute()
const content = ref("")
const path = ref("")
const error = ref(false)
const errorMessage = ref("")
const getRaw = async () => {
await fetchGet('/api/getWireguardConfigurationRawFile', {
configurationName: route.params.id
}, (res) => {
content.value = res.data.content
path.value = res.data.path
})
}
await getRaw()
const dashboardStore = DashboardConfigurationStore();
const saving = ref(false)
const saveRaw = async () => {
saving.value = true
await fetchPost('/api/updateWireguardConfigurationRawFile', {
configurationName: route.params.id,
rawConfiguration: content.value
}, (res) => {
if (res.status){
error.value = false
dashboardStore.newMessage("Server", "Configuration saved", "success")
}else{
error.value = true
errorMessage.value = res.message
}
saving.value = false
})
}
</script>
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal" style="width: 1000px">
<div class="card rounded-3 shadow flex-grow-1" id="deleteConfigurationContainer">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0">
<h5 class="mb-0">
<LocaleText t="Edit Raw Configuration File"></LocaleText>
</h5>
<button type="button" class="btn-close ms-auto" @click="emits('close')"></button>
</div>
<div class="card-body px-4 d-flex flex-column gap-3">
<div class="alert alert-danger rounded-3 mb-0" v-if="error">
<div class="mb-2">
<strong>
<LocaleText t="Failed to save configuration. Please see the following error message:"></LocaleText>
</strong>
</div>
<div class="bg-body w-100 p-2 rounded-3">
<pre>{{errorMessage}}</pre>
</div>
</div>
<CodeEditor
:disabled="true"
:read-only="saving"
v-model="content"
:theme="dashboardStore.Configuration.Server.dashboard_theme === 'dark' ? 'github-dark':'github'"
:languages="[['ini', path]]"
width="100%" height="600px">
</CodeEditor>
<div class="d-flex gap-2">
<button class="btn bg-secondary-subtle border-secondary-subtle text-secondary-emphasis rounded-3 shadow ms-auto px-3 py-2"
:disabled="saving"
@click="getRaw()">
<i class="bi bi-arrow-clockwise me-2"></i>
<LocaleText t="Reset"></LocaleText>
</button>
<button
@click="saveRaw()"
:disabled="saving"
class="btn bg-danger-subtle border-danger-subtle text-danger-emphasis rounded-3 px-3 py-2 shadow"
>
<i class="bi bi-save-fill me-2"></i>
<LocaleText t="Save" v-if="!saving"></LocaleText>
<LocaleText t="Saving..." v-else></LocaleText>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,110 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import LocaleText from "@/components/text/localeText.vue";
import {fetchPost} from "@/utilities/fetch.js";
import {useRouter} from "vue-router";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
const props = defineProps({
configurationName: String
})
const emit = defineEmits(['close'])
const newConfigurationName = reactive({
data: "",
valid: false
});
const store = WireguardConfigurationsStore()
onMounted(() => {
watch(() => newConfigurationName.data, (newVal) => {
newConfigurationName.valid = /^[a-zA-Z0-9_=+.-]{1,15}$/.test(newVal) && newVal.length > 0 && !store.Configurations.find(x => x.Name === newVal);
})
})
const dashboardConfigurationStore = DashboardConfigurationStore()
const loading = ref(false)
const router = useRouter()
const rename = async () => {
if (newConfigurationName.data){
loading.value = true
clearInterval(dashboardConfigurationStore.Peers.RefreshInterval)
await fetchPost("/api/renameWireguardConfiguration", {
ConfigurationName: props.configurationName,
NewConfigurationName: newConfigurationName.data
}, async (res) => {
if (res.status){
await store.getConfigurations()
dashboardConfigurationStore.newMessage("Server", "Configuration renamed", "success")
router.push(`/configuration/${newConfigurationName.data}/peers`)
}else{
dashboardConfigurationStore.newMessage("Server", res.message, "danger")
loading.value = false
}
})
}
}
</script>
<template>
<div class="card rounded-3 flex-grow-1 bg-danger-subtle border-danger-subtle border shadow">
<div class="card-body">
<p>
<LocaleText t="To update this configuration's name, WGDashboard will execute the following operations:"></LocaleText>
</p>
<ol>
<li>
<LocaleText t="Duplicate current configuration's database table and .conf file with the new name"></LocaleText>
</li>
<li>
<LocaleText t="Delete current configuration's database table and .conf file"></LocaleText>
</li>
</ol>
<div class="d-flex align-items-center gap-3 inputGroup">
<input class="form-control form-control-sm rounded-3" :value="configurationName" disabled>
<h3 class="mb-0">
<i class="bi bi-arrow-right"></i>
</h3>
<input class="form-control form-control-sm rounded-3"
id="newConfigurationName"
:class="[newConfigurationName.data ? (newConfigurationName.valid ? 'is-valid' : 'is-invalid') : '']"
v-model="newConfigurationName.data">
</div>
<div class="invalid-feedback" :class="{'d-block': !newConfigurationName.valid && newConfigurationName.data}">
<LocaleText t="Configuration name is invalid. Possible reasons:"></LocaleText>
<ul class="mb-0">
<li>
<LocaleText t="Configuration name already exist"></LocaleText>
</li>
<li>
<LocaleText t="Configuration name can only contain 15 lower/uppercase alphabet, numbers, underscore, equal sign, plus sign, period and hyphen."></LocaleText>
</li>
</ul>
</div>
<div class="d-flex mt-3">
<button
@click="emit('close')"
class="btn btn-sm bg-secondary-subtle border-secondary-subtle text-secondary-emphasis rounded-3">
<LocaleText t="Cancel"></LocaleText>
</button>
<button
@click="rename()"
:disabled="!newConfigurationName.data || loading"
class="btn btn-sm btn-danger rounded-3 ms-auto">
<LocaleText t="Save"></LocaleText>
</button>
</div>
</div>
</div>
</template>
<style scoped>
@media screen and (max-width: 567px) {
.inputGroup{
flex-direction: column;
h3{
transform: rotate(90deg);
}
}
}
</style>

View File

@@ -0,0 +1,207 @@
<script>
import {fetchGet} from "@/utilities/fetch.js";
import {WireguardConfigurationsStore} from "@/stores/WireguardConfigurationsStore.js";
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
import LocaleText from "@/components/text/localeText.vue";
import {GetLocale} from "@/utilities/locale.js";
import {ref} from "vue";
export default {
name: "allowedIPsInput",
components: {LocaleText},
props: {
data: Object,
saving: Boolean,
bulk: Boolean,
availableIp: undefined,
},
data(){
return {
allowedIp: [],
availableIpSearchString: "",
customAvailableIp: "",
allowedIpFormatError: false
}
},
setup(props){
const store = WireguardConfigurationsStore();
const dashboardStore = DashboardConfigurationStore();
const selectedSubnet = ref("")
if(Object.keys(props.availableIp).length > 0){
selectedSubnet.value = Object.keys(props.availableIp)[0]
}
return {store, dashboardStore, selectedSubnet}
},
computed: {
searchAvailableIps(){
return (this.availableIpSearchString ?
this.availableIp[this.selectedSubnet].filter(x =>
x.includes(this.availableIpSearchString) && !this.data.allowed_ips.includes(x)) :
this.availableIp[this.selectedSubnet].filter(x => !this.data.allowed_ips.includes(x)))
},
inputGetLocale(){
return GetLocale("Enter IP Address/CIDR")
}
},
methods: {
addAllowedIp(ip){
let list = ip.split(',')
for (let i = 0; i < list.length; i++){
let ipaddress = list[i].trim();
if(this.store.checkCIDR(ipaddress)){
this.data.allowed_ips.push(ipaddress);
}else{
this.allowedIpFormatError = true;
this.dashboardStore.newMessage('WGDashboard',
`This Allowed IP address is invalid: ${ipaddress}`, 'danger')
return false;
}
}
this.customAvailableIp = ''
return true;
}
},
watch: {
customAvailableIp(){
this.allowedIpFormatError = false;
}
},
mounted() {
if (this.availableIp !== undefined &&
Object.keys(this.availableIp).length > 0 && this.data.allowed_ips.length === 0){
for (let subnet in this.availableIp){
if (this.availableIp[subnet].length > 0){
this.addAllowedIp(this.availableIp[subnet][0])
}
}
}
}
}
</script>
<template>
<div :class="{inactiveField: this.bulk}">
<div class="d-flex flex-column flex-md-row mb-2">
<label for="peer_allowed_ip_textbox" class="form-label mb-0">
<small class="text-muted">
<LocaleText t="Allowed IPs"></LocaleText> <code><LocaleText t="(Required)"></LocaleText></code>
</small>
</label>
<div class="form-check form-switch ms-md-auto">
<input class="form-check-input" type="checkbox"
v-model="this.data.allowed_ips_validation"
role="switch" id="disableIPValidation">
<label class="form-check-label" for="disableIPValidation">
<small>
<LocaleText t="Allowed IPs Validation"></LocaleText>
</small>
</label>
</div>
</div>
<div class="d-flex">
<div class="d-flex gap-2 flex-wrap" :class="{'mb-2': this.data.allowed_ips.length > 0}">
<TransitionGroup name="list">
<span class="badge rounded-pill text-bg-success" v-for="(ip, index) in this.data.allowed_ips" :key="ip">
{{ip}}
<a role="button" @click="this.data.allowed_ips.splice(index, 1)">
<i class="bi bi-x-circle-fill ms-1"></i></a>
</span>
</TransitionGroup>
</div>
</div>
<div class="d-flex gap-2 align-items-center">
<div class="input-group">
<input type="text" class="form-control form-control-sm rounded-start-3"
:placeholder="this.inputGetLocale"
:class="{'is-invalid': this.allowedIpFormatError}"
@keyup.enter="this.customAvailableIp ? this.addAllowedIp(this.customAvailableIp) : undefined"
v-model="customAvailableIp"
id="peer_allowed_ip_textbox"
:disabled="bulk">
<button class="btn btn-sm rounded-end-3"
:class="[this.customAvailableIp ? 'btn-success':'btn-outline-success']"
:disabled="bulk || !this.customAvailableIp"
@click="this.addAllowedIp(this.customAvailableIp)"
type="button" id="button-addon2">
<i class="bi bi-plus-lg"></i>
</button>
</div>
<small class="text-muted">
<LocaleText t="or"></LocaleText>
</small>
<div class="dropdown flex-grow-1">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle rounded-3 w-100"
:disabled="!availableIp || bulk"
data-bs-auto-close="outside"
type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-filter-circle me-2"></i>
<LocaleText t="Pick Available IP"></LocaleText>
</button>
<ul class="dropdown-menu mt-2 shadow w-100 dropdown-menu-end rounded-3 pb-0"
v-if="this.availableIp"
style="width: 300px !important;">
<li>
<div class="px-3 d-flex gap-3 align-items-center">
<label for="availableIpSearchString" class="text-muted">
<i class="bi bi-search"></i>
</label>
<input
id="availableIpSearchString"
class="form-control form-control-sm rounded-3"
v-model="this.availableIpSearchString">
</div>
<hr class="my-2">
<div class="px-3 overflow-x-scroll d-flex overflow-x-scroll overflow-y-hidden align-items-center gap-2">
<small class="text-muted">Subnet</small>
<button
v-for="key in Object.keys(this.availableIp)"
:key="key"
@click="this.selectedSubnet = key"
:class="{'bg-primary-subtle': this.selectedSubnet === key}"
class="btn btn-sm text-primary-emphasis rounded-3">
{{key}}
</button>
</div>
<hr class="mt-2 mb-0">
</li>
<li>
<div class="overflow-y-scroll" style="height: 270px;">
<div v-for="ip in this.searchAvailableIps" style="" :key="ip">
<a class="dropdown-item d-flex" role="button" @click="this.addAllowedIp(ip)">
<span class="me-auto"><small>{{ip}}</small></span>
</a>
</div>
<div v-if="this.searchAvailableIps.length === 0" class="px-3 py-2">
<small class="text-muted" v-if="this.availableIpSearchString"><LocaleText t="No available IP containing"></LocaleText>"{{this.availableIpSearchString}}"</small>
<small class="text-muted" v-else><LocaleText t="No more IP address available in this subnet"></LocaleText></small>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<style scoped>
.list-move, /* apply transition to moving elements */
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.list-leave-active {
position: absolute;
}
</style>

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