Compare commits

...

141 Commits

Author SHA1 Message Date
Lucas Rattz 380ff5c2f1 Improve documentation on password hash (#1901)
* Improve documentation on password hash

* Change branch name

* Add single quote docker run info

* Tag versions, docker run version

* separate docker run and compose

---------

Co-authored-by: Bernd Storath <32197462+kaaax0815@users.noreply.github.com>
2025-06-03 09:58:52 +02:00
Bernd Storath ae540593fe fix iptables alias
!skipci
2025-05-31 21:29:43 +02:00
Bernd Storath 42adeb391c update dockerfile, update workflows
!skipci
2025-05-31 21:22:56 +02:00
Bernd Storath 02589a3ce9 early fail if old password variable (#1350) 2024-09-04 18:42:42 +02:00
Philip H. 0a6645b526 Version 14: Home Assistent support, PASSWORD_HASH (inc. Helper), translation updates, bugfixes and more (#1199) 2024-08-09 21:32:32 +02:00
NPM Update Bot a18a715f6f npm: package updates 2024-08-08 18:37:52 +00:00
Philip H. ec202d8575 fix: Status Bar Color Issue in PWA on iOS 18 (#1257)
#1256
Reported by @xK1t
2024-08-08 20:37:19 +02:00
Philip H 9dd7f256ba fix: Status Bar Color Issue in PWA on iOS 18
Signed-off-by: Philip H <47042125+pheiduck@users.noreply.github.com>
2024-08-08 20:33:01 +02:00
Philip H. 33e95bac5e Update Ukraine translation (#1251) 2024-08-07 17:23:09 +02:00
Nikolas 72fe64385e Update i18n.js 2024-08-07 17:20:38 +02:00
NPM Update Bot 2b7c846823 npm: package updates 2024-08-07 14:11:55 +00:00
Philip H. 9275cf611a Add autocomplete attribute to password input (#1249) 2024-08-07 16:11:25 +02:00
İbrahim Çetin 95934c6008 Add autocomplete attribute to password input 2024-08-07 10:29:33 +03:00
Philip H. babb9983aa chore: Update i18n.js Turkish translations (#1238)
Thank you @babico!
2024-08-03 09:22:51 +02:00
Müslüm Barış Korkmazer c9ff248011 chore: Update i18n.js Turkish translations 2024-08-02 22:49:56 +03:00
Philip H. f9edec0ac1 Create pull_request_template.md (#1226) 2024-08-02 19:48:08 +02:00
Philip H. eb0fa90cd0 Create pull_request_template.md 2024-08-02 19:47:30 +02:00
Philip H. 1607fd1562 fixup: docker-compose.dev.yml (#1236)
Improving compose file for dev.
Some variables are missed which lead to an error.
Fixes: #1234
2024-08-01 20:09:01 +02:00
Philip H. 5938474bf8 fixup: docker-compose.dev.yml
Improving compose file for dev.
Some variables are missed which lead to an error.
Fixes: #1234
2024-08-01 17:20:11 +02:00
Philip H. ff9c1b49b6 CODEOWNERS: add maintainer 2024-08-01 17:11:01 +02:00
Philip H. 72562dc660 Spelling in How_to_generate_an_bcrypt_hash.md (#1233) 2024-08-01 07:30:28 +02:00
kikawala 4ffa6b37de Spelling in How_to_generate_an_bcrypt_hash.md 2024-07-31 17:10:25 -05:00
Philip H. 1416613cc6 README.md: Reduce confusion in the readme 2024-07-30 17:57:15 +02:00
Philip H. a3c5cf359f remove PASSWORD env unused and replace by PASSWORD_HASH (#1229) 2024-07-30 17:47:18 +02:00
pheiduck d8a48aef29 remove PASSWORD env unused and replace by PASSWORD_HASH 2024-07-30 17:45:00 +02:00
NPM Update Bot 5dad038796 npm: package updates 2024-07-27 11:05:05 +00:00
Philip H. 63f49a20ed translations: Add missing Russian translations (#1219)
thank you @mcmimik!
2024-07-27 13:04:32 +02:00
Андрей 39949d2704 translations: Add missing Russian translations 2024-07-27 14:00:48 +03:00
Андрей 13fcccb2f2 translations: Add missing Russian translations 2024-07-27 13:50:18 +03:00
NPM Update Bot 200332df4b npm: package updates 2024-07-24 15:54:42 +00:00
Philip H. 3d0070f3f6 prepare: version bump and changelog (#1211) 2024-07-24 17:54:08 +02:00
pheiduck 14fd01f4d0 prepare: version bump and changelog
Signed-off-by: pheiduck <47042125+pheiduck@users.noreply.github.com>
2024-07-24 17:46:31 +02:00
Philip H. 52bcfb056a Get the version info inside the release object (#1208)
Fix "invalid reference format" in production Docker build
2024-07-23 07:47:07 +02:00
Dartegnian d5b8d707ef Get the version info inside the release object 2024-07-23 13:01:08 +08:00
Philip H. caad2e4162 fix: responsive buttons on mobile (#1206)
* fix: buttons on mobile
* fix: lint error with workspaces
* fix: redundant css
2024-07-22 13:49:46 +02:00
tetuaoro 3d376e542f fix: redundant css 2024-07-22 13:28:30 +02:00
tetuaoro 74372dc05d fix: lint error with workspaces 2024-07-22 13:05:18 +02:00
tetuaoro b46018efd8 fix: buttons on mobile 2024-07-22 12:44:53 +02:00
NPM Update Bot 2ef264d06f npm: package updates 2024-07-20 14:35:18 +00:00
Philip H. d23c5f7d01 Bugfix: Line Charts
Fixes: #1111
2024-07-20 16:34:46 +02:00
Sergei Birukov 73f2ad4ac3 Fix #1111 2024-07-20 17:20:54 +03:00
Philip H 5a075683c4 fix typo: How_to_generate_an_bcrypt_hash.md 2024-07-15 15:20:15 +02:00
Philip H c28e5befa6 feat: PASSWORD_HASH helpers (#1180)
* feat: generate PASSWORD_HASH on the fly

* remove PASSWORD environment variable in favor of PASSWORD_HASH
* enhance password validity check server function
* update Dockerfile to include building a binary for generating hashed password
* update README with comprehensive Docker usage instructions hash generation

* fix: try fix git action docker build

* Dockerfile: use alpine-base image and install required build packages

* rewrite in js

* move files

* fix: lint errors

* some corrections

---------

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
2024-07-15 10:32:38 +02:00
NPM Update Bot 42ad29b494 npm: package updates 2024-07-15 00:03:14 +00:00
tetuaoro 53dad56bb6 some corrections 2024-07-14 18:33:11 +02:00
tetuaoro f5d93f6c5a fix: lint errors 2024-07-14 18:09:13 +02:00
tetuaoro a9c798deda move files 2024-07-14 17:59:52 +02:00
tetuaoro 781d56d0ff Merge branch 'wgpassword_js' into wgpassword 2024-07-14 17:20:47 +02:00
tetuaoro 883ca34182 rewrite in js 2024-07-14 17:13:27 +02:00
Philip H cc5d45b833 Dockerfile: use alpine-base image and install required build packages 2024-07-14 16:43:53 +02:00
tetuaoro 8bfcb5d502 fix: try fix git action docker build 2024-07-12 22:39:26 +02:00
tetuaoro 9a19430dc8 feat: generate PASSWORD_HASH on the fly
* remove PASSWORD environment variable in favor of PASSWORD_HASH
* enhance password validity check server function
* update Dockerfile to include building a binary for generating hashed password
* update README with comprehensive Docker usage instructions hash generation
2024-07-12 21:24:09 +02:00
NPM Update Bot 62ea932d33 npm: package updates 2024-07-11 13:46:35 +00:00
Philip H be8a592072 refactor: optimize build config, factorize code, enhance SVG icons (#1174)
* focus on syncing configuration without shutting down current wg session
	refactor build configuration logic to optimize code structure
* enhance SVG icons for better visual appeal (https://github.com/wg-easy/wg-easy/pull/1166#issuecomment-2222418606)
* update the screenshot to reflect the latest UI changes
* fix: prevent logging private key during user creation
2024-07-11 15:45:58 +02:00
tetuaoro 9371b78a21 refactor: optimize build config, factorize code, enhance SVG icons
* focus on syncing configuration without shutting down current wg session
	refactor build configuration logic to optimize code structure
* enhance SVG icons for better visual appeal (https://github.com/wg-easy/wg-easy/pull/1166#issuecomment-2222418606)
* update the screenshot to reflect the latest UI changes
* fix: prevent logging private key during user creation
2024-07-11 12:58:25 +02:00
Philip H 4ba638c09c i18n.js: fix typo 2024-07-10 18:55:24 +02:00
NPM Update Bot 3ad2607515 npm: package updates 2024-07-10 16:49:35 +00:00
Philip H 7f05448a5d import & export configuration (#1161,#1166)
* fix: auto formatter

* Revert "i18n.js: german translation"

This reverts commit e4a7ff08c6.

* fix conficts

* feat: load configuration from file

* import json config file & update the config (restore)
* export the config and save it to json file (backup)

* fix: reload configuration

* run linter
* screenshot update

* feat: support more langs

* add translations for French, Spanish, and Italian
* change the wording for better understanding of this feature:
    - "import" to "restore"
    - "export" to "backup"
* rename functions to reflect these changes

* i18n.js: german translation

* npm: package updates

* fix: icons & buttons view

* update the viewBox of svg elements
* add cursor pointer when hover the restore button
* rebuild the css

---------

Co-authored-by: tetuaoro <tetuaoropro@gmail.com>
Co-authored-by: tetuaoro <65575727+tetuaoro@users.noreply.github.com>
2024-07-10 18:48:33 +02:00
Philip H c5b3bcd31d fix: icons & buttons view (#1167)
* update the viewBox of svg elements
* add cursor pointer when hover the restore button
* rebuild the css
2024-07-10 18:40:15 +02:00
tetuaoro 10d24fa04b fix: icons & buttons view
* update the viewBox of svg elements
* add cursor pointer when hover the restore button
* rebuild the css
2024-07-10 18:11:28 +02:00
Philip H 3dc83f9c25 start fix pr 1161 (#1165)
* feat: load configuration from file

* import json config file & update the config (restore)
* export the config and save it to json file (backup)

* fix: reload configuration

* run linter
* screenshot update

* feat: support more langs

* add translations for French, Spanish, and Italian
* change the wording for better understanding of this feature:
    - "import" to "restore"
    - "export" to "backup"
* rename functions to reflect these changes

* i18n.js: german translation

* npm: package updates

* Revert "import & export configuration"

* npm: package updates

* Revert "import & export configuration"

* fix: auto formatter

* Revert "i18n.js: german translation"

This reverts commit e4a7ff08c6.

* fix conficts

---------

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
Co-authored-by: NPM Update Bot <npmupbot@users.noreply.github.com>
2024-07-10 15:51:38 +02:00
Philip H 1a54a0b016 Merge branch 'imexport' into imexport 2024-07-10 15:49:42 +02:00
NPM Update Bot a0ed35fd76 npm: package updates 2024-07-10 15:46:36 +02:00
Philip H 8421e313b5 i18n.js: german translation 2024-07-10 15:46:36 +02:00
tetuaoro ce20bb7fcb feat: support more langs
* add translations for French, Spanish, and Italian
* change the wording for better understanding of this feature:
    - "import" to "restore"
    - "export" to "backup"
* rename functions to reflect these changes
2024-07-10 15:46:36 +02:00
tetuaoro e3ee09b755 fix: reload configuration
* run linter
* screenshot update
2024-07-10 15:46:36 +02:00
tetuaoro 03b7d8e537 feat: load configuration from file
* import json config file & update the config (restore)
* export the config and save it to json file (backup)
2024-07-10 15:46:36 +02:00
tetuaoro e7d4bbc12c Merge branch 'master' into imexport 2024-07-10 15:14:41 +02:00
tetuaoro 45087a9683 fix conficts 2024-07-10 15:01:39 +02:00
tetuaoro 39d32b0a1c Revert "i18n.js: german translation"
This reverts commit e4a7ff08c6.
2024-07-10 14:44:40 +02:00
tetuaoro f47e740861 fix: auto formatter 2024-07-10 14:34:57 +02:00
Philip H ba85c085ab Revert "import & export configuration" (#1163) 2024-07-10 13:12:56 +02:00
Philip H 9aafbd73d2 Revert "import & export configuration" 2024-07-10 12:51:45 +02:00
NPM Update Bot 9efac11680 npm: package updates 2024-07-10 10:49:29 +00:00
Philip H e5131fb707 Revert "import & export configuration" (#1162) 2024-07-10 12:48:50 +02:00
Philip H abdf96011e Revert "import & export configuration" 2024-07-10 12:44:59 +02:00
NPM Update Bot 8b2706e3c2 npm: package updates 2024-07-10 10:38:02 +00:00
Philip H 6fe197f4fd import & export configuration (#1161)
* feat: load configuration from file

* import json config file & update the config (restore)
* export the config and save it to json file (backup)

* fix: reload configuration

* run linter
* screenshot update

* feat: support more langs

* add translations for French, Spanish, and Italian
* change the wording for better understanding of this feature:
    - "import" to "restore"
    - "export" to "backup"
* rename functions to reflect these changes

* i18n.js: german translation

---------

Co-authored-by: Philip H <47042125+pheiduck@users.noreply.github.com>
2024-07-10 12:37:28 +02:00
Philip H e4a7ff08c6 i18n.js: german translation 2024-07-10 12:34:11 +02:00
tetuaoro 43b193b76d feat: support more langs
* add translations for French, Spanish, and Italian
* change the wording for better understanding of this feature:
    - "import" to "restore"
    - "export" to "backup"
* rename functions to reflect these changes
2024-07-10 12:06:25 +02:00
tetuaoro 4deca34faf fix: reload configuration
* run linter
* screenshot update
2024-07-09 19:49:40 +02:00
tetuaoro 72ba79b5f2 feat: load configuration from file
* import json config file & update the config (restore)
* export the config and save it to json file (backup)
2024-07-09 17:06:19 +02:00
NPM Update Bot 94d87681c3 npm: package updates 2024-07-09 15:01:53 +00:00
Philip H e3315d92c4 Fix a small typo in README.md (#1160)
Thank you @ThreadR-r!
2024-07-09 17:01:15 +02:00
Elian (ThreadR) Freyermuth a0c495ddad Fix a small typo in README.md
Changed from "Home Assistent" to "Home Assistant"
2024-07-09 14:11:07 +02:00
NPM Update Bot c73c6c7291 npm: package updates 2024-07-08 08:42:56 +00:00
Philip H 04d1ca18b7 Fix bcrypt hash one-liner (#1154)
Thank you @steviegalluscio!
2024-07-08 10:42:23 +02:00
Stevie Galluscio 438fc7ccf9 Fix bcrypt hash one-liner 2024-07-08 10:39:29 +02:00
Philip H a2c758dbcb How_to_generate_an_bcrypt_hash.md: macos homebrew 2024-07-07 19:15:57 +02:00
NPM Update Bot 6a588ee3fa npm: package updates 2024-07-07 17:13:42 +00:00
Philip H 378464a424 How_to_generate_an_bcrypt_hash.md: macos guide 2024-07-07 19:13:03 +02:00
Philip H 7ecf7b08b1 fixup: typos 2024-07-05 22:42:38 +02:00
Philip H cea9e9302d translations: Update Traditional Chinese translations (#1145)
Thank you @bluehomewu!
2024-07-04 19:02:19 +02:00
EdwardWu 11f5122c39 translations: Update Traditional Chinese translations
* Update strings closer than Taiwanese used.

Signed-off-by: EdwardWu <bluehome.wu@gmail.com>
2024-07-04 10:47:18 +08:00
NPM Update Bot ee117ddb91 npm: package updates 2024-07-01 00:03:23 +00:00
NPM Update Bot d3e8e627e9 npm: package updates 2024-06-28 10:37:56 +00:00
Philip H 864bb00d0b Enhance bcrypt doc: rename, add one-liner, usage info, and assert (#1138)
Thank you @mathys-lopinto!
2024-06-28 12:37:22 +02:00
Mathys Lopinto 7608f91913 Right README
Push the latest README.md
2024-06-27 21:06:15 +02:00
Mathys Lopinto 4d849fc508 Enhance bcrypt doc: rename, add one-liner, usage info, and assert
- Rename the file to a more readable name
- Add one-liner command for quick execution
- Include dedicated paragraph on using the output
- Implement assert to prevent bcrypt limitation issues
- Comment the python script
- Improves clarity and usability of bcrypt documentation
- Mention documentation file in docker-compose.yml and README.me file
2024-06-27 21:00:11 +02:00
NPM Update Bot 436ccac824 npm: package updates 2024-06-27 18:34:47 +00:00
Philip H b4ca454ec5 Add: Generate.bcrypt.hash.md (#1135)
Thank you @mathys-lopinto!
2024-06-27 20:34:05 +02:00
Philip H 8044c53815 add: Fedora and Arch Linux install guide 2024-06-27 10:18:09 +02:00
Philip H e7e374cfd7 comment: created by 2024-06-26 18:11:02 +02:00
Philip H 9afd549273 Add: Generate.bcrypt.hash.md
Thanks to: @mathys-lopinto
2024-06-26 13:03:14 +02:00
Philip H 6b67f20b6a build(deps): bump docker/build-push-action from 5 to 6 (#1134) 2024-06-24 10:34:41 +02:00
dependabot[bot] d31524a531 build(deps): bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-24 04:23:33 +00:00
NPM Update Bot 34c28805c4 npm: package updates 2024-06-24 00:04:04 +00:00
Philip H 9b6ac7cd8d docker-compose.yml: PASSWORD_HASH is replacing PASSWORD
in nightly and next releases
2024-06-20 16:15:10 +02:00
Philip H 3613d26d4a docker-compose.yml: fixup every single $ has to be $$ 2024-06-20 14:43:17 +02:00
Philip H ccacc5ea87 docker-compose.yml: refinements 2024-06-20 14:37:12 +02:00
Philip H bfd7ef9e46 docker-compose.yml: fixup use '' for hashed Password
otherwise docker think it is an env variable and set it to blank
2024-06-20 12:24:57 +02:00
NPM Update Bot 2f956248db npm: package updates 2024-06-20 09:46:37 +00:00
Philip H e0e2a6deba docker-compose.yml: add missing PASSWORD_HASH option (#1121) 2024-06-20 11:46:03 +02:00
Philip H 304506d26d docker-compose.yml: add missing PASSWORD_HASH option 2024-06-20 11:43:23 +02:00
Peter Lewis e0775c0d2e Merge pull request #1117 from wg-easy/peterlewis-patch-1
README refinements
2024-06-18 22:38:04 +01:00
Peter Lewis 8598a167ef Update README.md
Refinement
2024-06-18 22:30:28 +01:00
Philip H 6659785514 feat: introduce PASSWORD_HASH and deprecate PASSWORD (#1116)
Thank you @RobertHeim!
2024-06-18 22:50:57 +02:00
Robert Heim 34ae8e42f3 fix: lint errors 2024-06-18 22:30:55 +02:00
Robert Heim eaa4b1ebaa feat: introduce PASSWORD_HASH and deprecate PASSWORD 2024-06-18 20:17:00 +02:00
Philip H 72fbf1baf6 README.md: add docs for WG_CONFIG_PORT 2024-06-17 15:22:54 +02:00
Philip H 2a102eea93 deploy-development.yml: disable pull request
until we can deploy on other branches from contributors/authors
2024-06-16 19:02:32 +02:00
Philip H 85913b71ed CI: no cache-dependency-path
it's useless and can lead to confusion
2024-06-16 16:25:51 +02:00
NPM Update Bot 7d0e2729b6 npm: package updates 2024-06-16 14:14:58 +00:00
Philip H b5372f0dbc bring password hash back
users want to have this instead cleartext password. Mitigates security issues.
2024-06-16 16:14:19 +02:00
NPM Update Bot 390b72c94a npm: package updates 2024-06-10 00:03:26 +00:00
Philip H de22768079 config: Add support for custom client port configuration (#1090)
Thank you @adriy-be!
This will enable homeassistant support
2024-06-08 11:47:52 +02:00
Philip H 00acd1a07e config: Add support for custom client port configuration (#1080)
merge for testing (1)
2024-06-07 12:55:14 +02:00
adrien a082a40bf6 config: Add support for custom client port configuration
This commit introduces the ability to specify a custom port for the client
configuration. This feature is particularly useful when the WireGuard server
is behind a port forwarding setup, allowing clients to connect using the
correct port number.

With this change, users can now define the desired client port in the
configuration file, ensuring seamless connectivity even in scenarios where
the client's listening port differs from the standard WireGuard port.
2024-06-07 12:53:54 +02:00
Philip H 3d1e42c722 fix typo in Server.js (#1089)
Thank you @Max-42!
2024-06-07 09:04:58 +02:00
Max e6d2d95340 fix typo in Server.js 2024-06-06 23:01:39 +02:00
NPM Update Bot 1370141f03 npm: package updates 2024-06-06 15:21:02 +00:00
Philip H ac552e0384 Readme: Inform Podman users about cap-add=NET_RAW (#1085)
Thank you @iguanajuice!
2024-06-06 17:20:26 +02:00
iguanajuice ca737f9452 Inform Podman users about cap-add=NET_RAW 2024-06-04 01:17:05 -04:00
NPM Update Bot b60f0e9668 npm: package updates 2024-06-02 13:20:07 +00:00
Philip H 0e1ad23f17 Everyting owned by WeeJeWel 2024-06-02 15:19:29 +02:00
Philip H 3638e81718 Update CODEOWNERS 2024-05-30 15:28:13 +02:00
NPM Update Bot 44417d3db6 npm: package updates 2024-05-30 11:48:00 +00:00
Philip H e5e63c43e6 package.json: fixup license identifier 2024-05-30 13:47:24 +02:00
NPM Update Bot f06b7e00aa npm: package updates 2024-05-30 07:31:06 +00:00
Philip H 70d59d0fdd cdnjs: apexcharts.min.js 3.49.1 (#1081) 2024-05-30 09:30:29 +02:00
Philip H 332039de56 cdnjs: apexcharts.min.js 3.49.1 2024-05-30 09:24:58 +02:00
31 changed files with 1098 additions and 530 deletions
+4 -1
View File
@@ -1,2 +1,5 @@
# Copyright (c) Emile Nijssen
# Copyright (c) Emile Nijssen (WeeJeWel)
# Founder and Codeowner of WireGuard Easy (wg-easy)
# Maintained by Bernd Storath (kaaax0815)
* @WeeJeWel
* @kaaax0815
@@ -0,0 +1,28 @@
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How has this been tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->
## Screenshots (if appropriate):
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
-41
View File
@@ -1,41 +0,0 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "15 0 * * *"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript-typescript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
-38
View File
@@ -1,38 +0,0 @@
name: Build & Publish Development
on:
workflow_dispatch:
pull_request:
jobs:
deploy:
name: Build & Deploy
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: production
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & Publish Docker Image
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
tags: ghcr.io/wg-easy/wg-easy:development
-39
View File
@@ -1,39 +0,0 @@
name: Build & Publish Nightly
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
deploy:
name: Build & Deploy
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: production
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & Publish Docker Image
uses: docker/build-push-action@v5
with:
push: true
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
tags: ghcr.io/wg-easy/wg-easy:nightly
+1 -4
View File
@@ -1,7 +1,6 @@
name: Build Pull Request
on:
workflow_dispatch:
pull_request:
jobs:
@@ -14,8 +13,6 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: production
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -31,7 +28,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
push: false
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
+7 -9
View File
@@ -1,23 +1,24 @@
name: Build & Publish Latest
on:
workflow_dispatch:
push:
branches:
- production
- v14
jobs:
deploy:
name: Build & Deploy
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
if: |
github.repository_owner == 'wg-easy' &&
!contains(github.event.head_commit.message, '!skipci')
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: production
ref: v14
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -32,12 +33,9 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set environment variables
run: echo RELEASE=$(cat ./src/package.json | jq -r .release) >> $GITHUB_ENV
- name: Build & Publish Docker Image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
push: true
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8
tags: ghcr.io/wg-easy/wg-easy:latest, ghcr.io/wg-easy/wg-easy:${{ env.RELEASE }}
tags: ghcr.io/wg-easy/wg-easy:latest, ghcr.io/wg-easy/wg-easy:14
+1 -5
View File
@@ -3,8 +3,7 @@ name: Lint
on:
push:
branches:
- master
- production
- v14
pull_request:
jobs:
@@ -21,9 +20,6 @@ jobs:
node-version: '20'
check-latest: true
cache: 'npm'
cache-dependency-path: |
package-lock.json
src/package-lock.json
- name: npm run lint
run: |
-43
View File
@@ -1,43 +0,0 @@
name: NPM Update Bot 🤖
on:
push:
branches: [ "master" ]
schedule:
- cron: "0 0 * * 1"
jobs:
npmupbot:
name: NPM Update Bot 🤖
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
repository: wg-easy/wg-easy
ref: master
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
check-latest: true
cache: 'npm'
cache-dependency-path: |
package-lock.json
src/package-lock.json
- name: Bot 🤖 "Updating NPM Packages..."
run: |
npm install -g --silent npm-check-updates
ncu -u
npm update
cd src
ncu -u
npm update
npm run buildcss
git config --global user.name 'NPM Update Bot'
git config --global user.email 'npmupbot@users.noreply.github.com'
git add .
git commit -am "npm: package updates" || true
git push
-35
View File
@@ -1,35 +0,0 @@
# 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: '*/5 * * * *'
jobs:
stale:
runs-on: ubuntu-latest
if: github.repository_owner == 'wg-easy'
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: 30
days-before-pr-close: 14
stale-pr-message: "This PR is stale because it has been open for 30 days with no activity."
close-pr-message: "This PR was closed because it has been inactive for 14 days since being marked as stale."
repo-token: ${{ secrets.GITHUB_TOKEN }}
operations-per-run: 100
+8 -4
View File
@@ -1,6 +1,6 @@
# As a workaround we have to build on nodejs 18
# nodejs 20 hangs on build with armv6/armv7
FROM docker.io/library/node:18-alpine AS build_node_modules
FROM docker.io/library/node:lts-alpine AS build_node_modules
# Update npm to latest
RUN npm install -g npm@latest
@@ -13,7 +13,7 @@ RUN npm ci --omit=dev &&\
# Copy build result to a new image.
# This saves a lot of disk space.
FROM docker.io/library/node:20-alpine
FROM docker.io/library/node:lts-alpine
HEALTHCHECK CMD /usr/bin/timeout 5s /bin/sh -c "/usr/bin/wg show | /bin/grep -q interface || exit 1" --interval=1m --timeout=5s --retries=3
COPY --from=build_node_modules /app /app
@@ -26,6 +26,10 @@ COPY --from=build_node_modules /app /app
# than what runs inside of docker.
COPY --from=build_node_modules /node_modules /node_modules
# Copy the needed wg-password scripts
COPY --from=build_node_modules /app/wgpw.sh /bin/wgpw
RUN chmod +x /bin/wgpw
# Install Linux packages
RUN apk add --no-cache \
dpkg \
@@ -35,11 +39,11 @@ RUN apk add --no-cache \
wireguard-tools
# Use iptables-legacy
RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save
RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables-legacy 10 --slave /usr/sbin/iptables-restore iptables-restore /usr/sbin/iptables-legacy-restore --slave /usr/sbin/iptables-save iptables-save /usr/sbin/iptables-legacy-save
# Set Environment
ENV DEBUG=Server,WireGuard
# Run Web UI
WORKDIR /app
CMD ["/usr/bin/dumb-init", "node", "server.js"]
CMD ["/usr/bin/dumb-init", "node", "server.js"]
+45
View File
@@ -0,0 +1,45 @@
# Generating bcrypt-hashed password
With version 14 of wg-easy, a password hashed with bcrypt is needed instead of the plain-text password string. This doc explains how to generate the hash based on a plain-text password.
## Using Docker + node
- You are using docker compose
The easiest way to generate a bcrypt password hash with wgpw is using docker and node:
```sh
docker run ghcr.io/wg-easy/wg-easy:14 node -e 'const bcrypt = require("bcryptjs"); const hash = bcrypt.hashSync("YOUR_PASSWORD", 10); console.log(hash.replace(/\$/g, "$$$$"));'
```
The hashed password will get printed on your terminal. Copy it and use on the `PASSWORD_HASH` environment variable in your docker compose.
- You are using `docker run`
If you are using `docker run` for running wg-easy, you must enclose the hash string in single quotes (`'...'`). You can use this command:
```sh
docker run --rm ghcr.io/wg-easy/wg-easy:14 node -e "const bcrypt = require('bcryptjs'); const hash = bcrypt.hashSync('YOUR_PASSWORD', 10); console.log('\'' + hash + '\'');"
```
The hashed password will get printed on your terminal. Copy it and use on the `PASSWORD_HASH` environment variable in your docker run command.
## Using Docker + wgpw
`wg-password` (wgpw) is a script that generates bcrypt password hashes. You can use it with docker:
```sh
docker run ghcr.io/wg-easy/wg-easy:14 wgpw YOUR_PASSWORD
```
You will see an output similar to this:
```sh
PASSWORD_HASH='$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW'
```
In this example, the `$2b$12$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW` string is your hashed password. For using it with docker-compose, you need to escape each `$` characters by adding another `$` before them, or they will get interpreted as variables. The final password you can use in docker-compose will look like this:
```sh
$$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW
```
+28 -40
View File
@@ -32,14 +32,8 @@ You have found the easiest way to install & manage WireGuard on any Linux host!
## Versions
We provide more then 1 docker image to get, this will help you decide which one is best for you.
| tag | Branch | Example | Description |
| - | - | - | - |
| `latest` | production | `ghcr.io/wg-easy/wg-easy:latest` or `ghcr.io/wg-easy/wg-easy` | stable as possbile get bug fixes quickly when needed, deployed against `production`. |
| `13` | production | `ghcr.io/wg-easy/wg-easy:13` | same as latest, stick to a version tag. |
| `nightly` | master | `ghcr.io/wg-easy/wg-easy:nightly` | mostly unstable gets frequent package and code updates, deployed against `master`. |
| `development` | pull requests | `ghcr.io/wg-easy/wg-easy:development` | used for development, testing code from PRs before landing into `master`. |
This branch is only for the v14 release of WireGuard Easy.
For newer versions, please refer to the [master branch](https://github.com/wg-easy/wg-easy/tree/master).
## Installation
@@ -64,7 +58,7 @@ To automatically install & run wg-easy, simply run:
--name=wg-easy \
-e LANG=de \
-e WG_HOST=<🚨YOUR_SERVER_IP> \
-e PASSWORD=<🚨YOUR_ADMIN_PASSWORD> \
-e PASSWORD_HASH=<🚨YOUR_ADMIN_PASSWORD_HASH> \
-e PORT=51821 \
-e WG_PORT=51820 \
-v ~/.wg-easy:/etc/wireguard \
@@ -75,12 +69,12 @@ To automatically install & run wg-easy, simply run:
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv4.ip_forward=1" \
--restart unless-stopped \
ghcr.io/wg-easy/wg-easy
ghcr.io/wg-easy/wg-easy:14
```
> 💡 Replace `YOUR_SERVER_IP` with your WAN IP, or a Dynamic DNS hostname.
>
> 💡 Replace `YOUR_ADMIN_PASSWORD` with a password to log in on the Web UI.
> 💡 Replace `YOUR_ADMIN_PASSWORD_HASH` with a bcrypt password hash to log in on the Web UI. See [How_to_generate_an_bcrypt_hash.md](./How_to_generate_an_bcrypt_hash.md) for know how generate the hash.
The Web UI will now be available on `http://0.0.0.0:51821`.
@@ -98,26 +92,27 @@ Are you enjoying this project? [Buy Emile a beer!](https://github.com/sponsors/W
These options can be configured by setting environment variables using `-e KEY="VALUE"` in the `docker run` command.
| Env | Default | Example | Description |
| - | - | - | - |
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
| `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
| `PASSWORD` | - | `foobar123` | When set, requires a password when logging in to the Web UI. |
| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. |
| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. |
| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. |
| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. |
| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. |
| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. |
| `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. |
| `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. |
| `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. |
| `WG_POST_UP` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L20) for the default value. |
| `WG_PRE_DOWN` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L27) for the default value. |
| `WG_POST_DOWN` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L28) for the default value. |
| `LANG` | `en` | `de` | Web UI language (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi). |
| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI |
| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart |
| Env | Default | Example | Description |
| - | - | - |------------------------------------------------------------------------------------------------------------------------------------------------------|
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
| `WEBUI_HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
| `PASSWORD_HASH` | - | `$2y$05$Ci...` | When set, requires a password when logging in to the Web UI. See [How to generate an bcrypt hash.md]("https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md") for know how generate the hash. |
| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. |
| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. |
| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. |
| `WG_CONFIG_PORT`| `51820` | `12345` | The UDP port used on [Home Assistant Plugin](https://github.com/adriy-be/homeassistant-addons-jdeath/tree/main/wgeasy)
| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. |
| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. |
| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. |
| `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. |
| `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. |
| `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. |
| `WG_POST_UP` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L20) for the default value. |
| `WG_PRE_DOWN` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L27) for the default value. |
| `WG_POST_DOWN` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L28) for the default value. |
| `LANG` | `en` | `de` | Web UI language (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi). |
| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI |
| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart |
> If you change `WG_PORT`, make sure to also change the exposed port.
@@ -128,7 +123,7 @@ To update to the latest version, simply run:
```bash
docker stop wg-easy
docker rm wg-easy
docker pull ghcr.io/wg-easy/wg-easy
docker pull ghcr.io/wg-easy/wg-easy:14
```
And then run the `docker run -d \ ...` command above again.
@@ -138,12 +133,5 @@ With Docker Compose WireGuard Easy can be updated with a single command:
Compose file and it is not `latest`, make sure that it is changed to the desired
one; by default it is omitted and
[defaults to `latest`](https://docs.docker.com/engine/reference/run/#image-references)). \
The WireGuared Easy container will be automatically recreated if a newer image
The WireGuard Easy container will be automatically recreated if a newer image
was pulled.
## Common Use Cases
* [Using WireGuard-Easy with Pi-Hole](https://github.com/wg-easy/wg-easy/wiki/Using-WireGuard-Easy-with-Pi-Hole)
* [Using WireGuard-Easy with nginx/SSL](https://github.com/wg-easy/wg-easy/wiki/Using-WireGuard-Easy-with-nginx-SSL)
For less common or specific edge-case scenarios, please refer to the detailed information provided in the [Wiki](https://github.com/wg-easy/wg-easy/wiki).
Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 104 KiB

+10 -2
View File
@@ -1,9 +1,17 @@
services:
wg-easy:
image: wg-easy
build:
dockerfile: ./Dockerfile
command: npm run serve
volumes:
- ./src/:/app/
# - ./data/:/etc/wireguard
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
# - PASSWORD=p
# - PASSWORD_HASH=p
- WG_HOST=192.168.1.233
+4 -2
View File
@@ -12,9 +12,10 @@ services:
- WG_HOST=raspberrypi.local
# Optional:
# - PASSWORD=foobar123
# - PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG # (needs double $$, hash of 'foobar123'; see "How_to_generate_an_bcrypt_hash.md" for generate the hash)
# - PORT=51821
# - WG_PORT=51820
# - WG_CONFIG_PORT=92820
# - WG_DEFAULT_ADDRESS=10.8.0.x
# - WG_DEFAULT_DNS=1.1.1.1
# - WG_MTU=1420
@@ -27,7 +28,7 @@ services:
# - UI_TRAFFIC_STATS=true
# - UI_CHART_TYPE=0 # (0 Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart)
image: ghcr.io/wg-easy/wg-easy
image: ghcr.io/wg-easy/wg-easy:14
container_name: wg-easy
volumes:
- etc_wireguard:/etc/wireguard
@@ -38,6 +39,7 @@ services:
cap_add:
- NET_ADMIN
- SYS_MODULE
# - NET_RAW # ⚠️ Uncomment if using Podman
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
+3 -2
View File
@@ -1,6 +1,6 @@
{
"1": "Initial version. Enjoy!",
"2": "You can now rename a client, and update the address. Enjoy!",
"2": "You can now rename a client & update the address. Enjoy!",
"3": "Many improvements and small changes. Enjoy!",
"4": "Now with pretty charts for client's network speed. Enjoy!",
"5": "Many small improvements & feature requests. Enjoy!",
@@ -11,5 +11,6 @@
"10": "Added sessionless HTTP API auth & automatic dark mode.",
"11": "Multilanguage Support & various bugfixes.",
"12": "UI_TRAFFIC_STATS, Import json configurations with no PreShared-Key, allow clients with no privateKey & more.",
"13": "New framework (h3), UI_CHART_TYPE, some bugfixes and more."
"13": "New framework (h3), UI_CHART_TYPE, some bugfixes & more.",
"14": "Home Assistent support, PASSWORD_HASH (inc. Helper), translation updates bugfixes & more."
}
+3 -1
View File
@@ -1,8 +1,10 @@
{
"version": "1.0.1",
"scripts": {
"sudobuild": "DOCKER_BUILDKIT=1 sudo docker build --tag wg-easy .",
"build": "DOCKER_BUILDKIT=1 docker build --tag wg-easy .",
"serve": "docker compose -f docker-compose.yml -f docker-compose.dev.yml up",
"sudostart": "sudo docker run --env WG_HOST=0.0.0.0 --name wg-easy --cap-add=NET_ADMIN --cap-add=SYS_MODULE --sysctl=\"net.ipv4.conf.all.src_valid_mark=1\" --mount type=bind,source=\"$(pwd)\"/config,target=/etc/wireguard -p 51820:51820/udp -p 51821:51821/tcp wg-easy",
"start": "docker run --env WG_HOST=0.0.0.0 --name wg-easy --cap-add=NET_ADMIN --cap-add=SYS_MODULE --sysctl=\"net.ipv4.conf.all.src_valid_mark=1\" --mount type=bind,source=\"$(pwd)\"/config,target=/etc/wireguard -p 51820:51820/udp -p 51821:51821/tcp wg-easy"
}
}
}
+5 -2
View File
@@ -1,15 +1,18 @@
'use strict';
const { release } = require('./package.json');
const { release: { version } } = require('./package.json');
module.exports.RELEASE = release;
module.exports.RELEASE = version;
module.exports.PORT = process.env.PORT || '51821';
module.exports.WEBUI_HOST = process.env.WEBUI_HOST || '0.0.0.0';
/** This is only kept for migration purpose. DO NOT USE! */
module.exports.PASSWORD = process.env.PASSWORD;
module.exports.PASSWORD_HASH = process.env.PASSWORD_HASH;
module.exports.WG_PATH = process.env.WG_PATH || '/etc/wireguard/';
module.exports.WG_DEVICE = process.env.WG_DEVICE || 'eth0';
module.exports.WG_HOST = process.env.WG_HOST;
module.exports.WG_PORT = process.env.WG_PORT || '51820';
module.exports.WG_CONFIG_PORT = process.env.WG_CONFIG_PORT || process.env.WG_PORT || '51820';
module.exports.WG_MTU = process.env.WG_MTU || null;
module.exports.WG_PERSISTENT_KEEPALIVE = process.env.WG_PERSISTENT_KEEPALIVE || '0';
module.exports.WG_DEFAULT_ADDRESS = process.env.WG_DEFAULT_ADDRESS || '10.8.0.x';
+61 -6
View File
@@ -1,5 +1,6 @@
'use strict';
const bcrypt = require('bcryptjs');
const crypto = require('node:crypto');
const { createServer } = require('node:http');
const { stat, readFile } = require('node:fs/promises');
@@ -28,11 +29,34 @@ const {
WEBUI_HOST,
RELEASE,
PASSWORD,
PASSWORD_HASH,
LANG,
UI_TRAFFIC_STATS,
UI_CHART_TYPE,
} = require('../config');
const requiresPassword = !!PASSWORD_HASH;
/**
* Checks if `password` matches the PASSWORD_HASH.
*
* If environment variable is not set, the password is always invalid.
*
* @param {string} password String to test
* @returns {boolean} true if matching environment, otherwise false
*/
const isPasswordValid = (password) => {
if (typeof password !== 'string') {
return false;
}
if (PASSWORD_HASH) {
return bcrypt.compareSync(password, PASSWORD_HASH);
}
return false;
};
module.exports = class Server {
constructor() {
@@ -71,7 +95,6 @@ module.exports = class Server {
// Authentication
.get('/api/session', defineEventHandler((event) => {
const requiresPassword = !!process.env.PASSWORD;
const authenticated = requiresPassword
? !!(event.node.req.session && event.node.req.session.authenticated)
: true;
@@ -84,14 +107,16 @@ module.exports = class Server {
.post('/api/session', defineEventHandler(async (event) => {
const { password } = await readBody(event);
if (typeof password !== 'string') {
if (!requiresPassword) {
// if no password is required, the API should never be called.
// Do not automatically authenticate the user.
throw createError({
status: 401,
message: 'Missing: Password',
message: 'Invalid state',
});
}
if (password !== PASSWORD) {
if (!isPasswordValid(password)) {
throw createError({
status: 401,
message: 'Incorrect Password',
@@ -103,13 +128,13 @@ module.exports = class Server {
debug(`New Session: ${event.node.req.session.id}`);
return { succcess: true };
return { success: true };
}));
// WireGuard
app.use(
fromNodeMiddleware((req, res, next) => {
if (!PASSWORD || !req.url.startsWith('/api/')) {
if (!requiresPassword || !req.url.startsWith('/api/')) {
return next();
}
@@ -117,6 +142,15 @@ module.exports = class Server {
return next();
}
if (req.url.startsWith('/api/') && req.headers['authorization']) {
if (isPasswordValid(req.headers['authorization'])) {
return next();
}
return res.status(401).json({
error: 'Incorrect Password',
});
}
return res.status(401).json({
error: 'Not Logged In',
});
@@ -225,6 +259,23 @@ module.exports = class Server {
});
};
// backup_restore
const router3 = createRouter();
app.use(router3);
router3
.get('/api/wireguard/backup', defineEventHandler(async (event) => {
const config = await WireGuard.backupConfiguration();
setHeader(event, 'Content-Disposition', 'attachment; filename="wg0.json"');
setHeader(event, 'Content-Type', 'text/json');
return config;
}))
.put('/api/wireguard/restore', defineEventHandler(async (event) => {
const { file } = await readBody(event);
await WireGuard.restoreConfiguration(file);
return { success: true };
}));
// Static assets
const publicDir = '/app/www';
app.use(
@@ -256,6 +307,10 @@ module.exports = class Server {
}),
);
if (PASSWORD) {
throw new Error('DO NOT USE PASSWORD ENVIRONMENT VARIABLE. USE PASSWORD_HASH INSTEAD.\nSee https://github.com/wg-easy/wg-easy/blob/v14/How_to_generate_an_bcrypt_hash.md');
}
createServer(toNodeListener(app)).listen(PORT, WEBUI_HOST);
debug(`Listening on http://${WEBUI_HOST}:${PORT}`);
}
+76 -46
View File
@@ -13,6 +13,7 @@ const {
WG_PATH,
WG_HOST,
WG_PORT,
WG_CONFIG_PORT,
WG_MTU,
WG_DEFAULT_DNS,
WG_DEFAULT_ADDRESS,
@@ -26,54 +27,60 @@ const {
module.exports = class WireGuard {
async __buildConfig() {
this.__configPromise = Promise.resolve().then(async () => {
if (!WG_HOST) {
throw new Error('WG_HOST Environment Variable Not Set!');
}
debug('Loading configuration...');
let config;
try {
config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8');
config = JSON.parse(config);
debug('Configuration loaded.');
} catch (err) {
const privateKey = await Util.exec('wg genkey');
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const address = WG_DEFAULT_ADDRESS.replace('x', '1');
config = {
server: {
privateKey,
publicKey,
address,
},
clients: {},
};
debug('Configuration generated.');
}
return config;
});
return this.__configPromise;
}
async getConfig() {
if (!this.__configPromise) {
this.__configPromise = Promise.resolve().then(async () => {
if (!WG_HOST) {
throw new Error('WG_HOST Environment Variable Not Set!');
const config = await this.__buildConfig();
await this.__saveConfig(config);
await Util.exec('wg-quick down wg0').catch(() => {});
await Util.exec('wg-quick up wg0').catch((err) => {
if (err && err.message && err.message.includes('Cannot find device "wg0"')) {
throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!');
}
debug('Loading configuration...');
let config;
try {
config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8');
config = JSON.parse(config);
debug('Configuration loaded.');
} catch (err) {
const privateKey = await Util.exec('wg genkey');
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const address = WG_DEFAULT_ADDRESS.replace('x', '1');
config = {
server: {
privateKey,
publicKey,
address,
},
clients: {},
};
debug('Configuration generated.');
}
await this.__saveConfig(config);
await Util.exec('wg-quick down wg0').catch(() => { });
await Util.exec('wg-quick up wg0').catch((err) => {
if (err && err.message && err.message.includes('Cannot find device "wg0"')) {
throw new Error('WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!');
}
throw err;
});
// await Util.exec(`iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ' + WG_DEVICE + ' -j MASQUERADE`);
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
await this.__syncConfig();
return config;
throw err;
});
// await Util.exec(`iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ' + WG_DEVICE + ' -j MASQUERADE`);
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
await this.__syncConfig();
}
return this.__configPromise;
@@ -207,7 +214,7 @@ PublicKey = ${config.server.publicKey}
${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
}AllowedIPs = ${WG_ALLOWED_IPS}
PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE}
Endpoint = ${WG_HOST}:${WG_PORT}`;
Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
}
async getClientQRCodeSVG({ clientId }) {
@@ -226,7 +233,9 @@ Endpoint = ${WG_HOST}:${WG_PORT}`;
const config = await this.getConfig();
const privateKey = await Util.exec('wg genkey');
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`);
const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey',
});
const preSharedKey = await Util.exec('wg genpsk');
// Calculate next IP
@@ -318,9 +327,30 @@ Endpoint = ${WG_HOST}:${WG_PORT}`;
await this.saveConfig();
}
async __reloadConfig() {
await this.__buildConfig();
await this.__syncConfig();
}
async restoreConfiguration(config) {
debug('Starting configuration restore process.');
const _config = JSON.parse(config);
await this.__saveConfig(_config);
await this.__reloadConfig();
debug('Configuration restore process completed.');
}
async backupConfiguration() {
debug('Starting configuration backup.');
const config = await this.getConfig();
const backup = JSON.stringify(config, null, 2);
debug('Configuration backup completed.');
return backup;
}
// Shutdown wireguard
async Shutdown() {
await Util.exec('wg-quick down wg0').catch(() => { });
await Util.exec('wg-quick down wg0').catch(() => {});
}
};
+571 -169
View File
File diff suppressed because it is too large Load Diff
+10 -7
View File
@@ -1,5 +1,7 @@
{
"release": "13",
"release": {
"version": "14"
},
"name": "wg-easy",
"version": "1.0.1",
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
@@ -11,17 +13,18 @@
"buildcss": "npx tailwindcss -i ./www/src/css/app.css -o ./www/css/app.css"
},
"author": "Emile Nijssen",
"license": "GPL",
"license": "CC BY-NC-SA 4.0",
"dependencies": {
"debug": "^4.3.4",
"bcryptjs": "^2.4.3",
"debug": "^4.3.6",
"express-session": "^1.18.0",
"h3": "^1.11.1",
"qrcode": "^1.5.3"
"h3": "^1.12.0",
"qrcode": "^1.5.4"
},
"devDependencies": {
"eslint-config-athom": "^3.1.3",
"nodemon": "^3.1.1",
"tailwindcss": "^3.4.3"
"nodemon": "^3.1.4",
"tailwindcss": "^3.4.9"
},
"nodemonConfig": {
"ignore": [
+54
View File
@@ -0,0 +1,54 @@
'use strict';
// Import needed libraries
import bcrypt from 'bcryptjs';
// Function to generate hash
const generateHash = async (password) => {
try {
const salt = await bcrypt.genSalt(12);
const hash = await bcrypt.hash(password, salt);
// eslint-disable-next-line no-console
console.log(`PASSWORD_HASH='${hash}'`);
} catch (error) {
throw new Error(`Failed to generate hash : ${error}`);
}
};
// Function to compare password with hash
const comparePassword = async (password, hash) => {
try {
const match = await bcrypt.compare(password, hash);
if (match) {
// eslint-disable-next-line no-console
console.log('Password matches the hash !');
} else {
// eslint-disable-next-line no-console
console.log('Password does not match the hash.');
}
} catch (error) {
throw new Error(`Failed to compare password and hash : ${error}`);
}
};
(async () => {
try {
// Retrieve command line arguments
const args = process.argv.slice(2); // Ignore the first two arguments
if (args.length > 2) {
throw new Error('Usage : wgpw YOUR_PASSWORD [HASH]');
}
const [password, hash] = args;
if (password && hash) {
await comparePassword(password, hash);
} else if (password) {
await generateHash(password);
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
// eslint-disable-next-line no-process-exit
process.exit(1);
}
})();
Executable
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
# This script is intended to be run only inside a docker container, not on the development host machine
set -e
# proxy command
node /app/wgpw.mjs "$@"
+59 -5
View File
@@ -1,5 +1,5 @@
/*
! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
! tailwindcss v3.4.9 | MIT License | https://tailwindcss.com
*/
/*
@@ -734,10 +734,6 @@ video {
margin-right: 0.5rem;
}
.mt-0 {
margin-top: 0px;
}
.mt-0\.5 {
margin-top: 0.125rem;
}
@@ -802,6 +798,11 @@ video {
display: none;
}
.size-6 {
width: 1.5rem;
height: 1.5rem;
}
.h-1 {
height: 0.25rem;
}
@@ -846,6 +847,10 @@ video {
min-height: 100vh;
}
.w-1 {
width: 0.25rem;
}
.w-10 {
width: 2.5rem;
}
@@ -1041,6 +1046,16 @@ video {
border-radius: 0.375rem;
}
.rounded-l-full {
border-top-left-radius: 9999px;
border-bottom-left-radius: 9999px;
}
.rounded-r-full {
border-top-right-radius: 9999px;
border-bottom-right-radius: 9999px;
}
.border {
border-width: 1px;
}
@@ -1454,6 +1469,10 @@ video {
border-bottom-width: 0px;
}
.hover\:cursor-pointer:hover {
cursor: pointer;
}
.hover\:border-red-800:hover {
--tw-border-opacity: 1;
border-color: rgb(153 27 27 / var(--tw-border-opacity));
@@ -1525,6 +1544,25 @@ video {
fill: #4b5563;
}
@media not all and (min-width: 768px) {
.max-md\:hidden {
display: none;
}
.max-md\:border-x-0 {
border-left-width: 0px;
border-right-width: 0px;
}
.max-md\:border-l-0 {
border-left-width: 0px;
}
.max-md\:border-r-0 {
border-right-width: 0px;
}
}
@media (min-width: 450px) {
.xxs\:flex-row {
flex-direction: row;
@@ -1652,6 +1690,14 @@ video {
}
@media (min-width: 768px) {
.md\:mr-2 {
margin-right: 0.5rem;
}
.md\:block {
display: block;
}
.md\:inline-block {
display: inline-block;
}
@@ -1660,10 +1706,18 @@ video {
min-width: 6rem;
}
.md\:flex-shrink-0 {
flex-shrink: 0;
}
.md\:gap-4 {
gap: 1rem;
}
.md\:rounded {
border-radius: 0.25rem;
}
.md\:px-0 {
padding-left: 0px;
padding-right: 0px;
+30 -8
View File
@@ -10,11 +10,15 @@
<link rel="apple-touch-icon" href="./img/apple-touch-icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
</head>
<style>
[v-cloak] {
display: none;
}
.line-chart .apexcharts-svg{
transform: translateY(3px);
}
</style>
<body class="bg-gray-50 dark:bg-neutral-800">
@@ -90,15 +94,33 @@
<div class="flex-grow">
<p class="text-2xl font-medium dark:text-neutral-200">{{$t("clients")}}</p>
</div>
<div class="flex-shrink-0">
<div class="flex md:block md:flex-shrink-0">
<!-- Restore configuration -->
<label for="inputRC" :title="$t('titleRestoreConfig')"
class="hover:cursor-pointer hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 max-md:border-r-0 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded-l-full md:rounded inline-flex items-center transition">
<svg inline class="w-4 md:mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"></path>
</svg>
<span class="max-md:hidden text-sm">{{$t("restore")}}</span>
<input id="inputRC" type="file" name="configurationfile" accept="text/*,.json" @change="restoreConfig" class="hidden"/>
</label>
<!-- Backup configuration -->
<a href="./api/wireguard/backup" :title="$t('titleBackupConfig')"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 max-md:border-x-0 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 md:rounded inline-flex items-center transition">
<svg inline class="w-4 md:mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.7L5.737 5.1a3.375 3.375 0 0 1 2.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 0 1 .9 2.7m0 0a3 3 0 0 1-3 3m0 3h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Zm-3 6h.008v.008h-.008v-.008Zm0-6h.008v.008h-.008v-.008Z"></path>
</svg>
<span class="max-md:hidden text-sm">{{$t("backup")}}</span>
</a>
<!-- New client -->
<button @click="clientCreate = true; clientCreateName = '';"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded inline-flex items-center transition">
<svg class="w-4 mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 max-md:border-l-0 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 rounded-r-full md:rounded inline-flex items-center transition">
<svg class="w-4 md:mr-2" inline xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
<span class="text-sm">{{$t("new")}}</span>
<span class="max-md:hidden text-sm">{{$t("new")}}</span>
</button>
</div>
</div>
@@ -109,11 +131,11 @@
class="relative overflow-hidden border-b last:border-b-0 border-gray-100 dark:border-neutral-600 border-solid">
<!-- Chart -->
<div v-if="uiChartType" class="absolute z-0 bottom-0 left-0 right-0 h-6" >
<div v-if="uiChartType" :class="`absolute z-0 bottom-0 left-0 right-0 h-6 ${uiChartType === 1 && 'line-chart'}`" >
<apexchart width="100%" height="100%" :options="chartOptionsTX" :series="client.transferTxSeries">
</apexchart>
</div>
<div v-if="uiChartType" class="absolute z-0 top-0 left-0 right-0 h-6" >
<div v-if="uiChartType" :class="`absolute z-0 top-0 left-0 right-0 h-6 ${uiChartType === 1 && 'line-chart'}`" >
<apexchart width="100%" height="100%" :options="chartOptionsRX" :series="client.transferRxSeries"
style="transform: scaleY(-1);">
</apexchart>
@@ -538,7 +560,7 @@
</svg>
</div>
<input type="password" name="password" :placeholder="$t('password')" v-model="password"
<input type="password" name="password" :placeholder="$t('password')" v-model="password" autocomplete="current-password"
class="px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 outline-none" />
<button v-if="authenticating"
@@ -593,4 +615,4 @@
<script src="./js/app.js"></script>
</body>
</html>
</html>
+8
View File
@@ -138,4 +138,12 @@ class API {
});
}
async restoreConfiguration(file) {
return this.call({
method: 'put',
path: '/wireguard/restore',
body: { file },
});
}
}
+16
View File
@@ -299,6 +299,22 @@ new Vue({
.catch((err) => alert(err.message || err.toString()))
.finally(() => this.refresh().catch(console.error));
},
restoreConfig(e) {
e.preventDefault();
const file = e.currentTarget.files.item(0);
if (file) {
file.text()
.then((content) => {
this.api.restoreConfiguration(content)
.then((_result) => alert('The configuration was updated.'))
.catch((err) => alert(err.message || err.toString()))
.finally(() => this.refresh().catch(console.error));
})
.catch((err) => alert(err.message || err.toString()));
} else {
alert('Failed to load your file!');
}
},
toggleTheme() {
const themes = ['light', 'dark', 'auto'];
const currentIndex = themes.indexOf(this.uiTheme);
+57 -17
View File
@@ -30,6 +30,10 @@ const messages = { // eslint-disable-line no-unused-vars
donate: 'Donate',
toggleCharts: 'Show/hide Charts',
theme: { dark: 'Dark theme', light: 'Light theme', auto: 'Auto theme' },
restore: 'Restore',
backup: 'Backup',
titleRestoreConfig: 'Restore your configuration',
titleBackupConfig: 'Backup your configuration',
},
ua: {
name: 'Ім`я',
@@ -53,10 +57,17 @@ const messages = { // eslint-disable-line no-unused-vars
disableClient: 'Вимкнути клієнта',
enableClient: 'Увімкнути клієнта',
noClients: 'Ще немає клієнтів.',
noPrivKey: 'У цього клієнта немає відомого приватного ключа. Неможливо створити конфігурацію.',
showQR: 'Показати QR-код',
downloadConfig: 'Завантажити конфігурацію',
madeBy: 'Зроблено',
donate: 'Пожертвувати',
toggleCharts: 'Показати/сховати діаграми',
theme: { dark: 'Темна тема', light: 'Світла тема', auto: 'Автоматична тема' },
restore: 'Відновити',
backup: 'Резервна копія',
titleRestoreConfig: 'Відновити конфігурацію',
titleBackupConfig: 'Створити резервну копію конфігурації',
},
ru: {
name: 'Имя',
@@ -80,10 +91,17 @@ const messages = { // eslint-disable-line no-unused-vars
disableClient: 'Выключить клиента',
enableClient: 'Включить клиента',
noClients: 'Пока нет клиентов.',
noPrivKey: 'Невозможно создать конфигурацию: у клиента нет известного приватного ключа.',
showQR: 'Показать QR-код',
downloadConfig: 'Скачать конфигурацию',
madeBy: 'Автор',
donate: 'Поблагодарить',
toggleCharts: 'Показать/скрыть графики',
theme: { dark: 'Темная тема', light: 'Светлая тема', auto: 'Как в системе' },
restore: 'Восстановить',
backup: 'Резервная копия',
titleRestoreConfig: 'Восстановить конфигурацию',
titleBackupConfig: 'Создать резервную копию конфигурации',
},
tr: { // Müslüm Barış Korkmazer @babico
name: 'İsim',
@@ -99,19 +117,25 @@ const messages = { // eslint-disable-line no-unused-vars
deleteDialog2: 'Bu işlem geri alınamaz.',
cancel: 'İptal',
create: 'Oluştur',
createdAt: 'Şu saatte oluşturuldu: ',
createdOn: 'Şu saatte oluşturuldu: ',
lastSeen: 'Son görülme tarihi: ',
totalDownload: 'Toplam İndirme: ',
totalUpload: 'Toplam Yükleme: ',
newClient: 'Yeni Kullanıcı',
disableClient: 'İstemciyi Devre Dışı Bırak',
enableClient: 'İstemciyi Etkinleştir',
disableClient: 'Kullanıcıyı Devre Dışı Bırak',
enableClient: 'Kullanıcıyı Etkinleştir',
noClients: 'Henüz kullanıcı yok.',
noPrivKey: 'Bu istemcinin bilinen bir özel anahtarı yok. Yapılandırma oluşturulamıyor.',
showQR: 'QR Kodunu Göster',
downloadConfig: 'Yapılandırmayı İndir',
madeBy: 'Yapan Kişi: ',
donate: 'Bağış Yap',
changeLang: 'Dil Değiştir',
toggleCharts: 'Grafiği göster/gizle',
theme: { dark: 'Karanlık tema', light: 'Açık tema', auto: 'Otomatik tema' },
restore: 'Geri yükle',
backup: 'Yedekle',
titleRestoreConfig: 'Yapılandırmanızı geri yükleyin',
titleBackupConfig: 'Yapılandırmanızı yedekleyin',
},
no: { // github.com/digvalley
name: 'Navn',
@@ -193,6 +217,10 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Télécharger la configuration',
madeBy: 'Développé par',
donate: 'Soutenir',
restore: 'Restaurer',
backup: 'Sauvegarder',
titleRestoreConfig: 'Restaurer votre configuration',
titleBackupConfig: 'Sauvegarder votre configuration',
},
de: { // github.com/florian-asche
name: 'Name',
@@ -221,6 +249,10 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Konfiguration herunterladen',
madeBy: 'Erstellt von',
donate: 'Spenden',
restore: 'Wiederherstellen',
backup: 'Sichern',
titleRestoreConfig: 'Stelle deine Konfiguration wieder her',
titleBackupConfig: 'Sichere deine Konfiguration',
},
ca: { // github.com/guillembonet
name: 'Nom',
@@ -277,6 +309,10 @@ const messages = { // eslint-disable-line no-unused-vars
donate: 'Donar',
toggleCharts: 'Mostrar/Ocultar gráficos',
theme: { dark: 'Modo oscuro', light: 'Modo claro', auto: 'Modo automático' },
restore: 'Restaurar',
backup: 'Realizar copia de seguridad',
titleRestoreConfig: 'Restaurar su configuración',
titleBackupConfig: 'Realizar copia de seguridad de su configuración',
},
ko: {
name: '이름',
@@ -445,27 +481,27 @@ const messages = { // eslint-disable-line no-unused-vars
password: '密碼',
signIn: '登入',
logout: '登出',
updateAvailable: '有新版本可用!',
updateAvailable: '有新版本可以使用!',
update: '更新',
clients: '客戶',
new: '建',
deleteClient: '刪除客戶',
clients: '使用者',
new: '建',
deleteClient: '刪除使用者',
deleteDialog1: '您確定要刪除',
deleteDialog2: '此操作無法撤銷。',
deleteDialog2: '此作業無法復原。',
cancel: '取消',
create: '建立',
createdOn: '建立於 ',
lastSeen: '最後訪問於 ',
lastSeen: '最後存取於 ',
totalDownload: '總下載: ',
totalUpload: '總上傳: ',
newClient: '新戶',
disableClient: '禁用客戶',
enableClient: '啟用客戶',
noClients: '目前沒有客戶。',
showQR: '顯示二維碼',
downloadConfig: '下載配置',
newClient: '新戶',
disableClient: '停用使用者',
enableClient: '啟用使用者',
noClients: '目前沒有使用者。',
showQR: '顯示 QR Code',
downloadConfig: '下載 Config 檔',
madeBy: '由',
donate: '捐贈',
donate: '抖內',
},
it: {
name: 'Nome',
@@ -493,6 +529,10 @@ const messages = { // eslint-disable-line no-unused-vars
downloadConfig: 'Scarica configurazione',
madeBy: 'Realizzato da',
donate: 'Donazione',
restore: 'Ripristina',
backup: 'Backup',
titleRestoreConfig: 'Ripristina la tua configurazione',
titleBackupConfig: 'Esegui il backup della tua configurazione',
},
th: {
name: 'ชื่อ',
File diff suppressed because one or more lines are too long