Compare commits

...

59 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 53867985d1 Initial plan 2026-02-12 17:48:29 +00:00
Bernd Storath b3cc1ce839 reduce container size
from around 700mb to 400mb
2026-02-11 15:36:29 +01:00
Bernd Storath 71aaec93ef add unit tests
this adds the groundwork to start unit testing some modules
2026-02-11 15:23:04 +01:00
HackingAll 7a219b73d4 Adding galician (#2473)
* Adding galego -> gl.json

* Update i18n.config.ts

* Update nuxt.config.ts
2026-02-10 11:18:02 +01:00
Bare7a c456c5e7dd Add Bulgarian translation (#2466) 2026-02-09 08:00:38 +01:00
Bernd Storath a5880cc0b8 update packages 2026-02-09 08:00:07 +01:00
Bernd Storath 5fca628ebd change date in copyright footer 2026-02-06 15:32:39 +01:00
Bernd Storath 7ab297c366 Bump version to 15.2.2 2026-02-06 14:55:20 +01:00
Bernd Storath c5de8f0f44 cli: reset 2fa on admin reset (#2461)
reset 2fa on cli reset
2026-02-06 12:28:13 +01:00
Bernd Storath c0641889cf replace watchtower (#2456)
update to maintained fork
2026-02-04 08:24:48 +01:00
Bernd Storath 9141562f91 update tagging convention for latest tag 2026-02-04 08:17:58 +01:00
thebigpotatoe d21af70df1 fix: correct help text for prometheus metrics (#2453) 2026-02-03 11:27:03 +01:00
Bernd Storath 56ee86cc1c update packages 2026-02-02 08:27:05 +01:00
Runar Ingebrigtsen f017b4968c Add Norwegian bokmål translation (#2447)
* add Norwegian bokmål translation

Signed-off-by: Runar Ingebrigtsen <runar@rin.no>

* add nb config, available in UI

Signed-off-by: Runar Ingebrigtsen <runar@rin.no>

---------

Signed-off-by: Runar Ingebrigtsen <runar@rin.no>
2026-02-02 08:18:31 +01:00
Alexander Chepurnoy 6004457666 feat: update client and server interface parameters (#2440) 2026-01-28 09:34:11 +01:00
Bernd Storath 1a5a0180ea Fix LangSelector and ClientCard z-index (#2434)
fix client card
2026-01-27 08:24:53 +01:00
Ayush Chothe c732f149e6 feat: Add wireguard-go package in Dockerfile (#2419)
* feat: Add `wireguard-go` package in `Dockerfile`

* feat: add amneziawg-go
Co-authored-by: cany748 <cany748@gmail.com>
2026-01-27 08:08:24 +01:00
Bernd Storath 4819480eb0 update packages 2026-01-26 09:02:25 +01:00
Alexander Chepurnoy fc7ab0dc21 feat(docs): edit amnezia.md (#2430)
* feat(docs): edit amnezia.md

* Update docs/content/advanced/config/amnezia.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update docs/content/advanced/config/amnezia.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-26 08:43:09 +01:00
Bernd Storath eb6b96c0f1 lang: Add dutch language (#2413)
add dutch language

Co-authored-by: Stephan Paternotte <Stephan-P@users.noreply.github.com>
2026-01-21 09:39:18 +01:00
Bernd Storath f62fad9c40 update packages 2026-01-20 08:51:19 +01:00
Maksim M. e9a472c8f7 fix(i18n/ru): use "мусор" for AmneziaWG junk packets (#2402)
The RU translation changed "junk" from "мусорный" to "шумовой".
Amnezia authors consistently describe these packets/bytes as "мусор" in their docs and Habr posts. Align wording with upstream terminology to avoid confusion for RU users.
2026-01-15 08:14:38 +01:00
Bernd Storath 552e2b8cbf update screenshot 2026-01-14 09:53:04 +01:00
Bernd Storath a0b4192cbd Bump version to 15.2.1 2026-01-14 08:51:01 +01:00
Bernd Storath 32a055093a exclude i18n from setup middleware 2026-01-13 13:15:46 +01:00
Bernd Storath 51558c7027 refactor: session handling (#2398)
* refactor session handling

* simplify
2026-01-13 10:11:13 +01:00
binnichtaktiv b85286f0ab Lang(de): Improve and add missing translations (#2393)
* add missing german translations

* fix typos and improve existing translations

* fix punctuation

* fix last overlooked typos
2026-01-13 08:21:08 +01:00
Bernd Storath 48f3fbd715 always generate awg h1-h5 2026-01-13 08:07:13 +01:00
Bernd Storath 458f66818a fix search magnifying icon 2026-01-12 12:04:50 +01:00
Bernd Storath 7964dc7993 Bump version to 15.2.0 2026-01-12 08:28:23 +01:00
RaffaelHold 0ac5d7d461 feat(docs): Extend docs for routed setup with nftables (#2380)
* Extend docs for routed setup with nftables

When using nftables in a routed setup different up and down hooks need to be used. 
To limit interaction with docker managed chains a custom WG_EASY chain is added as a jump target.
Since nft only supports deletion via handles awk is needed to get the handle of the jump rule for deletion

* Remove link to podman-nft

* Fix formatting according to prettier rules

* Add additional whitespace
2026-01-12 08:21:18 +01:00
Bernd Storath 826914a4f3 update packages 2026-01-12 08:19:01 +01:00
Bernd Storath 261da431e7 Fix: reset onetimelink expiration instead of failing (#2370)
* update expiresAt instead of failing

* add changelog
2025-12-29 19:12:53 +01:00
Bernd Storath 94b33abf5e Remove armv7 support (#2369)
remove armv7 support
2025-12-29 18:54:47 +01:00
Bernd Storath 8325056ccc update lockfile 2025-12-29 18:47:48 +01:00
Bernd Storath 81a1b2c907 update packages 2025-12-29 18:36:51 +01:00
dependabot[bot] fc8f89fb83 build(deps): bump actions/download-artifact from 6 to 7 (#2343)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 07:58:23 +01:00
dependabot[bot] d846c7745f build(deps): bump actions/upload-artifact from 5 to 6 (#2344)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 07:58:12 +01:00
Bernd Storath 61c6fd6c02 update packages 2025-12-15 08:03:25 +01:00
David DIVERRES abe5708058 Update fr.json (#2326)
Update fr.json - Add missing translations and improve existing ones

- Add missing keys: client.delete, client.search, client.config, client.viewConfig
- Add complete copy section (4 keys)
- Add complete awg section (27 keys for AmneziaWG parameters)
- Fix terminology: "double facteur" → "deux facteurs" (standard French)
- Fix zod.generic.validBoolean translation
- Fix zod.generic.stringMin capitalization and wording
- Translate zod.client.id to French
- Improve admin.general route descriptions
2025-12-08 08:51:38 +01:00
Bernd Storath 626339bddb update packages 2025-12-08 08:30:53 +01:00
Danya 381ae23c07 Update ru (#2324)
* Update ru.json

Full revision of the Russian localization for the AWG configuration block, including terminology corrections, improved consistency, and clarified parameter descriptions.

* Update ru.json

* fix formatting

---------

Co-authored-by: Bernd Storath <999999bst@gmail.com>
2025-12-05 15:59:12 +01:00
Nikolas 52382d1d7a Update uk.json (#2323) 2025-12-05 07:35:15 +01:00
Mike 68e5216d4b Update ru.json (#2319)
* Update ru.json

* format

---------

Co-authored-by: Bernd Storath <999999bst@gmail.com>
2025-12-02 12:26:04 +01:00
Bernd Storath ceff95b336 Bump version to 15.2.0-beta.3 2025-12-01 10:12:01 +01:00
Alexander Chepurnoy 782d1c215f feat(docs): edit amnezia page (#2292)
* feat(docs): edit amnezia page

* Fix AmneziaWG documentation link

* Update AmneziaWG client compatibility information
2025-12-01 08:23:01 +01:00
Bernd Storath e8e26cfe10 update packages 2025-12-01 07:54:59 +01:00
Bernd Storath 400d4d992e Fix light mode admin menu active text color (#2307)
* fix color

* remove duplicates
2025-11-25 08:26:18 +01:00
Bernd Storath b08df55321 fix build 2025-11-24 08:03:37 +01:00
Bernd Storath b26a8110e0 update packages 2025-11-24 08:01:11 +01:00
杨黄林 692f550596 Improve zh-CN translate (#2298)
Fix zh-CN translate

Co-authored-by: yanghuanglin <yanghuanglin@qq.com>
2025-11-24 07:57:17 +01:00
Chiahong badae8b8e4 fix(i18n): Add missing translation for delete action (#2295) 2025-11-21 17:55:11 +01:00
Nikolas 7f89bde99e Update uk.json (#2293) 2025-11-21 08:02:47 +01:00
Bernd Storath 326717444b Bump version to 15.2.0-beta.2 2025-11-18 15:05:42 +01:00
Bernd Storath 4e4bfc75e3 feat: add config btn and modal to view and copy config (#2289)
* add view config btn and modal

* show loading state

* add note about keyboard
2025-11-18 11:36:46 +01:00
Bernd Storath 5c97a8ba73 try all qr ecc levels (#2288)
try ecc levels
2025-11-18 09:25:57 +01:00
Bernd Storath cba7a160ea intellicode deprecated 2025-11-17 08:04:10 +01:00
Nikolas 4a75e1379d Update uk.json (#2286)
* Update uk.json

* fix formatting

---------

Co-authored-by: Bernd Storath <999999bst@gmail.com>
2025-11-17 07:54:50 +01:00
Chiahong 10a140d188 feat(i18n): Add Traditional Chinese (Taiwan, zh-TW) support (#2285) 2025-11-17 07:53:03 +01:00
63 changed files with 5098 additions and 2392 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v4 uses: github/codeql-action/init@v4
+6 -6
View File
@@ -18,10 +18,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
- platform: linux/arm64 - platform: linux/arm64
os: ubuntu-24.04-arm os: ubuntu-24.04-arm
- platform: linux/arm/v7 # - platform: linux/arm/v7
os: ubuntu-24.04-arm # os: ubuntu-24.04-arm
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Prepare - name: Prepare
run: | run: |
@@ -69,7 +69,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}" touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: digests-${{ env.PLATFORM_PAIR }} name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/* path: ${{ runner.temp }}/digests/*
@@ -85,7 +85,7 @@ jobs:
needs: docker-build needs: docker-build
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v6 uses: actions/download-artifact@v7
with: with:
path: ${{ runner.temp }}/digests path: ${{ runner.temp }}/digests
pattern: digests-* pattern: digests-*
@@ -138,7 +138,7 @@ jobs:
contents: write contents: write
needs: docker-merge needs: docker-merge
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v6 uses: actions/setup-python@v6
+6 -6
View File
@@ -25,10 +25,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
- platform: linux/arm64 - platform: linux/arm64
os: ubuntu-24.04-arm os: ubuntu-24.04-arm
- platform: linux/arm/v7 # - platform: linux/arm/v7
os: ubuntu-24.04-arm # os: ubuntu-24.04-arm
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
ref: master ref: master
@@ -78,7 +78,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}" touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: digests-${{ env.PLATFORM_PAIR }} name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/* path: ${{ runner.temp }}/digests/*
@@ -94,7 +94,7 @@ jobs:
needs: docker-build needs: docker-build
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v6 uses: actions/download-artifact@v7
with: with:
path: ${{ runner.temp }}/digests path: ${{ runner.temp }}/digests
pattern: digests-* pattern: digests-*
@@ -147,7 +147,7 @@ jobs:
contents: write contents: write
needs: docker-merge needs: docker-merge
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
ref: master ref: master
+3 -3
View File
@@ -21,10 +21,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
- platform: linux/arm64 - platform: linux/arm64
os: ubuntu-24.04-arm os: ubuntu-24.04-arm
- platform: linux/arm/v7 # - platform: linux/arm/v7
os: ubuntu-24.04-arm # os: ubuntu-24.04-arm
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Prepare - name: Prepare
run: | run: |
+6 -6
View File
@@ -26,10 +26,10 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
- platform: linux/arm64 - platform: linux/arm64
os: ubuntu-24.04-arm os: ubuntu-24.04-arm
- platform: linux/arm/v7 # - platform: linux/arm/v7
os: ubuntu-24.04-arm # os: ubuntu-24.04-arm
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Prepare - name: Prepare
run: | run: |
@@ -77,7 +77,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}" touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: digests-${{ env.PLATFORM_PAIR }} name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/* path: ${{ runner.temp }}/digests/*
@@ -95,7 +95,7 @@ jobs:
needs: docker-build needs: docker-build
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v6 uses: actions/download-artifact@v7
with: with:
path: ${{ runner.temp }}/digests path: ${{ runner.temp }}/digests
pattern: digests-* pattern: digests-*
@@ -152,7 +152,7 @@ jobs:
contents: write contents: write
needs: docker-merge needs: docker-merge
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v6 uses: actions/setup-python@v6
+2 -2
View File
@@ -14,7 +14,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
@@ -47,7 +47,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
name: Install pnpm name: Install pnpm
-1
View File
@@ -3,7 +3,6 @@
"aaron-bond.better-comments", "aaron-bond.better-comments",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"antfu.goto-alias", "antfu.goto-alias",
"visualstudioexptteam.vscodeintellicode",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"yoavbls.pretty-ts-errors", "yoavbls.pretty-ts-errors",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
+38 -5
View File
@@ -7,19 +7,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## Added ## [15.2.2] - 2026-02-06
### Added
- Added Userspace WireGuard support (https://github.com/wg-easy/wg-easy/pull/2419)
### Fixed
- LangSelector overlapping with Buttons (https://github.com/wg-easy/wg-easy/pull/2434)
- AmnzeziaWG config parameters (https://github.com/wg-easy/wg-easy/pull/2440)
- OpenMetrics help string format (https://github.com/wg-easy/wg-easy/pull/2453)
- Reset 2fa when resetting admin password (https://github.com/wg-easy/wg-easy/pull/2461)
### Docs
- Replace Watchtower with maintained fork (https://github.com/wg-easy/wg-easy/pull/2456)
## [15.2.1] - 2026-01-14
### Fixed
- Icon in Searchbar (https://github.com/wg-easy/wg-easy/commit/458f66818a400f181e2c6326ede077c8793d71f2)
- Interface save not working (https://github.com/wg-easy/wg-easy/commit/48f3fbd715a889e2425702a8a46332f2752aef91)
- Error Messages in Setup (https://github.com/wg-easy/wg-easy/commit/32a055093a76342c40858d8dcf563b0700a8bd48)
## [15.2.0] - 2026-01-12
### Added
- AmneziaWG integration (https://github.com/wg-easy/wg-easy/pull/2102, https://github.com/wg-easy/wg-easy/pull/2226) - AmneziaWG integration (https://github.com/wg-easy/wg-easy/pull/2102, https://github.com/wg-easy/wg-easy/pull/2226)
- Search / filter box (https://github.com/wg-easy/wg-easy/pull/2170) - Search / filter box (https://github.com/wg-easy/wg-easy/pull/2170)
- `INIT_ALLOWED_IPS` env var (https://github.com/wg-easy/wg-easy/pull/2164) - `INIT_ALLOWED_IPS` env var (https://github.com/wg-easy/wg-easy/pull/2164)
- Show client endpoint (https://github.com/wg-easy/wg-easy/pull/2058) - Show client endpoint (https://github.com/wg-easy/wg-easy/pull/2058)
- Add option to view and copy config (https://github.com/wg-easy/wg-easy/pull/2289)
## Fixed ### Fixed
- Fix download as conf.txt (https://github.com/wg-easy/wg-easy/pull/2269) - Fix download as conf.txt (https://github.com/wg-easy/wg-easy/pull/2269)
- Clean filename for OTL download (https://github.com/wg-easy/wg-easy/pull/2253) - Clean filename for OTL download (https://github.com/wg-easy/wg-easy/pull/2253)
- Text color in admin menu in light mode (https://github.com/wg-easy/wg-easy/pull/2307)
## Changed ### Changed
- Allow lower MTU (https://github.com/wg-easy/wg-easy/pull/2228) - Allow lower MTU (https://github.com/wg-easy/wg-easy/pull/2228)
- Use /32 and /128 for client Cidr (https://github.com/wg-easy/wg-easy/pull/2217) - Use /32 and /128 for client Cidr (https://github.com/wg-easy/wg-easy/pull/2217)
@@ -27,11 +56,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Publish on Codeberg (https://github.com/wg-easy/wg-easy/pull/2160) - Publish on Codeberg (https://github.com/wg-easy/wg-easy/pull/2160)
- Allow empty DNS (https://github.com/wg-easy/wg-easy/pull/2052, https://github.com/wg-easy/wg-easy/pull/2057) - Allow empty DNS (https://github.com/wg-easy/wg-easy/pull/2052, https://github.com/wg-easy/wg-easy/pull/2057)
- Don't include keys in API responses (https://github.com/wg-easy/wg-easy/pull/2015) - Don't include keys in API responses (https://github.com/wg-easy/wg-easy/pull/2015)
- Try all QR ecc levels (https://github.com/wg-easy/wg-easy/pull/2288)
- Update OneTimeLink expiry on reuse (https://github.com/wg-easy/wg-easy/pull/2370)
- Removed ARMv7 support (https://github.com/wg-easy/wg-easy/pull/2369)
## Docs ### Docs
- Add AdGuard Home (https://github.com/wg-easy/wg-easy/pull/2175) - Add AdGuard Home (https://github.com/wg-easy/wg-easy/pull/2175)
- Add Routed (No NAT) docs (https://github.com/wg-easy/wg-easy/pull/2181) - Add Routed (No NAT) docs (https://github.com/wg-easy/wg-easy/pull/2181, https://github.com/wg-easy/wg-easy/pull/2380)
- Add AmneziaWG docs (https://github.com/wg-easy/wg-easy/pull/2108, https://github.com/wg-easy/wg-easy/pull/2292)
## [15.1.0] - 2025-07-01 ## [15.1.0] - 2025-07-01
+10 -3
View File
@@ -15,9 +15,12 @@ COPY src ./
RUN pnpm build RUN pnpm build
# Build amneziawg-tools # Build amneziawg-tools
RUN apk add linux-headers build-base git && \ RUN apk add linux-headers build-base go git && \
git clone https://github.com/amnezia-vpn/amneziawg-tools.git && \ git clone https://github.com/amnezia-vpn/amneziawg-tools.git && \
cd amneziawg-tools/src && \ git clone https://github.com/amnezia-vpn/amneziawg-go && \
cd amneziawg-go && \
make && \
cd ../amneziawg-tools/src && \
make make
# Copy build result to a new image. # Copy build result to a new image.
@@ -33,11 +36,14 @@ COPY --from=build /app/.output /app
COPY --from=build /app/server/database/migrations /app/server/database/migrations COPY --from=build /app/server/database/migrations /app/server/database/migrations
# libsql (https://github.com/nitrojs/nitro/issues/3328) # libsql (https://github.com/nitrojs/nitro/issues/3328)
RUN cd /app/server && \ RUN cd /app/server && \
npm install --no-save libsql && \ npm install --no-save --omit=dev libsql && \
npm cache clean --force npm cache clean --force
# cli # cli
COPY --from=build /app/cli/cli.sh /usr/local/bin/cli COPY --from=build /app/cli/cli.sh /usr/local/bin/cli
RUN chmod +x /usr/local/bin/cli RUN chmod +x /usr/local/bin/cli
# Copy amneziawg-go
COPY --from=build /app/amneziawg-go/amneziawg-go /usr/bin/amneziawg-go
RUN chmod +x /usr/bin/amneziawg-go
# Copy amneziawg-tools # Copy amneziawg-tools
COPY --from=build /app/amneziawg-tools/src/wg /usr/bin/awg COPY --from=build /app/amneziawg-tools/src/wg /usr/bin/awg
COPY --from=build /app/amneziawg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick COPY --from=build /app/amneziawg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick
@@ -52,6 +58,7 @@ RUN apk add --no-cache \
nftables \ nftables \
kmod \ kmod \
iptables-legacy \ iptables-legacy \
wireguard-go \
wireguard-tools wireguard-tools
RUN mkdir -p /etc/amnezia RUN mkdir -p /etc/amnezia
+1
View File
@@ -16,6 +16,7 @@ RUN apk add --no-cache \
ip6tables \ ip6tables \
kmod \ kmod \
iptables-legacy \ iptables-legacy \
wireguard-go \
wireguard-tools wireguard-tools
# Use iptables-legacy # Use iptables-legacy
Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 167 KiB

+47 -5
View File
@@ -2,7 +2,9 @@
title: AmneziaWG title: AmneziaWG
--- ---
Experimental support for AmneziaWG can be enabled by setting the `EXPERIMENTAL_AWG` environment variable to `true`. This feature is still under development and may change in future releases. ## Introduction
**AmneziaWG** is a modified version of the WireGuard protocol with enhanced traffic obfuscation capabilities. AmneziaWG's primary goal is to counter deep packet inspection (DPI) systems and bypass VPN blocking.
AmneziaWG adds multi-level transport-layer obfuscation by: AmneziaWG adds multi-level transport-layer obfuscation by:
@@ -12,6 +14,12 @@ AmneziaWG adds multi-level transport-layer obfuscation by:
These measures make it harder for third parties to analyze or identify your traffic, enhancing both privacy and security. These measures make it harder for third parties to analyze or identify your traffic, enhancing both privacy and security.
## Activating AmneziaWG
You must install the [AmneziaWG kernel module](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module) on the host system.
Experimental support for AmneziaWG can be enabled by setting the `EXPERIMENTAL_AWG` environment variable to `true`. Starting from wg-easy version 16, this setting will be enabled by default. This feature is still under development and may change in future releases.
When enabled, wg-easy will automatically detect whether the AmneziaWG kernel module is available. If it is not, the system will fall back to the standard WireGuard module. When enabled, wg-easy will automatically detect whether the AmneziaWG kernel module is available. If it is not, the system will fall back to the standard WireGuard module.
To override this automatic detection, set the `OVERRIDE_AUTO_AWG` environment variable. By default, this variable is unset. To override this automatic detection, set the `OVERRIDE_AUTO_AWG` environment variable. By default, this variable is unset.
@@ -21,17 +29,51 @@ Possible values:
- `awg` — Force use of AmneziaWG - `awg` — Force use of AmneziaWG
- `wg` — Force use of standard WireGuard - `wg` — Force use of standard WireGuard
To be able to connect to wg-easy if AmneziaWG is enabled, you must have a AmneziaWG-compatible client. ## AmneziaWG Parameters
Parameter descriptions can be found in the [AmneziaWG documentation](https://docs.amnezia.org/documentation/amnezia-wg) and on the [kernel module page](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module).
All parameters except I1-I5 will be set at first startup. For information on how to set I1-I5 parameters, refer to the [AmneziaWG documentation](https://docs.amnezia.org/documentation/instructions/new-amneziawg-selfhosted/#how-to-extract-a-protocol-signature-for-amneziawg-15-manually).
If a parameter is not set, it will not be added to the configuration. If all AmneziaWG-specific parameters are absent, AmneziaWG will be fully compatible with standard WireGuard.
### Parameter Compatibility Table
| Parameter | Can differ between server and client | Configurable on server | Configurable on client |
| --------- | ------------------------------------ | ---------------------- | ----------------------- |
| Jc | ✅ Yes | ✅ | ✅ |
| Jmin | ✅ Yes | ✅ | ✅ |
| Jmax | ✅ Yes | ✅ | ✅ |
| S1-S4 | ❌ No, must match | ✅ | ❌ (copied from server) |
| H1-H4 | ❌ No, must match | ✅ | ❌ (copied from server) |
| I1-I5 | ✅ Yes | ✅ | ✅ |
## Client Applications
To be able to connect to wg-easy if AmneziaWG is enabled, you must have an AmneziaWG-compatible client. Where an AmneziaWG app is available for your platform, it is recommended to use it rather than Amnezia VPN.
Android: Android:
- [AmneziaWG](https://play.google.com/store/apps/details?id=org.amnezia.awg) - Official Client - [AmneziaWG](https://play.google.com/store/apps/details?id=org.amnezia.awg) - AmneziaWG Official Client
- [WG Tunnel](https://play.google.com/store/apps/details?id=com.zaneschepke.wireguardautotunnel) - Third Party Client - [WG Tunnel](https://play.google.com/store/apps/details?id=com.zaneschepke.wireguardautotunnel) - Third Party Client
- [Amnezia VPN](https://play.google.com/store/apps/details?id=org.amnezia.vpn) - Amnezia VPN Official Client
iOS and macOS: iOS and macOS:
- [AmneziaWG](https://apps.apple.com/us/app/amneziawg/id6478942365) - Official Client - [AmneziaWG](https://apps.apple.com/us/app/amneziawg/id6478942365) - AmneziaWG Official Client
- [Amnezia VPN](https://apps.apple.com/us/app/amneziavpn/id1600529900) - Amnezia VPN Official Client
Windows: Windows:
- [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-windows-client/releases) - Official Client - [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-windows-client/releases) - AmneziaWG Official Client (Requires building from source code)
- [Amnezia VPN](https://amnezia.org/downloads) - Amnezia VPN Official Client
Linux:
- [Amnezia VPN](https://amnezia.org/downloads) - Amnezia VPN Official Client
- [amneziawg-tools](https://github.com/amnezia-vpn/amneziawg-tools) - AmneziaWG Tools
OpenWRT:
- [AmneziaWG OpenWRT](https://github.com/Slava-Shchipunov/awg-openwrt) - AmneziaWG OpenWRT Packages
- [AmneziaWG OpenWRT](https://github.com/lolo6oT/awg-openwrt) - AmneziaWG OpenWRT Packages
@@ -7,7 +7,7 @@ This guide will help you migrate from `v14` to version `v15` of `wg-easy`.
## Changes ## Changes
- This is a complete rewrite of the `wg-easy` project, therefore the configuration files and the way you interact with the project have changed. - This is a complete rewrite of the `wg-easy` project, therefore the configuration files and the way you interact with the project have changed.
- If you use armv6, you unfortunately won't be able to migrate to `v15`. - If you use armv6 or armv7, you unfortunately won't be able to migrate to `v15`.
- If you are connecting to the Web UI via HTTP, you need to set the `INSECURE` environment variable to `true` in the new container. - If you are connecting to the Web UI via HTTP, you need to set the `INSECURE` environment variable to `true` in the new container.
## Migration ## Migration
@@ -20,7 +20,7 @@ File: `/etc/docker/containers/watchtower/docker-compose.yml`
```yaml ```yaml
services: services:
watchtower: watchtower:
image: containrrr/watchtower:latest image: nickfedor/watchtower:latest
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
env_file: env_file:
@@ -8,7 +8,7 @@ title: Basic Installation
1. You need to have a host that you can manage 1. You need to have a host that you can manage
2. You need to have a domain name or a public IP address 2. You need to have a domain name or a public IP address
3. You need a supported architecture (x86_64, arm64, armv7) 3. You need a supported architecture (x86_64, arm64)
4. You need curl installed on your host 4. You need curl installed on your host
## Install Docker ## Install Docker
+16
View File
@@ -93,3 +93,19 @@ PostDown
```shell ```shell
iptables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; ip6tables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -D FORWARD -o wg0 -j ACCEPT iptables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; ip6tables -D INPUT -p udp -m udp --dport {{port}} -j ACCEPT; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -D FORWARD -o wg0 -j ACCEPT
``` ```
/// warning | Important: When using nftables use the following hooks instead.
PostUp
```shell
nft add chain ip filter WG_EASY; nft add rule ip filter DOCKER-USER jump WG_EASY; nft add rule ip filter WG_EASY iifname {{device}} accept; nft add rule ip filter WG_EASY oifname {{device}} accept; nft add chain ip6 filter WG_EASY; nft add rule ip6 filter DOCKER-USER jump WG_EASY; nft add rule ip6 filter WG_EASY iifname {{device}} accept; nft add rule ip6 filter WG_EASY oifname {{device}} accept;
```
PostDown
```shell
nft delete rule ip filter DOCKER-USER handle $(nft -a list chain ip filter DOCKER-USER | awk '/jump WG_EASY/ {print $NF}'); nft flush chain ip filter WG_EASY; nft delete chain ip filter WG_EASY; nft delete rule ip6 filter DOCKER-USER handle $(nft -a list chain ip6 filter DOCKER-USER | awk '/jump WG_EASY/ {print $NF}'); nft flush chain ip6 filter WG_EASY; nft delete chain ip6 filter WG_EASY
```
///
+3 -3
View File
@@ -12,7 +12,7 @@ Before you can get started with deploying your own VPN, there are some requireme
1. You need to have a host that you can manage 1. You need to have a host that you can manage
2. You need to have a domain name or a public IP address 2. You need to have a domain name or a public IP address
3. You need a supported architecture (x86_64, arm64, armv7) 3. You need a supported architecture (x86_64, arm64)
### Host Setup ### Host Setup
@@ -45,15 +45,15 @@ All workflows are using the tagging convention listed below. It is subsequently
| tag | Type | Example | Description | | tag | Type | Example | Description |
| ------------- | ------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------- | | ------------- | ------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `15` | latest minor for that major tag | `ghcr.io/wg-easy/wg-easy:15` | latest features for specific major versions, no breaking changes, recommended | | `15` | latest minor for that major tag | `ghcr.io/wg-easy/wg-easy:15` | latest features for specific major versions, no breaking changes, recommended |
| `latest` | latest tag | `ghcr.io/wg-easy/wg-easy:latest` or `ghcr.io/wg-easy/wg-easy` | points to latest release, can include breaking changes |
| `15.0` | latest patch for that minor tag | `ghcr.io/wg-easy/wg-easy:15.0` | latest patches for specific minor version | | `15.0` | latest patch for that minor tag | `ghcr.io/wg-easy/wg-easy:15.0` | latest patches for specific minor version |
| `15.0.0` | specific tag | `ghcr.io/wg-easy/wg-easy:15.0.0` | specific release, no updates | | `15.0.0` | specific tag | `ghcr.io/wg-easy/wg-easy:15.0.0` | specific release, no updates |
| `edge` | push to `master` | `ghcr.io/wg-easy/wg-easy:edge` | mostly unstable, gets frequent package and code updates | | `edge` | push to `master` | `ghcr.io/wg-easy/wg-easy:edge` | mostly unstable, gets frequent package and code updates |
| `development` | pull requests | `ghcr.io/wg-easy/wg-easy:development` | used for development, testing code from PRs | | `development` | pull requests | `ghcr.io/wg-easy/wg-easy:development` | used for development, testing code from PRs |
| `latest` | latest tag | `ghcr.io/wg-easy/wg-easy:latest` or `ghcr.io/wg-easy/wg-easy` | points to the v14 release, should be avoided |
<!-- ref: major version (check links too) --> <!-- ref: major version (check links too) -->
When publishing a tag we follow the [Semantic Versioning][semver] specification. The `latest` tag is always pointing to the latest stable release. If you want to avoid breaking changes, use the major version tag (e.g. `15`). When publishing a tag we follow the [Semantic Versioning][semver] specification. Pin to the latest major version to avoid breaking changes (e.g. `15`), avoid using the `latest` tag.
[github-ci]: https://github.com/wg-easy/wg-easy/actions [github-ci]: https://github.com/wg-easy/wg-easy/actions
[ghcr-image]: https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy [ghcr-image]: https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy
+1 -1
View File
@@ -8,7 +8,7 @@ hide:
/// info | This Documentation is Versioned /// info | This Documentation is Versioned
**Make sure** to select the correct version of this documentation! It should match the version of the image you are using. The default version corresponds to the `:latest` image tag - [the most recent stable release][docs-tagging]. **Make sure** to select the correct version of this documentation! It should match the version of the image you are using. The default version corresponds to [the most recent stable release][docs-tagging].
/// ///
This documentation provides you not only with the basic setup and configuration of `wg-easy` but also with advanced configuration, elaborate usage scenarios, detailed examples, hints and more. This documentation provides you not only with the basic setup and configuration of `wg-easy` but also with advanced configuration, elaborate usage scenarios, detailed examples, hints and more.
+3 -2
View File
@@ -7,10 +7,11 @@
"build": "docker build -t wg-easy .", "build": "docker build -t wg-easy .",
"docs:preview": "docker run --rm -it -p 8080:8080 -v ./docs:/docs squidfunk/mkdocs-material serve -a 0.0.0.0:8080", "docs:preview": "docker run --rm -it -p 8080:8080 -v ./docs:/docs squidfunk/mkdocs-material serve -a 0.0.0.0:8080",
"scripts:version": "bash scripts/version.sh", "scripts:version": "bash scripts/version.sh",
"scripts:i18n": "bash scripts/i18n.sh",
"format:check:docs": "prettier --check docs" "format:check:docs": "prettier --check docs"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^3.6.2" "prettier": "^3.8.1"
}, },
"packageManager": "pnpm@10.21.0" "packageManager": "pnpm@10.29.2"
} }
+5 -5
View File
@@ -9,16 +9,16 @@ importers:
.: .:
devDependencies: devDependencies:
prettier: prettier:
specifier: ^3.6.2 specifier: ^3.8.1
version: 3.6.2 version: 3.8.1
packages: packages:
prettier@3.6.2: prettier@3.8.1:
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
snapshots: snapshots:
prettier@3.6.2: {} prettier@3.8.1: {}
+1
View File
@@ -30,6 +30,7 @@ echo "Updated package.json to version $new_version"
echo "----" echo "----"
echo "If you changed the major version, remember to update the docker-compose.yml file and docs (search for: ref: major version)" echo "If you changed the major version, remember to update the docker-compose.yml file and docs (search for: ref: major version)"
echo "Make sure to stage any changes before proceeding (e.g. Changelog updates)."
echo "----" echo "----"
echo "If you did everything press 'y' to commit the changes and create a new tag" echo "If you did everything press 'y' to commit the changes and create a new tag"
+2
View File
@@ -23,4 +23,6 @@ logs
.env.* .env.*
!.env.example !.env.example
coverage/
wg-easy.db wg-easy.db
+1
View File
@@ -0,0 +1 @@
setups.@nuxt/test-utils="3.23.0"
+29
View File
@@ -0,0 +1,29 @@
<template>
<div class="overflow-x-auto rounded border-2 border-red-800 py-2">
<pre
class="mx-2 inline-block"
@click="selectCode"
><code ref="codeBlock">{{ code }}</code></pre>
</div>
</template>
<script setup lang="ts">
defineProps<{
code: string;
}>();
const codeBlock = useTemplateRef('codeBlock');
function selectCode() {
// TODO: keyboard support?
if (codeBlock.value) {
const range = document.createRange();
range.selectNodeContents(codeBlock.value);
const sel = window.getSelection();
if (sel) {
sel.removeAllRanges();
sel.addRange(range);
}
}
}
</script>
+1 -1
View File
@@ -1,7 +1,7 @@
<template> <template>
<ClientCardCharts :client="client" /> <ClientCardCharts :client="client" />
<div <div
class="relative z-10 flex flex-col justify-between gap-3 px-3 py-3 sm:flex-row md:py-5" class="relative flex flex-col justify-between gap-3 px-3 py-3 sm:flex-row md:py-5"
> >
<div class="flex w-full items-center gap-3 md:gap-4"> <div class="flex w-full items-center gap-3 md:gap-4">
<ClientCardAvatar :client="client" /> <ClientCardAvatar :client="client" />
@@ -0,0 +1,74 @@
<template>
<BaseDialog :trigger-class="triggerClass">
<template #trigger>
<slot />
</template>
<template #title>
{{ $t('client.config') }}
</template>
<template #description>
<div v-if="status === 'success'">
<BaseCodeBlock :code="config ?? ''" />
</div>
<div v-else>
<span>{{ $t('general.loading') }}</span>
</div>
</template>
<template #actions>
<DialogClose as-child>
<BaseSecondaryButton>{{ $t('dialog.cancel') }}</BaseSecondaryButton>
</DialogClose>
<DialogClose as-child>
<BasePrimaryButton @click="copyCode">
{{ $t('copy.copy') }}
</BasePrimaryButton>
</DialogClose>
</template>
</BaseDialog>
</template>
<script setup lang="ts">
const props = defineProps<{ triggerClass?: string; clientId: number }>();
const toast = useToast();
const { copied, copy, isSupported } = useClipboard({
// fallback does not work
legacy: false,
});
const { data: config, status } = useFetch(
`/api/client/${props.clientId}/configuration`,
{
responseType: 'text',
server: false,
}
);
async function copyCode() {
if (status.value !== 'success') {
return;
}
if (!isSupported.value) {
toast.showToast({
type: 'error',
message: $t('copy.notSupported'),
});
return;
}
await copy(config.value ?? '');
if (copied.value) {
toast.showToast({
type: 'success',
message: $t('copy.copied'),
});
} else {
toast.showToast({
type: 'error',
message: $t('copy.failed'),
});
}
}
</script>
+1 -1
View File
@@ -9,7 +9,7 @@
</div> </div>
</template> </template>
<template #actions> <template #actions>
<DialogClose> <DialogClose as-child>
<BaseSecondaryButton>{{ $t('dialog.cancel') }}</BaseSecondaryButton> <BaseSecondaryButton>{{ $t('dialog.cancel') }}</BaseSecondaryButton>
</DialogClose> </DialogClose>
</template> </template>
+2 -2
View File
@@ -1,14 +1,14 @@
<template> <template>
<div class="relative w-60 md:mr-2"> <div class="relative w-60 md:mr-2">
<div class="relative flex h-full items-center"> <div class="relative flex h-full items-center">
<MagnifyingGlassIcon <IconsMagnifyingGlass
class="absolute left-2.5 h-4 w-4 text-gray-400 dark:text-neutral-500" class="absolute left-2.5 h-4 w-4 text-gray-400 dark:text-neutral-500"
/> />
<input <input
v-model="searchQuery" v-model="searchQuery"
type="text" type="text"
:placeholder="$t('client.search')" :placeholder="$t('client.search')"
class="w-full rounded bg-white py-2 pr-8 text-sm text-gray-900 shadow-sm ring-1 ring-gray-300 transition-all placeholder:text-gray-400 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-red-600 dark:bg-neutral-800 dark:text-white dark:ring-neutral-700 dark:placeholder:text-neutral-500 dark:focus:ring-red-700" class="w-full rounded bg-white px-8 py-2 text-sm text-gray-900 shadow-sm ring-1 ring-gray-300 transition-all placeholder:text-gray-400 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-red-600 dark:bg-neutral-800 dark:text-white dark:ring-neutral-700 dark:placeholder:text-neutral-500 dark:focus:ring-red-700"
@input="updateSearch" @input="updateSearch"
/> />
<button <button
@@ -0,0 +1,7 @@
<template>
<MagnifyingGlassIcon />
</template>
<script lang="ts" setup>
import MagnifyingGlassIcon from '@heroicons/vue/24/outline/esm/MagnifyingGlassIcon';
</script>
+1 -1
View File
@@ -7,7 +7,7 @@
href="https://github.com/wg-easy/wg-easy" href="https://github.com/wg-easy/wg-easy"
>WireGuard Easy</a >WireGuard Easy</a
> >
({{ globalStore.information?.currentRelease }}) © 2021-2025 by ({{ globalStore.information?.currentRelease }}) © 2021-2026 by
<a <a
class="hover:underline" class="hover:underline"
target="_blank" target="_blank"
+6 -4
View File
@@ -4,25 +4,27 @@ export default defineNuxtRouteMiddleware(async (to) => {
return; return;
} }
const event = useRequestEvent();
const authStore = useAuthStore(); const authStore = useAuthStore();
const userData = await authStore.getSession(); authStore.userData = await authStore.getSession(event);
// skip login if already logged in // skip login if already logged in
if (to.path === '/login') { if (to.path === '/login') {
if (userData?.username) { if (authStore.userData?.username) {
return navigateTo('/', { redirectCode: 302 }); return navigateTo('/', { redirectCode: 302 });
} }
return; return;
} }
// Require auth for every page other than Login // Require auth for every page other than Login
if (!userData?.username) { if (!authStore.userData?.username) {
return navigateTo('/login', { redirectCode: 302 }); return navigateTo('/login', { redirectCode: 302 });
} }
// Check for admin access // Check for admin access
if (to.path.startsWith('/admin')) { if (to.path.startsWith('/admin')) {
if (!hasPermissions(userData, 'admin', 'any')) { if (!hasPermissions(authStore.userData, 'admin', 'any')) {
return abortNavigation('Not allowed to access Admin Panel'); return abortNavigation('Not allowed to access Admin Panel');
} }
} }
+3 -5
View File
@@ -13,11 +13,12 @@
v-for="(item, index) in menuItems" v-for="(item, index) in menuItems"
:key="index" :key="index"
:to="`/admin/${item.id}`" :to="`/admin/${item.id}`"
active-class="bg-red-800 rounded" class="group rounded"
active-class="bg-red-800 active"
> >
<BaseSecondaryButton <BaseSecondaryButton
as="span" as="span"
class="w-full cursor-pointer rounded p-2 font-medium transition-colors duration-200 hover:bg-red-800 dark:text-neutral-200" class="w-full font-medium group-[.active]:text-white"
> >
{{ item.name }} {{ item.name }}
</BaseSecondaryButton> </BaseSecondaryButton>
@@ -37,9 +38,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
+13 -3
View File
@@ -179,13 +179,25 @@
@delete="deleteClient" @delete="deleteClient"
> >
<FormSecondaryActionField <FormSecondaryActionField
label="Delete" :label="$t('client.delete')"
class="w-full" class="w-full"
type="button" type="button"
tabindex="-1" tabindex="-1"
as="span" as="span"
/> />
</ClientsDeleteDialog> </ClientsDeleteDialog>
<ClientsConfigDialog
trigger-class="col-span-2"
:client-id="data.id"
>
<FormSecondaryActionField
:label="$t('client.viewConfig')"
class="w-full"
type="button"
tabindex="-1"
as="span"
/>
</ClientsConfigDialog>
</FormGroup> </FormGroup>
</FormElement> </FormElement>
</PanelBody> </PanelBody>
@@ -194,9 +206,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
const authStore = useAuthStore();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
authStore.update();
const route = useRoute(); const route = useRoute();
const id = route.params.id as string; const id = route.params.id as string;
-3
View File
@@ -29,9 +29,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
const clientsStore = useClientsStore(); const clientsStore = useClientsStore();
-3
View File
@@ -67,9 +67,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const authStore = useAuthStore();
authStore.update();
const toast = useToast(); const toast = useToast();
const { t } = useI18n(); const { t } = useI18n();
-1
View File
@@ -120,7 +120,6 @@
import { encodeQR } from 'qr'; import { encodeQR } from 'qr';
const authStore = useAuthStore(); const authStore = useAuthStore();
authStore.update();
const name = ref(authStore.userData?.name); const name = ref(authStore.userData?.name);
const email = ref(authStore.userData?.email); const email = ref(authStore.userData?.email);
+14 -7
View File
@@ -1,18 +1,25 @@
export const useAuthStore = defineStore('Auth', () => { import type { H3Event } from 'h3';
const { data: userData, refresh: update } = useFetch('/api/session', { import type { SharedPublicUser } from '~~/shared/utils/permissions';
method: 'get',
});
async function getSession() { export const useAuthStore = defineStore('Auth', () => {
const userData = useState<SharedPublicUser | null>('user-data', () => null);
async function getSession(event?: H3Event) {
const fetch = event?.$fetch || $fetch;
try { try {
const { data } = await useFetch('/api/session', { const data = await fetch('/api/session', {
method: 'get', method: 'get',
}); });
return data.value; return data;
} catch { } catch {
return null; return null;
} }
} }
async function update() {
const data = await getSession();
userData.value = data;
}
return { userData, update, getSession }; return { userData, update, getSession };
}); });
+5 -4
View File
@@ -66,10 +66,11 @@ export const useClientsStore = defineStore('Clients', () => {
const clientPersist = clientsPersist.value[client.id]!; const clientPersist = clientsPersist.value[client.id]!;
// Debug // Debug
// client.transferRx = this.clientsPersist[client.id].transferRxPrevious + Math.random() * 1000; /* client.transferRx =
// client.transferTx = this.clientsPersist[client.id].transferTxPrevious + Math.random() * 1000; clientPersist.transferRxPrevious + Math.random() * 1000;
// client.latestHandshakeAt = new Date(); client.transferTx =
// this.requiresPassword = true; clientPersist.transferTxPrevious + Math.random() * 1000;
client.latestHandshakeAt = new Date().toISOString(); */
clientPersist.transferRxCurrent = clientPersist.transferRxCurrent =
(client.transferRx ?? 0) - clientPersist.transferRxPrevious; (client.transferRx ?? 0) - clientPersist.transferRxPrevious;
+3 -1
View File
@@ -18,7 +18,7 @@ const db = drizzle({ client, schema });
const dbAdminReset = defineCommand({ const dbAdminReset = defineCommand({
meta: { meta: {
name: 'db:admin:reset', name: 'db:admin:reset',
description: 'Reset the admin user', description: 'Reset the admin user password and TOTP settings',
}, },
args: { args: {
password: { password: {
@@ -61,6 +61,8 @@ const dbAdminReset = defineCommand({
.update(schema.user) .update(schema.user)
.set({ .set({
password: hash, password: hash,
totpVerified: false,
totpKey: null,
}) })
.where(eq(schema.user.id, 1)); .where(eq(schema.user.id, 1));
+10
View File
@@ -7,12 +7,17 @@ import it from './locales/it.json';
import ru from './locales/ru.json'; import ru from './locales/ru.json';
import zhhk from './locales/zh-HK.json'; import zhhk from './locales/zh-HK.json';
import zhcn from './locales/zh-CN.json'; import zhcn from './locales/zh-CN.json';
import zhtw from './locales/zh-TW.json';
import ko from './locales/ko.json'; import ko from './locales/ko.json';
import es from './locales/es.json'; import es from './locales/es.json';
import ptbr from './locales/pt-BR.json'; import ptbr from './locales/pt-BR.json';
import tr from './locales/tr.json'; import tr from './locales/tr.json';
import bn from './locales/bn.json'; import bn from './locales/bn.json';
import id from './locales/id.json'; import id from './locales/id.json';
import nl from './locales/nl.json';
import nb from './locales/nb.json';
import bg from './locales/bg.json';
import gl from './locales/gl.json';
export default defineI18nConfig(() => ({ export default defineI18nConfig(() => ({
legacy: false, legacy: false,
@@ -27,11 +32,16 @@ export default defineI18nConfig(() => ({
ru, ru,
'zh-HK': zhhk, 'zh-HK': zhhk,
'zh-CN': zhcn, 'zh-CN': zhcn,
'zh-TW': zhtw,
ko, ko,
es, es,
'pt-BR': ptbr, 'pt-BR': ptbr,
tr, tr,
bn, bn,
id, id,
nl,
nb,
bg,
gl,
}, },
})); }));
+286
View File
@@ -0,0 +1,286 @@
{
"pages": {
"me": "Профил",
"clients": "Клиенти",
"admin": {
"panel": "Админ Панел",
"general": "Общи",
"config": "Конфигурация",
"interface": "Интерфейс",
"hooks": "Hooks"
}
},
"user": {
"email": "Имейл"
},
"me": {
"currentPassword": "Текуща парола",
"enable2fa": "Активирай двуфакторна автентикация",
"enable2faDesc": "Сканирай QR кода с твоето приложение за автентикатор или въведи ключа ръчно.",
"2faKey": "TOTP ключ",
"2faCodeDesc": "Въведи кода от твоето приложение за автентикатор.",
"disable2fa": "Деактивирай двуфакторна автентикация",
"disable2faDesc": "Въведи паролата си, за да деактивираш двуфакторната автентикация."
},
"general": {
"name": "Име",
"username": "Потребителско име",
"password": "Парола",
"newPassword": "Нова парола",
"updatePassword": "Обнови парола",
"mtu": "MTU",
"allowedIps": "Разрешени IP-та",
"dns": "DNS",
"persistentKeepalive": "Постоянно поддържане на връзката",
"logout": "Изход",
"continue": "Продължи",
"host": "Хост",
"port": "Порт",
"yes": "Да",
"no": "Не",
"confirmPassword": "Потвърди парола",
"loading": "Зареждане...",
"2fa": "Двуфакторна автентикация",
"2faCode": "TOTP код"
},
"setup": {
"welcome": "Добре дошъл в първоначалната настройка на wg-easy",
"welcomeDesc": "Откри най-лесния начин да инсталираш и управляваш WireGuard на всеки Linux сървър",
"existingSetup": "Имаш ли вече съществуваща инсталация?",
"createAdminDesc": "Моля, първо въведи администраторско потребителско име и силна сигурна парола. Тези данни ще се използват за вход в административния панел.",
"setupConfigDesc": "Моля, въведи хост и порт. Тази информация ще се използва при генериране на клиентски конфигурации за WireGuard.",
"setupMigrationDesc": "Ако желаеш да мигрираш данните от предишна версия на wg-easy, качи резервното копие.",
"upload": "Качи",
"migration": "Възстанови от резервно копие:",
"createAccount": "Създай акаунт",
"successful": "Настройката е успешна",
"hostDesc": "Публично име/адрес, към който клиентите ще се свързват",
"portDesc": "Публичен UDP порт, на който клиентите ще се свързват и на който WireGuard слуша"
},
"update": {
"updateAvailable": "Налична е актуализация!",
"update": "Актуализирай"
},
"theme": {
"dark": "Тъмна тема",
"light": "Светла тема",
"system": "Системна тема"
},
"layout": {
"toggleCharts": "Покажи/скрий графики",
"donate": "Дарение"
},
"login": {
"signIn": "Вход",
"rememberMe": "Запомни ме",
"rememberMeDesc": "Остани влязъл след затваряне на браузъра",
"insecure": "Не можеш да влезеш през несигурна връзка. Използвай HTTPS.",
"2faRequired": "Изисква се двуфакторна автентикация",
"2faWrong": "Грешен код за двуфакторна автентикация"
},
"client": {
"empty": "Все още няма клиенти.",
"newShort": "Нов",
"sort": "Сортирай",
"create": "Създай клиент",
"created": "Клиентът е създаден",
"new": "Нов клиент",
"name": "Име",
"expireDate": "Дата на изтичане",
"expireDateDesc": "Дата, след която клиентът ще бъде деактивиран. Празно = постоянен",
"delete": "Изтрий",
"deleteClient": "Изтрий клиент",
"deleteDialog1": "Сигурен ли си, че искаш да изтриеш",
"deleteDialog2": "Това действие е необратимо.",
"enabled": "Активен",
"address": "Адрес",
"serverAllowedIps": "Разрешени IP-та от сървъра",
"otlDesc": "Генерирай кратък еднократен линк",
"permanent": "Постоянно",
"createdOn": "Създаден на ",
"lastSeen": "Последно видян на ",
"totalDownload": "Общо изтеглени: ",
"totalUpload": "Общо качени: ",
"newClient": "Нов клиент",
"disableClient": "Деактивирай клиент",
"enableClient": "Активирай клиент",
"noPrivKey": "Този клиент няма известен частен ключ. Не може да се създаде конфигурация.",
"showQR": "Покажи QR код",
"downloadConfig": "Изтегли конфигурация",
"allowedIpsDesc": "Кои IP-та ще се насочват през VPN (замества глобалната настройка)",
"serverAllowedIpsDesc": "Кои IP-та сървърът ще насочва към клиента",
"mtuDesc": "Задава максималния размер на пакета (MTU) за VPN тунела",
"persistentKeepaliveDesc": "Интервал (в секунди) за изпращане на keep-alive пакети. 0 = изключено",
"hooks": "Hooks",
"hooksDescription": "Hooks работят само с wg-quick",
"hooksLeaveEmpty": "Само за wg-quick. В противен случай остави празно",
"dnsDesc": "DNS сървър, който клиентите ще използват (замества глобалната настройка)",
"notConnected": "Клиентът не е свързан",
"endpoint": "Крайна точка",
"endpointDesc": "IP адресът на клиента, от който е установена WireGuard връзката",
"search": "Търси клиенти...",
"config": "Конфигурация",
"viewConfig": "Прегледай конфигурацията"
},
"dialog": {
"change": "Промени",
"cancel": "Отказ",
"create": "Създай"
},
"toast": {
"success": "Успех",
"saved": "Запазено",
"error": "Грешка"
},
"form": {
"actions": "Действия",
"save": "Запази",
"revert": "Отмени промените",
"sectionGeneral": "Общи",
"sectionAdvanced": "Разширени",
"noItems": "Няма елементи",
"nullNoItems": "Няма елементи. Използва се глобалната конфигурация",
"add": "Добави"
},
"admin": {
"general": {
"sessionTimeout": "Време на сесията",
"sessionTimeoutDesc": "Продължителност на сесията при „Запомни ме“ (в секунди)",
"metrics": "Метрики",
"metricsPassword": "Парола",
"metricsPasswordDesc": "Bearer парола за достъп до metrics ендпойнт (парола или argon2 хеш)",
"json": "JSON",
"jsonDesc": "Път за метрики в JSON формат",
"prometheus": "Prometheus",
"prometheusDesc": "Път за Prometheus метрики"
},
"config": {
"connection": "Връзка",
"hostDesc": "Публично име/адрес за клиентите (инвалидира конфигурациите)",
"portDesc": "Публичен UDP порт за клиентите (инвалидира конфигурациите; вероятно искаш да смениш и порта на интерфейса)",
"allowedIpsDesc": "Разрешени IP-та за клиентите (глобална настройка)",
"dnsDesc": "DNS сървър за клиентите (глобална настройка)",
"mtuDesc": "MTU, който ще ползват клиентите (само за нови клиенти)",
"persistentKeepaliveDesc": "Интервал в секунди за keep-alive към сървъра. 0 = изключено (само за нови клиенти)",
"suggest": "Предложи",
"suggestDesc": "Избери IP адрес или хост за полето Host"
},
"interface": {
"cidrSuccess": "CIDR променен",
"device": "Устройство",
"deviceDesc": "Мрежово устройство, през което да се препраща WireGuard трафикът",
"mtuDesc": "MTU, който ще ползва WireGuard",
"portDesc": "UDP порт, на който слуша WireGuard (вероятно искаш да смениш и порта в Config)",
"changeCidr": "Смени CIDR",
"restart": "Рестартирай интерфейс",
"restartDesc": "Рестартиране на WireGuard интерфейса",
"restartWarn": "Сигурен ли си, че искаш да рестартираш интерфейса? Всички клиенти ще бъдат изключени.",
"restartSuccess": "Интерфейсът е рестартиран"
},
"introText": "Добре дошъл в административния панел.\n\nТук можеш да управляваш общите настройки, конфигурацията, настройките на интерфейса и hooks.\n\nЗапочни, като избереш някоя от секциите в страничното меню."
},
"zod": {
"generic": {
"required": "{0} е задължително",
"validNumber": "{0} трябва да е валидно число",
"validString": "{0} трябва да е валиден текст",
"validBoolean": "{0} трябва да е валидна булева стойност",
"validArray": "{0} трябва да е валиден масив",
"stringMin": "{0} трябва да съдържа поне {1} символа",
"numberMin": "{0} трябва да е поне {1}"
},
"client": {
"id": "ID на клиента",
"name": "Име",
"expiresAt": "Изтича на",
"address4": "IPv4 адрес",
"address6": "IPv6 адрес",
"serverAllowedIps": "Разрешени IP-та от сървъра"
},
"user": {
"username": "Потребителско име",
"password": "Парола",
"remember": "Запомни",
"name": "Име",
"email": "Имейл",
"emailInvalid": "Имейлът трябва да е валиден",
"passwordMatch": "Паролите трябва да съвпадат",
"totpEnable": "Активиране на TOTP",
"totpEnableTrue": "TOTP Enable трябва да е true",
"totpCode": "TOTP код"
},
"userConfig": {
"host": "Хост"
},
"general": {
"sessionTimeout": "Време на сесията",
"metricsEnabled": "Метрики",
"metricsPassword": "Парола за метрики"
},
"interface": {
"cidr": "CIDR",
"device": "Устройство",
"cidrValid": "CIDR трябва да е валиден"
},
"otl": "Еднократен линк",
"stringMalformed": "Невалиден формат на низа",
"body": "Тялото трябва да е валиден обект",
"hook": "Hook",
"enabled": "Активиран",
"mtu": "MTU",
"port": "Порт",
"persistentKeepalive": "Постоянно поддържане на връзката",
"address": "IP адрес",
"dns": "DNS",
"allowedIps": "Разрешени IP-та",
"file": "Файл"
},
"hooks": {
"preUp": "PreUp",
"postUp": "PostUp",
"preDown": "PreDown",
"postDown": "PostDown"
},
"copy": {
"notSupported": "Копиране не се поддържа",
"copied": "Копирано!",
"failed": "Копирането неуспешно",
"copy": "Копирай"
},
"awg": {
"jCLabel": "Брой junk пакети (Jc)",
"jCDescription": "Брой junk пакети за изпращане (1–128, препоръчително: 4–12)",
"jMinLabel": "Минимален размер на junk пакети (Jmin)",
"jMinDescription": "Минимален размер на junk пакетите (0–1279*, препоръчително: 8, трябва да е < Jmax)",
"jMaxLabel": "Максимален размер на junk пакети (Jmax)",
"jMaxDescription": "Максимален размер на junk пакетите (1–1280*, препоръчително: 80, трябва да е > Jmin)",
"s1Label": "Размер на junk в init пакета (S1)",
"s1Description": "Размер на junk в init пакета (01132 [1280*148=1132], препоръчително: 15150, S1+56 ≠ S2)",
"s2Label": "Размер на junk в отговорния пакет (S2)",
"s2Description": "Размер на junk в response пакета (01188 [1280*92=1188], препоръчително: 15–150)",
"s3Label": "Размер на junk в cookie reply пакета (S3)",
"s3Description": "Размер на junk в cookie reply пакета",
"s4Label": "Размер на junk в транспортния пакет (S4)",
"s4Description": "Размер на junk в транспортния пакет",
"i1Label": "Специален junk пакет 1 (I1)",
"i1Description": "Пакет за имитация на протокол в hex формат: <b 0x...>",
"i2Label": "Специален junk пакет 2 (I2)",
"i2Description": "Пакет за имитация на протокол в hex формат: <b 0x...>",
"i3Label": "Специален junk пакет 3 (I3)",
"i3Description": "Пакет за имитация на протокол в hex формат: <b 0x...>",
"i4Label": "Специален junk пакет 4 (I4)",
"i4Description": "Пакет за имитация на протокол в hex формат: <b 0x...>",
"i5Label": "Специален junk пакет 5 (I5)",
"i5Description": "Пакет за имитация на протокол в hex формат: <b 0x...>",
"h1Label": "Init magic header (H1)",
"h1Description": "Стойност на хедера в init пакета (5–2147483647, уникална спрямо H2–H4)",
"h2Label": "Response magic header (H2)",
"h2Description": "Стойност на хедера в response пакета (52147483647, уникална спрямо H1, H3, H4)",
"h3Label": "Cookie reply magic header (H3)",
"h3Description": "Стойност на хедера в cookie reply пакета (52147483647, уникална спрямо H1, H2, H4)",
"h4Label": "Transport magic header (H4)",
"h4Description": "Стойност на хедера в транспортния пакет (5–2147483647, уникална спрямо H1–H3)",
"mtuNote": "Стойностите зависят от MTU",
"obfuscationParameters": "Параметри за обфускация на AmneziaWG"
}
}
+74 -25
View File
@@ -11,12 +11,12 @@
} }
}, },
"user": { "user": {
"email": "Email" "email": "E-Mail"
}, },
"me": { "me": {
"currentPassword": "Aktuelles Passwort", "currentPassword": "Aktuelles Passwort",
"enable2fa": "Zwei-Faktor-Authentifizierunng aktivieren", "enable2fa": "Zwei-Faktor-Authentifizierung aktivieren",
"enable2faDesc": "Scannen Sie den QR-Code mit ihrer Authentifizierungs-App oder geben Sie den Schlüssel manuell ein.", "enable2faDesc": "Scannen Sie den QR-Code mit Ihrer Authentifizierungs-App oder geben Sie den Schlüssel manuell ein.",
"2faKey": "TOTP-Schlüssel", "2faKey": "TOTP-Schlüssel",
"2faCodeDesc": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein.", "2faCodeDesc": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein.",
"disable2fa": "Zwei-Faktor-Authentifizierung deaktivieren", "disable2fa": "Zwei-Faktor-Authentifizierung deaktivieren",
@@ -45,26 +45,26 @@
}, },
"setup": { "setup": {
"welcome": "Willkommen zur Ersteinrichtung von wg-easy", "welcome": "Willkommen zur Ersteinrichtung von wg-easy",
"welcomeDesc": "Das ist der einfachste Weg, um Wireguard auf jedem Linux-Server zu installieren und zu betreiben.", "welcomeDesc": "Sie haben den einfachsten Weg gefunden, WireGuard auf jedem Linux-Server zu installieren und zu verwalten.",
"existingSetup": "Haben Sie eine bestehende Einrichtung?", "existingSetup": "Haben Sie eine bestehende Einrichtung?",
"createAdminDesc": "Bitte geben Sie zuerst einen Admin-Benutzernamen sowie ein starkes, sicheres Passwort ein. Diese Anmeldedaten benötigen Sie, um sich im Admin-Panel anzumelden.", "createAdminDesc": "Bitte geben Sie zuerst einen Admin-Benutzernamen sowie ein starkes, sicheres Passwort ein. Diese Anmeldedaten benötigen Sie, um sich in der Admin-Konsole anzumelden.",
"setupConfigDesc": "Bitte geben Sie die Host- und Portinformationen ein. Diese werden für die Client-Konfiguration verwendet, wenn Sie WireGuard auf Ihren Geräten einrichten.", "setupConfigDesc": "Bitte geben Sie die Host- und Portinformationen ein. Diese werden für die Client-Konfiguration verwendet, wenn Sie WireGuard auf Ihren Geräten einrichten.",
"setupMigrationDesc": "Bitte halten Sie die Sicherungsdatei bereit, wenn Sie Ihre Daten von Ihrer vorherigen wg-easy Version auf ihre neue Einrichtung migrieren möchten.", "setupMigrationDesc": "Bitte halten Sie die Sicherungsdatei bereit, wenn Sie Ihre Daten von Ihrer vorherigen wg-easy Version auf ihre neue Einrichtung migrieren möchten.",
"upload": "Hochladen", "upload": "Hochladen",
"migration": "Sicherung wiederherstellen:", "migration": "Backup wiederherstellen:",
"createAccount": "Konto erstellen", "createAccount": "Konto erstellen",
"successful": "Einrichtung erfolgreich", "successful": "Einrichtung erfolgreich",
"hostDesc": "Öffentlicher Hostname mit dem sich die Clients verbinden", "hostDesc": "Öffentlicher Hostname mit dem sich die Clients verbinden",
"portDesc": "Öffentlicher UDP-Port an dem sich die Clients verbinden und auf dem Wireguard läuft" "portDesc": "Öffentlicher UDP-Port an dem sich die Clients verbinden und auf dem WireGuard läuft"
}, },
"update": { "update": {
"updateAvailable": "Es ist ein neue Aktualisierung verfügbar!", "updateAvailable": "Ein neues Update ist verfügbar!",
"update": "Aktualisieren" "update": "Aktualisieren"
}, },
"theme": { "theme": {
"dark": "Dunkles Thema", "dark": "Dunkles Thema",
"light": "Helles Thema", "light": "Helles Thema",
"system": "System-Thema" "system": "System Thema"
}, },
"layout": { "layout": {
"toggleCharts": "Statistiken ein-/ausblenden", "toggleCharts": "Statistiken ein-/ausblenden",
@@ -84,16 +84,16 @@
"sort": "Sortieren", "sort": "Sortieren",
"create": "Client erstellen", "create": "Client erstellen",
"created": "Client wurde erstellt", "created": "Client wurde erstellt",
"new": "Neuer client", "new": "Neuer Client",
"name": "Name", "name": "Name",
"expireDate": "Ablaufdatum", "expireDate": "Ablaufdatum",
"expireDateDesc": "Datum, an dem der Client deaktiviert wird. Leer lassen, damit dies nie passiert.", "expireDateDesc": "Datum, an dem der Client deaktiviert wird. Leer lassen für dauerhaft aktiv.",
"deleteClient": "Client löschen", "deleteClient": "Client löschen",
"deleteDialog1": "Sind Sie sicher, dass Sie diesen Client löschen wollen", "deleteDialog1": "Sind Sie sicher, dass Sie diesen Client löschen möchten",
"deleteDialog2": "Diese Aktion kann nicht rückgängig gemacht werden.", "deleteDialog2": "Diese Aktion kann nicht rückgängig gemacht werden.",
"enabled": "Aktiviert", "enabled": "Aktiviert",
"address": "Adresse", "address": "Adresse",
"serverAllowedIps": "serverseitig erlaubte IP-Adressen", "serverAllowedIps": "Serverseitig erlaubte IP-Adressen",
"otlDesc": "Einen kurzen Einmal-Link erzeugen", "otlDesc": "Einen kurzen Einmal-Link erzeugen",
"permanent": "Dauerhaft", "permanent": "Dauerhaft",
"createdOn": "Angelegt am ", "createdOn": "Angelegt am ",
@@ -112,8 +112,15 @@
"persistentKeepaliveDesc": "Legt das Intervall (in Sekunden) für Keepalive-Pakete fest. 0 deaktiviert es", "persistentKeepaliveDesc": "Legt das Intervall (in Sekunden) für Keepalive-Pakete fest. 0 deaktiviert es",
"hooks": "Hooks", "hooks": "Hooks",
"hooksDescription": "Hooks funktionieren nur mit wg-quick", "hooksDescription": "Hooks funktionieren nur mit wg-quick",
"hooksLeaveEmpty": "Nur für wg-quick. Sonst leer lassen", "hooksLeaveEmpty": "Nur für wg-quick. Andernfalls leer lassen",
"dnsDesc": "DNS-Server, den die Clients benutzen (überschreibt die globale Konfiguration)" "dnsDesc": "DNS-Server, den die Clients benutzen (überschreibt die globale Konfiguration)",
"delete": "Löschen",
"notConnected": "Client nicht verbunden",
"endpoint": "Endpunkt",
"endpointDesc": "IP-Adresse des Clients, von dem aus die WireGuard-Verbindung hergestellt wird",
"search": "Suche Clients...",
"config": "Konfiguration",
"viewConfig": "Konfiguration anzeigen"
}, },
"dialog": { "dialog": {
"change": "Ändern", "change": "Ändern",
@@ -150,24 +157,24 @@
"config": { "config": {
"connection": "Verbindung", "connection": "Verbindung",
"hostDesc": "Öffentlicher Hostname mit dem sich die Clients verbinden (überschreibt die Konfiguration)", "hostDesc": "Öffentlicher Hostname mit dem sich die Clients verbinden (überschreibt die Konfiguration)",
"portDesc": "Öffentlicher UDP-Port an dem sich die Clients verbinden (überschreibt die Konfiguration, vermutlich wollen Sie ebenfalls den Port der Weboberfläche ändern)", "portDesc": "Öffentlicher UDP-Port an dem sich die Clients verbinden (überschreibt die Konfiguration, vermutlich wollen Sie auch den Interface-Port ändern)",
"allowedIpsDesc": "Erlaubte IP-Adressen, die die Clients nutzen werden (Globale Konfiguration)", "allowedIpsDesc": "Erlaubte IP-Adressen, die die Clients nutzen werden (Globale Konfiguration)",
"dnsDesc": "DNS-Server, den die Clients nutzen werden (Globale Konfiguration)", "dnsDesc": "DNS-Server, den die Clients nutzen werden (Globale Konfiguration)",
"mtuDesc": "MTU, den die Clients benutzen werden (nur für neue Clients)", "mtuDesc": "MTU, den die Clients benutzen werden (nur für neue Clients)",
"persistentKeepaliveDesc": "Intervall in Sekunden, in dem Keepalive-Packete an den Server gesendet werden. 0 = deaktiviert (nur für neue Clients)", "persistentKeepaliveDesc": "Intervall in Sekunden, in dem Keepalive-Pakete an den Server gesendet werden. 0 = deaktiviert (nur für neue Clients)",
"suggest": "Vorschlagen", "suggest": "Vorschlagen",
"suggestDesc": "Wählen Sie eine IP-Adresse oder einen Hostnamen für das Host-Feld aus" "suggestDesc": "Wählen Sie eine IP-Adresse oder einen Hostnamen für das Host-Feld aus"
}, },
"interface": { "interface": {
"cidrSuccess": "CIDR wurde geändert", "cidrSuccess": "CIDR wurde geändert",
"device": "Gerät", "device": "Gerät",
"deviceDesc": "Ethernet-Gerät, durch das der Wireguard-Datenverkehr geleitet werden soll", "deviceDesc": "Ethernet-Gerät, durch das der WireGuard-Datenverkehr geleitet werden soll",
"mtuDesc": "MTU, den WireGuard benutzen wird", "mtuDesc": "MTU, den WireGuard benutzen wird",
"portDesc": "UDP Port, auf dem WireGuard lauschen wird (Sie wollen wahrscheinlich auch den Config-Port ändern)", "portDesc": "UDP-Port, auf dem WireGuard lauschen wird (Sie wollen wahrscheinlich auch den Interface-Port ändern)",
"changeCidr": "CIDR ändern", "changeCidr": "CIDR ändern",
"restart": "Interface neu starten", "restart": "Interface neu starten",
"restartDesc": "Das WireGuard-Interface neu starten", "restartDesc": "Das WireGuard-Interface neu starten",
"restartWarn": "Sind Sie sicher, dass Sie das Interface neu starten wollen? Dies wird die Verbindungen aller Clients trennen.", "restartWarn": "Sind Sie sicher, dass Sie das Interface neu starten möchten? Dies wird die Verbindungen aller Clients trennen.",
"restartSuccess": "Interface neu gestartet" "restartSuccess": "Interface neu gestartet"
}, },
"introText": "Willkommen in der Admin-Konsole.\n\nHier können Sie die allgemeinen Einstellungen, die Konfiguration, die Schnittstelleneinstellungen und die Hooks verwalten.\n\nBeginnen Sie, indem Sie einen der Bereiche in der Seitenleiste auswählen." "introText": "Willkommen in der Admin-Konsole.\n\nHier können Sie die allgemeinen Einstellungen, die Konfiguration, die Schnittstelleneinstellungen und die Hooks verwalten.\n\nBeginnen Sie, indem Sie einen der Bereiche in der Seitenleiste auswählen."
@@ -188,15 +195,15 @@
"expiresAt": "Läuft ab am", "expiresAt": "Läuft ab am",
"address4": "IPv4-Adresse", "address4": "IPv4-Adresse",
"address6": "IPv6-Adresse", "address6": "IPv6-Adresse",
"serverAllowedIps": "serverseitig erlaubte IP-Adressen" "serverAllowedIps": "Serverseitig erlaubte IP-Adressen"
}, },
"user": { "user": {
"username": "Benutzername", "username": "Benutzername",
"password": "Passwort", "password": "Passwort",
"remember": "Merken", "remember": "Merken",
"name": "Name", "name": "Name",
"email": "Email", "email": "E-Mail",
"emailInvalid": "Die Email-Adresse muss valide sein", "emailInvalid": "Die E-Mail-Adresse muss gültig sein",
"passwordMatch": "Die Passwörter müssen übereinstimmen", "passwordMatch": "Die Passwörter müssen übereinstimmen",
"totpEnable": "TOTP aktivieren", "totpEnable": "TOTP aktivieren",
"totpEnableTrue": "\"TOTP aktivieren\" muss ausgewählt sein", "totpEnableTrue": "\"TOTP aktivieren\" muss ausgewählt sein",
@@ -212,8 +219,8 @@
}, },
"interface": { "interface": {
"cidr": "CIDR", "cidr": "CIDR",
"device": "Geräte", "device": "Gerät",
"cidrValid": "CIDR muss valide sein" "cidrValid": "CIDR muss gültig sein"
}, },
"otl": "Einmal-Link", "otl": "Einmal-Link",
"stringMalformed": "Zeichenkette ist fehlerhaft", "stringMalformed": "Zeichenkette ist fehlerhaft",
@@ -233,5 +240,47 @@
"postUp": "PostUp", "postUp": "PostUp",
"preDown": "PreDown", "preDown": "PreDown",
"postDown": "PostDown" "postDown": "PostDown"
},
"copy": {
"notSupported": "Kopieren ist nicht unterstützt",
"copied": "Kopiert!",
"failed": "Kopieren fehlgeschlagen",
"copy": "Kopieren"
},
"awg": {
"jCLabel": "Anzahl der Junk-Pakete (Jc)",
"jCDescription": "Anzahl der zu sendenden Junk-Pakete (1-128, empfohlen: 4-12)",
"jMinLabel": "Minimale Junk-Paketgröße (Jmin)",
"jMinDescription": "Mindestgröße von Junk-Paketen (0-1279*, empfohlen: 8, muss < Jmax sein)",
"jMaxLabel": "Maximale Junk-Paketgröße (Jmax)",
"jMaxDescription": "Maximalgröße von Junk-Paketen (1-1280*, empfohlen: 80, muss > Jmin sein)",
"s1Label": "Junk-Paketgröße des Init-Pakets (S1)",
"s1Description": "Junk-Paketgröße des Init-Pakets (0-1132[1280* - 148 = 1132], empfohlen: 15-150, S1+56 ≠ S2)",
"s2Label": "Junk-Paketgröße des Antwort-Pakets (S2)",
"s2Description": "Junk-Paketgröße des Antwort-Pakets (0-1188[1280* - 92 = 1188], empfohlen: 15-150)",
"s3Label": "Junk-Paketgröße des Cookie-Antwort-Pakets (S3)",
"s3Description": "Junk-Paketgröße des Cookie-Antwort-Pakets",
"s4Label": "Junk-Paketgröße des Transport-Pakets (S4)",
"s4Description": "Junk-Paketgröße des Transport-Pakets",
"i1Label": "Spezial-Junk-Paket 1 (I1)",
"i1Description": "Protokoll-Nachahmungspaket im Hex-Format: <b 0x...>",
"i2Label": "Spezial-Junk-Paket 2 (I2)",
"i2Description": "Protokoll-Nachahmungspaket im Hex-Format: <b 0x...>",
"i3Label": "Spezial-Junk-Paket 3 (I3)",
"i3Description": "Protokoll-Nachahmungspaket im Hex-Format: <b 0x...>",
"i4Label": "Spezial-Junk-Paket 4 (I4)",
"i4Description": "Protokoll-Nachahmungspaket im Hex-Format: <b 0x...>",
"i5Label": "Spezial-Junk-Paket 5 (I5)",
"i5Description": "Protokoll-Nachahmungspaket im Hex-Format: <b 0x...>",
"h1Label": "Init-Magic-Header (H1)",
"h1Description": "Wert des Init-Paket-Headers (5-2147483647, muss eindeutig zu H2-H4 sein)",
"h2Label": "Antwort-Magic-Header (H2)",
"h2Description": "Wert des Antwort-Paket-Headers (5-2147483647, muss eindeutig zu H1, H3, H4 sein)",
"h3Label": "Cookie-Antwort-Magic-Header (H3)",
"h3Description": "Wert des Cookie-Antwort-Paket-Headers (5-2147483647, muss eindeutig zu H1, H2, H4 sein)",
"h4Label": "Transport-Magic-Header (H4)",
"h4Description": "Wert des Transport-Paket-Headers (5-2147483647, muss eindeutig zu H1-H3 sein)",
"mtuNote": "Werte hängen von der MTU ab",
"obfuscationParameters": "AmneziaWG Verschleierungsparameter"
} }
} }
+10 -1
View File
@@ -88,6 +88,7 @@
"name": "Name", "name": "Name",
"expireDate": "Expire Date", "expireDate": "Expire Date",
"expireDateDesc": "Date the client will be disabled. Blank for permanent", "expireDateDesc": "Date the client will be disabled. Blank for permanent",
"delete": "Delete",
"deleteClient": "Delete Client", "deleteClient": "Delete Client",
"deleteDialog1": "Are you sure you want to delete", "deleteDialog1": "Are you sure you want to delete",
"deleteDialog2": "This action cannot be undone.", "deleteDialog2": "This action cannot be undone.",
@@ -117,7 +118,9 @@
"notConnected": "Client not connected", "notConnected": "Client not connected",
"endpoint": "Endpoint", "endpoint": "Endpoint",
"endpointDesc": "IP of the client from which the WireGuard connection is established", "endpointDesc": "IP of the client from which the WireGuard connection is established",
"search": "Search clients..." "search": "Search clients...",
"config": "Configuration",
"viewConfig": "View Configuration"
}, },
"dialog": { "dialog": {
"change": "Change", "change": "Change",
@@ -238,6 +241,12 @@
"preDown": "PreDown", "preDown": "PreDown",
"postDown": "PostDown" "postDown": "PostDown"
}, },
"copy": {
"notSupported": "Copy is not supported",
"copied": "Copied!",
"failed": "Copy failed",
"copy": "Copy"
},
"awg": { "awg": {
"jCLabel": "Junk packet count (Jc)", "jCLabel": "Junk packet count (Jc)",
"jCDescription": "Number of junk packets to send (1-128, recommended: 4-12)", "jCDescription": "Number of junk packets to send (1-128, recommended: 4-12)",
+59 -13
View File
@@ -15,12 +15,12 @@
}, },
"me": { "me": {
"currentPassword": "Mot de passe actuel", "currentPassword": "Mot de passe actuel",
"enable2fa": "Activer l'authentification à double facteur", "enable2fa": "Activer l'authentification à deux facteurs",
"enable2faDesc": "Scannez le code QR avec votre application d'authentification ou saisissez la clé manuellement.", "enable2faDesc": "Scannez le code QR avec votre application d'authentification ou saisissez la clé manuellement.",
"2faKey": "Clé TOTP", "2faKey": "Clé TOTP",
"2faCodeDesc": "Saisissez le code de votre application d'authentification.", "2faCodeDesc": "Saisissez le code de votre application d'authentification.",
"disable2fa": "Désactiver l'authentification à double facteur", "disable2fa": "Désactiver l'authentification à deux facteurs",
"disable2faDesc": "Saisissez votre mot de passe pour désactiver l'authentification à double facteur" "disable2faDesc": "Saisissez votre mot de passe pour désactiver l'authentification à deux facteurs."
}, },
"general": { "general": {
"name": "Nom", "name": "Nom",
@@ -40,7 +40,7 @@
"no": "Non", "no": "Non",
"confirmPassword": "Confirmer le mot de passe", "confirmPassword": "Confirmer le mot de passe",
"loading": "Chargement...", "loading": "Chargement...",
"2fa": "Authentification à double facteur", "2fa": "Authentification à deux facteurs",
"2faCode": "Code TOTP" "2faCode": "Code TOTP"
}, },
"setup": { "setup": {
@@ -75,8 +75,8 @@
"rememberMe": "Se souvenir de moi", "rememberMe": "Se souvenir de moi",
"rememberMeDesc": "Rester connecté après avoir fermé le navigateur", "rememberMeDesc": "Rester connecté après avoir fermé le navigateur",
"insecure": "Vous ne pouvez pas vous connecter avec une connexion non sécurisée. Utilisez HTTPS.", "insecure": "Vous ne pouvez pas vous connecter avec une connexion non sécurisée. Utilisez HTTPS.",
"2faRequired": "Une authentification à double facteur est requise", "2faRequired": "L'authentification à deux facteurs est requise",
"2faWrong": "L'authentification à double facteur est incorrecte" "2faWrong": "Le code d'authentification à deux facteurs est incorrect"
}, },
"client": { "client": {
"empty": "Il n'y a pas encore de clients.", "empty": "Il n'y a pas encore de clients.",
@@ -108,7 +108,7 @@
"downloadConfig": "Télécharger la configuration", "downloadConfig": "Télécharger la configuration",
"allowedIpsDesc": "Quelles IPs seront acheminées par le VPN (remplace la configuration globale)", "allowedIpsDesc": "Quelles IPs seront acheminées par le VPN (remplace la configuration globale)",
"serverAllowedIpsDesc": "Les IPs que le serveur acheminera vers le client", "serverAllowedIpsDesc": "Les IPs que le serveur acheminera vers le client",
"mtuDesc": "Définit le nombre maximum d'unités de transmission (taille des paquets) pour le tunnel VPN.", "mtuDesc": "Définit l'unité de transmission maximale (taille des paquets) pour le tunnel VPN",
"persistentKeepaliveDesc": "Définit l'intervalle (en secondes) pour les paquets keep-alive. 0 le désactive", "persistentKeepaliveDesc": "Définit l'intervalle (en secondes) pour les paquets keep-alive. 0 le désactive",
"hooks": "Hooks", "hooks": "Hooks",
"hooksDescription": "Les hooks ne fonctionnent qu'avec wg-quick", "hooksDescription": "Les hooks ne fonctionnent qu'avec wg-quick",
@@ -116,7 +116,11 @@
"dnsDesc": "Serveur DNS que les clients utiliseront (remplace la configuration globale)", "dnsDesc": "Serveur DNS que les clients utiliseront (remplace la configuration globale)",
"notConnected": "Client non connecté", "notConnected": "Client non connecté",
"endpoint": "Endpoint", "endpoint": "Endpoint",
"endpointDesc": "Adresse IP du client à partir duquel la connexion WireGuard est établie" "endpointDesc": "Adresse IP du client à partir duquel la connexion WireGuard est établie",
"search": "Rechercher des clients...",
"config": "Configuration",
"viewConfig": "Voir la configuration",
"delete": "Supprimer"
}, },
"dialog": { "dialog": {
"change": "Modifier", "change": "Modifier",
@@ -146,9 +150,9 @@
"metricsPassword": "Mot de passe", "metricsPassword": "Mot de passe",
"metricsPasswordDesc": "Mot de passe Bearer pour le endpoint des métriques (mot de passe ou argon2 hash)", "metricsPasswordDesc": "Mot de passe Bearer pour le endpoint des métriques (mot de passe ou argon2 hash)",
"json": "JSON", "json": "JSON",
"jsonDesc": "Acheminement pour les métriques au format JSON", "jsonDesc": "Route pour les métriques au format JSON",
"prometheus": "Prometheus", "prometheus": "Prometheus",
"prometheusDesc": "Acheminement pour les métriques de Prometheus" "prometheusDesc": "Route pour les métriques Prometheus"
}, },
"config": { "config": {
"connection": "Connexion", "connection": "Connexion",
@@ -180,13 +184,13 @@
"required": "{0} est requis", "required": "{0} est requis",
"validNumber": "{0} doit être un nombre valide", "validNumber": "{0} doit être un nombre valide",
"validString": "{0} doit être une chaîne de caractères valide", "validString": "{0} doit être une chaîne de caractères valide",
"validBoolean": "{0} doit être une variable valide", "validBoolean": "{0} doit être un booléen valide",
"validArray": "{0} doit être un tableau valide", "validArray": "{0} doit être un tableau valide",
"stringMin": "{0} doit être d'au moins {1} Caractère", "stringMin": "{0} doit comporter au moins {1} caractère(s)",
"numberMin": "{0} doit être d'au moins {1}" "numberMin": "{0} doit être d'au moins {1}"
}, },
"client": { "client": {
"id": "Client ID", "id": "ID du client",
"name": "Nom", "name": "Nom",
"expiresAt": "Expire le", "expiresAt": "Expire le",
"address4": "Adresse IPv4", "address4": "Adresse IPv4",
@@ -236,5 +240,47 @@
"postUp": "PostUp", "postUp": "PostUp",
"preDown": "PreDown", "preDown": "PreDown",
"postDown": "PostDown" "postDown": "PostDown"
},
"copy": {
"notSupported": "La copie n'est pas prise en charge",
"copied": "Copié !",
"failed": "Échec de la copie",
"copy": "Copier"
},
"awg": {
"jCLabel": "Nombre de paquets parasites (Jc)",
"jCDescription": "Nombre de paquets parasites à envoyer (1-128, recommandé : 4-12)",
"jMinLabel": "Taille min des paquets parasites (Jmin)",
"jMinDescription": "Taille minimale des paquets parasites (0-1279*, recommandé : 8, doit être < Jmax)",
"jMaxLabel": "Taille max des paquets parasites (Jmax)",
"jMaxDescription": "Taille maximale des paquets parasites (1-1280*, recommandé : 80, doit être > Jmin)",
"s1Label": "Taille parasite du paquet init (S1)",
"s1Description": "Taille parasite du paquet d'initialisation (0-1132[1280* - 148 = 1132], recommandé : 15-150, S1+56 ≠ S2)",
"s2Label": "Taille parasite du paquet réponse (S2)",
"s2Description": "Taille parasite du paquet de réponse (0-1188[1280* - 92 = 1188], recommandé : 15-150)",
"s3Label": "Taille parasite du paquet cookie reply (S3)",
"s3Description": "Taille parasite du paquet de réponse cookie",
"s4Label": "Taille parasite du paquet transport (S4)",
"s4Description": "Taille parasite du paquet de transport",
"i1Label": "Paquet parasite spécial 1 (I1)",
"i1Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
"i2Label": "Paquet parasite spécial 2 (I2)",
"i2Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
"i3Label": "Paquet parasite spécial 3 (I3)",
"i3Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
"i4Label": "Paquet parasite spécial 4 (I4)",
"i4Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
"i5Label": "Paquet parasite spécial 5 (I5)",
"i5Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
"h1Label": "En-tête magique init (H1)",
"h1Description": "Valeur d'en-tête du paquet init (5-2147483647, doit être unique par rapport à H2-H4)",
"h2Label": "En-tête magique réponse (H2)",
"h2Description": "Valeur d'en-tête du paquet réponse (5-2147483647, doit être unique par rapport à H1, H3, H4)",
"h3Label": "En-tête magique cookie reply (H3)",
"h3Description": "Valeur d'en-tête du paquet cookie reply (5-2147483647, doit être unique par rapport à H1, H2, H4)",
"h4Label": "En-tête magique transport (H4)",
"h4Description": "Valeur d'en-tête du paquet transport (5-2147483647, doit être unique par rapport à H1-H3)",
"mtuNote": "Les valeurs dépendent du MTU",
"obfuscationParameters": "Paramètres d'obfuscation AmneziaWG"
} }
} }
+145
View File
@@ -0,0 +1,145 @@
{
"pages": {
"me": "Conta",
"clients": "Clientes",
"admin": {
"panel": "Panel de administración",
"general": "Xeral",
"config": "Configuración",
"interface": "Interface",
"hooks": "Hooks"
}
},
"user": {
"email": "Correo electrónico"
},
"me": {
"currentPassword": "Contrasinal actual",
"enable2fa": "Activar a autenticación de dobre factor",
"enable2faDesc": "Escanea o código QR coa túa aplicación de autenticación ou introduce a chave manualmente.",
"2faKey": "Chave TOTP",
"2faCodeDesc": "Introduce o código da túa aplicación de autenticación.",
"disable2fa": "Desactivar a autenticación de dobre factor",
"disable2faDesc": "Introduce o teu contrasinal para desactivar a autenticación de dobre factor."
},
"general": {
"name": "Nome",
"username": "Nome de usuario",
"password": "Contrasinal",
"newPassword": "Novo contrasinal",
"updatePassword": "Actualizar contrasinal",
"mtu": "MTU",
"allowedIps": "IP permitidas",
"dns": "DNS",
"persistentKeepalive": "Keepalive persistente",
"logout": "Pechar sesión",
"continue": "Continuar",
"host": "Host",
"port": "Porto",
"yes": "Si",
"no": "Non",
"confirmPassword": "Confirmar o contrasinal",
"loading": "Cargando...",
"2fa": "Autenticación de dobre factor",
"2faCode": "Código TOTP"
},
"setup": {
"welcome": "Benvido á túa primeira configuración de wg-easy",
"welcomeDesc": "Atopaches a forma máis doada de instalar e xestionar WireGuard en calquera sistema Linux",
"existingSetup": "Tes unha configuración existente?",
"createAdminDesc": "Por favor, introduce primeiro un usuario administrador cun contrasinal seguro. Esta información empregarase para acceder ao panel de administración.",
"setupConfigDesc": "Por favor, introduce a información do host e do porto. Isto empregarase para a configuración dos clientes ao configurar WireGuard nos seus dispositivos.",
"setupMigrationDesc": "Por favor, fornece o ficheiro da copia de seguridade se queres migrar os datos da túa versión anterior de wg-easy á nova configuración.",
"upload": "Subir",
"migration": "Recuperar a copia de seguridade:",
"createAccount": "Crear conta",
"successful": "Configuración completada con éxito",
"hostDesc": "Nome de host público ao que se conectarán os clientes",
"portDesc": "Porto UDP público ao que se conectarán os clientes e no que escoitará WireGuard"
},
"update": {
"updateAvailable": "Hai unha actualización dispoñible!",
"update": "Actualizar"
},
"theme": {
"dark": "Tema escuro",
"light": "Tema claro",
"system": "Tema do sistema"
},
"layout": {
"toggleCharts": "Amosar/Ocultar gráficas",
"donate": "Doar"
},
"login": {
"signIn": "Iniciar sesión",
"rememberMe": "Lembrarme",
"rememberMeDesc": "Manter a sesión iniciada ao pechar o navegador",
"insecure": "Non podes iniciar sesión cunha conexión insegura. Usa HTTPS.",
"2faRequired": "É necesaria a autenticación de dobre factor",
"2faWrong": "A autenticación de dobre factor é incorrecta"
},
"client": {
"empty": "Aínda non hai clientes.",
"newShort": "Novo",
"sort": "Ordenar",
"create": "Crear cliente",
"created": "Cliente creado",
"new": "Novo cliente",
"name": "Nome",
"expireDate": "Data de caducidade",
"expireDateDesc": "Data na que o cliente será desactivado. Déixao en branco para permanente",
"delete": "Eliminar",
"deleteClient": "Eliminar cliente",
"deleteDialog1": "Seguro que queres eliminar",
"deleteDialog2": "Esta acción non se pode desfacer.",
"enabled": "Activado",
"address": "Enderezo",
"serverAllowedIps": "IP permitidas polo servidor",
"otlDesc": "Xerar ligazón curta dun só uso",
"permanent": "Permanente",
"createdOn": "Creado o ",
"lastSeen": "Visto por última vez o ",
"totalDownload": "Descarga total: ",
"totalUpload": "Subida total: ",
"newClient": "Novo cliente",
"disableClient": "Desactivar cliente",
"enableClient": "Activar cliente",
"noPrivKey": "Este cliente non ten unha chave privada coñecida. Non se pode crear a configuración.",
"showQR": "Amosar código QR",
"downloadConfig": "Descargar configuración",
"allowedIpsDesc": "IP que se encamiñarán a través da VPN (sobrescribe a configuración global)",
"serverAllowedIpsDesc": "IP que o servidor encamiñará ao cliente",
"mtuDesc": "Define a unidade máxima de transmisión (tamaño do paquete) para o túnel VPN",
"persistentKeepaliveDesc": "Define o intervalo (en segundos) para os paquetes keep-alive. 0 desactívaos",
"hooks": "Hooks",
"hooksDescription": "Os hooks só funcionan con wg-quick",
"hooksLeaveEmpty": "Só para wg-quick. Noutro caso, déixao baleiro",
"dnsDesc": "Servidor DNS que empregarán os clientes (sobrescribe a configuración global)",
"notConnected": "Cliente non conectado",
"endpoint": "Punto final",
"endpointDesc": "IP do cliente desde a que se establece a conexión WireGuard",
"search": "Buscar clientes...",
"config": "Configuración",
"viewConfig": "Ver configuración"
},
"dialog": {
"change": "Cambiar",
"cancel": "Cancelar",
"create": "Crear"
},
"toast": {
"success": "Éxito",
"saved": "Gardado",
"error": "Erro"
},
"form": {
"actions": "Accións",
"save": "Gardar",
"revert": "Reverter",
"sectionGeneral": "Xeral",
"sectionAdvanced": "Avanzado",
"noItems": "Sen elementos",
"nullNoItems": "Sen elementos. Usando a configuración global",
"add": "Engadir"
}
}
+286
View File
@@ -0,0 +1,286 @@
{
"pages": {
"me": "Konto",
"clients": "Klienter",
"admin": {
"panel": "Adminpanel",
"general": "Generelt",
"config": "Oppsett",
"interface": "Grensesnitt",
"hooks": "Hooks"
}
},
"user": {
"email": "E-post"
},
"me": {
"currentPassword": "Nåværende passord",
"enable2fa": "Aktiver tofaktorautentisering",
"enable2faDesc": "Skann QR-koden med autentiseringsappen din eller skriv inn nøkkelen manuelt.",
"2faKey": "TOTP-nøkkel",
"2faCodeDesc": "Skriv inn koden fra autentiseringsappen din.",
"disable2fa": "Deaktiver tofaktorautentisering",
"disable2faDesc": "Skriv inn passordet ditt for å deaktivere tofaktorautentisering."
},
"general": {
"name": "Navn",
"username": "Brukernavn",
"password": "Passord",
"newPassword": "Nytt passord",
"updatePassword": "Oppdater passord",
"mtu": "MTU",
"allowedIps": "Tillatte IP-er",
"dns": "DNS",
"persistentKeepalive": "Vedvarende keepalive",
"logout": "Logg ut",
"continue": "Fortsett",
"host": "Vert",
"port": "Port",
"yes": "Ja",
"no": "Nei",
"confirmPassword": "Bekreft passord",
"loading": "Laster...",
"2fa": "Tofaktorautentisering",
"2faCode": "TOTP-kode"
},
"setup": {
"welcome": "Velkommen til ditt oppsett av wg-easy",
"welcomeDesc": "Du har funnet den enkleste måten å installere og administrere WireGuard på en hvilken som helst Linux-vert",
"existingSetup": "Har du et eksisterende oppsett?",
"createAdminDesc": "Skriv først inn et adminbrukernavn og et sterkt, sikkert passord. Denne informasjonen brukes til å logge inn i administrasjonspanelet.",
"setupConfigDesc": "Skriv inn vert- og portinformasjon. Dette brukes til klientkonfigurasjonen når du setter opp WireGuard på enhetene deres.",
"setupMigrationDesc": "Oppgi sikkerhetskopifilen hvis du vil migrere dataene dine fra forrige wg-easy-versjon til det nye oppsettet.",
"upload": "Last opp",
"migration": "Gjenopprett sikkerhetskopien:",
"createAccount": "Opprett konto",
"successful": "Oppsett vellykket",
"hostDesc": "Offentlig vertsnavn klienter vil koble seg til",
"portDesc": "Offentlig UDP-port klienter vil koble til og WireGuard vil lytte på"
},
"update": {
"updateAvailable": "En oppdatering er tilgjengelig!",
"update": "Oppdater"
},
"theme": {
"dark": "Mørkt tema",
"light": "Lyst tema",
"system": "Systemtema"
},
"layout": {
"toggleCharts": "Vis/skjul diagrammer",
"donate": "Doner"
},
"login": {
"signIn": "Logg inn",
"rememberMe": "Husk meg",
"rememberMeDesc": "Hold deg innlogget etter at nettleseren lukkes",
"insecure": "Du kan ikke logge inn med en usikker tilkobling. Bruk HTTPS.",
"2faRequired": "Tofaktorautentisering er påkrevd",
"2faWrong": "Tofaktorautentisering er feil"
},
"client": {
"empty": "Det finnes ingen klienter ennå.",
"newShort": "Ny",
"sort": "Sorter",
"create": "Opprett klient",
"created": "Klient opprettet",
"new": "Ny klient",
"name": "Navn",
"expireDate": "Utløpsdato",
"expireDateDesc": "Datoen klienten blir deaktivert. Tomt for permanent",
"delete": "Slett",
"deleteClient": "Slett klient",
"deleteDialog1": "Er du sikker på at du vil slette",
"deleteDialog2": "Denne handlingen kan ikke angres.",
"enabled": "Aktivert",
"address": "Adresse",
"serverAllowedIps": "Server tillatte IP-er",
"otlDesc": "Generer kort engangslenke",
"permanent": "Permanent",
"createdOn": "Opprettet ",
"lastSeen": "Sist sett ",
"totalDownload": "Totalt nedlastet: ",
"totalUpload": "Totalt opplastet: ",
"newClient": "Ny klient",
"disableClient": "Deaktiver klient",
"enableClient": "Aktiver klient",
"noPrivKey": "Denne klienten har ingen kjent privat nøkkel. Kan ikke opprette konfigurasjon.",
"showQR": "Vis QR-kode",
"downloadConfig": "Last ned konfigurasjon",
"allowedIpsDesc": "Hvilke IP-er som rutes gjennom VPN (overstyrer global konfig)",
"serverAllowedIpsDesc": "Hvilke IP-er serveren ruter til klienten",
"mtuDesc": "Setter maksimal overføringsenhet (pakkestørrelse) for VPN-tunnelen",
"persistentKeepaliveDesc": "Setter intervallet (i sekunder) for keepalive-pakker. 0 deaktiverer det",
"hooks": "Hooks",
"hooksDescription": "Hooks fungerer bare med wg-quick",
"hooksLeaveEmpty": "Kun for wg-quick. Ellers la det være tomt",
"dnsDesc": "DNS-server klienter vil bruke (overstyrer global konfig)",
"notConnected": "Klient ikke tilkoblet",
"endpoint": "Endepunkt",
"endpointDesc": "IP-en til klienten som WireGuard-tilkoblingen etableres fra",
"search": "Søk etter klienter...",
"config": "Konfigurasjon",
"viewConfig": "Vis konfigurasjon"
},
"dialog": {
"change": "Endre",
"cancel": "Avbryt",
"create": "Opprett"
},
"toast": {
"success": "Vellykket",
"saved": "Lagret",
"error": "Feil"
},
"form": {
"actions": "Handlinger",
"save": "Lagre",
"revert": "Tilbakestill",
"sectionGeneral": "Generelt",
"sectionAdvanced": "Avansert",
"noItems": "Ingen elementer",
"nullNoItems": "Ingen elementer. Bruker global konfig",
"add": "Legg til"
},
"admin": {
"general": {
"sessionTimeout": "Øktutløp",
"sessionTimeoutDesc": "Øktvarighet for Husk meg (sekunder)",
"metrics": "Målinger",
"metricsPassword": "Passord",
"metricsPasswordDesc": "Bearer-passord for metrics-endepunktet (passord eller argon2-hash)",
"json": "JSON",
"jsonDesc": "Rute for metrics i JSON-format",
"prometheus": "Prometheus",
"prometheusDesc": "Rute for Prometheus-målinger"
},
"config": {
"connection": "Tilkobling",
"hostDesc": "Offentlig vertsnavn klienter vil koble til (ugyldiggjør konfig)",
"portDesc": "Offentlig UDP-port klienter vil koble til (ugyldiggjør konfig, du vil sannsynligvis også endre Grensesnitt-port)",
"allowedIpsDesc": "Tillatte IP-er klienter vil bruke (global konfig)",
"dnsDesc": "DNS-server klienter vil bruke (global konfig)",
"mtuDesc": "MTU klienter vil bruke (kun for nye klienter)",
"persistentKeepaliveDesc": "Intervall i sekunder for å sende keepalives til serveren. 0 = deaktivert (kun for nye klienter)",
"suggest": "Foreslå",
"suggestDesc": "Velg en IP-adresse eller et vertsnavn for Vert-feltet"
},
"interface": {
"cidrSuccess": "CIDR endret",
"device": "Enhet",
"deviceDesc": "Ethernet-enhet som WireGuard-trafikken skal videresendes gjennom",
"mtuDesc": "MTU WireGuard vil bruke",
"portDesc": "UDP-port WireGuard vil lytte på (du vil sannsynligvis også endre Konfig-port)",
"changeCidr": "Endre CIDR",
"restart": "Start grensesnitt på nytt",
"restartDesc": "Start WireGuard-grensesnittet på nytt",
"restartWarn": "Er du sikker på at du vil starte grensesnittet på nytt? Dette vil koble fra alle klienter.",
"restartSuccess": "Grensesnitt startet på nytt"
},
"introText": "Velkommen til adminpanelet.\n\nHer kan du administrere de generelle innstillingene, konfigurasjonen, grensesnittinnstillingene og hooks.\n\nStart med å velge en av seksjonene i sidepanelet."
},
"zod": {
"generic": {
"required": "{0} er påkrevd",
"validNumber": "{0} må være et gyldig tall",
"validString": "{0} må være en gyldig streng",
"validBoolean": "{0} må være en gyldig boolsk verdi",
"validArray": "{0} må være en gyldig liste",
"stringMin": "{0} må være minst {1} tegn",
"numberMin": "{0} må være minst {1}"
},
"client": {
"id": "Klient-ID",
"name": "Navn",
"expiresAt": "Utløper",
"address4": "IPv4-adresse",
"address6": "IPv6-adresse",
"serverAllowedIps": "Server tillatte IP-er"
},
"user": {
"username": "Brukernavn",
"password": "Passord",
"remember": "Husk",
"name": "Navn",
"email": "E-post",
"emailInvalid": "E-post må være en gyldig e-postadresse",
"passwordMatch": "Passord må være like",
"totpEnable": "TOTP aktivert",
"totpEnableTrue": "TOTP aktivert må være sant",
"totpCode": "TOTP-kode"
},
"userConfig": {
"host": "Vert"
},
"general": {
"sessionTimeout": "Øktutløp",
"metricsEnabled": "Målinger",
"metricsPassword": "Målingspassord"
},
"interface": {
"cidr": "CIDR",
"device": "Enhet",
"cidrValid": "CIDR må være gyldig"
},
"otl": "Engangslenke",
"stringMalformed": "Strengen er ugyldig",
"body": "Innholdet må være et gyldig objekt",
"hook": "Hook",
"enabled": "Aktivert",
"mtu": "MTU",
"port": "Port",
"persistentKeepalive": "Vedvarende keepalive",
"address": "IP-adresse",
"dns": "DNS",
"allowedIps": "Tillatte IP-er",
"file": "Fil"
},
"hooks": {
"preUp": "PreUp",
"postUp": "PostUp",
"preDown": "PreDown",
"postDown": "PostDown"
},
"copy": {
"notSupported": "Kopiering støttes ikke",
"copied": "Kopiert!",
"failed": "Kopiering mislyktes",
"copy": "Kopier"
},
"awg": {
"jCLabel": "Antall junk-pakker (Jc)",
"jCDescription": "Antall junk-pakker som skal sendes (1-128, anbefalt: 4-12)",
"jMinLabel": "Min. størrelse på junk-pakker (Jmin)",
"jMinDescription": "Minimum størrelse på junk-pakker (0-1279*, anbefalt: 8, må være < Jmax)",
"jMaxLabel": "Maks. størrelse på junk-pakker (Jmax)",
"jMaxDescription": "Maksimal størrelse på junk-pakker (1-1280*, anbefalt: 80, må være > Jmin)",
"s1Label": "Init-pakke junk-størrelse (S1)",
"s1Description": "Init-pakke junk-størrelse (0-1132[1280* - 148 = 1132], anbefalt: 15-150, S1+56 ≠ S2)",
"s2Label": "Svarpakke junk-størrelse (S2)",
"s2Description": "Svarpakke junk-størrelse (0-1188[1280* - 92 = 1188], anbefalt: 15-150)",
"s3Label": "Cookie-svarpakke junk-størrelse (S3)",
"s3Description": "Cookie-svarpakke junk-størrelse",
"s4Label": "Transportpakke junk-størrelse (S4)",
"s4Description": "Transportpakke junk-størrelse",
"i1Label": "Spesiell junk-pakke 1 (I1)",
"i1Description": "Protokolllignende pakke i heksformat: <b 0x...>",
"i2Label": "Spesiell junk-pakke 2 (I2)",
"i2Description": "Protokolllignende pakke i heksformat: <b 0x...>",
"i3Label": "Spesiell junk-pakke 3 (I3)",
"i3Description": "Protokolllignende pakke i heksformat: <b 0x...>",
"i4Label": "Spesiell junk-pakke 4 (I4)",
"i4Description": "Protokolllignende pakke i heksformat: <b 0x...>",
"i5Label": "Spesiell junk-pakke 5 (I5)",
"i5Description": "Protokolllignende pakke i heksformat: <b 0x...>",
"h1Label": "Init magisk header (H1)",
"h1Description": "Init-pakke header-verdi (5-2147483647, må være unik fra H2-H4)",
"h2Label": "Svar magisk header (H2)",
"h2Description": "Svarpakke header-verdi (5-2147483647, må være unik fra H1, H3, H4)",
"h3Label": "Cookie-svar magisk header (H3)",
"h3Description": "Cookie-svarpakke header-verdi (5-2147483647, må være unik fra H1, H2, H4)",
"h4Label": "Transport magisk header (H4)",
"h4Description": "Transportpakke header-verdi (5-2147483647, må være unik fra H1-H3)",
"mtuNote": "Verdier avhenger av MTU",
"obfuscationParameters": "AmneziaWG obfuskasjonsparametere"
}
}
+286
View File
@@ -0,0 +1,286 @@
{
"pages": {
"me": "Account",
"clients": "Cliënten",
"admin": {
"panel": "Admin-paneel",
"general": "Algemeen",
"config": "Config",
"interface": "Interface",
"hooks": "Hooks"
}
},
"user": {
"email": "E-mail"
},
"me": {
"currentPassword": "Huidig wachtwoord",
"enable2fa": "Twee-factor-authenticatie inschakelen",
"enable2faDesc": "Scan de QR-code met uw authenticator-app of voer de sleutel handmatig in.",
"2faKey": "TOTP-sleutel",
"2faCodeDesc": "Voer de code in van uw authenticator-app.",
"disable2fa": "Twee-factor-authenticatie uitschakelen",
"disable2faDesc": "Voer uw wachtwoord in om de twee-factor-authenticatie uit te schakelen."
},
"general": {
"name": "Naam",
"username": "Gebruikersnaam",
"password": "Wachtwoord",
"newPassword": "Nieuw wachtwoord",
"updatePassword": "Wachtwoord bijwerken",
"mtu": "MTU",
"allowedIps": "Toegestane IP's",
"dns": "DNS",
"persistentKeepalive": "Aanhoudende verbinding",
"logout": "Uitloggen",
"continue": "Doorgaan",
"host": "Host",
"port": "Port",
"yes": "Ja",
"no": "Nee",
"confirmPassword": "Wachtwoord bevestigen",
"loading": "Laden...",
"2fa": "Twee-factor-authenticatie uitschakelen",
"2faCode": "TOTP-code"
},
"setup": {
"welcome": "Welkom bij uw eerste installatie van wg-easy",
"welcomeDesc": "U hebt de gemakkelijkste manier gevonden om WireGuard op elke Linux-host te installeren en te beheren",
"existingSetup": "Heeft u een bestaande installatie?",
"createAdminDesc": "Voer eerst een beheerdersgebruikersnaam en een sterk veilig wachtwoord in. Deze gegevens worden gebruikt om in te loggen op uw beheerderspaneel.",
"setupConfigDesc": "Voer alstublieft de host- en poortinformatie in. Dit wordt gebruikt voor de clientconfiguratie bij het instellen van WireGuard op hun apparaten.",
"setupMigrationDesc": "Geef alstublieft het back-upbestand als u uw gegevens van uw vorige wg-easy-versie naar uw nieuwe installatie wilt overzetten.",
"upload": "Uploaden",
"migration": "Herstel de back-up:",
"createAccount": "Account aanmaken",
"successful": "Installatie succesvol",
"hostDesc": "Publieke hostnaam waar clients verbinding mee maken",
"portDesc": "Publieke UDP-poort waarop clients verbinding maken en waarop WireGuard luistert"
},
"update": {
"updateAvailable": "Er is een update beschikbaar!",
"update": "Bijwerken"
},
"theme": {
"dark": "Donker thema",
"light": "Licht thema",
"system": "Systeem-thema"
},
"layout": {
"toggleCharts": "Grafieken tonen/verbergen",
"donate": "Donatie"
},
"login": {
"signIn": "Inloggen",
"rememberMe": "Onthoud mij",
"rememberMeDesc": "Ingelogd blijven na het sluiten van de browser",
"insecure": "U kunt niet inloggen via een onveilige verbinding. Gebruik HTTPS.",
"2faRequired": "Twee-factor-authenticatie is vereist",
"2faWrong": "Twee-factor-authenticatiecode is fout"
},
"client": {
"empty": "Er zijn nog geen cliënten.",
"newShort": "Nieuw",
"sort": "Sortering",
"create": "Cliënt aanmaken",
"created": "Cliënt aangemaakt",
"new": "Nieuwe cliënt",
"name": "Naam",
"expireDate": "Verloopdatum",
"expireDateDesc": "Datum waarop de cliënt wordt uitgeschakeld. Laat leeg voor permanent.",
"delete": "Verwijderen",
"deleteClient": "Cliënt verwijderen",
"deleteDialog1": "Weet u zeker dat u wilt verwijderen",
"deleteDialog2": "Deze actie kan niet ongedaan worden gemaakt.",
"enabled": "Ingeschakeld",
"address": "Adres",
"serverAllowedIps": "Toegestane IP's van de server",
"otlDesc": "Korte eenmalige link genereren",
"permanent": "Permanent",
"createdOn": "Aangemaakt op ",
"lastSeen": "Laatst gezien op ",
"totalDownload": "Totaal gedownload: ",
"totalUpload": "Totaal geüpload: ",
"newClient": "Nieuwe cliënt",
"disableClient": "Cliënt uitschakelen",
"enableClient": "Cliënt inschakelen",
"noPrivKey": "Deze cliënt heeft geen bekende privésleutel. Kan de configuratie niet aanmaken.",
"showQR": "QR-code weergeven",
"downloadConfig": "Configuratie downloaden",
"allowedIpsDesc": "Welke IP's via de VPN worden geleid (overschrijft algemene instellingen)",
"serverAllowedIpsDesc": "Naar welke IP's de server het cliëntverkeer zal routeren",
"mtuDesc": "Stelt de maximale transmissie-eenheid (pakketgrootte) voor de VPN-tunnel in",
"persistentKeepaliveDesc": "Stelt het interval (seconden) in voor keep-alive-pakketten. 0 schakelt dit uit",
"hooks": "Hooks",
"hooksDescription": "Hooks functioneren alleen met wg-quick",
"hooksLeaveEmpty": "Alleen voor wg-quick. Anders leeg laten",
"dnsDesc": "DNS-serverclients zullen gebruiken (overschrijft algemene instellingen)",
"notConnected": "Cliënt niet verbonden",
"endpoint": "Eindpunt",
"endpointDesc": "IP van de cliënt vanaf welke de WireGuard-verbinding tot stand wordt gebracht",
"search": "Cliënten zoeken...",
"config": "Configuratie",
"viewConfig": "Configuratie weergeven"
},
"dialog": {
"change": "Wijzigen",
"cancel": "Annuleren",
"create": "Aanmaken"
},
"toast": {
"success": "Succes",
"saved": "Opgeslagen",
"error": "Fout"
},
"form": {
"actions": "Acties",
"save": "Opslaan",
"revert": "Terugzetten",
"sectionGeneral": "Algemeen",
"sectionAdvanced": "Geavanceerd",
"noItems": "Geen items",
"nullNoItems": "Geen items. Globale configuratie gebruiken",
"add": "Toevoegen"
},
"admin": {
"general": {
"sessionTimeout": "Sessie verlopen",
"sessionTimeoutDesc": "Sessieduur voor Onthoud mij (sec.)",
"metrics": "Metrics",
"metricsPassword": "Wachtwoord",
"metricsPasswordDesc": "Bearer-wachtwoord voor het metrics-eindpunt (wachtwoord of argon2-hash)",
"json": "JSON",
"jsonDesc": "Route voor metrics in JSON-formaat",
"prometheus": "Prometheus",
"prometheusDesc": "Route voor Prometheus-metrics"
},
"config": {
"connection": "Verbinding",
"hostDesc": "Publieke hostnaam waarmee cliënten verbinding maken (maakt configuratie ongedaan)",
"portDesc": "Publieke UDP-poort waarmee clients verbinding maken (maakt configuratie ongedaan; u dient waarschijnlijk ook de interfacepoort te wijzigen)",
"allowedIpsDesc": "Toegestane IP's die cliënten zullen gebruiken (algemene configuratie)",
"dnsDesc": "DNS-server die cliënten zullen gebruiken (algemene configuratie)",
"mtuDesc": "MTU die cliënten zullen gebruiken (alleen voor nieuwe cliënten)",
"persistentKeepaliveDesc": "Interval in seconden om keepalives naar de server te sturen. 0 = uitgeschakeld (alleen voor nieuwe cliënten)",
"suggest": "Voorstellen",
"suggestDesc": "Kies een IP-adres of hostnaam voor het veld Host"
},
"interface": {
"cidrSuccess": "CIDR gewijzigd",
"device": "Apparaat",
"deviceDesc": "Ethernet-apparaat waar het WireGuard-verkeer doorheen moet worden doorgestuurd",
"mtuDesc": "MTU die WireGuard zal toepassen",
"portDesc": "UDP-poort waarop WireGuard zal luisteren (u dient waarschijnlijk ook de Config-poort te wijzigen)",
"changeCidr": "CIDR wijzigen",
"restart": "Interface opnieuw starten",
"restartDesc": "WireGuard-interface opnieuw starten",
"restartWarn": "Weet u zeker dat u de interface wilt herstarten? Dit zal alle cliënten loskoppelen.",
"restartSuccess": "Interface opnieuw gestart"
},
"introText": "Welkom bij het Admin-paneel.\n\nHier kunt u de algemene instellingen, de configuratie, de interface-instellingen en de hooks beheren.\n\nBegin met het kiezen van een van de secties in de zijbalk."
},
"zod": {
"generic": {
"required": "{0} is vereist",
"validNumber": "{0} moet een geldig nummer zijn",
"validString": "{0} moet een geldige tekenreeks zijn",
"validBoolean": "{0} moet een geldige boolean zijn",
"validArray": "{0} moet een geldige array zijn",
"stringMin": "{0} moet minstens {1} teken bevatten",
"numberMin": "{0} moet minstens {1} zijn"
},
"client": {
"id": "Cliënt-ID",
"name": "Naam",
"expiresAt": "Verloopt op",
"address4": "IPv4-adres",
"address6": "IPv6-adres",
"serverAllowedIps": "Toegestane IP's van de server"
},
"user": {
"username": "Gebruikersnaam",
"password": "Wachtwoord",
"remember": "Onthouden",
"name": "Naam",
"email": "E-mail",
"emailInvalid": "E-mail moet een geldig e-mailadres zijn",
"passwordMatch": "Wachtwoorden moeten overeenkomen",
"totpEnable": "TOTP inschakelen",
"totpEnableTrue": "TOTP inschakelen moet waar zijn",
"totpCode": "TOTP-code"
},
"userConfig": {
"host": "Host"
},
"general": {
"sessionTimeout": "Sessie-verlooptijd",
"metricsEnabled": "Metrics",
"metricsPassword": "Metrics-wachtwoord"
},
"interface": {
"cidr": "CIDR",
"device": "Apparaat",
"cidrValid": "CIDR moet geldig zijn"
},
"otl": "Eenmalige link",
"stringMalformed": "Tekenreeks is beschadigd",
"body": "Body moet een geldig object bevatten",
"hook": "Hook",
"enabled": "Ingeschakeld",
"mtu": "MTU",
"port": "Poort",
"persistentKeepalive": "Aanhoudende verbinding",
"address": "IP-adres",
"dns": "DNS",
"allowedIps": "Toegestane IP's",
"file": "Bestand"
},
"hooks": {
"preUp": "Pre-Up",
"postUp": "Post-Up",
"preDown": "Pre-Down",
"postDown": "Post-Down"
},
"copy": {
"notSupported": "Kopiëren wordt niet ondersteund",
"copied": "Gekopieerd!",
"failed": "Kopiëren is mislukt",
"copy": "Kopiëren"
},
"awg": {
"jCLabel": "Junk packet count (Jc)",
"jCDescription": "Aantal te verzenden junk packets (1-128, aanbevolen: 4-12)",
"jMinLabel": "Junk packet min size (Jmin)",
"jMinDescription": "Minimale grootte van junk packets (0-1279*, aanbevolen: 8, moet zijn < Jmax)",
"jMaxLabel": "Junk packet max size (Jmax)",
"jMaxDescription": "Maximale grootte van junk packets (1-1280*, aanbevolen: 80, moet zijn > Jmin)",
"s1Label": "Init packet junk size (S1)",
"s1Description": "Grootte Init packet junk (0-1132[1280* - 148 = 1132], aanbevolen: 15-150, S1+56 ≠ S2)",
"s2Label": "Response packet junk size (S2)",
"s2Description": "Grootte Response packet junk (0-1188[1280* - 92 = 1188], aanbevolen: 15-150)",
"s3Label": "Cookie reply packet junk size (S3)",
"s3Description": "Grootte Cookie reply packet junk",
"s4Label": "Transport packet junk size (S4)",
"s4Description": "Grootte Transport packet junk",
"i1Label": "Special junk packet 1 (I1)",
"i1Description": "Protocol mimic packet in hex formaat: <b 0x...>",
"i2Label": "Special junk packet 2 (I2)",
"i2Description": "Protocol mimic packet in hex formaat: <b 0x...>",
"i3Label": "Special junk packet 3 (I3)",
"i3Description": "Protocol mimic packet in hex formaat: <b 0x...>",
"i4Label": "Special junk packet 4 (I4)",
"i4Description": "Protocol mimic packet in hex formaat: <b 0x...>",
"i5Label": "Special junk packet 5 (I5)",
"i5Description": "Protocol mimic packet in hex formaat: <b 0x...>",
"h1Label": "Init magic header (H1)",
"h1Description": "Waarde Init packet header (5-2147483647, moet uniek zijn t.o.v. H2-H4)",
"h2Label": "Response magic header (H2)",
"h2Description": "Waarde Response packet header (5-2147483647, moet uniek zijn t.o.v. H1, H3, H4)",
"h3Label": "Cookie reply magic header (H3)",
"h3Description": "Waarde Cookie reply packet header (5-2147483647, moet uniek zijn t.o.v. H1, H2, H4)",
"h4Label": "Transport magic header (H4)",
"h4Description": "Waarde Transport packet header (5-2147483647, moet uniek zijn t.o.v. H1-H3)",
"mtuNote": "Waarden zijn afhankelijk van de MTU",
"obfuscationParameters": "AmneziaWG Obfuscation Parameters"
}
}
+117 -71
View File
@@ -3,8 +3,8 @@
"me": "Аккаунт", "me": "Аккаунт",
"clients": "Клиенты", "clients": "Клиенты",
"admin": { "admin": {
"panel": "Админ панель", "panel": "Админ-панель",
"general": "Общие", "general": "Общие настройки",
"config": "Конфигурация", "config": "Конфигурация",
"interface": "Интерфейс", "interface": "Интерфейс",
"hooks": "Хуки" "hooks": "Хуки"
@@ -16,11 +16,11 @@
"me": { "me": {
"currentPassword": "Текущий пароль", "currentPassword": "Текущий пароль",
"enable2fa": "Включить двухфакторную аутентификацию", "enable2fa": "Включить двухфакторную аутентификацию",
"enable2faDesc": "Отсканируйте QR-код приложением-аутентификатором или введите ключ вручную.", "enable2faDesc": "Отсканируйте QRкод с помощью приложения‑аутентификатора или введите ключ вручную.",
"2faKey": "TOTP-ключ", "2faKey": "Ключ TOTP",
"2faCodeDesc": "Введите код из приложения-аутентификатора.", "2faCodeDesc": "Введите код из приложенияаутентификатора.",
"disable2fa": "Отключить двухфакторную аутентификацию", "disable2fa": "Отключить двухфакторную аутентификацию",
"disable2faDesc": "Введите пароль, чтобы отключить двухфакторную аутентификацию" "disable2faDesc": "Введите пароль, чтобы отключить двухфакторную аутентификацию."
}, },
"general": { "general": {
"name": "Имя", "name": "Имя",
@@ -29,9 +29,9 @@
"newPassword": "Новый пароль", "newPassword": "Новый пароль",
"updatePassword": "Обновить пароль", "updatePassword": "Обновить пароль",
"mtu": "MTU", "mtu": "MTU",
"allowedIps": "Разрешённые IP", "allowedIps": "Разрешённые IP‑адреса",
"dns": "DNS", "dns": "DNS",
"persistentKeepalive": "Постоянный keepalive", "persistentKeepalive": "Постоянное поддержание соединения",
"logout": "Выйти", "logout": "Выйти",
"continue": "Продолжить", "continue": "Продолжить",
"host": "Хост", "host": "Хост",
@@ -41,21 +41,21 @@
"confirmPassword": "Подтвердите пароль", "confirmPassword": "Подтвердите пароль",
"loading": "Загрузка...", "loading": "Загрузка...",
"2fa": "Двухфакторная аутентификация", "2fa": "Двухфакторная аутентификация",
"2faCode": "TOTP‑код" "2faCode": "Код TOTP"
}, },
"setup": { "setup": {
"welcome": "Добро пожаловать в первичную настройку wg-easy", "welcome": "Добро пожаловать в первичную настройку wg-easy",
"welcomeDesc": "Вы нашли самый простой способ установить и управлять WireGuard на любом Linux-хосте", "welcomeDesc": "Вы нашли самый простой способ установить и управлять WireGuard на любом Linuxхосте",
"existingSetup": "У вас уже есть существующая установка?", "existingSetup": "У вас уже есть существующая настройка?",
"createAdminDesc": "Сначала введите имя администратора и надёжный пароль. Эти данные понадобятся для входа в панель управления", "createAdminDesc": "Сначала введите имя администратора и надёжный пароль. Эти данные будут использоваться для входа в Админ-панель.",
"setupConfigDesc": "Введите информацию о хосте и порте. Она будет использоваться в конфигурации клиента при установке WireGuard на устройствах", "setupConfigDesc": "Введите данные хоста и порта. Они будут использоваться для настройки клиента при установке WireGuard на устройствах.",
"setupMigrationDesc": "Укажите файл резервной копии, если хотите перенести данные из предыдущей версии wg-easy", "setupMigrationDesc": "Укажите файл резервной копии, если хотите перенести данные из предыдущей версии wg-easy.",
"upload": "Загрузить", "upload": "Загрузить",
"migration": "Восстановить из резервной копии:", "migration": "Восстановить из резервной копии:",
"createAccount": "Создать аккаунт", "createAccount": "Создать аккаунт",
"successful": "Настройка успешна", "successful": "Настройка завершена успешно",
"hostDesc": "Публичное имя хоста, к которому будут подключаться клиенты", "hostDesc": "Публичное имя хоста, к которому будут подключаться клиенты",
"portDesc": "Публичный UDP‑порт для подключения клиентов и прослушивания WireGuard" "portDesc": "Публичный UDP‑порт, к которому будут подключаться клиенты и на котором будет слушать WireGuard"
}, },
"update": { "update": {
"updateAvailable": "Доступно обновление!", "updateAvailable": "Доступно обновление!",
@@ -68,7 +68,7 @@
}, },
"layout": { "layout": {
"toggleCharts": "Показать/скрыть графики", "toggleCharts": "Показать/скрыть графики",
"donate": "Пожертвовать" "donate": "Поддержать"
}, },
"login": { "login": {
"signIn": "Войти", "signIn": "Войти",
@@ -87,18 +87,19 @@
"new": "Новый клиент", "new": "Новый клиент",
"name": "Имя", "name": "Имя",
"expireDate": "Дата отключения", "expireDate": "Дата отключения",
"expireDateDesc": "Дата, когда клиент будет отключён. Пусто — бессрочно", "expireDateDesc": "Дата, когда клиент будет отключён. Оставьте пустым для бессрочного доступа",
"delete": "Удалить",
"deleteClient": "Удалить клиента", "deleteClient": "Удалить клиента",
"deleteDialog1": "Вы уверены, что хотите удалить", "deleteDialog1": "Вы уверены, что хотите удалить",
"deleteDialog2": "Это действие необратимо.", "deleteDialog2": "Это действие нельзя отменить.",
"enabled": "Включен", "enabled": "Включён",
"address": "Адрес", "address": "Адрес",
"serverAllowedIps": "Разрешённые IP сервера", "serverAllowedIps": "Разрешённые IP‑адреса сервера",
"otlDesc": "Сгенерировать одноразовую короткую ссылку", "otlDesc": "Сгенерировать короткую одноразовую ссылку",
"permanent": "Постоянный", "permanent": "Бессрочный",
"createdOn": "Создан ", "createdOn": "Создан ",
"lastSeen": "Последнее подключение ", "lastSeen": "Последнее подключение ",
"totalDownload": "Всего загружено: ", "totalDownload": "Всего скачано: ",
"totalUpload": "Всего отправлено: ", "totalUpload": "Всего отправлено: ",
"newClient": "Новый клиент", "newClient": "Новый клиент",
"disableClient": "Отключить клиента", "disableClient": "Отключить клиента",
@@ -106,25 +107,28 @@
"noPrivKey": "У этого клиента нет приватного ключа. Невозможно создать конфигурацию.", "noPrivKey": "У этого клиента нет приватного ключа. Невозможно создать конфигурацию.",
"showQR": "Показать QR‑код", "showQR": "Показать QR‑код",
"downloadConfig": "Скачать конфигурацию", "downloadConfig": "Скачать конфигурацию",
"allowedIpsDesc": "Какие IP будут маршрутизироваться через VPN (перезаписывает общую конфигурацию)", "allowedIpsDesc": "Какие IP‑адреса будут маршрутизироваться через VPN (переопределяет глобальную конфигурацию)",
"serverAllowedIpsDesc": "Какие IP сервер будет отправлять клиенту", "serverAllowedIpsDesc": "Какие IP‑адреса сервер будет отправлять клиенту",
"mtuDesc": "Максимальный размер пакета для VPN‑туннеля", "mtuDesc": "Максимальный размер пакета (MTU) для VPN‑туннеля",
"persistentKeepaliveDesc": "Интервал пакетов для поддержания соединения (в секундах). 0 — отключено.", "persistentKeepaliveDesc": "Устанавливает интервал (в секундах) для пакетов поддержания соединения. 0 — отключить",
"hooks": "Хуки", "hooks": "Хуки",
"hooksDescription": "Хуки работают только с wg-quick", "hooksDescription": "Хуки работают только с wgquick",
"hooksLeaveEmpty": "Только для wg-quick. Иначе оставьте пустым", "hooksLeaveEmpty": "Только для wgquick. В остальных случаях оставьте пустым",
"dnsDesc": "DNS‑сервер, который будут использовать клиенты (перезаписывает общую конфигурацию)", "dnsDesc": "DNS‑сервер, который будут использовать клиенты (переопределяет глобальную конфигурацию)",
"notConnected": "Клиент не подключен", "notConnected": "Клиент не подключен",
"endpoint": "Конечная точка", "endpoint": "Точка подключения",
"endpointDesc": "IP-адрес клиента, с которого установлено соединение WireGuard" "endpointDesc": "IPадрес клиента, с которого установлено соединение WireGuard",
"search": "Поиск клиентов...",
"config": "Конфигурация",
"viewConfig": "Просмотреть конфигурацию"
}, },
"dialog": { "dialog": {
"change": "Изменить", "change": "Изменить",
"cancel": "Отмена", "cancel": "Отменить",
"create": "Создать" "create": "Создать"
}, },
"toast": { "toast": {
"success": "Успех", "success": "Успешно",
"saved": "Сохранено", "saved": "Сохранено",
"error": "Ошибка" "error": "Ошибка"
}, },
@@ -133,18 +137,18 @@
"save": "Сохранить", "save": "Сохранить",
"revert": "Отменить", "revert": "Отменить",
"sectionGeneral": "Общие", "sectionGeneral": "Общие",
"sectionAdvanced": "Дополнительно", "sectionAdvanced": "Расширенные",
"noItems": "Нет элементов", "noItems": "Нет элементов",
"nullNoItems": "Нет элементов. Используется глобальная конфигурация", "nullNoItems": "Нет элементов. Используется глобальная конфигурация",
"add": "Добавить" "add": "Добавить"
}, },
"admin": { "admin": {
"general": { "general": {
"sessionTimeout": "Тайм-аут сессии", "sessionTimeout": "Время жизни сессии",
"sessionTimeoutDesc": "Длительность сеанса для \"Запомнить меня\" (секунды)", "sessionTimeoutDesc": "Длительность сессии для «Запомнить меня» (в секундах)",
"metrics": "Метрики", "metrics": "Метрики",
"metricsPassword": "Пароль", "metricsPassword": "Пароль",
"metricsPasswordDesc": "Пароль Bearer для эндпоинта метрик (пароль или хеш argon2)", "metricsPasswordDesc": "Пароль Bearer для конечной точки метрик (пароль или хэш argon2)",
"json": "JSON", "json": "JSON",
"jsonDesc": "Путь для метрик в формате JSON", "jsonDesc": "Путь для метрик в формате JSON",
"prometheus": "Prometheus", "prometheus": "Prometheus",
@@ -152,83 +156,83 @@
}, },
"config": { "config": {
"connection": "Соединение", "connection": "Соединение",
"hostDesc": "Публичное имя хоста для подключения клиентов (сбросит конфигурацию)", "hostDesc": "Публичное имя хоста для подключения клиентов(обнуляет конфигурацию)",
"portDesc": "Публичный UDP‑порт для подключения клиентов (также стоит изменить порт интерфейса)", "portDesc": "Публичный UDP‑порт для подключения клиентов (также рекомендуется изменить порт интерфейса)",
"allowedIpsDesc": "Разрешённые IP для клиентов (общая конфигурация)", "allowedIpsDesc": "Разрешённые IP‑адреса для клиентов(глобальная конфигурация)",
"dnsDesc": "DNS‑сервер для клиентов (общая конфигурация)", "dnsDesc": "DNS‑сервер для клиентов (глобальная конфигурация)",
"mtuDesc": "MTU для клиентов (только для новых)", "mtuDesc": "MTU для клиентов (только для новых)",
"persistentKeepaliveDesc": "Интервал отправки keepalive на сервер (секунды). 0 = отключено (только для новых)", "persistentKeepaliveDesc": "Интервал в секундах для отправки пакетов поддержания соединения на сервер. 0 = отключено (только для новых клиентов)",
"suggest": "Определить", "suggest": "Предложить",
"suggestDesc": "Выберите IP‑адрес или имя хоста для поля Host" "suggestDesc": "Выберите IP‑адрес или имя хоста для поля «Хост»"
}, },
"interface": { "interface": {
"cidrSuccess": "CIDR изменён", "cidrSuccess": "CIDR изменён",
"device": "Устройство", "device": "Устройство",
"deviceDesc": "Сетевое устройство, через которое должен проходить трафик WireGuard", "deviceDesc": "Сетевое устройство Ethernet, через которое должен проходить трафик WireGuard",
"mtuDesc": "MTU, который использует WireGuard", "mtuDesc": "MTU, который будет использовать WireGuard",
"portDesc": "UDP‑порт, на котором WireGuard будет слушать (возможно, нужно изменить и порт конфигурации)", "portDesc": "UDP‑порт, на котором будет слушать WireGuard (возможно, нужно также изменить порт конфигурации)",
"changeCidr": "Изменить CIDR", "changeCidr": "Изменить CIDR",
"restart": "Перезапустить интерфейс", "restart": "Перезапустить интерфейс",
"restartDesc": "Перезапустить интерфейс WireGuard", "restartDesc": "Перезапустить интерфейс WireGuard",
"restartWarn": "Вы уверены, что хотите перезапустить интерфейс? Все клиенты будут отключены.", "restartWarn": "Вы уверены, что хотите перезапустить интерфейс? Это приведёт к отключению всех клиентов.",
"restartSuccess": "Интерфейс перезапущен" "restartSuccess": "Интерфейс перезапущен"
}, },
"introText": "Добро пожаловать в панель администратора.\n\nЗдесь вы можете управлять общими настройками, конфигурацией, параметрами интерфейса и хуками.\n\nНачните с выбора раздела в боковой панели." "introText": "Добро пожаловать в панель администратора.\n\nЗдесь вы можете управлять общими настройками, конфигурацией, настройками интерфейса и хуками.\n\nНачните с выбора одного из разделов на боковой панели."
}, },
"zod": { "zod": {
"generic": { "generic": {
"required": "{0} обязательное поле", "required": "{0} обязательно для заполнения",
"validNumber": "{0} должен быть числом", "validNumber": "{0} должно быть числом",
"validString": "{0} должна быть строкой", "validString": "{0} должно быть строкой",
"validBoolean": "{0} должен быть булевым значением", "validBoolean": "{0} должно быть логическим значением",
"validArray": "{0} должен быть массивом", "validArray": "{0} должно быть массивом",
"stringMin": "{0} должен содержать не менее {1} символов", "stringMin": "{0} должно содержать не менее {1} символа",
"numberMin": "{0} должен быть не меньше {1}" "numberMin": "{0} должно быть не менее {1}"
}, },
"client": { "client": {
"id": "ID клиента", "id": "ID клиента",
"name": "Имя", "name": "Имя",
"expiresAt": ействителен до", "expiresAt": ата окончания действия",
"address4": "IPv4 адрес", "address4": "IPv4адрес",
"address6": "IPv6 адрес", "address6": "IPv6адрес",
"serverAllowedIps": "Разрешённые IP сервера" "serverAllowedIps": "Разрешённые IP‑адреса сервера"
}, },
"user": { "user": {
"username": "Имя пользователя", "username": "Имя пользователя",
"password": "Пароль", "password": "Пароль",
"remember": "Запомнить", "remember": "Запомнить",
"name": "Имя", "name": "Имя",
"email": "Email", "email": "Электронная почта",
"emailInvalid": "Email должен быть валидным", "emailInvalid": "Адрес электронной почты должен быть корректным",
"passwordMatch": "Пароли должны совпадать", "passwordMatch": "Пароли должны совпадать",
"totpEnable": "Включить TOTP", "totpEnable": "Включить TOTP",
"totpEnableTrue": "Необходимо включить TOTP", "totpEnableTrue": "TOTP должен быть включён",
"totpCode": "TOTP‑код" "totpCode": "Код TOTP"
}, },
"userConfig": { "userConfig": {
"host": "Хост" "host": "Хост"
}, },
"general": { "general": {
"sessionTimeout": "Тайм-аут сессии", "sessionTimeout": "Время жизни сессии",
"metricsEnabled": "Метрики", "metricsEnabled": "Метрики",
"metricsPassword": "Пароль для метрик" "metricsPassword": "Пароль для метрик"
}, },
"interface": { "interface": {
"cidr": "CIDR", "cidr": "CIDR",
"device": "Устройство", "device": "Устройство",
"cidrValid": "CIDR должен быть валидным" "cidrValid": "CIDR должен быть корректным"
}, },
"otl": "Одноразовая ссылка", "otl": "Одноразовая ссылка",
"stringMalformed": "Строка имеет неверный формат", "stringMalformed": "Строка имеет неверный формат",
"body": "Тело должно быть объектом", "body": "Тело должно быть корректным объектом",
"hook": "Хук", "hook": "Хук",
"enabled": "Включено", "enabled": "Включено",
"mtu": "MTU", "mtu": "MTU",
"port": "Порт", "port": "Порт",
"persistentKeepalive": "Поддерживать соединение", "persistentKeepalive": "Постоянное поддержание соединения",
"address": "IP‑адрес", "address": "IP‑адрес",
"dns": "DNS", "dns": "DNS",
"allowedIps": "Разрешённые IP", "allowedIps": "Разрешённые IP‑адреса",
"file": "Файл" "file": "Файл"
}, },
"hooks": { "hooks": {
@@ -236,5 +240,47 @@
"postUp": "PostUp", "postUp": "PostUp",
"preDown": "PreDown", "preDown": "PreDown",
"postDown": "PostDown" "postDown": "PostDown"
},
"copy": {
"notSupported": "Копирование не поддерживается",
"copied": "Скопировано!",
"failed": "Ошибка копирования",
"copy": "Копировать"
},
"awg": {
"jCLabel": "Количество мусорных пакетов (Jc)",
"jCDescription": "Число мусорных пакетов для отправки (1-128, рекомендуется: 4-12)",
"jMinLabel": "Минимальный размер мусорных пакетов (Jmin)",
"jMinDescription": "Минимальный размер мусорных пакетов (0-1279*, рекомендуется: 8, должен быть < Jmax)",
"jMaxLabel": "Максимальный размер мусорных пакетов (Jmax)",
"jMaxDescription": "Максимальный размер мусорных пакетов (1-1280*, рекомендуется: 80, должен быть > Jmin)",
"s1Label": "Размер мусорных данных в init-пакете (S1)",
"s1Description": "Размер мусорных данных в init-пакете (0-1132[1280* - 148 = 1132], рекомендуется: 15-150, S1+56 ≠ S2)",
"s2Label": "Размер мусорных данных в ответном пакете (S2)",
"s2Description": "Размер мусорных данных в ответном пакете (0-1188[1280* - 92 = 1188], рекомендуется: 15-150)",
"s3Label": "Размер мусорных данных в cookie-reply пакете (S3)",
"s3Description": "Размер мусорных данных в cookie-reply пакете",
"s4Label": "Размер мусорных данных в транспортном пакете (S4)",
"s4Description": "Размер мусорных данных в транспортном пакете",
"i1Label": "Специальный мусорный пакет 1 (I1)",
"i1Description": "Пакет имитации протокола в hex формате: <b 0x...>",
"i2Label": "Специальный мусорный пакет 2 (I2)",
"i2Description": "Пакет имитации протокола в hex формате: <b 0x...>",
"i3Label": "Специальный мусорный пакет 3 (I3)",
"i3Description": "Пакет имитации протокола в hex формате: <b 0x...>",
"i4Label": "Специальный мусорный пакет 4 (I4)",
"i4Description": "Пакет имитации протокола в hex формате: <b 0x...>",
"i5Label": "Специальный мусорный пакет 5 (I5)",
"i5Description": "Пакет имитации протокола в hex формате: <b 0x...>",
"h1Label": "Init magic заголовок (H1)",
"h1Description": "Значение заголовка init-пакета (5-2147483647, должно отличаться от H2-H4)",
"h2Label": "Response magic заголовок (H2)",
"h2Description": "Значение заголовка ответного пакета (5-2147483647, должно отличаться от H1, H3, H4)",
"h3Label": "Cookie reply magic заголовок (H3)",
"h3Description": "Значение заголовка cookie-reply пакета (5-2147483647, должно отличаться от H1, H2, H4)",
"h4Label": "Transport magic заголовок (H4)",
"h4Description": "Значение заголовка транспортного пакета (5-2147483647, должно отличаться от H1-H3)",
"mtuNote": "Значения зависят от MTU",
"obfuscationParameters": "Параметры обфускации AmneziaWG"
} }
} }
+47 -1
View File
@@ -88,6 +88,7 @@
"name": "Ім'я", "name": "Ім'я",
"expireDate": "Термін дії", "expireDate": "Термін дії",
"expireDateDesc": "Дата, коли клієнт буде відключений. Порожнє для постійного користування", "expireDateDesc": "Дата, коли клієнт буде відключений. Порожнє для постійного користування",
"delete": "Видалити",
"deleteClient": "Видалити клієнта", "deleteClient": "Видалити клієнта",
"deleteDialog1": "Ви впевнені, що бажаєте видалити", "deleteDialog1": "Ви впевнені, що бажаєте видалити",
"deleteDialog2": "Цю дію неможливо скасувати.", "deleteDialog2": "Цю дію неможливо скасувати.",
@@ -116,7 +117,10 @@
"dnsDesc": "DNS сервер, який використовуватимуть клієнти (перевизначає глобальну конфігурацію)", "dnsDesc": "DNS сервер, який використовуватимуть клієнти (перевизначає глобальну конфігурацію)",
"notConnected": "Клієнт не підключений", "notConnected": "Клієнт не підключений",
"endpoint": "Кінцева точка", "endpoint": "Кінцева точка",
"endpointDesc": "IP-адреса клієнта, з якої встановлюється з’єднання WireGuard" "endpointDesc": "IP-адреса клієнта, з якої встановлюється з’єднання WireGuard",
"search": "Пошук клієнтів...",
"config": "Конфігурація",
"viewConfig": "Переглянути конфігурацію"
}, },
"dialog": { "dialog": {
"change": "Змінити", "change": "Змінити",
@@ -236,5 +240,47 @@
"postUp": "PostUp", "postUp": "PostUp",
"preDown": "PreDown", "preDown": "PreDown",
"postDown": "PostDown" "postDown": "PostDown"
},
"copy": {
"notSupported": "Копіювання не підтримується",
"copied": "Скопійовано!",
"failed": "Не вдалося скопіювати",
"copy": "Копіювати"
},
"awg": {
"jCLabel": "Кількість сміттєвих пакетів (Jc)",
"jCDescription": "Кількість сміттєвих пакетів для відправки (1–128, рекомендовано: 4–12)",
"jMinLabel": "Мінімальний розмір сміттєвого пакета (Jmin)",
"jMinDescription": "Мінімальний розмір сміттєвих пакетів (0–1279*, рекомендовано: 8, має бути < Jmax)",
"jMaxLabel": "Максимальний розмір сміттєвого пакета (Jmax)",
"jMaxDescription": "Максимальний розмір сміттєвих пакетів (1–1280*, рекомендовано: 80, має бути > Jmin)",
"s1Label": "Розмір сміттєвих даних у початковому пакеті (S1)",
"s1Description": "Розмір сміттєвих даних у початковому пакеті (0–1132 [1280* - 148 = 1132], рекомендовано: 15150, S1+56 ≠ S2)",
"s2Label": "Розмір сміттєвих даних у пакеті відповіді (S2)",
"s2Description": "Розмір сміттєвих даних у пакеті відповіді (0–1188 [1280* - 92 = 1188], рекомендовано: 15–150)",
"s3Label": "Розмір сміттєвих даних у пакеті «cookie reply» (S3)",
"s3Description": "Розмір сміттєвих даних у пакеті «cookie reply»",
"s4Label": "Розмір сміттєвих даних у транспортному пакеті (S4)",
"s4Description": "Розмір сміттєвих даних у транспортному пакеті",
"i1Label": "Спеціальний сміттєвий пакет 1 (I1)",
"i1Description": "Пакет-імітація протоколу у hex-форматі: <b 0x...>",
"i2Label": "Спеціальний сміттєвий пакет 2 (I2)",
"i2Description": "Пакет-імітація протоколу у hex-форматі: <b 0x...>",
"i3Label": "Спеціальний сміттєвий пакет 3 (I3)",
"i3Description": "Пакет-імітація протоколу у hex-форматі: <b 0x...>",
"i4Label": "Спеціальний сміттєвий пакет 4 (I4)",
"i4Description": "Пакет-імітація протоколу у hex-форматі: <b 0x...>",
"i5Label": "Спеціальний сміттєвий пакет 5 (I5)",
"i5Description": "Пакет-імітація протоколу у hex-форматі: <b 0x...>",
"h1Label": "Початковий магічний заголовок (H1)",
"h1Description": "Значення заголовка початкового пакета (5–2147483647, має бути унікальним від H2–H4)",
"h2Label": "Магічний заголовок відповіді (H2)",
"h2Description": "Значення заголовка пакета відповіді (5–2147483647, має бути унікальним від H1, H3, H4)",
"h3Label": "Магічний заголовок «cookie reply» (H3)",
"h3Description": "Значення заголовка пакета «cookie reply» (52147483647, має бути унікальним від H1, H2, H4)",
"h4Label": "Магічний заголовок транспортного пакета (H4)",
"h4Description": "Значення заголовка транспортного пакета (5–2147483647, має бути унікальним від H1–H3)",
"mtuNote": "Значення залежать від MTU",
"obfuscationParameters": "Параметри обфускації AmneziaWG"
} }
} }
+51 -2
View File
@@ -88,8 +88,9 @@
"name": "客户端名称", "name": "客户端名称",
"expireDate": "过期日期", "expireDate": "过期日期",
"expireDateDesc": "客户端将被自动禁用的日期。留空表示永久有效", "expireDateDesc": "客户端将被自动禁用的日期。留空表示永久有效",
"delete": "删除客户端",
"deleteClient": "删除客户端", "deleteClient": "删除客户端",
"deleteDialog1": "您确定要删除客户端吗?", "deleteDialog1": "您确定要删除客户端",
"deleteDialog2": "此操作无法撤销。", "deleteDialog2": "此操作无法撤销。",
"enabled": "已启用", "enabled": "已启用",
"address": "IP地址", "address": "IP地址",
@@ -113,7 +114,13 @@
"hooks": "钩子脚本", "hooks": "钩子脚本",
"hooksDescription": "钩子脚本仅在使用wg-quick时有效", "hooksDescription": "钩子脚本仅在使用wg-quick时有效",
"hooksLeaveEmpty": "如果不使用wg-quick,请留空此字段", "hooksLeaveEmpty": "如果不使用wg-quick,请留空此字段",
"search": "搜索客户端..." "dnsDesc": "客户端将使用的 DNS 服务器(将覆盖全局配置)",
"notConnected": "客户端未连接",
"endpoint": "端点",
"endpointDesc": "建立 WireGuard 连接时客户端的 IP 地址",
"search": "搜索客户端...",
"config": "配置",
"viewConfig": "查看配置文本"
}, },
"dialog": { "dialog": {
"change": "确认修改", "change": "确认修改",
@@ -233,5 +240,47 @@
"postUp": "启动后脚本", "postUp": "启动后脚本",
"preDown": "停止前脚本", "preDown": "停止前脚本",
"postDown": "停止后脚本" "postDown": "停止后脚本"
},
"copy": {
"notSupported": "不支持复制",
"copied": "已复制!",
"failed": "复制失败",
"copy": "复制"
},
"awg": {
"jCLabel": "垃圾数据包计数(Jc",
"jCDescription": "发送的垃圾数据包数量(范围:1-128,推荐值:4-12",
"jMinLabel": "垃圾数据包最小尺寸(Jmin",
"jMinDescription": "垃圾数据包的最小尺寸(范围:0-1279*,推荐值:8,必须小于 Jmax",
"jMaxLabel": "垃圾数据包最大尺寸(Jmax",
"jMaxDescription": "垃圾数据包的最大尺寸(范围:1-1280*,推荐值:80,必须大于 Jmin",
"s1Label": "初始数据包垃圾数据大小(S1)",
"s1Description": "初始数据包中垃圾数据的大小(范围:0-1132[1280* - 148 = 1132],推荐值:15-150S1+56 ≠ S2",
"s2Label": "响应数据包垃圾数据大小(S2)",
"s2Description": "响应数据包中垃圾数据的大小(范围:0-1188[1280* - 92 = 1188],推荐值:15-150",
"s3Label": "Cookie 回复数据包垃圾数据大小(S3)",
"s3Description": "Cookie 回复数据包中垃圾数据的大小",
"s4Label": "传输数据包垃圾数据大小(S4)",
"s4Description": "传输数据包中垃圾数据的大小",
"i1Label": "特殊垃圾数据包 1I1",
"i1Description": "协议模拟数据包(十六进制格式):<b 0x...>",
"i2Label": "特殊垃圾数据包 2I2",
"i2Description": "协议模拟数据包(十六进制格式):<b 0x...>",
"i3Label": "特殊垃圾数据包 3I3",
"i3Description": "协议模拟数据包(十六进制格式):<b 0x...>",
"i4Label": "特殊垃圾数据包 4I4",
"i4Description": "协议模拟数据包(十六进制格式):<b 0x...>",
"i5Label": "特殊垃圾数据包 5I5",
"i5Description": "协议模拟数据包(十六进制格式):<b 0x...>",
"h1Label": "初始数据包魔术头部(H1",
"h1Description": "初始数据包头部值(范围:5-2147483647,必须与 H2-H4 不同)",
"h2Label": "响应数据包魔术头部(H2",
"h2Description": "响应数据包头部值(范围:5-2147483647,必须与 H1、H3、H4 不同)",
"h3Label": "Cookie 回复数据包魔术头部(H3",
"h3Description": "Cookie 回复数据包头部值(范围:5-2147483647,必须与 H1、H2、H4 不同)",
"h4Label": "传输数据包魔术头部(H4",
"h4Description": "传输数据包头部值(范围:5-2147483647,必须与 H1-H3 不同)",
"mtuNote": "具体数值取决于 MTU(最大传输单元)",
"obfuscationParameters": "AmneziaWG 混淆参数"
} }
} }
+286
View File
@@ -0,0 +1,286 @@
{
"pages": {
"me": "帳戶",
"clients": "用戶端",
"admin": {
"panel": "管理面板",
"general": "一般設定",
"config": "組態設定",
"interface": "介面設定",
"hooks": "Hook 設定"
}
},
"user": {
"email": "電子郵件"
},
"me": {
"currentPassword": "目前密碼",
"enable2fa": "啟用兩步驟驗證",
"enable2faDesc": "請使用您的驗證碼應用程式掃描 QR Code,或手動輸入金鑰。",
"2faKey": "TOTP 金鑰",
"2faCodeDesc": "請輸入驗證碼應用程式提供的驗證碼。",
"disable2fa": "停用兩步驟驗證",
"disable2faDesc": "請輸入您的密碼以停用兩步驟驗證。"
},
"general": {
"name": "名稱",
"username": "使用者名稱",
"password": "密碼",
"newPassword": "新密碼",
"updatePassword": "更新密碼",
"mtu": "MTU",
"allowedIps": "允許的 IP",
"dns": "DNS",
"persistentKeepalive": "保持連線",
"logout": "登出",
"continue": "繼續",
"host": "主機",
"port": "連接埠",
"yes": "是",
"no": "否",
"confirmPassword": "確認密碼",
"loading": "正在載入...",
"2fa": "兩步驟驗證",
"2faCode": "TOTP 驗證碼"
},
"setup": {
"welcome": "歡迎首次設定您的 wg-easy",
"welcomeDesc": "這是您在任何 Linux 主機上安裝與管理 WireGuard 最簡單的方式",
"existingSetup": "您已有現存的設定了嗎?",
"createAdminDesc": "請先輸入管理員使用者名稱與高強度密碼。此資訊將用於登入管理面板。",
"setupConfigDesc": "請輸入主機與連接埠資訊。此資訊將用於設定用戶端的 WireGuard 連線。",
"setupMigrationDesc": "若要從先前的 wg-easy 版本移轉資料,請提供備份檔案。",
"upload": "上傳",
"migration": "還原備份:",
"createAccount": "建立帳戶",
"successful": "設定成功",
"hostDesc": "用戶端將連線的公開主機名稱",
"portDesc": "用戶端將連線的公開 UDP 連接埠,且 WireGuard 會在此監聽"
},
"update": {
"updateAvailable": "已有更新可供使用!",
"update": "更新"
},
"theme": {
"dark": "深色佈景主題",
"light": "淺色佈景主題",
"system": "系統佈景主題"
},
"layout": {
"toggleCharts": "顯示/隱藏圖表",
"donate": "贊助"
},
"login": {
"signIn": "登入",
"rememberMe": "記住我",
"rememberMeDesc": "關閉瀏覽器後仍保持登入狀態",
"insecure": "您無法在不安全的連線下登入。請使用 HTTPS。",
"2faRequired": "需要兩步驟驗證",
"2faWrong": "兩步驟驗證碼不正確"
},
"client": {
"empty": "尚無用戶端。",
"newShort": "新增",
"sort": "排序",
"create": "建立用戶端",
"created": "已建立用戶端",
"new": "新增用戶端",
"name": "名稱",
"expireDate": "到期日",
"expireDateDesc": "用戶端將被停用的日期。留白表示永久有效",
"delete": "刪除",
"deleteClient": "刪除用戶端",
"deleteDialog1": "您確定要刪除",
"deleteDialog2": "此動作無法復原。",
"enabled": "啟用",
"address": "位址",
"serverAllowedIps": "伺服器允許的 IP",
"otlDesc": "產生暫時性單次連結",
"permanent": "永久",
"createdOn": "建立於 ",
"lastSeen": "上次連線於 ",
"totalDownload": "總下載量: ",
"totalUpload": "總上傳量: ",
"newClient": "新增用戶端",
"disableClient": "停用用戶端",
"enableClient": "啟用用戶端",
"noPrivKey": "此用戶端沒有已知的私密金鑰,無法建立設定。",
"showQR": "顯示 QR Code",
"downloadConfig": "下載組態設定檔",
"allowedIpsDesc": "將透過 VPN 路由的 IP (會覆寫全域設定)",
"serverAllowedIpsDesc": "伺服器將路由至用戶端的 IP",
"mtuDesc": "設定 VPN 通道的最大傳輸單位 (封包大小)",
"persistentKeepaliveDesc": "Keep-alive 封包的間隔秒數。0 表示停用",
"hooks": "Hook 設定",
"hooksDescription": "Hook 設定僅適用於 wg-quick",
"hooksLeaveEmpty": "僅適用於 wg-quick,否則請保持空白",
"dnsDesc": "用戶端使用的 DNS 伺服器 (會覆寫全域設定)",
"notConnected": "用戶端未連線",
"endpoint": "端點",
"endpointDesc": "用戶端建立 WireGuard 連線的來源 IP",
"search": "搜尋用戶端...",
"config": "組態設定",
"viewConfig": "檢視組態設定"
},
"dialog": {
"change": "變更",
"cancel": "取消",
"create": "建立"
},
"toast": {
"success": "成功",
"saved": "已儲存",
"error": "錯誤"
},
"form": {
"actions": "操作",
"save": "儲存",
"revert": "還原",
"sectionGeneral": "一般設定",
"sectionAdvanced": "進階設定",
"noItems": "沒有項目",
"nullNoItems": "沒有項目。使用全域設定",
"add": "新增"
},
"admin": {
"general": {
"sessionTimeout": "工作階段逾時",
"sessionTimeoutDesc": "「記住我」的工作階段持續時間 (秒)",
"metrics": "計量",
"metricsPassword": "密碼",
"metricsPasswordDesc": "計量端點的 Bearer 密碼 (密碼或 argon2 雜湊)",
"json": "JSON",
"jsonDesc": "提供 JSON 格式計量的路由",
"prometheus": "Prometheus",
"prometheusDesc": "提供 Prometheus 計量的路由"
},
"config": {
"connection": "連線",
"hostDesc": "用戶端將連線的公開主機名稱 (變更後會使目前組態設定檔失效)",
"portDesc": "用戶端將連線的公開 UDP 連接埠 (變更後會使目前組態設定檔失效,您可能也需要變更介面連接埠)",
"allowedIpsDesc": "用戶端將使用的允許 IP (全域設定)",
"dnsDesc": "用戶端將使用的 DNS 伺服器 (全域設定)",
"mtuDesc": "用戶端使用的 MTU (僅適用於新用戶端)",
"persistentKeepaliveDesc": "傳送 keepalive 的間隔秒數。以 0 表示停用 (僅適用於新用戶端)",
"suggest": "建議",
"suggestDesc": "為主機欄位選擇 IP 位址或主機名稱"
},
"interface": {
"cidrSuccess": "已變更 CIDR",
"device": "裝置",
"deviceDesc": "用於轉送 WireGuard 流量的乙太網路裝置",
"mtuDesc": "WireGuard 將使用的 MTU",
"portDesc": "WireGuard 監聽的 UDP 連接埠 (您可能也需要變更連接埠組態設定檔)",
"changeCidr": "變更 CIDR",
"restart": "重新啟動介面",
"restartDesc": "重新啟動 WireGuard 介面",
"restartWarn": "您確定要重新啟動介面嗎? 所有用戶端將被中斷連線。",
"restartSuccess": "介面已重新啟動"
},
"introText": "歡迎使用管理面板。\n\n您可在此管理一般、組態、介面與 Hook 設定。\n\n請從側邊欄選擇任一項目開始。"
},
"zod": {
"generic": {
"required": "{0} 為必填項目",
"validNumber": "{0} 必須為有效的數字",
"validString": "{0} 必須為有效的字串",
"validBoolean": "{0} 必須為有效的布林值",
"validArray": "{0} 必須為有效的陣列",
"stringMin": "{0} 至少需要 {1} 個字元",
"numberMin": "{0} 不能小於 {1}"
},
"client": {
"id": "用戶端 ID",
"name": "名稱",
"expiresAt": "到期時間",
"address4": "IPv4 位址",
"address6": "IPv6 位址",
"serverAllowedIps": "伺服器允許的 IP"
},
"user": {
"username": "使用者名稱",
"password": "密碼",
"remember": "記住我",
"name": "名稱",
"email": "電子郵件",
"emailInvalid": "電子郵件格式無效",
"passwordMatch": "密碼必須一致",
"totpEnable": "啟用 TOTP",
"totpEnableTrue": "必須啟用 TOTP",
"totpCode": "TOTP 驗證碼"
},
"userConfig": {
"host": "主機"
},
"general": {
"sessionTimeout": "工作階段逾時",
"metricsEnabled": "計量",
"metricsPassword": "計量密碼"
},
"interface": {
"cidr": "CIDR",
"device": "裝置",
"cidrValid": "CIDR 格式無效"
},
"otl": "單次連結",
"stringMalformed": "字串格式錯誤",
"body": "Body 必須為有效的物件",
"hook": "Hook",
"enabled": "啟用",
"mtu": "MTU",
"port": "連接埠",
"persistentKeepalive": "保持連線",
"address": "IP 位址",
"dns": "DNS",
"allowedIps": "允許的 IP",
"file": "檔案"
},
"hooks": {
"preUp": "PreUp",
"postUp": "PostUp",
"preDown": "PreDown",
"postDown": "PostDown"
},
"copy": {
"notSupported": "無法複製",
"copied": "已複製!",
"failed": "複製失敗",
"copy": "複製"
},
"awg": {
"jCLabel": "填充封包數量 (Jc)",
"jCDescription": "要傳送的填充封包數量 (1-128,建議: 4-12)",
"jMinLabel": "填充封包最小大小 (Jmin)",
"jMinDescription": "填充封包的最小大小 (0-1279*,建議: 8,必須小於 Jmax)",
"jMaxLabel": "填充封包最大大小 (Jmax)",
"jMaxDescription": "填充封包的最大大小 (1-1280*,建議: 80,必須大於 Jmin)",
"s1Label": "初始封包填充大小 (S1)",
"s1Description": "初始封包填充大小 (0-1132 [1280* - 148 = 1132],建議: 15-150S1+56 ≠ S2)",
"s2Label": "回應封包填充大小 (S2)",
"s2Description": "回應封包填充大小 (0-1188 [1280* - 92 = 1188],建議: 15-150)",
"s3Label": "Cookie 回覆封包填充大小 (S3)",
"s3Description": "Cookie 回覆封包填充大小",
"s4Label": "傳輸封包填充大小 (S4)",
"s4Description": "傳輸封包填充大小",
"i1Label": "特殊填充封包 1 (I1)",
"i1Description": "協定模仿封包 (16 進位格式): <b 0x...>",
"i2Label": "特殊填充封包 2 (I2)",
"i2Description": "協定模仿封包 (16 進位格式): <b 0x...>",
"i3Label": "特殊填充封包 3 (I3)",
"i3Description": "協定模仿封包 (16 進位格式): <b 0x...>",
"i4Label": "特殊填充封包 4 (I4)",
"i4Description": "協定模仿封包 (16 進位格式): <b 0x...>",
"i5Label": "特殊填充封包 5 (I5)",
"i5Description": "協定模仿封包 (16 進位格式): <b 0x...>",
"h1Label": "初始特徵標頭 (H1)",
"h1Description": "初始封包標頭值 (5-2147483647,必須與 H2-H4 不同)",
"h2Label": "回應特徵標頭 (H2)",
"h2Description": "回應封包標頭值 (5-2147483647,必須與 H1、H3、H4 不同)",
"h3Label": "Cookie 回覆特徵標頭 (H3)",
"h3Description": "Cookie 回覆封包標頭值 (5-2147483647,必須與 H1、H2、H4 不同)",
"h4Label": "傳輸特徵標頭 (H4)",
"h4Description": "傳輸封包標頭值 (5-2147483647,必須與 H1-H3 不同)",
"mtuNote": "數值取決於 MTU",
"obfuscationParameters": "AmneziaWG 混淆參數"
}
}
+27 -1
View File
@@ -5,7 +5,7 @@ export default defineNuxtConfig({
future: { future: {
compatibilityVersion: 4, compatibilityVersion: 4,
}, },
compatibilityDate: '2025-02-04', compatibilityDate: '2026-02-06',
devtools: { enabled: true }, devtools: { enabled: true },
modules: [ modules: [
'@nuxtjs/i18n', '@nuxtjs/i18n',
@@ -15,6 +15,7 @@ export default defineNuxtConfig({
'radix-vue/nuxt', 'radix-vue/nuxt',
'@vueuse/nuxt', '@vueuse/nuxt',
'@nuxt/eslint', '@nuxt/eslint',
'@nuxt/test-utils/module',
], ],
colorMode: { colorMode: {
preference: 'system', preference: 'system',
@@ -79,6 +80,11 @@ export default defineNuxtConfig({
language: 'zh-HK', language: 'zh-HK',
name: '繁體中文(香港)', name: '繁體中文(香港)',
}, },
{
code: 'zh-TW',
language: 'zh-TW',
name: '正體中文 (台灣)',
},
{ {
code: 'pl', code: 'pl',
language: 'pl-PL', language: 'pl-PL',
@@ -104,6 +110,26 @@ export default defineNuxtConfig({
language: 'id-ID', language: 'id-ID',
name: 'Bahasa Indonesia', name: 'Bahasa Indonesia',
}, },
{
code: 'nl',
language: 'nl-NL',
name: 'Nederlands',
},
{
code: 'nb',
language: 'nb-NO',
name: 'Norsk bokmål',
},
{
code: 'bg',
language: 'bg-BG',
name: 'Български',
},
{
code: 'gl',
language: 'gl-ES',
name: 'Galego',
},
], ],
defaultLocale: 'en', defaultLocale: 'en',
vueI18n: './i18n.config.ts', vueI18n: './i18n.config.ts',
+32 -27
View File
@@ -1,6 +1,6 @@
{ {
"name": "wg-easy", "name": "wg-easy",
"version": "15.2.0-beta.1", "version": "15.2.2",
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.", "description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
"private": true, "private": true,
"type": "module", "type": "module",
@@ -17,57 +17,62 @@
"check:all": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build", "check:all": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build",
"db:generate": "drizzle-kit generate", "db:generate": "drizzle-kit generate",
"cli:build": "node cli/build.js", "cli:build": "node cli/build.js",
"cli:dev": "tsx cli/index.ts" "cli:dev": "tsx cli/index.ts",
"test:unit": "vitest run --project unit"
}, },
"dependencies": { "dependencies": {
"@eschricht/nuxt-color-mode": "^1.2.0", "@eschricht/nuxt-color-mode": "^1.2.0",
"@heroicons/vue": "^2.2.0", "@heroicons/vue": "^2.2.0",
"@libsql/client": "^0.15.15", "@libsql/client": "^0.17.0",
"@nuxtjs/i18n": "^10.2.0", "@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0", "@nuxtjs/tailwindcss": "^6.14.0",
"@phc/format": "^1.0.0", "@phc/format": "^1.0.0",
"@pinia/nuxt": "^0.11.3", "@pinia/nuxt": "^0.11.3",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.11",
"@vueuse/core": "^14.0.0", "@vueuse/core": "^14.2.0",
"@vueuse/nuxt": "^14.0.0", "@vueuse/nuxt": "^14.2.0",
"apexcharts": "^5.3.6", "apexcharts": "^5.3.6",
"argon2": "^0.44.0", "argon2": "^0.44.0",
"cidr-tools": "^11.0.3", "cidr-tools": "^11.0.6",
"citty": "^0.1.6", "citty": "^0.2.0",
"consola": "^3.4.2", "consola": "^3.4.2",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"debug": "^4.4.3", "debug": "^4.4.3",
"drizzle-orm": "^0.44.7", "drizzle-orm": "^0.45.1",
"ip-bigint": "^8.2.2", "ip-bigint": "^8.2.4",
"is-cidr": "^6.0.1", "is-cidr": "^6.0.2",
"is-ip": "^5.0.1", "is-ip": "^5.0.1",
"js-sha256": "^0.11.1", "js-sha256": "^0.11.1",
"nuxt": "^3.20.1", "nuxt": "^3.21.1",
"otpauth": "^9.4.1", "otpauth": "^9.5.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"qr": "^0.5.2", "qr": "^0.5.4",
"radix-vue": "^1.9.17", "radix-vue": "^1.9.17",
"semver": "^7.7.3", "semver": "^7.7.4",
"tailwindcss": "^3.4.18", "tailwindcss": "^3.4.19",
"timeago.js": "^4.0.2", "timeago.js": "^4.0.2",
"vue": "latest", "vue": "latest",
"vue3-apexcharts": "^1.10.0", "vue3-apexcharts": "^1.10.0",
"zod": "^4.1.12" "zod": "^4.3.6"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint": "^1.10.0", "@nuxt/eslint": "^1.14.0",
"@nuxt/test-utils": "^3.23.0",
"@types/debug": "^4.1.12", "@types/debug": "^4.1.12",
"@types/phc__format": "^1.0.1", "@types/phc__format": "^1.0.1",
"@types/semver": "^7.7.1", "@types/semver": "^7.7.1",
"drizzle-kit": "^0.31.6", "@vitest/coverage-v8": "^4.0.18",
"esbuild": "^0.27.0", "@vitest/ui": "4.0.18",
"eslint": "^9.39.1", "drizzle-kit": "^0.31.8",
"esbuild": "^0.27.3",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"prettier": "^3.6.2", "prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.1", "prettier-plugin-tailwindcss": "^0.7.2",
"tsx": "^4.20.6", "tsx": "^4.21.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vue-tsc": "^3.1.3" "vitest": "^4.0.18",
"vue-tsc": "^3.2.4"
}, },
"packageManager": "pnpm@10.21.0" "packageManager": "pnpm@10.29.2"
} }
+2982 -2142
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -1,9 +1,14 @@
import type { SharedPublicUser } from '~~/shared/utils/permissions';
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const session = await useWGSession(event); const session = await useWGSession(event);
if (!session.data.userId) { if (!session.data.userId) {
// not logged in // not logged in
return null; throw createError({
statusCode: 401,
statusMessage: 'Not authenticated',
});
} }
const user = await Database.users.get(session.data.userId); const user = await Database.users.get(session.data.userId);
@@ -21,5 +26,5 @@ export default defineEventHandler(async (event) => {
name: user.name, name: user.name,
email: user.email, email: user.email,
totpVerified: user.totpVerified, totpVerified: user.totpVerified,
}; } satisfies SharedPublicUser;
}); });
@@ -16,6 +16,12 @@ function createPreparedStatement(db: DBType) {
oneTimeLink: sql.placeholder('oneTimeLink'), oneTimeLink: sql.placeholder('oneTimeLink'),
expiresAt: sql.placeholder('expiresAt'), expiresAt: sql.placeholder('expiresAt'),
}) })
.onConflictDoUpdate({
target: oneTimeLink.id,
set: {
expiresAt: sql.placeholder('expiresAt') as never as string,
},
})
.prepare(), .prepare(),
erase: db erase: db
.update(oneTimeLink) .update(oneTimeLink)
+1 -1
View File
@@ -3,7 +3,7 @@ export default defineEventHandler(async (event) => {
const url = getRequestURL(event); const url = getRequestURL(event);
// User can't be logged in, and public routes can be accessed whenever // User can't be logged in, and public routes can be accessed whenever
if (url.pathname.startsWith('/api/')) { if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/_i18n/')) {
return; return;
} }
@@ -39,8 +39,6 @@ async function getPrometheusResponse() {
const id = `interface="${wgInterface.name}"`; const id = `interface="${wgInterface.name}"`;
const returnText = [ const returnText = [
'# HELP wg-easy and wireguard metrics',
'',
'# HELP wireguard_configured_peers', '# HELP wireguard_configured_peers',
'# TYPE wireguard_configured_peers gauge', '# TYPE wireguard_configured_peers gauge',
`wireguard_configured_peers{${id}} ${wireguardPeerCount}`, `wireguard_configured_peers{${id}} ${wireguardPeerCount}`,
+19 -6
View File
@@ -166,11 +166,24 @@ class WireGuard {
async getClientQRCodeSVG({ clientId }: { clientId: ID }) { async getClientQRCodeSVG({ clientId }: { clientId: ID }) {
const config = await this.getClientConfiguration({ clientId }); const config = await this.getClientConfiguration({ clientId });
return encodeQR(config, 'svg', { const ECMode = ['high', 'quartile', 'medium', 'low'] as const;
ecc: 'high', for (const ecc of ECMode) {
scale: 2, try {
encoding: 'byte', return encodeQR(config, 'svg', {
}); ecc,
scale: 2,
encoding: 'byte',
});
} catch (err) {
if (!(err instanceof Error && err.message === 'Capacity overflow')) {
throw err;
}
// retry with lower ecc
}
}
throw new Error(
'Failed to generate QR code: Capacity overflow at all ECC levels'
);
} }
cleanClientFilename(name: string): string { cleanClientFilename(name: string): string {
@@ -200,7 +213,7 @@ class WireGuard {
WG_DEBUG('New Wireguard Keys generated successfully.'); WG_DEBUG('New Wireguard Keys generated successfully.');
} }
if (WG_ENV.WG_EXECUTABLE === 'awg' && wgInterface.h1 === 0) { if (wgInterface.h1 === 0) {
WG_DEBUG('Generating random AmneziaWG obfuscation parameters...'); WG_DEBUG('Generating random AmneziaWG obfuscation parameters...');
const headers = new Set<number>(); const headers = new Set<number>();
+10 -10
View File
@@ -63,11 +63,11 @@ AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join(
S2: wgInterface.s2, S2: wgInterface.s2,
S3: wgInterface.s3, S3: wgInterface.s3,
S4: wgInterface.s4, S4: wgInterface.s4,
i1: wgInterface.i1, I1: wgInterface.i1,
i2: wgInterface.i2, I2: wgInterface.i2,
i3: wgInterface.i3, I3: wgInterface.i3,
i4: wgInterface.i4, I4: wgInterface.i4,
i5: wgInterface.i5, I5: wgInterface.i5,
H1: wgInterface.h1, H1: wgInterface.h1,
H2: wgInterface.h2, H2: wgInterface.h2,
H3: wgInterface.h3, H3: wgInterface.h3,
@@ -131,11 +131,11 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
S2: wgInterface.s2, S2: wgInterface.s2,
S3: wgInterface.s3, S3: wgInterface.s3,
S4: wgInterface.s4, S4: wgInterface.s4,
i1: client.i1, I1: client.i1,
i2: client.i2, I2: client.i2,
i3: client.i3, I3: client.i3,
i4: client.i4, I4: client.i4,
i5: client.i5, I5: client.i5,
H1: wgInterface.h1, H1: wgInterface.h1,
H2: wgInterface.h2, H2: wgInterface.h2,
H3: wgInterface.h3, H3: wgInterface.h3,
+5
View File
@@ -45,6 +45,11 @@ type SharedUserType =
| Pick<UserType, 'id' | 'role'> | Pick<UserType, 'id' | 'role'>
| (Pick<UserType, 'id'> & { role: BrandedNumber }); | (Pick<UserType, 'id'> & { role: BrandedNumber });
export type SharedPublicUser = Pick<
UserType,
'id' | 'username' | 'name' | 'email' | 'totpVerified'
> & { role: BrandedNumber };
type PermissionCheck<Key extends keyof Permissions> = type PermissionCheck<Key extends keyof Permissions> =
| boolean | boolean
| ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean); | ((user: SharedUserType, data: Permissions[Key]['dataType']) => boolean);
+20
View File
@@ -0,0 +1,20 @@
import { expect, test, describe } from 'vitest';
import {
hashPassword,
isPasswordValid,
isValidPasswordHash,
} from '../../server/utils/password';
describe('password', () => {
test('password', async () => {
const hash = await hashPassword('password');
await expect(isPasswordValid('password', hash)).resolves.toBe(true);
await expect(isPasswordValid('wrong', hash)).resolves.toBe(false);
expect(isValidPasswordHash('not a hash')).toBe(false);
expect(isValidPasswordHash(hash)).toBe(true);
expect(isValidPasswordHash(hash.replace('argon2', 'argon3'))).toBe(false);
});
});
+18
View File
@@ -0,0 +1,18 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
projects: [
{
test: {
name: 'unit',
include: ['test/unit/*.{test,spec}.ts'],
environment: 'node',
},
},
],
coverage: {
enabled: true,
},
},
});