Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da61cb680f | |||
| 8b5e6c4c7a | |||
| e192855280 | |||
| 3a52e1321b | |||
| b29703af86 | |||
| 516a3fa72c | |||
| e5cdb2b57a | |||
| 7fbc1cef68 | |||
| 432e7a8197 | |||
| d12045e10c | |||
| 015f3c5ba2 | |||
| e42f7313ab | |||
| 993c130f65 | |||
| fbf24410db | |||
| c1d5822f41 | |||
| 268916782d | |||
| 11ab71b5d2 | |||
| 67185192fd | |||
| 5fd3ee9843 | |||
| e444936c04 | |||
| 5d6c35b183 |
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
|
||||
@@ -18,10 +18,10 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
- platform: linux/arm64
|
||||
os: ubuntu-24.04-arm
|
||||
# - platform: linux/arm/v7
|
||||
# os: ubuntu-24.04-arm
|
||||
- platform: linux/arm/v7
|
||||
os: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -38,21 +38,21 @@ jobs:
|
||||
latest=false
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.arch.platform }}
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
@@ -85,32 +85,32 @@ jobs:
|
||||
needs: docker-build
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Codeberg
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: codeberg.org
|
||||
username: ${{ secrets.CODEBERG_USER }}
|
||||
password: ${{ secrets.CODEBERG_PASS }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -138,7 +138,7 @@ jobs:
|
||||
contents: write
|
||||
needs: docker-merge
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
- platform: linux/arm64
|
||||
os: ubuntu-24.04-arm
|
||||
# - platform: linux/arm/v7
|
||||
# os: ubuntu-24.04-arm
|
||||
- platform: linux/arm/v7
|
||||
os: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: master
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -47,21 +47,21 @@ jobs:
|
||||
latest=false
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.arch.platform }}
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
@@ -94,32 +94,32 @@ jobs:
|
||||
needs: docker-build
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Codeberg
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: codeberg.org
|
||||
username: ${{ secrets.CODEBERG_USER }}
|
||||
password: ${{ secrets.CODEBERG_PASS }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
contents: write
|
||||
needs: docker-merge
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: master
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
- platform: linux/arm64
|
||||
os: ubuntu-24.04-arm
|
||||
# - platform: linux/arm/v7
|
||||
# os: ubuntu-24.04-arm
|
||||
- platform: linux/arm/v7
|
||||
os: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
@@ -32,20 +32,20 @@ jobs:
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Docker Image
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
|
||||
@@ -26,10 +26,10 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
- platform: linux/arm64
|
||||
os: ubuntu-24.04-arm
|
||||
# - platform: linux/arm/v7
|
||||
# os: ubuntu-24.04-arm
|
||||
- platform: linux/arm/v7
|
||||
os: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -46,21 +46,21 @@ jobs:
|
||||
latest=false
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ matrix.arch.platform }}
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
@@ -95,32 +95,32 @@ jobs:
|
||||
needs: docker-build
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Codeberg
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: codeberg.org
|
||||
username: ${{ secrets.CODEBERG_USER }}
|
||||
password: ${{ secrets.CODEBERG_PASS }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v6
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
contents: write
|
||||
needs: docker-merge
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "lts/krypton"
|
||||
node-version: "lts/jod"
|
||||
check-latest: true
|
||||
cache: "pnpm"
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
name: Install pnpm
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "lts/krypton"
|
||||
node-version: "lts/jod"
|
||||
check-latest: true
|
||||
cache: "pnpm"
|
||||
|
||||
|
||||
Vendored
+1
@@ -3,6 +3,7 @@
|
||||
"aaron-bond.better-comments",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"antfu.goto-alias",
|
||||
"visualstudioexptteam.vscodeintellicode",
|
||||
"esbenp.prettier-vscode",
|
||||
"yoavbls.pretty-ts-errors",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
|
||||
+5
-50
@@ -7,60 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- AWG: support for H1-H4 ranges (https://github.com/wg-easy/wg-easy/pull/2480)
|
||||
- Client Firewall (https://github.com/wg-easy/wg-easy/pull/2418)
|
||||
- CLI: Show QR code (https://github.com/wg-easy/wg-easy/pull/2518)
|
||||
- Copy QR code to clipboard / save as png (https://github.com/wg-easy/wg-easy/pull/2521)
|
||||
|
||||
### Changed
|
||||
|
||||
- Hooks are now Textareas (https://github.com/wg-easy/wg-easy/pull/2522)
|
||||
- Update to Node Krypton (24) (https://github.com/wg-easy/wg-easy/pull/2536)
|
||||
|
||||
## [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
|
||||
## Added
|
||||
|
||||
- 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)
|
||||
- `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)
|
||||
- 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)
|
||||
- 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)
|
||||
- Use /32 and /128 for client Cidr (https://github.com/wg-easy/wg-easy/pull/2217)
|
||||
@@ -68,15 +27,11 @@ 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)
|
||||
- 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)
|
||||
- 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 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)
|
||||
- Add Routed (No NAT) docs (https://github.com/wg-easy/wg-easy/pull/2181)
|
||||
|
||||
## [15.1.0] - 2025-07-01
|
||||
|
||||
|
||||
+5
-12
@@ -1,4 +1,4 @@
|
||||
FROM docker.io/library/node:krypton-alpine AS build
|
||||
FROM docker.io/library/node:jod-alpine AS build
|
||||
WORKDIR /app
|
||||
|
||||
# update corepack
|
||||
@@ -15,17 +15,14 @@ COPY src ./
|
||||
RUN pnpm build
|
||||
|
||||
# Build amneziawg-tools
|
||||
RUN apk add linux-headers build-base go git && \
|
||||
RUN apk add linux-headers build-base git && \
|
||||
git clone https://github.com/amnezia-vpn/amneziawg-tools.git && \
|
||||
git clone https://github.com/amnezia-vpn/amneziawg-go && \
|
||||
cd amneziawg-go && \
|
||||
make && \
|
||||
cd ../amneziawg-tools/src && \
|
||||
cd amneziawg-tools/src && \
|
||||
make
|
||||
|
||||
# Copy build result to a new image.
|
||||
# This saves a lot of disk space.
|
||||
FROM docker.io/library/node:krypton-alpine
|
||||
FROM docker.io/library/node:jod-alpine
|
||||
WORKDIR /app
|
||||
|
||||
HEALTHCHECK --interval=1m --timeout=5s --retries=3 CMD /usr/bin/timeout 5s /bin/sh -c "/usr/bin/wg show | /bin/grep -q interface || exit 1"
|
||||
@@ -36,14 +33,11 @@ COPY --from=build /app/.output /app
|
||||
COPY --from=build /app/server/database/migrations /app/server/database/migrations
|
||||
# libsql (https://github.com/nitrojs/nitro/issues/3328)
|
||||
RUN cd /app/server && \
|
||||
npm install --no-save --omit=dev libsql && \
|
||||
npm install --no-save libsql && \
|
||||
npm cache clean --force
|
||||
# cli
|
||||
COPY --from=build /app/cli/cli.sh /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 --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
|
||||
@@ -58,7 +52,6 @@ RUN apk add --no-cache \
|
||||
nftables \
|
||||
kmod \
|
||||
iptables-legacy \
|
||||
wireguard-go \
|
||||
wireguard-tools
|
||||
|
||||
RUN mkdir -p /etc/amnezia
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
FROM docker.io/library/node:krypton-alpine
|
||||
FROM docker.io/library/node:jod-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# update corepack
|
||||
@@ -16,7 +16,6 @@ RUN apk add --no-cache \
|
||||
ip6tables \
|
||||
kmod \
|
||||
iptables-legacy \
|
||||
wireguard-go \
|
||||
wireguard-tools
|
||||
|
||||
# Use iptables-legacy
|
||||
|
||||
@@ -33,7 +33,6 @@ You have found the easiest way to install & manage WireGuard on any Linux host!
|
||||
- IPv6 support
|
||||
- CIDR support
|
||||
- 2FA support
|
||||
- Per-client firewall filtering (requires iptables)
|
||||
|
||||
> [!NOTE]
|
||||
> To better manage documentation for this project, it has its own site here: [https://wg-easy.github.io/wg-easy/latest](https://wg-easy.github.io/wg-easy/latest)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 185 KiB |
@@ -2,9 +2,7 @@
|
||||
title: AmneziaWG
|
||||
---
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
AmneziaWG adds multi-level transport-layer obfuscation by:
|
||||
|
||||
@@ -14,12 +12,6 @@ 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.
|
||||
|
||||
## 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.
|
||||
|
||||
To override this automatic detection, set the `OVERRIDE_AUTO_AWG` environment variable. By default, this variable is unset.
|
||||
@@ -29,51 +21,17 @@ Possible values:
|
||||
- `awg` — Force use of AmneziaWG
|
||||
- `wg` — Force use of standard WireGuard
|
||||
|
||||
## 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.
|
||||
To be able to connect to wg-easy if AmneziaWG is enabled, you must have a AmneziaWG-compatible client.
|
||||
|
||||
Android:
|
||||
|
||||
- [AmneziaWG](https://play.google.com/store/apps/details?id=org.amnezia.awg) - AmneziaWG Official Client
|
||||
- [AmneziaWG](https://play.google.com/store/apps/details?id=org.amnezia.awg) - Official 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:
|
||||
|
||||
- [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
|
||||
- [AmneziaWG](https://apps.apple.com/us/app/amneziawg/id6478942365) - Official Client
|
||||
|
||||
Windows:
|
||||
|
||||
- [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
|
||||
- [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-windows-client/releases) - Official Client
|
||||
|
||||
@@ -20,3 +20,74 @@ You will however still see a IPv6 address in the Web UI, but it won't be used.
|
||||
This option can be removed in the future, as more devices support IPv6.
|
||||
|
||||
///
|
||||
|
||||
## Configuration Overrides
|
||||
|
||||
These environment variables allow you to override settings that would normally be configured through the Admin Panel. When set, these values take precedence over database settings at runtime.
|
||||
|
||||
### Interface Settings
|
||||
|
||||
| Env | Example | Description |
|
||||
| -------------- | ------------- | ------------------------- |
|
||||
| `WG_PORT` | `51820` | WireGuard interface port |
|
||||
| `WG_DEVICE` | `eth0` | Network device/interface |
|
||||
| `WG_MTU` | `1420` | Maximum Transmission Unit |
|
||||
| `WG_IPV4_CIDR` | `10.8.0.0/24` | IPv4 CIDR range |
|
||||
| `WG_IPV6_CIDR` | `fdcc::/112` | IPv6 CIDR range |
|
||||
|
||||
### Client Connection Settings
|
||||
|
||||
| Env | Example | Description |
|
||||
| --------------------------------- | ----------------- | ------------------------------- |
|
||||
| `WG_HOST` | `vpn.example.com` | Host clients will connect to |
|
||||
| `WG_CLIENT_PORT` | `51820` | Port clients will connect to |
|
||||
| `WG_DEFAULT_DNS` | `1.1.1.1,8.8.8.8` | Default DNS servers for clients |
|
||||
| `WG_DEFAULT_ALLOWED_IPS` | `0.0.0.0/0,::/0` | Default allowed IPs for clients |
|
||||
| `WG_DEFAULT_MTU` | `1420` | Default MTU for clients |
|
||||
| `WG_DEFAULT_PERSISTENT_KEEPALIVE` | `25` | Default persistent keepalive |
|
||||
|
||||
### General Settings
|
||||
|
||||
| Env | Example | Description |
|
||||
| ----------------------- | ----------------- | ------------------------- |
|
||||
| `WG_SESSION_TIMEOUT` | `3600` | Session timeout (seconds) |
|
||||
| `WG_METRICS_PASSWORD` | `mypassword123` | Metrics endpoint password |
|
||||
| `WG_METRICS_PROMETHEUS` | `true` or `false` | Enable Prometheus metrics |
|
||||
| `WG_METRICS_JSON` | `true` or `false` | Enable JSON metrics |
|
||||
|
||||
### Hooks
|
||||
|
||||
| Env | Example | Description |
|
||||
| -------------- | ------------------------- | --------------------- |
|
||||
| `WG_PRE_UP` | `echo "Starting WG"` | PreUp hook command |
|
||||
| `WG_POST_UP` | `iptables -A FORWARD ...` | PostUp hook command |
|
||||
| `WG_PRE_DOWN` | `echo "Stopping WG"` | PreDown hook command |
|
||||
| `WG_POST_DOWN` | `iptables -D FORWARD ...` | PostDown hook command |
|
||||
|
||||
/// warning | Override Behavior
|
||||
|
||||
When these override environment variables are set:
|
||||
|
||||
- The specified values will be used at runtime instead of database settings
|
||||
- You can still update these fields through the Web UI and they will be saved to the database
|
||||
- However, the overridden values from environment variables will always take precedence at runtime
|
||||
- The Web UI will display the database values with warning indicators showing which fields are overridden
|
||||
- On first start, if no database values exist, some overridden values will be saved to the database
|
||||
|
||||
Some overrides will not be applied to existing clients until they are manually edited.
|
||||
|
||||
- `WG_DEFAULT_*` settings will only apply to new clients
|
||||
- `WG_IPV4_CIDR` and `WG_IPV6_CIDR` changes will require clients to be manually edited to take effect
|
||||
|
||||
///
|
||||
|
||||
/// note | Note on Port Variables
|
||||
|
||||
- `WG_PORT` - The port WireGuard listens on (interface port)
|
||||
- `WG_CLIENT_PORT` - The port clients connect to (endpoint port, uses `WG_PORT` if not set)
|
||||
- `PORT` - The port the Web UI listens on (HTTP server port)
|
||||
|
||||
In most cases you will only need to set `WG_PORT` to change the WireGuard port.
|
||||
Keep in mind that you have to adjust both sides of the port publish option in your docker setup.
|
||||
|
||||
///
|
||||
|
||||
@@ -11,18 +11,20 @@ These will only be used during the first start of the container. After that, the
|
||||
| `INIT_ENABLED` | `true` | Enables the below env vars | 0 |
|
||||
| `INIT_USERNAME` | `admin` | Sets admin username | 1 |
|
||||
| `INIT_PASSWORD` | `Se!ureP%ssw` | Sets admin password | 1 |
|
||||
| `INIT_HOST` | `vpn.example.com` | Host clients will connect to | 1 |
|
||||
| `INIT_PORT` | `51820` | Port clients will connect to and wireguard will listen on | 1 |
|
||||
| `INIT_DNS` | `1.1.1.1,8.8.8.8` | Sets global dns setting | 2 |
|
||||
| `INIT_IPV4_CIDR` | `10.8.0.0/24` | Sets IPv4 cidr | 3 |
|
||||
| `INIT_IPV6_CIDR` | `2001:0DB8::/32` | Sets IPv6 cidr | 3 |
|
||||
| `INIT_ALLOWED_IPS` | `10.8.0.0/24,2001:0DB8::/32` | Sets global Allowed IPs | 4 |
|
||||
| `INIT_HOST` | `vpn.example.com` | Host clients will connect to | 2 |
|
||||
| `INIT_PORT` | `51820` | Port clients will connect to and WireGuard will listen on | 2 |
|
||||
| `INIT_DNS` | `1.1.1.1,8.8.8.8` | Sets global dns setting | 3 |
|
||||
| `INIT_IPV4_CIDR` | `10.8.0.0/24` | Sets IPv4 cidr | 4 |
|
||||
| `INIT_IPV6_CIDR` | `2001:0DB8::/32` | Sets IPv6 cidr | 4 |
|
||||
| `INIT_ALLOWED_IPS` | `10.8.0.0/24,2001:0DB8::/32` | Sets global Allowed IPs | 5 |
|
||||
|
||||
/// warning | Variables have to be used together
|
||||
|
||||
If variables are in the same group, you have to set all of them. For example, if you set `INIT_IPV4_CIDR`, you also have to set `INIT_IPV6_CIDR`.
|
||||
|
||||
If you want to skip the setup process, you have to configure group `1`
|
||||
To skip the setup process, you must configure groups `1` and `2`. You can alternatively use `WG_HOST` and `WG_PORT` to set group `2` without using the `INIT_` variables.
|
||||
|
||||
Avoid setting both `INIT_` and `WG_` variables for the same setting to prevent confusion.
|
||||
///
|
||||
|
||||
/// note | Security
|
||||
|
||||
@@ -7,7 +7,7 @@ This guide will help you migrate from `v14` to version `v15` of `wg-easy`.
|
||||
## 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.
|
||||
- If you use armv6 or armv7, you unfortunately won't be able to migrate to `v15`.
|
||||
- If you use armv6, 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.
|
||||
|
||||
## Migration
|
||||
@@ -51,7 +51,9 @@ In the setup wizard, select that you already have a configuration file and uploa
|
||||
|
||||
### Environment Variables
|
||||
|
||||
v15 does not use the same environment variables as v14, most of them have been moved to the Admin Panel in the Web UI.
|
||||
v15 does use some of the environment variables as v14. View [Configuration Overrides](../config/optional-config.md#configuration-overrides) to see which environment variables are supported in v15.
|
||||
|
||||
If you want to be able to change settings through the Web UI, do not set the corresponding environment variables, as they will override the database settings. Instead, manually change the settings through the Web UI after the migration.
|
||||
|
||||
### Done
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ File: `/etc/docker/containers/watchtower/docker-compose.yml`
|
||||
```yaml
|
||||
services:
|
||||
watchtower:
|
||||
image: nickfedor/watchtower:latest
|
||||
image: containrrr/watchtower:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
env_file:
|
||||
|
||||
@@ -8,7 +8,7 @@ title: Basic Installation
|
||||
|
||||
1. You need to have a host that you can manage
|
||||
2. You need to have a domain name or a public IP address
|
||||
3. You need a supported architecture (x86_64, arm64)
|
||||
3. You need a supported architecture (x86_64, arm64, armv7)
|
||||
4. You need curl installed on your host
|
||||
|
||||
## Install Docker
|
||||
|
||||
@@ -93,19 +93,3 @@ PostDown
|
||||
```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
|
||||
```
|
||||
|
||||
/// 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
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
@@ -6,20 +6,6 @@ hide:
|
||||
|
||||
Here are some frequently asked questions or errors about `wg-easy`. If you have a question that is not answered here, please feel free to open a discussion on GitHub.
|
||||
|
||||
## How do I restrict client access to specific networks or servers?
|
||||
|
||||
Use the **Per-Client Firewall** feature to enforce server-side restrictions on what each client can access.
|
||||
|
||||
**Requirements:** This feature requires `iptables` (and `ip6tables` for IPv6) to be installed on the host system.
|
||||
|
||||
1. Enable "Per-Client Firewall" in **Admin Panel → Interface**
|
||||
2. Edit a client and configure "Firewall Allowed IPs"
|
||||
3. Specify which destinations the client should be allowed to access
|
||||
|
||||
Unlike "Allowed IPs" which only controls client-side routing, firewall rules are enforced by the server and cannot be bypassed.
|
||||
|
||||
See the [Admin Panel Guide](./guides/admin.md#per-client-firewall) and [Client Guide](./guides/clients.md#firewall-allowed-ips) for detailed configuration.
|
||||
|
||||
## Error: WireGuard exited with the error: Cannot find device "wg0"
|
||||
|
||||
This error indicates that the WireGuard interface `wg0` does not exist. This can happen if the WireGuard kernel module is not loaded or if the interface was not created properly.
|
||||
|
||||
@@ -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
|
||||
2. You need to have a domain name or a public IP address
|
||||
3. You need a supported architecture (x86_64, arm64)
|
||||
3. You need a supported architecture (x86_64, arm64, armv7)
|
||||
|
||||
### Host Setup
|
||||
|
||||
@@ -45,15 +45,15 @@ All workflows are using the tagging convention listed below. It is subsequently
|
||||
| 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 |
|
||||
| `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.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 |
|
||||
| `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) -->
|
||||
|
||||
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.
|
||||
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`).
|
||||
|
||||
[github-ci]: https://github.com/wg-easy/wg-easy/actions
|
||||
[ghcr-image]: https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy
|
||||
|
||||
@@ -2,42 +2,4 @@
|
||||
title: Admin Panel
|
||||
---
|
||||
|
||||
## Interface Settings
|
||||
|
||||
### Per-Client Firewall
|
||||
|
||||
Enable server-side firewall filtering to enforce network access restrictions per client.
|
||||
|
||||
When enabled, each client can have custom "Firewall Allowed IPs" configured that restrict which destinations they can access through the VPN. These restrictions are enforced by the server using iptables/ip6tables and cannot be bypassed by the client.
|
||||
|
||||
/// warning | Experimental Feature
|
||||
|
||||
This feature is currently experimental. While functional, it should be thoroughly tested in your environment before relying on it for production security requirements. Always verify that firewall rules are working as expected using test traffic or by manually inspecting the rules.
|
||||
|
||||
///
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- `iptables` must be installed on the host system
|
||||
- `ip6tables` must be installed if IPv6 is enabled (default)
|
||||
- The feature cannot be enabled if these tools are not available
|
||||
|
||||
/// note
|
||||
Most Linux distributions include iptables by default. If you're running in a minimal container environment, you may need to install the `iptables` package on the host system.
|
||||
///
|
||||
|
||||
**Enable this feature if you want to:**
|
||||
|
||||
- Restrict certain clients to only access specific servers or networks
|
||||
- Prevent clients from accessing the internet while allowing LAN access
|
||||
- Enforce port-based restrictions (e.g., only allow HTTP/HTTPS)
|
||||
- Separate routing configuration from security enforcement
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Enable "Per-Client Firewall" in Admin Panel → Interface
|
||||
2. Edit any client to see the new "Firewall Allowed IPs" field
|
||||
3. Specify allowed destinations (IPs, subnets, ports) for that client
|
||||
4. Server enforces these rules automatically
|
||||
|
||||
See [Edit Client → Firewall Allowed IPs](./clients.md#firewall-allowed-ips) for detailed configuration syntax and examples.
|
||||
TODO
|
||||
|
||||
@@ -41,31 +41,3 @@ docker compose exec -it wg-easy cli db:admin:reset --password <new_password>
|
||||
```
|
||||
|
||||
This will reset the password for the admin user to the new password you provided. If you include special characters in the password, make sure to escape them properly.
|
||||
|
||||
### Show Clients
|
||||
|
||||
List all clients that are currently configured with details such as client ID, Name, Public Key, and enabled status.
|
||||
|
||||
```shell
|
||||
cli clients:list
|
||||
```
|
||||
|
||||
### Show Client QR Code
|
||||
|
||||
Display the QR code for a specific client, which can be scanned by a compatible app to import the client's configuration.
|
||||
|
||||
```shell
|
||||
cli clients:qr <client_id>
|
||||
```
|
||||
|
||||
Replace `<client_id>` with the actual client ID you want to show the QR code for.
|
||||
|
||||
/// warning | IPv6 Support
|
||||
|
||||
IPv6 support is enabled by default, even if you disabled it using environment variables. To disable it pass the `--no-ipv6` flag when running the CLI.
|
||||
|
||||
```shell
|
||||
cli clients:qr <client_id> --no-ipv6
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
@@ -19,58 +19,7 @@ Which IPs will be routed through the VPN.
|
||||
|
||||
This will not prevent the user from modifying it locally and accessing IP ranges that they should not be able to access.
|
||||
|
||||
Use the Firewall Allowed IPs feature to prevent access to IP ranges that the user should not be able to access.
|
||||
|
||||
## Firewall Allowed IPs
|
||||
|
||||
/// note | Attention
|
||||
|
||||
This field only appears when **Per-Client Firewall** is enabled in the Admin Panel → Interface settings.
|
||||
|
||||
///
|
||||
|
||||
Server-side firewall rules that restrict which destinations the client can access, regardless of their local configuration.
|
||||
|
||||
Unlike "Allowed IPs" which only controls routing on the client side, these rules are enforced by the server using iptables/ip6tables and cannot be bypassed by the client.
|
||||
|
||||
**Supported Formats:**
|
||||
|
||||
- `10.10.0.3`, `2001:db8::1` - Allow access to a single IP address
|
||||
- `10.10.0.0/24`, `2001:db8::/32` - Allow access to an entire subnet
|
||||
- `192.168.1.5:443` - Allow access to specific port (TCP+UDP)
|
||||
- `192.168.1.5:443/tcp` - Allow access to specific port (TCP only)
|
||||
- `192.168.1.5:443/udp` - Allow access to specific port (UDP only)
|
||||
- `10.10.0.0/24:443` - Allow access to an entire subnet on a specific port (TCP+UDP)
|
||||
- `10.10.0.0/24:443/tcp` - Allow access to an entire subnet on a specific port (TCP only)
|
||||
- `10.10.0.0/24:443/udp` - Allow access to an entire subnet on a specific port (UDP only)
|
||||
- `[2001:db8::1]:443` - IPv6 address with port (brackets required)
|
||||
- `[2001:db8::/32]:443/tcp` - IPv6 CIDR with port and protocol
|
||||
|
||||
/// warning | Invalid Formats
|
||||
|
||||
Protocol specifiers (`/tcp` or `/udp`) require a port number. The following formats are **not supported** and will result in an error:
|
||||
|
||||
- `10.10.0.3/tcp` (use `10.10.0.3:443/tcp` instead)
|
||||
- `10.10.0.0/24/udp` (use `10.10.0.0/24:53/udp` instead)
|
||||
|
||||
///
|
||||
|
||||
**Behavior:**
|
||||
|
||||
- **Empty**: Falls back to the client's "Allowed IPs" setting
|
||||
- **Specified**: Only listed destinations are accessible (allow-only, everything else is blocked)
|
||||
- **Disable for specific client**: To disable firewall filtering for a single client while keeping it enabled for others, add `0.0.0.0/0, ::/0` to allow all traffic
|
||||
|
||||
/// note
|
||||
To allow clients to reach the VPN server itself (e.g. for DNS), include the server's VPN address in the firewall allowed IPs.
|
||||
///
|
||||
|
||||
**Use Case Examples**:
|
||||
|
||||
- Allow only specific servers: `10.10.0.5`
|
||||
- Allow only internal network: `10.10.0.0/24, 192.168.1.0/24`
|
||||
- Allow only web browsing: `0.0.0.0/0:80, 0.0.0.0/0:443, [::/0]:80, [::/0]:443`
|
||||
- Block internet, allow LAN: Leave "Allowed IPs" as `0.0.0.0/0, ::/0` but set Firewall IPs to `10.0.0.0/8, 192.168.0.0/16`
|
||||
Use firewall rules to prevent access to IP ranges that the user should not be able to access.
|
||||
|
||||
## Server Allowed IPs
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ hide:
|
||||
|
||||
/// 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 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 `:latest` image tag - [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.
|
||||
|
||||
+2
-3
@@ -7,11 +7,10 @@
|
||||
"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",
|
||||
"scripts:version": "bash scripts/version.sh",
|
||||
"scripts:i18n": "bash scripts/i18n.sh",
|
||||
"format:check:docs": "prettier --check docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.8.1"
|
||||
"prettier": "^3.6.2"
|
||||
},
|
||||
"packageManager": "pnpm@10.31.0"
|
||||
"packageManager": "pnpm@10.21.0"
|
||||
}
|
||||
|
||||
Generated
+5
-5
@@ -9,16 +9,16 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
prettier:
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1
|
||||
specifier: ^3.6.2
|
||||
version: 3.6.2
|
||||
|
||||
packages:
|
||||
|
||||
prettier@3.8.1:
|
||||
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
|
||||
prettier@3.6.2:
|
||||
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
prettier@3.8.1: {}
|
||||
prettier@3.6.2: {}
|
||||
|
||||
@@ -30,7 +30,6 @@ echo "Updated package.json to version $new_version"
|
||||
|
||||
echo "----"
|
||||
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 "If you did everything press 'y' to commit the changes and create a new tag"
|
||||
|
||||
@@ -23,6 +23,4 @@ logs
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
coverage/
|
||||
|
||||
wg-easy.db
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
setups.@nuxt/test-utils="4.0.0"
|
||||
@@ -1,7 +0,0 @@
|
||||
:root {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<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,10 +0,0 @@
|
||||
<template>
|
||||
<textarea
|
||||
v-model="data"
|
||||
class="rounded-lg border-2 border-gray-100 text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-400"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = defineModel<string>();
|
||||
</script>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ClientCardCharts :client="client" />
|
||||
<div
|
||||
class="relative flex flex-col justify-between gap-3 px-3 py-3 sm:flex-row md:py-5"
|
||||
class="relative z-10 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">
|
||||
<ClientCardAvatar :client="client" />
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<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>
|
||||
@@ -5,25 +5,11 @@
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="bg-white">
|
||||
<img ref="img" :src="qrCode" />
|
||||
<img :src="qrCode" />
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
<BaseSecondaryButton
|
||||
class="flex items-center gap-2"
|
||||
:title="$t('client.copyPng')"
|
||||
@click="copyPng"
|
||||
>
|
||||
<IconsCopy class="size-5" /> PNG
|
||||
</BaseSecondaryButton>
|
||||
<BaseSecondaryButton
|
||||
class="flex items-center gap-2"
|
||||
:title="$t('client.downloadPng')"
|
||||
@click="downloadPng"
|
||||
>
|
||||
<IconsDownload class="size-5" /> PNG
|
||||
</BaseSecondaryButton>
|
||||
<DialogClose as-child>
|
||||
<DialogClose>
|
||||
<BaseSecondaryButton>{{ $t('dialog.cancel') }}</BaseSecondaryButton>
|
||||
</DialogClose>
|
||||
</template>
|
||||
@@ -32,87 +18,4 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{ qrCode: string }>();
|
||||
|
||||
const toast = useToast();
|
||||
const img = useTemplateRef('img');
|
||||
|
||||
async function svgToPng() {
|
||||
if (!img.value || !img.value.complete || img.value.naturalWidth === 0) {
|
||||
throw new Error('image is not loaded');
|
||||
}
|
||||
|
||||
const width = 1000;
|
||||
const height = 1000;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) {
|
||||
throw new Error('was not able to create 2d context');
|
||||
}
|
||||
ctx.drawImage(img.value!, 0, 0, width, height);
|
||||
|
||||
return new Promise<Blob>((res, rej) => {
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) {
|
||||
return rej(new Error('was not able to create blob'));
|
||||
}
|
||||
return res(blob);
|
||||
}, 'image/png');
|
||||
});
|
||||
}
|
||||
|
||||
async function downloadPng() {
|
||||
try {
|
||||
const blob = await svgToPng();
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'client-config.png';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (e) {
|
||||
console.error('failed to download png', e);
|
||||
toast.showToast({
|
||||
type: 'error',
|
||||
message: $t('toast.unknown'),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function copyPng() {
|
||||
const blob = await svgToPng().catch((e) => {
|
||||
console.error('failed to convert svg to png', e);
|
||||
toast.showToast({
|
||||
type: 'error',
|
||||
message: $t('toast.unknown'),
|
||||
});
|
||||
});
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob,
|
||||
}),
|
||||
]);
|
||||
|
||||
toast.showToast({
|
||||
type: 'success',
|
||||
message: $t('copy.copied'),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('failed to copy png', e);
|
||||
toast.showToast({
|
||||
type: 'error',
|
||||
message: $t('copy.failed'),
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="relative w-60 md:mr-2">
|
||||
<div class="relative flex h-full items-center">
|
||||
<IconsMagnifyingGlass
|
||||
<MagnifyingGlassIcon
|
||||
class="absolute left-2.5 h-4 w-4 text-gray-400 dark:text-neutral-500"
|
||||
/>
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
:placeholder="$t('client.search')"
|
||||
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"
|
||||
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"
|
||||
@input="updateSearch"
|
||||
/>
|
||||
<button
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
v-if="overridden"
|
||||
class="flex w-fit items-center gap-2 rounded-lg bg-amber-50 p-2 text-sm text-amber-700 dark:bg-amber-900/20 dark:text-amber-400"
|
||||
>
|
||||
<IconsWarning class="size-4" />
|
||||
<span>This field is overridden by an environment variable</span>
|
||||
</div>
|
||||
<div v-if="data?.length === 0">
|
||||
{{ emptyText || $t('form.noItems') }}
|
||||
</div>
|
||||
@@ -35,7 +42,11 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = defineModel<string[]>();
|
||||
defineProps<{ emptyText?: string[]; name: string }>();
|
||||
defineProps<{
|
||||
emptyText?: string[];
|
||||
name: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
function update(e: Event, i: number) {
|
||||
const v = (e.target as HTMLInputElement).value;
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="overridden"
|
||||
text="This field is overridden by an environment variable"
|
||||
>
|
||||
<IconsWarning class="size-4 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<BaseInput
|
||||
@@ -38,6 +44,7 @@ defineProps<{
|
||||
description?: string;
|
||||
placeholder?: string;
|
||||
url: '/api/admin/ip-info' | '/api/setup/4';
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string | null>({
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="overridden"
|
||||
text="This field is overridden by an environment variable"
|
||||
>
|
||||
<IconsWarning class="size-4 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput
|
||||
:id="id"
|
||||
@@ -24,6 +30,7 @@ defineProps<{
|
||||
description?: string;
|
||||
autocomplete?: string;
|
||||
placeholder?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string | null>({
|
||||
|
||||
@@ -6,12 +6,23 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="overridden"
|
||||
text="This field is overridden by an environment variable"
|
||||
>
|
||||
<IconsWarning class="size-4 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput :id="id" v-model.number="data" :name="id" type="number" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ id: string; label: string; description?: string }>();
|
||||
defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<number>();
|
||||
</script>
|
||||
|
||||
@@ -6,11 +6,22 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="overridden"
|
||||
text="This field is overridden by an environment variable"
|
||||
>
|
||||
<IconsWarning class="size-4 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseSwitch :id="id" v-model="data" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ id: string; label: string; description?: string }>();
|
||||
defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
const data = defineModel<boolean>();
|
||||
</script>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<div class="flex items-center">
|
||||
<FormLabel :for="id">
|
||||
{{ label }}
|
||||
</FormLabel>
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseTextArea
|
||||
:id="id"
|
||||
v-model.trim="data"
|
||||
:name="id"
|
||||
:autocomplete="autocomplete"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
autocomplete?: string;
|
||||
disabled?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string>();
|
||||
</script>
|
||||
@@ -6,6 +6,12 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip
|
||||
v-if="overridden"
|
||||
text="This field is overridden by an environment variable"
|
||||
>
|
||||
<IconsWarning class="size-4 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput
|
||||
:id="id"
|
||||
@@ -24,6 +30,7 @@ defineProps<{
|
||||
description?: string;
|
||||
autocomplete?: string;
|
||||
disabled?: boolean;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string>();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<Toggle
|
||||
:pressed="globalStore.uiShowCharts"
|
||||
class="group flex h-8 w-8 items-center justify-center rounded-full bg-gray-200 transition hover:bg-gray-300 dark:bg-neutral-700 dark:hover:bg-neutral-600"
|
||||
class="group inline-flex h-8 w-8 cursor-pointer items-center justify-center whitespace-nowrap rounded-full bg-gray-200 transition hover:bg-gray-300 dark:bg-neutral-700 dark:hover:bg-neutral-600"
|
||||
:title="$t('layout.toggleCharts')"
|
||||
@update:pressed="globalStore.toggleCharts"
|
||||
>
|
||||
<IconsChart
|
||||
class="h-5 w-5 transition group-data-[state=on]:fill-gray-600 dark:text-neutral-400 dark:group-data-[state=on]:fill-gray-300"
|
||||
class="h-5 w-5 fill-gray-400 transition group-data-[state=on]:fill-gray-600 dark:fill-neutral-600 dark:group-data-[state=on]:fill-neutral-400"
|
||||
/>
|
||||
</Toggle>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<ClipboardDocumentIcon />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ClipboardDocumentIcon from '@heroicons/vue/24/outline/esm/ClipboardDocumentIcon';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<MagnifyingGlassIcon />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MagnifyingGlassIcon from '@heroicons/vue/24/outline/esm/MagnifyingGlassIcon';
|
||||
</script>
|
||||
@@ -7,7 +7,7 @@
|
||||
href="https://github.com/wg-easy/wg-easy"
|
||||
>WireGuard Easy</a
|
||||
>
|
||||
({{ globalStore.information?.currentRelease }}) © 2021-2026 by
|
||||
({{ globalStore.information?.currentRelease }}) © 2021-2025 by
|
||||
<a
|
||||
class="hover:underline"
|
||||
target="_blank"
|
||||
|
||||
@@ -4,27 +4,25 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = useRequestEvent();
|
||||
|
||||
const authStore = useAuthStore();
|
||||
authStore.userData = await authStore.getSession(event);
|
||||
const userData = await authStore.getSession();
|
||||
|
||||
// skip login if already logged in
|
||||
if (to.path === '/login') {
|
||||
if (authStore.userData?.username) {
|
||||
if (userData?.username) {
|
||||
return navigateTo('/', { redirectCode: 302 });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Require auth for every page other than Login
|
||||
if (!authStore.userData?.username) {
|
||||
if (!userData?.username) {
|
||||
return navigateTo('/login', { redirectCode: 302 });
|
||||
}
|
||||
|
||||
// Check for admin access
|
||||
if (to.path.startsWith('/admin')) {
|
||||
if (!hasPermissions(authStore.userData, 'admin', 'any')) {
|
||||
if (!hasPermissions(userData, 'admin', 'any')) {
|
||||
return abortNavigation('Not allowed to access Admin Panel');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
:to="`/admin/${item.id}`"
|
||||
class="group rounded"
|
||||
active-class="bg-red-800 active"
|
||||
active-class="bg-red-800 rounded"
|
||||
>
|
||||
<BaseSecondaryButton
|
||||
as="span"
|
||||
class="w-full font-medium group-[.active]:text-white"
|
||||
class="w-full cursor-pointer rounded p-2 font-medium transition-colors duration-200 hover:bg-red-800 dark:text-neutral-200"
|
||||
>
|
||||
{{ item.name }}
|
||||
</BaseSecondaryButton>
|
||||
@@ -38,6 +37,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const authStore = useAuthStore();
|
||||
authStore.update();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
:label="$t('general.host')"
|
||||
:description="$t('admin.config.hostDesc')"
|
||||
url="/api/admin/ip-info"
|
||||
:overridden="overrides?.host"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="port"
|
||||
v-model="data.port"
|
||||
:label="$t('general.port')"
|
||||
:description="$t('admin.config.portDesc')"
|
||||
:overridden="overrides?.port"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -24,13 +26,18 @@
|
||||
<FormArrayField
|
||||
v-model="data.defaultAllowedIps"
|
||||
name="defaultAllowedIps"
|
||||
:overridden="overrides?.defaultAllowedIps"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading :description="$t('admin.config.dnsDesc')">
|
||||
{{ $t('general.dns') }}
|
||||
</FormHeading>
|
||||
<FormArrayField v-model="data.defaultDns" name="defaultDns" />
|
||||
<FormArrayField
|
||||
v-model="data.defaultDns"
|
||||
name="defaultDns"
|
||||
:overridden="overrides?.defaultDns"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('form.sectionAdvanced') }}</FormHeading>
|
||||
@@ -39,12 +46,14 @@
|
||||
v-model="data.defaultMtu"
|
||||
:label="$t('general.mtu')"
|
||||
:description="$t('admin.config.mtuDesc')"
|
||||
:overridden="overrides?.defaultMtu"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="defaultPersistentKeepalive"
|
||||
v-model="data.defaultPersistentKeepalive"
|
||||
:label="$t('general.persistentKeepalive')"
|
||||
:description="$t('admin.config.persistentKeepaliveDesc')"
|
||||
:overridden="overrides?.defaultPersistentKeepalive"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup v-if="globalStore.information?.isAwg">
|
||||
@@ -118,6 +127,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/userconfig`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.userConfig);
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
v-model="data.sessionTimeout"
|
||||
:label="$t('admin.general.sessionTimeout')"
|
||||
:description="$t('admin.general.sessionTimeoutDesc')"
|
||||
:overridden="overrides?.sessionTimeout"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -16,18 +17,21 @@
|
||||
v-model="data.metricsPassword"
|
||||
:label="$t('admin.general.metricsPassword')"
|
||||
:description="$t('admin.general.metricsPasswordDesc')"
|
||||
:overridden="overrides?.metricsPassword"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="prometheus"
|
||||
v-model="data.metricsPrometheus"
|
||||
:label="$t('admin.general.prometheus')"
|
||||
:description="$t('admin.general.prometheusDesc')"
|
||||
:overridden="overrides?.metricsPrometheus"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="json"
|
||||
v-model="data.metricsJson"
|
||||
:label="$t('admin.general.json')"
|
||||
:description="$t('admin.general.jsonDesc')"
|
||||
:overridden="overrides?.metricsJson"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -43,6 +47,13 @@
|
||||
const { data: _data, refresh } = await useFetch(`/api/admin/general`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.general);
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -2,25 +2,29 @@
|
||||
<main v-if="data">
|
||||
<FormElement @submit.prevent="submit">
|
||||
<FormGroup>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PreUp"
|
||||
v-model="data.preUp"
|
||||
:label="$t('hooks.preUp')"
|
||||
:overridden="overrides?.preUp"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PostUp"
|
||||
v-model="data.postUp"
|
||||
:label="$t('hooks.postUp')"
|
||||
:overridden="overrides?.postUp"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PreDown"
|
||||
v-model="data.preDown"
|
||||
:label="$t('hooks.preDown')"
|
||||
:overridden="overrides?.preDown"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PostDown"
|
||||
v-model="data.postDown"
|
||||
:label="$t('hooks.postDown')"
|
||||
:overridden="overrides?.postDown"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -37,6 +41,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/hooks`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.hooks);
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
v-model="data.mtu"
|
||||
:label="$t('general.mtu')"
|
||||
:description="$t('admin.interface.mtuDesc')"
|
||||
:overridden="overrides?.mtu"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="port"
|
||||
v-model="data.port"
|
||||
:label="$t('general.port')"
|
||||
:description="$t('admin.interface.portDesc')"
|
||||
:overridden="overrides?.port"
|
||||
/>
|
||||
<FormTextField
|
||||
id="device"
|
||||
v-model="data.device"
|
||||
:label="$t('admin.interface.device')"
|
||||
:description="$t('admin.interface.deviceDesc')"
|
||||
:overridden="overrides?.device"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup v-if="globalStore.information?.isAwg">
|
||||
@@ -69,30 +72,6 @@
|
||||
:label="$t('awg.s4Label')"
|
||||
:description="$t('awg.s4Description')"
|
||||
/>
|
||||
<FormNullTextField
|
||||
id="h1"
|
||||
v-model="data.h1"
|
||||
:label="$t('awg.h1Label')"
|
||||
:description="$t('awg.h1Description')"
|
||||
/>
|
||||
<FormNullTextField
|
||||
id="h2"
|
||||
v-model="data.h2"
|
||||
:label="$t('awg.h2Label')"
|
||||
:description="$t('awg.h2Description')"
|
||||
/>
|
||||
<FormNullTextField
|
||||
id="h3"
|
||||
v-model="data.h3"
|
||||
:label="$t('awg.h3Label')"
|
||||
:description="$t('awg.h3Description')"
|
||||
/>
|
||||
<FormNullTextField
|
||||
id="h4"
|
||||
v-model="data.h4"
|
||||
:label="$t('awg.h4Label')"
|
||||
:description="$t('awg.h4Description')"
|
||||
/>
|
||||
<FormNullTextField
|
||||
id="i1"
|
||||
v-model="data.i1"
|
||||
@@ -123,14 +102,29 @@
|
||||
:label="$t('awg.i5Label')"
|
||||
:description="$t('awg.i5Description')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('admin.interface.firewall') }}</FormHeading>
|
||||
<FormSwitchField
|
||||
id="firewallEnabled"
|
||||
v-model="data.firewallEnabled"
|
||||
:label="$t('admin.interface.firewallEnabled')"
|
||||
:description="$t('admin.interface.firewallEnabledDesc')"
|
||||
<FormNullNumberField
|
||||
id="h1"
|
||||
v-model="data.h1"
|
||||
:label="$t('awg.h1Label')"
|
||||
:description="$t('awg.h1Description')"
|
||||
/>
|
||||
<FormNullNumberField
|
||||
id="h2"
|
||||
v-model="data.h2"
|
||||
:label="$t('awg.h2Label')"
|
||||
:description="$t('awg.h2Description')"
|
||||
/>
|
||||
<FormNullNumberField
|
||||
id="h3"
|
||||
v-model="data.h3"
|
||||
:label="$t('awg.h3Label')"
|
||||
:description="$t('awg.h3Description')"
|
||||
/>
|
||||
<FormNullNumberField
|
||||
id="h4"
|
||||
v-model="data.h4"
|
||||
:label="$t('awg.h4Label')"
|
||||
:description="$t('awg.h4Description')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -173,6 +167,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/interface`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.interface);
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
@@ -180,15 +180,7 @@ const _submit = useSubmit(
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
{
|
||||
revert: async (success) => {
|
||||
await revert();
|
||||
if (success) {
|
||||
// Refresh global store information after successful save
|
||||
await globalStore.refreshInformation();
|
||||
}
|
||||
},
|
||||
}
|
||||
{ revert }
|
||||
);
|
||||
|
||||
function submit() {
|
||||
|
||||
@@ -61,12 +61,6 @@
|
||||
name="serverAllowedIps"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup v-if="globalStore.information?.firewallEnabled">
|
||||
<FormHeading :description="$t('client.firewallIpsDesc')">
|
||||
{{ $t('client.firewallIps') }}
|
||||
</FormHeading>
|
||||
<FormNullArrayField v-model="data.firewallIps" name="firewallIps" />
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading :description="$t('client.dnsDesc')">
|
||||
{{ $t('general.dns') }}
|
||||
@@ -147,25 +141,25 @@
|
||||
<FormHeading :description="$t('client.hooksDescription')">
|
||||
{{ $t('client.hooks') }}
|
||||
</FormHeading>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PreUp"
|
||||
v-model="data.preUp"
|
||||
:description="$t('client.hooksLeaveEmpty')"
|
||||
:label="$t('hooks.preUp')"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PostUp"
|
||||
v-model="data.postUp"
|
||||
:description="$t('client.hooksLeaveEmpty')"
|
||||
:label="$t('hooks.postUp')"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PreDown"
|
||||
v-model="data.preDown"
|
||||
:description="$t('client.hooksLeaveEmpty')"
|
||||
:label="$t('hooks.preDown')"
|
||||
/>
|
||||
<FormTextArea
|
||||
<FormTextField
|
||||
id="PostDown"
|
||||
v-model="data.postDown"
|
||||
:description="$t('client.hooksLeaveEmpty')"
|
||||
@@ -185,25 +179,13 @@
|
||||
@delete="deleteClient"
|
||||
>
|
||||
<FormSecondaryActionField
|
||||
:label="$t('client.delete')"
|
||||
label="Delete"
|
||||
class="w-full"
|
||||
type="button"
|
||||
tabindex="-1"
|
||||
as="span"
|
||||
/>
|
||||
</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>
|
||||
</FormElement>
|
||||
</PanelBody>
|
||||
@@ -212,7 +194,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const authStore = useAuthStore();
|
||||
const globalStore = useGlobalStore();
|
||||
authStore.update();
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.params.id as string;
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const authStore = useAuthStore();
|
||||
authStore.update();
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const clientsStore = useClientsStore();
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const authStore = useAuthStore();
|
||||
authStore.update();
|
||||
|
||||
const toast = useToast();
|
||||
const { t } = useI18n();
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
import { encodeQR } from 'qr';
|
||||
|
||||
const authStore = useAuthStore();
|
||||
authStore.update();
|
||||
|
||||
const name = ref(authStore.userData?.name);
|
||||
const email = ref(authStore.userData?.email);
|
||||
|
||||
@@ -55,9 +55,15 @@ const _submit = useSubmit(
|
||||
method: 'post',
|
||||
},
|
||||
{
|
||||
revert: async (success) => {
|
||||
revert: async (success, data) => {
|
||||
if (success) {
|
||||
await navigateTo('/setup/3');
|
||||
if (data?.setupDone) {
|
||||
// Setup is complete, redirect to success page
|
||||
await navigateTo('/setup/success');
|
||||
} else {
|
||||
// Continue to step 3
|
||||
await navigateTo('/setup/3');
|
||||
}
|
||||
}
|
||||
},
|
||||
noSuccessToast: true,
|
||||
|
||||
+6
-13
@@ -1,25 +1,18 @@
|
||||
import type { H3Event } from 'h3';
|
||||
import type { SharedPublicUser } from '~~/shared/utils/permissions';
|
||||
|
||||
export const useAuthStore = defineStore('Auth', () => {
|
||||
const userData = useState<SharedPublicUser | null>('user-data', () => null);
|
||||
const { data: userData, refresh: update } = useFetch('/api/session', {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
async function getSession(event?: H3Event) {
|
||||
const fetch = event?.$fetch || $fetch;
|
||||
async function getSession() {
|
||||
try {
|
||||
const data = await fetch('/api/session', {
|
||||
const { data } = await useFetch('/api/session', {
|
||||
method: 'get',
|
||||
});
|
||||
return data;
|
||||
return data.value;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function update() {
|
||||
const data = await getSession();
|
||||
userData.value = data;
|
||||
}
|
||||
|
||||
return { userData, update, getSession };
|
||||
});
|
||||
|
||||
@@ -66,11 +66,10 @@ export const useClientsStore = defineStore('Clients', () => {
|
||||
const clientPersist = clientsPersist.value[client.id]!;
|
||||
|
||||
// Debug
|
||||
/* client.transferRx =
|
||||
clientPersist.transferRxPrevious + Math.random() * 1000;
|
||||
client.transferTx =
|
||||
clientPersist.transferTxPrevious + Math.random() * 1000;
|
||||
client.latestHandshakeAt = new Date().toISOString(); */
|
||||
// client.transferRx = this.clientsPersist[client.id].transferRxPrevious + Math.random() * 1000;
|
||||
// client.transferTx = this.clientsPersist[client.id].transferTxPrevious + Math.random() * 1000;
|
||||
// client.latestHandshakeAt = new Date();
|
||||
// this.requiresPassword = true;
|
||||
|
||||
clientPersist.transferRxCurrent =
|
||||
(client.transferRx ?? 0) - clientPersist.transferRxPrevious;
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
export const useGlobalStore = defineStore('Global', () => {
|
||||
const { data: information, refresh: refreshInformation } = useFetch(
|
||||
'/api/information',
|
||||
{
|
||||
method: 'get',
|
||||
}
|
||||
);
|
||||
const { data: information } = useFetch('/api/information', {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const sortClient = ref(true); // Sort clients by name, true = asc, false = desc
|
||||
|
||||
@@ -25,7 +22,6 @@ export const useGlobalStore = defineStore('Global', () => {
|
||||
return {
|
||||
sortClient,
|
||||
information,
|
||||
refreshInformation,
|
||||
uiShowCharts,
|
||||
toggleCharts,
|
||||
uiChartType,
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { consola } from 'consola';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import { db, schema } from '../db';
|
||||
import { hashPassword } from '../../server/utils/password';
|
||||
|
||||
export default defineCommand({
|
||||
meta: {
|
||||
name: 'db:admin:reset',
|
||||
description: 'Reset the admin user password and TOTP settings',
|
||||
},
|
||||
args: {
|
||||
password: {
|
||||
type: 'string',
|
||||
description: 'New password for the admin user',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
async run(ctx) {
|
||||
let password = ctx.args.password || undefined;
|
||||
if (!password) {
|
||||
password = await consola.prompt('Please enter a new password:', {
|
||||
type: 'text',
|
||||
});
|
||||
}
|
||||
if (!password) {
|
||||
consola.error('Password is required');
|
||||
return;
|
||||
}
|
||||
if (password.length < 12) {
|
||||
consola.error('Password must be at least 12 characters long');
|
||||
return;
|
||||
}
|
||||
consola.info('Setting new password for admin user...');
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
const user = await db.transaction(async (tx) => {
|
||||
const user = await tx
|
||||
.select()
|
||||
.from(schema.user)
|
||||
.where(eq(schema.user.id, 1))
|
||||
.get();
|
||||
|
||||
if (!user) {
|
||||
consola.error('Admin user not found');
|
||||
return;
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(schema.user)
|
||||
.set({
|
||||
password: hash,
|
||||
totpVerified: false,
|
||||
totpKey: null,
|
||||
})
|
||||
.where(eq(schema.user.id, 1));
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
consola.error('Failed to update admin user');
|
||||
return;
|
||||
}
|
||||
|
||||
consola.success(
|
||||
`Successfully updated admin user ${user.id} (${user.username})`
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { consola } from 'consola';
|
||||
|
||||
import { db } from '../db';
|
||||
|
||||
export default defineCommand({
|
||||
meta: {
|
||||
name: 'clients:list',
|
||||
description: 'List all clients',
|
||||
},
|
||||
async run() {
|
||||
consola.info('Listing all clients...');
|
||||
const clients = await db.query.client.findMany({
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
publicKey: true,
|
||||
enabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (clients.length === 0) {
|
||||
consola.info('No clients found');
|
||||
return;
|
||||
}
|
||||
|
||||
console.table(clients);
|
||||
},
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
import { defineCommand } from 'citty';
|
||||
import { consola } from 'consola';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import { wg } from '../../server/utils/wgHelper';
|
||||
import { encodeQRCodeTerm } from '../../server/utils/qr';
|
||||
import { db, schema } from '../db';
|
||||
|
||||
export default defineCommand({
|
||||
meta: {
|
||||
name: 'clients:qr',
|
||||
description: 'Generate QR code for a client',
|
||||
},
|
||||
args: {
|
||||
id: {
|
||||
required: true,
|
||||
type: 'positional',
|
||||
},
|
||||
ipv6: {
|
||||
required: false,
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
async run(ctx) {
|
||||
const clientId = Number(ctx.args.id);
|
||||
const enableIpv6 = ctx.args.ipv6;
|
||||
|
||||
if (Number.isNaN(clientId)) {
|
||||
consola.error('Invalid client ID');
|
||||
return;
|
||||
}
|
||||
|
||||
consola.info('Generating QR code for client...');
|
||||
|
||||
const wgInterface = await db.query.wgInterface.findFirst({
|
||||
where: eq(schema.wgInterface.name, 'wg0'),
|
||||
});
|
||||
if (!wgInterface) {
|
||||
consola.error('WireGuard interface not found');
|
||||
return;
|
||||
}
|
||||
|
||||
const userConfig = await db.query.userConfig.findFirst({
|
||||
where: eq(schema.userConfig.id, 'wg0'),
|
||||
});
|
||||
if (!userConfig) {
|
||||
consola.error('User config not found');
|
||||
return;
|
||||
}
|
||||
|
||||
const client = await db.query.client.findFirst({
|
||||
where: eq(schema.client.id, clientId),
|
||||
});
|
||||
if (!client) {
|
||||
consola.error(`Client with ID ${clientId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
const clientConfig = wg.generateClientConfig(
|
||||
wgInterface,
|
||||
userConfig,
|
||||
client,
|
||||
{
|
||||
enableIpv6,
|
||||
}
|
||||
);
|
||||
|
||||
consola.log(encodeQRCodeTerm(clientConfig));
|
||||
},
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import { createClient } from '@libsql/client';
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
|
||||
import * as schema from '../server/database/schema';
|
||||
|
||||
//const client = createClient({ url: 'file:../data/wg-easy.db' });
|
||||
const client = createClient({ url: 'file:/etc/wireguard/wg-easy.db' });
|
||||
export const db = drizzle({ client, schema });
|
||||
|
||||
export { schema };
|
||||
+72
-26
@@ -1,38 +1,82 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import type { Resolvable, SubCommandsDef } from 'citty';
|
||||
// ! Auto Imports are not supported in this file
|
||||
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { createClient } from '@libsql/client';
|
||||
import { defineCommand, runMain } from 'citty';
|
||||
import { consola } from 'consola';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import packageJson from '../package.json';
|
||||
import * as schema from '../server/database/schema';
|
||||
import { hashPassword } from '../server/utils/password';
|
||||
|
||||
// Commands
|
||||
import dbAdminReset from './admin/reset';
|
||||
import clientsList from './clients/list';
|
||||
import clientsQr from './clients/qr';
|
||||
const subCommands = [dbAdminReset, clientsList, clientsQr] as const;
|
||||
const client = createClient({ url: 'file:/etc/wireguard/wg-easy.db' });
|
||||
const db = drizzle({ client, schema });
|
||||
|
||||
// from citty
|
||||
function resolveValue<T>(input: Resolvable<T>): T | Promise<T> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return typeof input === 'function' ? (input as any)() : input;
|
||||
}
|
||||
|
||||
async function generateSubCommands(): Promise<SubCommandsDef> {
|
||||
const subCommandsMap: Record<string, SubCommandsDef[string]> = {};
|
||||
|
||||
for (const cmd of subCommands) {
|
||||
const cmdMeta = await resolveValue(cmd.meta || {});
|
||||
if (!cmdMeta.name) {
|
||||
console.warn('Skipping command without name:', cmd);
|
||||
continue;
|
||||
const dbAdminReset = defineCommand({
|
||||
meta: {
|
||||
name: 'db:admin:reset',
|
||||
description: 'Reset the admin user',
|
||||
},
|
||||
args: {
|
||||
password: {
|
||||
type: 'string',
|
||||
description: 'New password for the admin user',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
async run(ctx) {
|
||||
let password = ctx.args.password || undefined;
|
||||
if (!password) {
|
||||
password = await consola.prompt('Please enter a new password:', {
|
||||
type: 'text',
|
||||
});
|
||||
}
|
||||
subCommandsMap[cmdMeta.name] = cmd;
|
||||
}
|
||||
if (!password) {
|
||||
consola.error('Password is required');
|
||||
return;
|
||||
}
|
||||
if (password.length < 12) {
|
||||
consola.error('Password must be at least 12 characters long');
|
||||
return;
|
||||
}
|
||||
console.info('Setting new password for admin user...');
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
return subCommandsMap;
|
||||
}
|
||||
const user = await db.transaction(async (tx) => {
|
||||
const user = await tx
|
||||
.select()
|
||||
.from(schema.user)
|
||||
.where(eq(schema.user.id, 1))
|
||||
.get();
|
||||
|
||||
const subCommandsMap = await generateSubCommands();
|
||||
if (!user) {
|
||||
consola.error('Admin user not found');
|
||||
return;
|
||||
}
|
||||
|
||||
await tx
|
||||
.update(schema.user)
|
||||
.set({
|
||||
password: hash,
|
||||
})
|
||||
.where(eq(schema.user.id, 1));
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
consola.error('Failed to update admin user');
|
||||
return;
|
||||
}
|
||||
|
||||
consola.success(
|
||||
`Successfully updated admin user ${user.id} (${user.username})`
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const main = defineCommand({
|
||||
meta: {
|
||||
@@ -40,7 +84,9 @@ const main = defineCommand({
|
||||
version: packageJson.version,
|
||||
description: 'Command Line Interface',
|
||||
},
|
||||
subCommands: subCommandsMap,
|
||||
subCommands: {
|
||||
'db:admin:reset': dbAdminReset,
|
||||
},
|
||||
});
|
||||
|
||||
runMain(main);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "esnext",
|
||||
"target": "es2024",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
}
|
||||
@@ -7,18 +7,12 @@ import it from './locales/it.json';
|
||||
import ru from './locales/ru.json';
|
||||
import zhhk from './locales/zh-HK.json';
|
||||
import zhcn from './locales/zh-CN.json';
|
||||
import zhtw from './locales/zh-TW.json';
|
||||
import ko from './locales/ko.json';
|
||||
import es from './locales/es.json';
|
||||
import ptbr from './locales/pt-BR.json';
|
||||
import tr from './locales/tr.json';
|
||||
import bn from './locales/bn.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';
|
||||
import cs from './locales/cs.json';
|
||||
|
||||
export default defineI18nConfig(() => ({
|
||||
legacy: false,
|
||||
@@ -33,17 +27,11 @@ export default defineI18nConfig(() => ({
|
||||
ru,
|
||||
'zh-HK': zhhk,
|
||||
'zh-CN': zhcn,
|
||||
'zh-TW': zhtw,
|
||||
ko,
|
||||
es,
|
||||
'pt-BR': ptbr,
|
||||
tr,
|
||||
bn,
|
||||
id,
|
||||
nl,
|
||||
nb,
|
||||
bg,
|
||||
gl,
|
||||
cs,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
{
|
||||
"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 пакета (0–1132 [1280*−148=1132], препоръчително: 15–150, S1+56 ≠ S2)",
|
||||
"s2Label": "Размер на junk в отговорния пакет (S2)",
|
||||
"s2Description": "Размер на junk в response пакета (0–1188 [1280*−92=1188], препоръчително: 15–150)",
|
||||
"s3Label": "Размер на junk в cookie reply пакета (S3)",
|
||||
"s3Description": "Размер на junk в cookie reply пакета",
|
||||
"s4Label": "Размер на junk в транспортния пакет (S4)",
|
||||
"s4Description": "Размер на junk в транспортния пакет",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Стойност на хедера в init пакета (5–2147483647, уникална спрямо H2–H4)",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Стойност на хедера в response пакета (5–2147483647, уникална спрямо H1, H3, H4)",
|
||||
"h3Label": "Cookie reply magic header (H3)",
|
||||
"h3Description": "Стойност на хедера в cookie reply пакета (5–2147483647, уникална спрямо H1, H2, H4)",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Стойност на хедера в транспортния пакет (5–2147483647, уникална спрямо H1–H3)",
|
||||
"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...>",
|
||||
"mtuNote": "Стойностите зависят от MTU",
|
||||
"obfuscationParameters": "Параметри за обфускация на AmneziaWG"
|
||||
}
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "Účet",
|
||||
"clients": "Klienti",
|
||||
"admin": {
|
||||
"panel": "Administrace",
|
||||
"general": "Obecné",
|
||||
"config": "Konfigurace",
|
||||
"interface": "Rozhraní",
|
||||
"hooks": "Nastavení reakcí"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"email": "E-mail"
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "Aktuální heslo",
|
||||
"enable2fa": "Zapnout dvoufázové ověření (2FA)",
|
||||
"enable2faDesc": "Naskenujte QR kód ve své autentizační aplikaci nebo zadejte klíč ručně.",
|
||||
"2faKey": "TOTP klíč",
|
||||
"2faCodeDesc": "Zadejte kód z vaší autentizační aplikace.",
|
||||
"disable2fa": "Vypnout dvoufázové ověření",
|
||||
"disable2faDesc": "Pro vypnutí dvoufázového ověření zadejte své heslo."
|
||||
},
|
||||
"general": {
|
||||
"name": "Jméno",
|
||||
"username": "Uživatelské jméno",
|
||||
"password": "Heslo",
|
||||
"newPassword": "Nové heslo",
|
||||
"updatePassword": "Aktualizovat heslo",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "Povolené IP adresy",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "Persistent Keepalive",
|
||||
"logout": "Odhlásit se",
|
||||
"continue": "Pokračovat",
|
||||
"host": "Hostitel",
|
||||
"port": "Port",
|
||||
"yes": "Ano",
|
||||
"no": "Ne",
|
||||
"confirmPassword": "Potvrdit heslo",
|
||||
"loading": "Načítání...",
|
||||
"2fa": "Dvoufázové ověření",
|
||||
"2faCode": "TOTP kód"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "Vítejte u první instalace wg-easy",
|
||||
"welcomeDesc": "Našli jste nejjednodušší způsob, jak instalovat a spravovat WireGuard na jakémkoliv Linuxovém hostiteli",
|
||||
"existingSetup": "Máte již existující nastavení?",
|
||||
"createAdminDesc": "Nejprve zadejte uživatelské jméno administrátora a silné heslo. Tyto údaje budou použity pro přihlášení do administrace.",
|
||||
"setupConfigDesc": "Zadejte údaje o hostiteli a portu. Tyto informace budou použity pro konfiguraci klientů při nastavování WireGuard na jejich zařízeních.",
|
||||
"setupMigrationDesc": "Pokud chcete migrovat data z předchozí verze wg-easy do nové instalace, nahrajte soubor se zálohou.",
|
||||
"upload": "Nahrát",
|
||||
"migration": "Obnovit zálohu:",
|
||||
"createAccount": "Vytvořit účet",
|
||||
"successful": "Nastavení bylo úspěšné",
|
||||
"hostDesc": "Veřejný název hostitele, ke kterému se budou klienti připojovat",
|
||||
"portDesc": "Veřejný UDP port, ke kterému se budou klienti připojovat a na kterém bude WireGuard naslouchat"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "Je k dispozici aktualizace!",
|
||||
"update": "Aktualizovat"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Tmavý režim",
|
||||
"light": "Světlý režim",
|
||||
"system": "Systémové nastavení"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Zobrazit/skrýt grafy",
|
||||
"donate": "Přispět"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "Přihlásit se",
|
||||
"rememberMe": "Zapamatovat si mě",
|
||||
"rememberMeDesc": "Zůstat přihlášen i po zavření prohlížeče",
|
||||
"insecure": "Nemůžete se přihlásit přes nezabezpečené připojení. Použijte HTTPS.",
|
||||
"2faRequired": "Je vyžadováno dvoufázové ověření",
|
||||
"2faWrong": "Neplatný kód dvoufázového ověření"
|
||||
},
|
||||
"client": {
|
||||
"empty": "Zatím zde nejsou žádní klienti.",
|
||||
"newShort": "Nový",
|
||||
"sort": "Seřadit",
|
||||
"create": "Vytvořit klienta",
|
||||
"created": "Klient vytvořen",
|
||||
"new": "Nový klient",
|
||||
"name": "Jméno",
|
||||
"expireDate": "Datum vypršení",
|
||||
"expireDateDesc": "Datum, kdy bude klient deaktivován. Ponechte prázdné pro trvalý přístup.",
|
||||
"delete": "Smazat",
|
||||
"deleteClient": "Smazat klienta",
|
||||
"deleteDialog1": "Opravdu chcete smazat uživatele",
|
||||
"deleteDialog2": "Tuto akci nelze vzít zpět.",
|
||||
"enabled": "Aktivní",
|
||||
"address": "Adresa",
|
||||
"serverAllowedIps": "Povolené IP adresy serveru",
|
||||
"otlDesc": "Generovat krátký jednorázový odkaz",
|
||||
"permanent": "Trvalý",
|
||||
"createdOn": "Vytvořeno dne ",
|
||||
"lastSeen": "Naposledy viděn ",
|
||||
"totalDownload": "Celkem staženo: ",
|
||||
"totalUpload": "Celkem nahráno: ",
|
||||
"newClient": "Nový klient",
|
||||
"disableClient": "Deaktivovat klienta",
|
||||
"enableClient": "Aktivovat klienta",
|
||||
"noPrivKey": "Tento klient nemá známý soukromý klíč. Nelze vytvořit konfiguraci.",
|
||||
"showQR": "Zobrazit QR kód",
|
||||
"downloadConfig": "Stáhnout konfiguraci",
|
||||
"allowedIpsDesc": "Které IP adresy budou směrovány přes VPN (přebíjí globální nastavení)",
|
||||
"serverAllowedIpsDesc": "Které IP adresy bude server směrovat ke klientovi",
|
||||
"mtuDesc": "Nastavuje maximální velikost přenášeného paketu (MTU) pro VPN tunel",
|
||||
"persistentKeepaliveDesc": "Nastavuje interval (v sekundách) pro udržovací pakety. 0 pro vypnutí",
|
||||
"hooks": "Hooky",
|
||||
"hooksDescription": "Hooky fungují pouze s wg-quick",
|
||||
"hooksLeaveEmpty": "Pouze pro wg-quick. Jinak ponechte prázdné",
|
||||
"dnsDesc": "DNS server, který budou klienti používat (přebíjí globální nastavení)",
|
||||
"notConnected": "Klient není připojen",
|
||||
"endpoint": "Koncový bod",
|
||||
"endpointDesc": "IP adresa klienta, ze které je navázáno spojení WireGuard",
|
||||
"search": "Hledat klienty...",
|
||||
"config": "Konfigurace",
|
||||
"viewConfig": "Zobrazit konfiguraci"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Změnit",
|
||||
"cancel": "Zrušit",
|
||||
"create": "Vytvořit"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Úspěch",
|
||||
"saved": "Uloženo",
|
||||
"error": "Chyba"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Akce",
|
||||
"save": "Uložit",
|
||||
"revert": "Vrátit změny",
|
||||
"sectionGeneral": "Obecné",
|
||||
"sectionAdvanced": "Pokročilé",
|
||||
"noItems": "Žádné položky",
|
||||
"nullNoItems": "Žádné položky. Používá se globální konfigurace",
|
||||
"add": "Přidat"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Vypršení relace",
|
||||
"sessionTimeoutDesc": "Doba trvání relace pro 'Zapamatovat si mě' (sekundy)",
|
||||
"metrics": "Metriky",
|
||||
"metricsPassword": "Heslo",
|
||||
"metricsPasswordDesc": "Bearer heslo pro koncový bod metrik (heslo nebo argon2 hash)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Cesta pro metriky ve formátu JSON",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Cesta pro metriky Prometheus"
|
||||
},
|
||||
"config": {
|
||||
"connection": "Připojení",
|
||||
"hostDesc": "Veřejný název hostitele, ke kterému se klienti připojují (zneplatní stávající konfigurace)",
|
||||
"portDesc": "Veřejný UDP port, ke kterému se klienti připojují (zneplatní stávající konfigurace, pravděpodobně budete chtít změnit i Port rozhraní)",
|
||||
"allowedIpsDesc": "Povolené IP adresy, které budou klienti používat (globální nastavení)",
|
||||
"dnsDesc": "DNS server, který budou klienti používat (globální nastavení)",
|
||||
"mtuDesc": "MTU, které budou klienti používat (pouze pro nové klienty)",
|
||||
"persistentKeepaliveDesc": "Interval v sekundách pro odesílání udržovacích paketů na server. 0 = vypnuto (pouze pro nové klienty)",
|
||||
"suggest": "Navrhnout",
|
||||
"suggestDesc": "Vyberte IP adresu nebo název hostitele pro pole Hostitel"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR změněn",
|
||||
"device": "Zařízení",
|
||||
"deviceDesc": "Ethernetové zařízení, přes které má být provoz WireGuard přeposílán",
|
||||
"mtuDesc": "MTU, které bude WireGuard používat",
|
||||
"portDesc": "UDP port, na kterém bude WireGuard naslouchat (pravděpodobně budete chtít změnit i Konfigurační port)",
|
||||
"changeCidr": "Změnit CIDR",
|
||||
"restart": "Restartovat rozhraní",
|
||||
"restartDesc": "Restartovat rozhraní WireGuard",
|
||||
"restartWarn": "Opravdu chcete restartovat rozhraní? Dojde k odpojení všech klientů.",
|
||||
"restartSuccess": "Rozhraní bylo restartováno"
|
||||
},
|
||||
"introText": "Vítejte v administraci.\n\nZde můžete spravovat obecná nastavení, konfiguraci, nastavení rozhraní a hooky.\n\nZačněte výběrem jedné ze sekcí v bočním panelu."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "Pole {0} je povinné",
|
||||
"validNumber": "{0} musí být platné číslo",
|
||||
"validNumberRange": "{0} musí být platné číslo nebo rozsah čísel",
|
||||
"validString": "{0} musí být platný řetězec",
|
||||
"validBoolean": "{0} musí být platná logická hodnota",
|
||||
"validArray": "{0} musí být platné pole",
|
||||
"stringMin": "{0} musí mít alespoň {1} znak(ů)",
|
||||
"numberMin": "{0} musí být alespoň {1}"
|
||||
},
|
||||
"client": {
|
||||
"id": "ID klienta",
|
||||
"name": "Jméno",
|
||||
"expiresAt": "Vyprší dne",
|
||||
"address4": "IPv4 adresa",
|
||||
"address6": "IPv6 adresa",
|
||||
"serverAllowedIps": "Povolené IP adresy serveru"
|
||||
},
|
||||
"user": {
|
||||
"username": "Uživatelské jméno",
|
||||
"password": "Heslo",
|
||||
"remember": "Pamatovat si",
|
||||
"name": "Jméno",
|
||||
"email": "E-mail",
|
||||
"emailInvalid": "E-mail musí být platná e-mailová adresa",
|
||||
"passwordMatch": "Hesla se musí shodovat",
|
||||
"totpEnable": "Zapnout TOTP",
|
||||
"totpEnableTrue": "Zapnutí TOTP musí být potvrzeno",
|
||||
"totpCode": "TOTP kód"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "Hostitel"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "Vypršení relace",
|
||||
"metricsEnabled": "Metriky",
|
||||
"metricsPassword": "Heslo k metrikám"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Zařízení",
|
||||
"cidrValid": "CIDR musí být platný"
|
||||
},
|
||||
"otl": "Jednorázový odkaz",
|
||||
"stringMalformed": "Řetězec má nesprávný formát",
|
||||
"body": "Tělo požadavku musí být platný objekt",
|
||||
"hook": "Hook",
|
||||
"enabled": "Aktivní",
|
||||
"mtu": "MTU",
|
||||
"port": "Port",
|
||||
"persistentKeepalive": "Persistent Keepalive",
|
||||
"address": "IP adresa",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "Povolené IP adresy",
|
||||
"file": "Soubor"
|
||||
},
|
||||
"hooks": {
|
||||
"preUp": "PreUp",
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Kopírování není podporováno",
|
||||
"copied": "Zkopírováno!",
|
||||
"failed": "Kopírování selhalo",
|
||||
"copy": "Kopírovat"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Počet junk paketů (Jc)",
|
||||
"jCDescription": "Počet odesílaných junk paketů (1-128, doporučeno: 4-12)",
|
||||
"jMinLabel": "Min. velikost junk paketu (Jmin)",
|
||||
"jMinDescription": "Minimální velikost junk paketů (0-1279*, doporučeno: 8, musí být < Jmax)",
|
||||
"jMaxLabel": "Max. velikost junk paketu (Jmax)",
|
||||
"jMaxDescription": "Maximální velikost junk paketů (1-1280*, doporučeno: 80, musí být > Jmin)",
|
||||
"s1Label": "Velikost junk dat u Init paketu (S1)",
|
||||
"s1Description": "Velikost junk dat u Init paketu (0-1132, doporučeno: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "Velikost junk dat u Response paketu (S2)",
|
||||
"s2Description": "Velikost junk dat u Response paketu (0-1188, doporučeno: 15-150)",
|
||||
"s3Label": "Velikost junk dat u Cookie reply paketu (S3)",
|
||||
"s3Description": "Velikost junk dat u paketu s odpovědí na cookie",
|
||||
"s4Label": "Velikost junk dat u Transport paketu (S4)",
|
||||
"s4Description": "Velikost junk dat u transportního paketu",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Hodnota nebo rozsah hlavičky Init paketu (X nebo X-Y, kde X<Y. Min 5, max 2147483647. Nesmí se překrývat s ostatními hlavičkami)",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Hodnota nebo rozsah hlavičky Response paketu (X nebo X-Y, kde X<Y. Min 5, max 2147483647. Nesmí se překrývat s ostatními hlavičkami)",
|
||||
"h3Label": "Cookie reply magic header (H3)",
|
||||
"h3Description": "Hodnota nebo rozsah hlavičky Cookie reply paketu (X nebo X-Y, kde X<Y. Min 5, max 2147483647. Nesmí se překrývat s ostatními hlavičkami)",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Hodnota nebo rozsah hlavičky Transport paketu (X nebo X-Y, kde X<Y. Min 5, max 2147483647. Nesmí se překrývat s ostatními hlavičkami)",
|
||||
"i1Label": "Speciální junk paket 1 (I1)",
|
||||
"i1Description": "Paket pro napodobení protokolu v hex formátu: <b 0x...>",
|
||||
"i2Label": "Speciální junk paket 2 (I2)",
|
||||
"i2Description": "Paket pro napodobení protokolu v hex formátu: <b 0x...>",
|
||||
"i3Label": "Speciální junk paket 3 (I3)",
|
||||
"i3Description": "Paket pro napodobení protokolu v hex formátu: <b 0x...>",
|
||||
"i4Label": "Speciální junk paket 4 (I4)",
|
||||
"i4Description": "Paket pro napodobení protokolu v hex formátu: <b 0x...>",
|
||||
"i5Label": "Speciální junk paket 5 (I5)",
|
||||
"i5Description": "Paket pro napodobení protokolu v hex formátu: <b 0x...>",
|
||||
"mtuNote": "Hodnoty závisí na nastavení MTU",
|
||||
"obfuscationParameters": "AmneziaWG parametry obfuskace"
|
||||
}
|
||||
}
|
||||
+25
-74
@@ -11,12 +11,12 @@
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"email": "E-Mail"
|
||||
"email": "Email"
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "Aktuelles Passwort",
|
||||
"enable2fa": "Zwei-Faktor-Authentifizierung aktivieren",
|
||||
"enable2faDesc": "Scannen Sie den QR-Code mit Ihrer Authentifizierungs-App oder geben Sie den Schlüssel manuell ein.",
|
||||
"enable2fa": "Zwei-Faktor-Authentifizierunng aktivieren",
|
||||
"enable2faDesc": "Scannen Sie den QR-Code mit ihrer Authentifizierungs-App oder geben Sie den Schlüssel manuell ein.",
|
||||
"2faKey": "TOTP-Schlüssel",
|
||||
"2faCodeDesc": "Geben Sie den Code aus Ihrer Authentifizierungs-App ein.",
|
||||
"disable2fa": "Zwei-Faktor-Authentifizierung deaktivieren",
|
||||
@@ -45,26 +45,26 @@
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "Willkommen zur Ersteinrichtung von wg-easy",
|
||||
"welcomeDesc": "Sie haben den einfachsten Weg gefunden, WireGuard auf jedem Linux-Server zu installieren und zu verwalten.",
|
||||
"welcomeDesc": "Das ist der einfachste Weg, um Wireguard auf jedem Linux-Server zu installieren und zu betreiben.",
|
||||
"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 in der Admin-Konsole anzumelden.",
|
||||
"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.",
|
||||
"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.",
|
||||
"upload": "Hochladen",
|
||||
"migration": "Backup wiederherstellen:",
|
||||
"migration": "Sicherung wiederherstellen:",
|
||||
"createAccount": "Konto erstellen",
|
||||
"successful": "Einrichtung erfolgreich",
|
||||
"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": {
|
||||
"updateAvailable": "Ein neues Update ist verfügbar!",
|
||||
"updateAvailable": "Es ist ein neue Aktualisierung verfügbar!",
|
||||
"update": "Aktualisieren"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Dunkles Thema",
|
||||
"light": "Helles Thema",
|
||||
"system": "System Thema"
|
||||
"system": "System-Thema"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Statistiken ein-/ausblenden",
|
||||
@@ -84,16 +84,16 @@
|
||||
"sort": "Sortieren",
|
||||
"create": "Client erstellen",
|
||||
"created": "Client wurde erstellt",
|
||||
"new": "Neuer Client",
|
||||
"new": "Neuer client",
|
||||
"name": "Name",
|
||||
"expireDate": "Ablaufdatum",
|
||||
"expireDateDesc": "Datum, an dem der Client deaktiviert wird. Leer lassen für dauerhaft aktiv.",
|
||||
"expireDateDesc": "Datum, an dem der Client deaktiviert wird. Leer lassen, damit dies nie passiert.",
|
||||
"deleteClient": "Client löschen",
|
||||
"deleteDialog1": "Sind Sie sicher, dass Sie diesen Client löschen möchten",
|
||||
"deleteDialog1": "Sind Sie sicher, dass Sie diesen Client löschen wollen",
|
||||
"deleteDialog2": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"enabled": "Aktiviert",
|
||||
"address": "Adresse",
|
||||
"serverAllowedIps": "Serverseitig erlaubte IP-Adressen",
|
||||
"serverAllowedIps": "serverseitig erlaubte IP-Adressen",
|
||||
"otlDesc": "Einen kurzen Einmal-Link erzeugen",
|
||||
"permanent": "Dauerhaft",
|
||||
"createdOn": "Angelegt am ",
|
||||
@@ -112,15 +112,8 @@
|
||||
"persistentKeepaliveDesc": "Legt das Intervall (in Sekunden) für Keepalive-Pakete fest. 0 deaktiviert es",
|
||||
"hooks": "Hooks",
|
||||
"hooksDescription": "Hooks funktionieren nur mit wg-quick",
|
||||
"hooksLeaveEmpty": "Nur für wg-quick. Andernfalls leer lassen",
|
||||
"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"
|
||||
"hooksLeaveEmpty": "Nur für wg-quick. Sonst leer lassen",
|
||||
"dnsDesc": "DNS-Server, den die Clients benutzen (überschreibt die globale Konfiguration)"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Ändern",
|
||||
@@ -157,24 +150,24 @@
|
||||
"config": {
|
||||
"connection": "Verbindung",
|
||||
"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 auch den Interface-Port ändern)",
|
||||
"portDesc": "Öffentlicher UDP-Port an dem sich die Clients verbinden (überschreibt die Konfiguration, vermutlich wollen Sie ebenfalls den Port der Weboberfläche ändern)",
|
||||
"allowedIpsDesc": "Erlaubte IP-Adressen, die 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)",
|
||||
"persistentKeepaliveDesc": "Intervall in Sekunden, in dem Keepalive-Pakete an den Server gesendet werden. 0 = deaktiviert (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)",
|
||||
"suggest": "Vorschlagen",
|
||||
"suggestDesc": "Wählen Sie eine IP-Adresse oder einen Hostnamen für das Host-Feld aus"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR wurde geändert",
|
||||
"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",
|
||||
"portDesc": "UDP-Port, auf dem WireGuard lauschen wird (Sie wollen wahrscheinlich auch den Interface-Port ändern)",
|
||||
"portDesc": "UDP Port, auf dem WireGuard lauschen wird (Sie wollen wahrscheinlich auch den Config-Port ändern)",
|
||||
"changeCidr": "CIDR ändern",
|
||||
"restart": "Interface neu starten",
|
||||
"restartDesc": "Das WireGuard-Interface neu starten",
|
||||
"restartWarn": "Sind Sie sicher, dass Sie das Interface neu starten möchten? Dies wird die Verbindungen aller Clients trennen.",
|
||||
"restartWarn": "Sind Sie sicher, dass Sie das Interface neu starten wollen? Dies wird die Verbindungen aller Clients trennen.",
|
||||
"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."
|
||||
@@ -195,15 +188,15 @@
|
||||
"expiresAt": "Läuft ab am",
|
||||
"address4": "IPv4-Adresse",
|
||||
"address6": "IPv6-Adresse",
|
||||
"serverAllowedIps": "Serverseitig erlaubte IP-Adressen"
|
||||
"serverAllowedIps": "serverseitig erlaubte IP-Adressen"
|
||||
},
|
||||
"user": {
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort",
|
||||
"remember": "Merken",
|
||||
"name": "Name",
|
||||
"email": "E-Mail",
|
||||
"emailInvalid": "Die E-Mail-Adresse muss gültig sein",
|
||||
"email": "Email",
|
||||
"emailInvalid": "Die Email-Adresse muss valide sein",
|
||||
"passwordMatch": "Die Passwörter müssen übereinstimmen",
|
||||
"totpEnable": "TOTP aktivieren",
|
||||
"totpEnableTrue": "\"TOTP aktivieren\" muss ausgewählt sein",
|
||||
@@ -219,8 +212,8 @@
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Gerät",
|
||||
"cidrValid": "CIDR muss gültig sein"
|
||||
"device": "Geräte",
|
||||
"cidrValid": "CIDR muss valide sein"
|
||||
},
|
||||
"otl": "Einmal-Link",
|
||||
"stringMalformed": "Zeichenkette ist fehlerhaft",
|
||||
@@ -240,47 +233,5 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"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",
|
||||
"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)",
|
||||
"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...>",
|
||||
"mtuNote": "Werte hängen von der MTU ab",
|
||||
"obfuscationParameters": "AmneziaWG Verschleierungsparameter"
|
||||
}
|
||||
}
|
||||
|
||||
+12
-32
@@ -88,7 +88,6 @@
|
||||
"name": "Name",
|
||||
"expireDate": "Expire Date",
|
||||
"expireDateDesc": "Date the client will be disabled. Blank for permanent",
|
||||
"delete": "Delete",
|
||||
"deleteClient": "Delete Client",
|
||||
"deleteDialog1": "Are you sure you want to delete",
|
||||
"deleteDialog2": "This action cannot be undone.",
|
||||
@@ -118,13 +117,7 @@
|
||||
"notConnected": "Client not connected",
|
||||
"endpoint": "Endpoint",
|
||||
"endpointDesc": "IP of the client from which the WireGuard connection is established",
|
||||
"search": "Search clients...",
|
||||
"config": "Configuration",
|
||||
"viewConfig": "View Configuration",
|
||||
"firewallIps": "Firewall Allowed IPs",
|
||||
"firewallIpsDesc": "Destination IPs/CIDRs this client can access (server-side enforcement). Leave empty to use Allowed IPs. Supports optional port and protocol filtering. See docs for syntax.",
|
||||
"downloadPng": "Download PNG",
|
||||
"copyPng": "Copy PNG"
|
||||
"search": "Search clients..."
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Change",
|
||||
@@ -134,8 +127,7 @@
|
||||
"toast": {
|
||||
"success": "Success",
|
||||
"saved": "Saved",
|
||||
"error": "Error",
|
||||
"unknown": "Unknown error. See console for more details"
|
||||
"error": "Error"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Actions",
|
||||
@@ -180,10 +172,7 @@
|
||||
"restart": "Restart Interface",
|
||||
"restartDesc": "Restart the WireGuard interface",
|
||||
"restartWarn": "Are you sure to restart the interface? This will disconnect all clients.",
|
||||
"restartSuccess": "Interface restarted",
|
||||
"firewall": "Traffic Filtering",
|
||||
"firewallEnabled": "Enable Per-Client Firewall",
|
||||
"firewallEnabledDesc": "Restrict client traffic to specific destination IPs using iptables. When enabled, each client can be configured with allowed destinations."
|
||||
"restartSuccess": "Interface restarted"
|
||||
},
|
||||
"introText": "Welcome to the admin panel.\n\nHere you can manage the general settings, the configuration, the interface settings and the hooks.\n\nStart by choosing one of the sections in the sidebar."
|
||||
},
|
||||
@@ -191,7 +180,6 @@
|
||||
"generic": {
|
||||
"required": "{0} is required",
|
||||
"validNumber": "{0} must be a valid number",
|
||||
"validNumberRange": "{0} must be a valid number or number range",
|
||||
"validString": "{0} must be a valid string",
|
||||
"validBoolean": "{0} must be a valid boolean",
|
||||
"validArray": "{0} must be a valid array",
|
||||
@@ -204,9 +192,7 @@
|
||||
"expiresAt": "Expires At",
|
||||
"address4": "IPv4 Address",
|
||||
"address6": "IPv6 Address",
|
||||
"serverAllowedIps": "Server Allowed IPs",
|
||||
"firewallIps": "Firewall Allowed IPs",
|
||||
"firewallIpsInvalid": "Invalid firewall IP entry. See docs for supported syntax."
|
||||
"serverAllowedIps": "Server Allowed IPs"
|
||||
},
|
||||
"user": {
|
||||
"username": "Username",
|
||||
@@ -252,12 +238,6 @@
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Copy is not supported",
|
||||
"copied": "Copied!",
|
||||
"failed": "Copy failed",
|
||||
"copy": "Copy"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Junk packet count (Jc)",
|
||||
"jCDescription": "Number of junk packets to send (1-128, recommended: 4-12)",
|
||||
@@ -273,14 +253,6 @@
|
||||
"s3Description": "Cookie reply packet junk size",
|
||||
"s4Label": "Transport packet junk size (S4)",
|
||||
"s4Description": "Transport packet junk size",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Init packet header value or range (X or X-Y, where X<Y. Min 5, max 2147483647. Value or range must not overlap with other headers)",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Response packet header value or range (X or X-Y, where X<Y. Min 5, max 2147483647. Value or range must not overlap with other headers)",
|
||||
"h3Label": "Cookie reply magic header (H3)",
|
||||
"h3Description": "Cookie reply packet header value or range (X or X-Y, where X<Y. Min 5, max 2147483647. Value or range must not overlap with other headers)",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Transport packet header value or range (X or X-Y, where X<Y. Min 5, max 2147483647. Value or range must not overlap with other headers)",
|
||||
"i1Label": "Special junk packet 1 (I1)",
|
||||
"i1Description": "Protocol mimic packet in hex format: <b 0x...>",
|
||||
"i2Label": "Special junk packet 2 (I2)",
|
||||
@@ -291,6 +263,14 @@
|
||||
"i4Description": "Protocol mimic packet in hex format: <b 0x...>",
|
||||
"i5Label": "Special junk packet 5 (I5)",
|
||||
"i5Description": "Protocol mimic packet in hex format: <b 0x...>",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Init packet header value (5-2147483647, must be unique from H2-H4)",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Response packet header value (5-2147483647, must be unique from H1, H3, H4)",
|
||||
"h3Label": "Cookie reply magic header (H3)",
|
||||
"h3Description": "Cookie reply packet header value (5-2147483647, must be unique from H1, H2, H4)",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Transport packet header value (5-2147483647, must be unique from H1-H3)",
|
||||
"mtuNote": "Values depend on the MTU",
|
||||
"obfuscationParameters": "AmneziaWG Obfuscation Parameters"
|
||||
}
|
||||
|
||||
+13
-59
@@ -15,12 +15,12 @@
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "Mot de passe actuel",
|
||||
"enable2fa": "Activer l'authentification à deux facteurs",
|
||||
"enable2fa": "Activer l'authentification à double facteur",
|
||||
"enable2faDesc": "Scannez le code QR avec votre application d'authentification ou saisissez la clé manuellement.",
|
||||
"2faKey": "Clé TOTP",
|
||||
"2faCodeDesc": "Saisissez le code de votre application d'authentification.",
|
||||
"disable2fa": "Désactiver l'authentification à deux facteurs",
|
||||
"disable2faDesc": "Saisissez votre mot de passe pour désactiver l'authentification à deux facteurs."
|
||||
"disable2fa": "Désactiver l'authentification à double facteur",
|
||||
"disable2faDesc": "Saisissez votre mot de passe pour désactiver l'authentification à double facteur"
|
||||
},
|
||||
"general": {
|
||||
"name": "Nom",
|
||||
@@ -40,7 +40,7 @@
|
||||
"no": "Non",
|
||||
"confirmPassword": "Confirmer le mot de passe",
|
||||
"loading": "Chargement...",
|
||||
"2fa": "Authentification à deux facteurs",
|
||||
"2fa": "Authentification à double facteur",
|
||||
"2faCode": "Code TOTP"
|
||||
},
|
||||
"setup": {
|
||||
@@ -75,8 +75,8 @@
|
||||
"rememberMe": "Se souvenir de moi",
|
||||
"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.",
|
||||
"2faRequired": "L'authentification à deux facteurs est requise",
|
||||
"2faWrong": "Le code d'authentification à deux facteurs est incorrect"
|
||||
"2faRequired": "Une authentification à double facteur est requise",
|
||||
"2faWrong": "L'authentification à double facteur est incorrecte"
|
||||
},
|
||||
"client": {
|
||||
"empty": "Il n'y a pas encore de clients.",
|
||||
@@ -108,7 +108,7 @@
|
||||
"downloadConfig": "Télécharger la configuration",
|
||||
"allowedIpsDesc": "Quelles IPs seront acheminées par le VPN (remplace la configuration globale)",
|
||||
"serverAllowedIpsDesc": "Les IPs que le serveur acheminera vers le client",
|
||||
"mtuDesc": "Définit l'unité de transmission maximale (taille des paquets) pour le tunnel VPN",
|
||||
"mtuDesc": "Définit le nombre maximum d'unités de transmission (taille des paquets) pour le tunnel VPN.",
|
||||
"persistentKeepaliveDesc": "Définit l'intervalle (en secondes) pour les paquets keep-alive. 0 le désactive",
|
||||
"hooks": "Hooks",
|
||||
"hooksDescription": "Les hooks ne fonctionnent qu'avec wg-quick",
|
||||
@@ -116,11 +116,7 @@
|
||||
"dnsDesc": "Serveur DNS que les clients utiliseront (remplace la configuration globale)",
|
||||
"notConnected": "Client non connecté",
|
||||
"endpoint": "Endpoint",
|
||||
"endpointDesc": "Adresse IP du client à partir duquel la connexion WireGuard est établie",
|
||||
"search": "Rechercher des clients...",
|
||||
"config": "Configuration",
|
||||
"viewConfig": "Voir la configuration",
|
||||
"delete": "Supprimer"
|
||||
"endpointDesc": "Adresse IP du client à partir duquel la connexion WireGuard est établie"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Modifier",
|
||||
@@ -150,9 +146,9 @@
|
||||
"metricsPassword": "Mot de passe",
|
||||
"metricsPasswordDesc": "Mot de passe Bearer pour le endpoint des métriques (mot de passe ou argon2 hash)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Route pour les métriques au format JSON",
|
||||
"jsonDesc": "Acheminement pour les métriques au format JSON",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Route pour les métriques Prometheus"
|
||||
"prometheusDesc": "Acheminement pour les métriques de Prometheus"
|
||||
},
|
||||
"config": {
|
||||
"connection": "Connexion",
|
||||
@@ -184,13 +180,13 @@
|
||||
"required": "{0} est requis",
|
||||
"validNumber": "{0} doit être un nombre valide",
|
||||
"validString": "{0} doit être une chaîne de caractères valide",
|
||||
"validBoolean": "{0} doit être un booléen valide",
|
||||
"validBoolean": "{0} doit être une variable valide",
|
||||
"validArray": "{0} doit être un tableau valide",
|
||||
"stringMin": "{0} doit comporter au moins {1} caractère(s)",
|
||||
"stringMin": "{0} doit être d'au moins {1} Caractère",
|
||||
"numberMin": "{0} doit être d'au moins {1}"
|
||||
},
|
||||
"client": {
|
||||
"id": "ID du client",
|
||||
"id": "Client ID",
|
||||
"name": "Nom",
|
||||
"expiresAt": "Expire le",
|
||||
"address4": "Adresse IPv4",
|
||||
@@ -240,47 +236,5 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"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",
|
||||
"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)",
|
||||
"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...>",
|
||||
"mtuNote": "Les valeurs dépendent du MTU",
|
||||
"obfuscationParameters": "Paramètres d'obfuscation AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
{
|
||||
"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",
|
||||
"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)",
|
||||
"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...>",
|
||||
"mtuNote": "Verdier avhenger av MTU",
|
||||
"obfuscationParameters": "AmneziaWG obfuskasjonsparametere"
|
||||
}
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "Account",
|
||||
"clients": "Cliënten",
|
||||
"admin": {
|
||||
"panel": "Admin-paneel",
|
||||
"general": "Algemeen",
|
||||
"config": "Configuratie",
|
||||
"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": "Poort",
|
||||
"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",
|
||||
"firewallIps": "Firewall-toegestane IPs",
|
||||
"firewallIpsDesc": "Bestemmings-IP's/CIDR's waartoe deze client toegang heeft (handhaving aan de serverzijde). Laat leeg om Toegestane IP's te gebruiken. Ondersteunt optionele poort - en protocolfiltering. Zie documentatie voor syntaxis.",
|
||||
"downloadPng": "PNG downloaden",
|
||||
"copyPng": "PNG kopiëren"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Wijzigen",
|
||||
"cancel": "Annuleren",
|
||||
"create": "Aanmaken"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Succes",
|
||||
"saved": "Opgeslagen",
|
||||
"error": "Fout",
|
||||
"unknown": "Onbekende fout. Zie console voor meer details"
|
||||
},
|
||||
"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",
|
||||
"firewall": "Traffic-filtering",
|
||||
"firewallEnabled": "Per-Client Firewall inschakelen",
|
||||
"firewallEnabledDesc": "Beperk het cliëntverkeer tot specifieke bestemmings-IP's met behulp van iptables. Indien ingeschakeld, kan elke cliënt worden geconfigureerd met toegestane bestemmingen."
|
||||
},
|
||||
"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 getal zijn",
|
||||
"validNumberRange": "{0} moet een geldig getal of bereik 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",
|
||||
"firewallIps": "Firewall-toegestane IPs",
|
||||
"firewallIpsInvalid": "Ongeldige IP-invoer van firewall. Zie documentatie voor ondersteunde syntaxis."
|
||||
},
|
||||
"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",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Waarde of bereik Init packet header (X of X-Y, waarbij X<Y. Min. 5, max. 2147483647. Waarde of bereik mag niet overlappen met andere headers)",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Waarde of bereik Response packet header (X of X-Y, waarbij X<Y. Min. 5, max. 2147483647. Waarde of bereik mag niet overlappen met andere headers)",
|
||||
"h3Label": "Cookie reply magic header (H3)",
|
||||
"h3Description": "Waarde of bereik Cookie reply packet header (X of X-Y, waarbij X<Y. Min. 5, max. 2147483647. Waarde of bereik mag niet overlappen met andere headers)",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Waarde of bereik Transport packet header (X of X-Y, waarbij X<Y. Min. 5, max. 2147483647. Waarde of bereik mag niet overlappen met andere headers)",
|
||||
"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...>",
|
||||
"mtuNote": "Waarden zijn afhankelijk van de MTU",
|
||||
"obfuscationParameters": "AmneziaWG Obfuscation Parameters"
|
||||
}
|
||||
}
|
||||
+75
-132
@@ -3,10 +3,10 @@
|
||||
"me": "Аккаунт",
|
||||
"clients": "Клиенты",
|
||||
"admin": {
|
||||
"panel": "Админ-панель",
|
||||
"general": "Общие настройки",
|
||||
"panel": "Админ панель",
|
||||
"general": "Общие",
|
||||
"config": "Конфигурация",
|
||||
"interface": "Сетевой интерфейс",
|
||||
"interface": "Интерфейс",
|
||||
"hooks": "Хуки"
|
||||
}
|
||||
},
|
||||
@@ -16,11 +16,11 @@
|
||||
"me": {
|
||||
"currentPassword": "Текущий пароль",
|
||||
"enable2fa": "Включить двухфакторную аутентификацию",
|
||||
"enable2faDesc": "Отсканируйте QR‑код с помощью приложения‑аутентификатора или введите ключ вручную.",
|
||||
"2faKey": "Ключ TOTP",
|
||||
"2faCodeDesc": "Введите код из приложения‑аутентификатора.",
|
||||
"enable2faDesc": "Отсканируйте QR-код приложением-аутентификатором или введите ключ вручную.",
|
||||
"2faKey": "TOTP-ключ",
|
||||
"2faCodeDesc": "Введите код из приложения-аутентификатора.",
|
||||
"disable2fa": "Отключить двухфакторную аутентификацию",
|
||||
"disable2faDesc": "Введите пароль, чтобы отключить двухфакторную аутентификацию."
|
||||
"disable2faDesc": "Введите пароль, чтобы отключить двухфакторную аутентификацию"
|
||||
},
|
||||
"general": {
|
||||
"name": "Имя",
|
||||
@@ -29,9 +29,9 @@
|
||||
"newPassword": "Новый пароль",
|
||||
"updatePassword": "Обновить пароль",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "Разрешённые IP‑адреса",
|
||||
"allowedIps": "Разрешённые IP",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "Постоянное поддержание соединения",
|
||||
"persistentKeepalive": "Постоянный keepalive",
|
||||
"logout": "Выйти",
|
||||
"continue": "Продолжить",
|
||||
"host": "Хост",
|
||||
@@ -41,21 +41,21 @@
|
||||
"confirmPassword": "Подтвердите пароль",
|
||||
"loading": "Загрузка...",
|
||||
"2fa": "Двухфакторная аутентификация",
|
||||
"2faCode": "Код TOTP"
|
||||
"2faCode": "TOTP‑код"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "Добро пожаловать в первичную настройку wg-easy",
|
||||
"welcomeDesc": "Вы нашли самый простой способ установить и управлять WireGuard на любом Linux‑хосте",
|
||||
"existingSetup": "У вас уже есть существующая настройка?",
|
||||
"createAdminDesc": "Сначала введите имя администратора и надёжный пароль. Эти данные будут использоваться для входа в Админ-панель.",
|
||||
"setupConfigDesc": "Введите данные хоста и порта. Они будут использоваться для настройки клиента при установке WireGuard на устройствах.",
|
||||
"setupMigrationDesc": "Укажите файл резервной копии, если хотите перенести данные из предыдущей версии wg-easy.",
|
||||
"welcomeDesc": "Вы нашли самый простой способ установить и управлять WireGuard на любом Linux-хосте",
|
||||
"existingSetup": "У вас уже есть существующая установка?",
|
||||
"createAdminDesc": "Сначала введите имя администратора и надёжный пароль. Эти данные понадобятся для входа в панель управления",
|
||||
"setupConfigDesc": "Введите информацию о хосте и порте. Она будет использоваться в конфигурации клиента при установке WireGuard на устройствах",
|
||||
"setupMigrationDesc": "Укажите файл резервной копии, если хотите перенести данные из предыдущей версии wg-easy",
|
||||
"upload": "Загрузить",
|
||||
"migration": "Восстановить из резервной копии:",
|
||||
"createAccount": "Создать аккаунт",
|
||||
"successful": "Настройка завершена успешно",
|
||||
"successful": "Настройка успешна",
|
||||
"hostDesc": "Публичное имя хоста, к которому будут подключаться клиенты",
|
||||
"portDesc": "Публичный UDP‑порт, к которому будут подключаться клиенты и на котором будет слушать WireGuard"
|
||||
"portDesc": "Публичный UDP‑порт для подключения клиентов и прослушивания WireGuard"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "Доступно обновление!",
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Показать/скрыть графики",
|
||||
"donate": "Поддержать"
|
||||
"donate": "Пожертвовать"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "Войти",
|
||||
@@ -87,19 +87,18 @@
|
||||
"new": "Новый клиент",
|
||||
"name": "Имя",
|
||||
"expireDate": "Дата отключения",
|
||||
"expireDateDesc": "Дата, когда клиент будет отключён. Оставьте пустым для бессрочного доступа",
|
||||
"delete": "Удалить",
|
||||
"expireDateDesc": "Дата, когда клиент будет отключён. Пусто — бессрочно",
|
||||
"deleteClient": "Удалить клиента",
|
||||
"deleteDialog1": "Вы уверены, что хотите удалить",
|
||||
"deleteDialog2": "Это действие нельзя отменить.",
|
||||
"enabled": "Включён",
|
||||
"deleteDialog2": "Это действие необратимо.",
|
||||
"enabled": "Включен",
|
||||
"address": "Адрес",
|
||||
"serverAllowedIps": "Разрешённые IP‑адреса сервера",
|
||||
"otlDesc": "Сгенерировать короткую одноразовую ссылку",
|
||||
"permanent": "Бессрочный",
|
||||
"serverAllowedIps": "Разрешённые IP сервера",
|
||||
"otlDesc": "Сгенерировать одноразовую короткую ссылку",
|
||||
"permanent": "Постоянный",
|
||||
"createdOn": "Создан ",
|
||||
"lastSeen": "Последнее подключение ",
|
||||
"totalDownload": "Всего скачано: ",
|
||||
"totalDownload": "Всего загружено: ",
|
||||
"totalUpload": "Всего отправлено: ",
|
||||
"newClient": "Новый клиент",
|
||||
"disableClient": "Отключить клиента",
|
||||
@@ -107,53 +106,45 @@
|
||||
"noPrivKey": "У этого клиента нет приватного ключа. Невозможно создать конфигурацию.",
|
||||
"showQR": "Показать QR‑код",
|
||||
"downloadConfig": "Скачать конфигурацию",
|
||||
"allowedIpsDesc": "Какие IP‑адреса будут маршрутизироваться через VPN (переопределяет глобальную конфигурацию)",
|
||||
"serverAllowedIpsDesc": "Какие IP‑адреса сервер будет отправлять клиенту",
|
||||
"mtuDesc": "Максимальный размер пакета (MTU) для VPN‑туннеля",
|
||||
"persistentKeepaliveDesc": "Устанавливает интервал (в секундах) для пакетов поддержания соединения. 0 — Отключить",
|
||||
"allowedIpsDesc": "Какие IP будут маршрутизироваться через VPN (перезаписывает общую конфигурацию)",
|
||||
"serverAllowedIpsDesc": "Какие IP сервер будет отправлять клиенту",
|
||||
"mtuDesc": "Максимальный размер пакета для VPN‑туннеля",
|
||||
"persistentKeepaliveDesc": "Интервал пакетов для поддержания соединения (в секундах). 0 — отключено.",
|
||||
"hooks": "Хуки",
|
||||
"hooksDescription": "Хуки работают только с wg‑quick",
|
||||
"hooksLeaveEmpty": "Только для wg‑quick. В остальных случаях оставьте пустым",
|
||||
"dnsDesc": "DNS‑сервер, который будут использовать клиенты (переопределяет глобальную конфигурацию)",
|
||||
"hooksDescription": "Хуки работают только с wg-quick",
|
||||
"hooksLeaveEmpty": "Только для wg-quick. Иначе оставьте пустым",
|
||||
"dnsDesc": "DNS‑сервер, который будут использовать клиенты (перезаписывает общую конфигурацию)",
|
||||
"notConnected": "Клиент не подключен",
|
||||
"endpoint": "Точка подключения",
|
||||
"endpointDesc": "IP‑адрес клиента, с которого установлено соединение WireGuard",
|
||||
"search": "Поиск клиентов...",
|
||||
"config": "Конфигурация",
|
||||
"viewConfig": "Просмотреть конфигурацию",
|
||||
"firewallIps": "Разрешённые фаерволом IP-адреса",
|
||||
"firewallIpsDesc": "IP‑адреса/CIDR-диапазоны, к которым может получить доступ клиент (проверка на сервере). Оставьте пустым, будут использоваться «Разрешённые IP‑адреса» (AllowedIPs). Поддерживается фильтрация по портам и протоколам. Подробности см. в документации.",
|
||||
"downloadPng": "Скачать PNG",
|
||||
"copyPng": "Копировать PNG"
|
||||
"endpoint": "Конечная точка",
|
||||
"endpointDesc": "IP-адрес клиента, с которого установлено соединение WireGuard"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Изменить",
|
||||
"cancel": "Отменить",
|
||||
"cancel": "Отмена",
|
||||
"create": "Создать"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Успешно",
|
||||
"success": "Успех",
|
||||
"saved": "Сохранено",
|
||||
"error": "Ошибка",
|
||||
"unknown": "Неизвестная ошибка. Подробности см. в консоли браузера"
|
||||
"error": "Ошибка"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Действия",
|
||||
"save": "Сохранить",
|
||||
"revert": "Отменить",
|
||||
"sectionGeneral": "Общие",
|
||||
"sectionAdvanced": "Расширенные",
|
||||
"sectionAdvanced": "Дополнительно",
|
||||
"noItems": "Нет элементов",
|
||||
"nullNoItems": "Нет элементов. Используется глобальная конфигурация",
|
||||
"add": "Добавить"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Время жизни сессии",
|
||||
"sessionTimeoutDesc": "Длительность сессии для «Запомнить меня» (в секундах)",
|
||||
"sessionTimeout": "Тайм-аут сессии",
|
||||
"sessionTimeoutDesc": "Длительность сеанса для \"Запомнить меня\" (секунды)",
|
||||
"metrics": "Метрики",
|
||||
"metricsPassword": "Пароль",
|
||||
"metricsPasswordDesc": "Пароль Bearer для конечной точки метрик (пароль или хэш argon2)",
|
||||
"metricsPasswordDesc": "Пароль Bearer для эндпоинта метрик (пароль или хеш argon2)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Путь для метрик в формате JSON",
|
||||
"prometheus": "Prometheus",
|
||||
@@ -161,89 +152,83 @@
|
||||
},
|
||||
"config": {
|
||||
"connection": "Соединение",
|
||||
"hostDesc": "Публичное имя хоста для подключения клиентов (обнуляет конфигурацию)",
|
||||
"portDesc": "Публичный UDP‑порт для подключения клиентов (также рекомендуется изменить порт интерфейса)",
|
||||
"allowedIpsDesc": "Разрешённые IP‑адреса для клиентов (глобальная конфигурация)",
|
||||
"dnsDesc": "DNS‑сервер для клиентов (глобальная конфигурация)",
|
||||
"hostDesc": "Публичное имя хоста для подключения клиентов (сбросит конфигурацию)",
|
||||
"portDesc": "Публичный UDP‑порт для подключения клиентов (также стоит изменить порт интерфейса)",
|
||||
"allowedIpsDesc": "Разрешённые IP для клиентов (общая конфигурация)",
|
||||
"dnsDesc": "DNS‑сервер для клиентов (общая конфигурация)",
|
||||
"mtuDesc": "MTU для клиентов (только для новых)",
|
||||
"persistentKeepaliveDesc": "Интервал в секундах для отправки пакетов поддержания соединения на сервер. 0 = отключено (только для новых клиентов)",
|
||||
"suggest": "Предложить",
|
||||
"suggestDesc": "Выберите IP‑адрес или имя хоста для поля «Хост»"
|
||||
"persistentKeepaliveDesc": "Интервал отправки keepalive на сервер (секунды). 0 = отключено (только для новых)",
|
||||
"suggest": "Определить",
|
||||
"suggestDesc": "Выберите IP‑адрес или имя хоста для поля Host"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR изменён",
|
||||
"device": "Устройство",
|
||||
"deviceDesc": "Сетевое устройство Ethernet, через которое должен проходить трафик WireGuard",
|
||||
"mtuDesc": "MTU, который будет использовать WireGuard",
|
||||
"portDesc": "UDP‑порт, на котором будет слушать WireGuard (возможно, также нужно изменить порт в конфигурации)",
|
||||
"deviceDesc": "Сетевое устройство, через которое должен проходить трафик WireGuard",
|
||||
"mtuDesc": "MTU, который использует WireGuard",
|
||||
"portDesc": "UDP‑порт, на котором WireGuard будет слушать (возможно, нужно изменить и порт конфигурации)",
|
||||
"changeCidr": "Изменить CIDR",
|
||||
"restart": "Перезапустить интерфейс",
|
||||
"restartDesc": "Перезапустить сетевой интерфейс WireGuard",
|
||||
"restartWarn": "Вы уверены, что хотите перезапустить сетевой интерфейс? Это приведёт к отключению всех клиентов.",
|
||||
"restartSuccess": "Интерфейс перезапущен",
|
||||
"firewall": "Фильтрация трафика",
|
||||
"firewallEnabled": "Включить фаервол для отдельных клиентов",
|
||||
"firewallEnabledDesc": "Ограничить трафик клиентов до определённых IP‑адресов с помощью iptables. При включении для каждого клиента можно настроить список разрешённых адресов."
|
||||
"restartDesc": "Перезапустить интерфейс WireGuard",
|
||||
"restartWarn": "Вы уверены, что хотите перезапустить интерфейс? Все клиенты будут отключены.",
|
||||
"restartSuccess": "Интерфейс перезапущен"
|
||||
},
|
||||
"introText": "Добро пожаловать в панель администратора.\n\nЗдесь вы можете управлять общими настройками, конфигурацией, настройками интерфейса и хуками.\n\nНачните с выбора одного из разделов на боковой панели."
|
||||
"introText": "Добро пожаловать в панель администратора.\n\nЗдесь вы можете управлять общими настройками, конфигурацией, параметрами интерфейса и хуками.\n\nНачните с выбора раздела в боковой панели."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} обязательно для заполнения",
|
||||
"validNumber": "{0} должно быть числом",
|
||||
"validNumberRange": "{0} должно быть числом или диапазоном чисел",
|
||||
"validString": "{0} должно быть строкой",
|
||||
"validBoolean": "{0} должно быть логическим значением",
|
||||
"validArray": "{0} должно быть массивом",
|
||||
"stringMin": "{0} должно содержать не менее {1} символа",
|
||||
"numberMin": "{0} должно быть не менее {1}"
|
||||
"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‑адреса сервера",
|
||||
"firewallIps": "Разрешённые фаерволом IP-адреса",
|
||||
"firewallIpsInvalid": "Некорректная запись IP-адреса для фаервола. Поддерживаемый синтаксис см. в документации"
|
||||
"expiresAt": "Действителен до",
|
||||
"address4": "IPv4 адрес",
|
||||
"address6": "IPv6 адрес",
|
||||
"serverAllowedIps": "Разрешённые IP сервера"
|
||||
},
|
||||
"user": {
|
||||
"username": "Имя пользователя",
|
||||
"password": "Пароль",
|
||||
"remember": "Запомнить",
|
||||
"name": "Имя",
|
||||
"email": "Электронная почта",
|
||||
"emailInvalid": "Адрес электронной почты должен быть корректным",
|
||||
"email": "Email",
|
||||
"emailInvalid": "Email должен быть валидным",
|
||||
"passwordMatch": "Пароли должны совпадать",
|
||||
"totpEnable": "Включить TOTP",
|
||||
"totpEnableTrue": "TOTP должен быть включён",
|
||||
"totpCode": "Код TOTP"
|
||||
"totpEnableTrue": "Необходимо включить TOTP",
|
||||
"totpCode": "TOTP‑код"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "Хост"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "Время жизни сессии",
|
||||
"sessionTimeout": "Тайм-аут сессии",
|
||||
"metricsEnabled": "Метрики",
|
||||
"metricsPassword": "Пароль для метрик"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Устройство",
|
||||
"cidrValid": "CIDR должен быть корректным"
|
||||
"cidrValid": "CIDR должен быть валидным"
|
||||
},
|
||||
"otl": "Одноразовая ссылка",
|
||||
"stringMalformed": "Строка имеет неверный формат",
|
||||
"body": "Тело должно быть корректным объектом",
|
||||
"body": "Тело должно быть объектом",
|
||||
"hook": "Хук",
|
||||
"enabled": "Включено",
|
||||
"mtu": "MTU",
|
||||
"port": "Порт",
|
||||
"persistentKeepalive": "Постоянное поддержание соединения",
|
||||
"persistentKeepalive": "Поддерживать соединение",
|
||||
"address": "IP‑адрес",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "Разрешённые IP‑адреса",
|
||||
"allowedIps": "Разрешённые IP",
|
||||
"file": "Файл"
|
||||
},
|
||||
"hooks": {
|
||||
@@ -251,47 +236,5 @@
|
||||
"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": "Размер мусорных данных в 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": "Размер мусорных данных в транспортном пакете",
|
||||
"h1Label": "Init magic заголовок (H1)",
|
||||
"h1Description": "Значение или диапазон заголовка init-пакета (X или X-Y, где X < Y. От 5 до 2147483647. Диапазоны H1–H4 не должны пересекаться между собой)",
|
||||
"h2Label": "Response magic заголовок (H2)",
|
||||
"h2Description": "Значение или диапазон заголовка ответного пакета (X или X-Y, где X < Y. От 5 до 2147483647. Диапазоны H1–H4 не должны пересекаться между собой)",
|
||||
"h3Label": "Cookie reply magic заголовок (H3)",
|
||||
"h3Description": "Значение или диапазон заголовка cookie-reply пакета (X или X-Y, где X < Y. От 5 до 2147483647. Диапазоны H1–H4 не должны пересекаться между собой)",
|
||||
"h4Label": "Transport magic заголовок (H4)",
|
||||
"h4Description": "Значение или диапазон заголовка транспортного пакета (X или X-Y, где X < Y. От 5 до 2147483647. Диапазоны H1–H4 не должны пересекаться между собой)",
|
||||
"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...>",
|
||||
"mtuNote": "Значения зависят от MTU",
|
||||
"obfuscationParameters": "Параметры обфускации AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
+103
-160
@@ -7,7 +7,7 @@
|
||||
"general": "Genel",
|
||||
"config": "Yapılandırma",
|
||||
"interface": "Arayüz",
|
||||
"hooks": "Hooks"
|
||||
"hooks": "Hook'lar"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
@@ -15,56 +15,56 @@
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "Mevcut Şifre",
|
||||
"enable2fa": "2FA'yı Etkinleştir",
|
||||
"enable2faDesc": "Kimlik doğrulama uygulamanızla QR kodunu tarayın veya anahtarı manuel olarak girin.",
|
||||
"enable2fa": "İki Faktörlü Kimlik Doğrulamayı Etkinleştir",
|
||||
"enable2faDesc": "QR kodunu kimlik doğrulayıcı uygulamanızla tarayın veya anahtarı manuel olarak girin.",
|
||||
"2faKey": "TOTP Anahtarı",
|
||||
"2faCodeDesc": "Uygulamanızdaki doğrulama kodunu girin.",
|
||||
"disable2fa": "2FA'yı Devre Dışı Bırak",
|
||||
"disable2faDesc": "2FA'yı kapatmak için şifrenizi girin."
|
||||
"2faCodeDesc": "Kimlik doğrulayıcı uygulamanızdan kodu girin.",
|
||||
"disable2fa": "İki Faktörlü Kimlik Doğrulamayı Devre Dışı Bırak",
|
||||
"disable2faDesc": "İki Faktörlü Kimlik Doğrulamayı devre dışı bırakmak için şifrenizi girin."
|
||||
},
|
||||
"general": {
|
||||
"name": "İsim",
|
||||
"name": "Ad",
|
||||
"username": "Kullanıcı Adı",
|
||||
"password": "Şifre",
|
||||
"newPassword": "Yeni Şifre",
|
||||
"updatePassword": "Şifreyi Güncelle",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "Allowed IPs",
|
||||
"allowedIps": "İzin Verilen IP'ler",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "Persistent Keepalive",
|
||||
"persistentKeepalive": "Kalıcı Keepalive",
|
||||
"logout": "Çıkış Yap",
|
||||
"continue": "Devam Et",
|
||||
"host": "Host",
|
||||
"host": "Ana Bilgisayar",
|
||||
"port": "Port",
|
||||
"yes": "Evet",
|
||||
"no": "Hayır",
|
||||
"confirmPassword": "Şifreyi Onayla",
|
||||
"loading": "Yükleniyor...",
|
||||
"2fa": "2FA (İki Faktörlü Doğrulama)",
|
||||
"2fa": "İki Faktörlü Kimlik Doğrulama",
|
||||
"2faCode": "TOTP Kodu"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "wg-easy kurulumuna hoş geldiniz",
|
||||
"welcomeDesc": "Linux üzerinde WireGuard kurmanın ve yönetmenin en kolay yolu.",
|
||||
"welcome": "wg-easy ilk kurulumunuza hoş geldiniz",
|
||||
"welcomeDesc": "Herhangi bir Linux ana bilgisayarda WireGuard kurmanın ve yönetmenin en kolay yolunu buldunuz",
|
||||
"existingSetup": "Mevcut bir kurulumunuz var mı?",
|
||||
"createAdminDesc": "Yönetim paneline giriş için bir kullanıcı adı ve güçlü bir şifre belirleyin.",
|
||||
"setupConfigDesc": "İstemci cihazların bağlanacağı Host ve Port bilgilerini girin.",
|
||||
"setupMigrationDesc": "Eski wg-easy verilerinizi taşımak için yedek dosyasını yükleyebilirsiniz.",
|
||||
"createAdminDesc": "Lütfen önce bir yönetici kullanıcı adı ve güçlü bir güvenli şifre girin. Bu bilgiler yönetim panelinize giriş yapmak için kullanılacaktır.",
|
||||
"setupConfigDesc": "Lütfen ana bilgisayar ve port bilgilerini girin. Bu, cihazlarında WireGuard kurulumu yaparken istemci yapılandırması için kullanılacaktır.",
|
||||
"setupMigrationDesc": "Verilerinizi önceki wg-easy sürümünüzden yeni kurulumunuza taşımak istiyorsanız yedekleme dosyasını sağlayın.",
|
||||
"upload": "Yükle",
|
||||
"migration": "Yedeği Geri Yükle:",
|
||||
"migration": "Yedeği geri yükle:",
|
||||
"createAccount": "Hesap Oluştur",
|
||||
"successful": "Kurulum Başarılı",
|
||||
"hostDesc": "İstemcilerin bağlanacağı public hostname/IP",
|
||||
"portDesc": "WireGuard'ın dinleyeceği public UDP portu"
|
||||
"successful": "Kurulum başarılı",
|
||||
"hostDesc": "İstemcilerin bağlanacağı genel ana bilgisayar adı",
|
||||
"portDesc": "İstemcilerin bağlanacağı ve WireGuard'ın dinleyeceği genel UDP portu"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "Yeni bir güncelleme mevcut!",
|
||||
"updateAvailable": "Güncelleme mevcut!",
|
||||
"update": "Güncelle"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Koyu Tema",
|
||||
"light": "Açık Tema",
|
||||
"system": "Sistem Teması"
|
||||
"dark": "Koyu tema",
|
||||
"light": "Açık tema",
|
||||
"system": "Sistem teması"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Grafikleri Göster/Gizle",
|
||||
@@ -73,58 +73,50 @@
|
||||
"login": {
|
||||
"signIn": "Giriş Yap",
|
||||
"rememberMe": "Beni hatırla",
|
||||
"rememberMeDesc": "Oturumu açık tut",
|
||||
"insecure": "Güvensiz bağlantı üzerinden giriş yapılamaz. Lütfen HTTPS kullanın.",
|
||||
"2faRequired": "2FA Doğrulaması Gerekli",
|
||||
"2faWrong": "Hatalı 2FA Kodu"
|
||||
"rememberMeDesc": "Tarayıcıyı kapattıktan sonra giriş yapmış olarak kal",
|
||||
"insecure": "Güvensiz bir bağlantı ile giriş yapamazsınız. HTTPS kullanın.",
|
||||
"2faRequired": "İki Faktörlü Kimlik Doğrulama gerekli",
|
||||
"2faWrong": "İki Faktörlü Kimlik Doğrulama yanlış"
|
||||
},
|
||||
"client": {
|
||||
"empty": "Henüz kayıtlı bir istemci yok.",
|
||||
"empty": "Henüz istemci yok.",
|
||||
"newShort": "Yeni",
|
||||
"sort": "Sırala",
|
||||
"create": "İstemci Oluştur",
|
||||
"created": "İstemci oluşturuldu",
|
||||
"new": "Yeni İstemci",
|
||||
"name": "İsim",
|
||||
"name": "Ad",
|
||||
"expireDate": "Son Kullanma Tarihi",
|
||||
"expireDateDesc": "Boş bırakılırsa süresiz olur.",
|
||||
"delete": "Sil",
|
||||
"expireDateDesc": "İstemcinin devre dışı bırakılacağı tarih. Kalıcı için boş bırakın",
|
||||
"deleteClient": "İstemciyi Sil",
|
||||
"deleteDialog1": "Silmek istediğinize emin misiniz",
|
||||
"deleteDialog2": "Bu işlem geri alınamaz.",
|
||||
"enabled": "Aktif",
|
||||
"deleteDialog1": "Silmek istediğinizden emin misiniz",
|
||||
"deleteDialog2": "Bu eylem geri alınamaz.",
|
||||
"enabled": "Etkin",
|
||||
"address": "Adres",
|
||||
"serverAllowedIps": "Server Allowed IPs",
|
||||
"otlDesc": "Tek seferlik kısa link oluştur",
|
||||
"permanent": "Süresiz",
|
||||
"createdOn": "Oluşturulma: ",
|
||||
"lastSeen": "Son Görülme: ",
|
||||
"serverAllowedIps": "Sunucu İzin Verilen IP'ler",
|
||||
"otlDesc": "Kısa tek seferlik bağlantı oluştur",
|
||||
"permanent": "Kalıcı",
|
||||
"createdOn": "Oluşturulma tarihi ",
|
||||
"lastSeen": "Son görülme ",
|
||||
"totalDownload": "Toplam İndirme: ",
|
||||
"totalUpload": "Toplam Yükleme: ",
|
||||
"newClient": "Yeni İstemci",
|
||||
"disableClient": "İstemciyi Devre Dışı Bırak",
|
||||
"enableClient": "İstemciyi Etkinleştir",
|
||||
"noPrivKey": "Özel anahtar (private key) bulunamadı. Yapılandırma oluşturulamaz.",
|
||||
"noPrivKey": "Bu istemcinin bilinen özel anahtarı yok. Yapılandırma oluşturulamıyor.",
|
||||
"showQR": "QR Kodunu Göster",
|
||||
"downloadConfig": "Config İndir",
|
||||
"allowedIpsDesc": "VPN üzerinden yönlendirilecek IP'ler (global ayarı ezer)",
|
||||
"downloadConfig": "Yapılandırmayı İndir",
|
||||
"allowedIpsDesc": "Hangi IP'lerin VPN üzerinden yönlendirileceği (genel yapılandırmayı geçersiz kılar)",
|
||||
"serverAllowedIpsDesc": "Sunucunun istemciye yönlendireceği IP'ler",
|
||||
"mtuDesc": "VPN tüneli için paket boyutu (MTU)",
|
||||
"persistentKeepaliveDesc": "Bağlantıyı ayakta tutma aralığı (saniye). 0 devre dışı bırakır.",
|
||||
"hooks": "Hooks",
|
||||
"hooksDescription": "Hooks sadece wg-quick ile çalışır",
|
||||
"hooksLeaveEmpty": "Sadece wg-quick içindir. Aksi halde boş bırakın.",
|
||||
"dnsDesc": "İstemci DNS sunucuları (global ayarı ezer)",
|
||||
"notConnected": "Bağlı Değil",
|
||||
"endpoint": "Endpoint",
|
||||
"endpointDesc": "İstemcinin WireGuard bağlantısı kurduğu IP adresi",
|
||||
"search": "İstemci ara...",
|
||||
"config": "Config",
|
||||
"viewConfig": "Config Görüntüle",
|
||||
"firewallIps": "Firewall Allowed IPs",
|
||||
"firewallIpsDesc": "İstemcinin erişebileceği hedef IP/CIDR'ler (isteğe bağlı port/protokol filtreleme ile). Boş bırakılırsa Allowed IPs kullanılır. Ayrıntılı söz dizimi için dokümantasyona bakın.",
|
||||
"downloadPng": "PNG İndir",
|
||||
"copyPng": "PNG Kopyala"
|
||||
"mtuDesc": "VPN tüneli için maksimum iletim birimini (paket boyutu) ayarlar",
|
||||
"persistentKeepaliveDesc": "Keepalive paketleri için aralığı (saniye cinsinden) ayarlar. 0 devre dışı bırakır",
|
||||
"hooks": "Hook'lar",
|
||||
"hooksDescription": "Hook'lar sadece wg-quick ile çalışır",
|
||||
"hooksLeaveEmpty": "Sadece wg-quick için. Aksi takdirde boş bırakın",
|
||||
"dnsDesc": "İstemcilerin kullanacağı DNS sunucusu (genel yapılandırmayı geçersiz kılar)",
|
||||
"notConnected": "İstemci bağlı değil",
|
||||
"endpoint": "Uç Nokta",
|
||||
"endpointDesc": "WireGuard bağlantısının kurulduğu istemcinin IP'si"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Değiştir",
|
||||
@@ -134,116 +126,109 @@
|
||||
"toast": {
|
||||
"success": "Başarılı",
|
||||
"saved": "Kaydedildi",
|
||||
"error": "Hata",
|
||||
"unknown": "Bilinmeyen hata. Detaylar için konsola bakın."
|
||||
"error": "Hata"
|
||||
},
|
||||
"form": {
|
||||
"actions": "İşlemler",
|
||||
"actions": "Eylemler",
|
||||
"save": "Kaydet",
|
||||
"revert": "Geri Al",
|
||||
"sectionGeneral": "Genel",
|
||||
"sectionAdvanced": "Gelişmiş",
|
||||
"noItems": "Öge yok",
|
||||
"nullNoItems": "Öge yok. Global ayarlar kullanılıyor.",
|
||||
"noItems": "Öğe yok",
|
||||
"nullNoItems": "Öğe yok. Genel yapılandırma kullanılıyor",
|
||||
"add": "Ekle"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Oturum Zaman Aşımı",
|
||||
"sessionTimeoutDesc": "Beni Hatırla süresi (saniye)",
|
||||
"sessionTimeoutDesc": "Beni Hatırla için oturum süresi (saniye)",
|
||||
"metrics": "Metrikler",
|
||||
"metricsPassword": "Şifre",
|
||||
"metricsPasswordDesc": "Metrics endpoint'i için Bearer şifresi (argon2 hash destekler)",
|
||||
"metricsPasswordDesc": "Metrik uç noktası için Bearer şifresi (şifre veya argon2 hash)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "JSON metrik rotası",
|
||||
"jsonDesc": "JSON formatında metrikler için rota",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Prometheus metrik rotası"
|
||||
"prometheusDesc": "Prometheus metrikleri için rota"
|
||||
},
|
||||
"config": {
|
||||
"connection": "Bağlantı",
|
||||
"hostDesc": "İstemcilerin bağlanacağı Host (configleri etkiler)",
|
||||
"portDesc": "İstemcilerin bağlanacağı UDP portu. Bunu değiştirmek mevcut istemci yapılandırmalarını geçersiz kılabilir ve WireGuard Arayüz Portu ile eşleşmelidir.",
|
||||
"allowedIpsDesc": "Genel Allowed IPs (izin verilen IP'ler)",
|
||||
"dnsDesc": "Global DNS",
|
||||
"mtuDesc": "Varsayılan MTU (yeni istemciler için)",
|
||||
"persistentKeepaliveDesc": "Varsayılan Keepalive (yeni istemciler için)",
|
||||
"hostDesc": "İstemcilerin bağlanacağı genel ana bilgisayar adı (yapılandırmayı geçersiz kılar)",
|
||||
"portDesc": "İstemcilerin bağlanacağı genel UDP portu (yapılandırmayı geçersiz kılar, muhtemelen Arayüz Portunu da değiştirmek isteyeceksiniz)",
|
||||
"allowedIpsDesc": "İstemcilerin kullanacağı İzin Verilen IP'ler (genel yapılandırma)",
|
||||
"dnsDesc": "İstemcilerin kullanacağı DNS sunucusu (genel yapılandırma)",
|
||||
"mtuDesc": "İstemcilerin kullanacağı MTU (sadece yeni istemciler için)",
|
||||
"persistentKeepaliveDesc": "Sunucuya keepalive göndermek için saniye cinsinden aralık. 0 = devre dışı (sadece yeni istemciler için)",
|
||||
"suggest": "Öner",
|
||||
"suggestDesc": "Host alanı için bir IP veya Hostname öner"
|
||||
"suggestDesc": "Ana Bilgisayar alanı için bir IP Adresi veya Ana Bilgisayar Adı seçin"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR güncellendi",
|
||||
"device": "Arayüz",
|
||||
"deviceDesc": "Trafiğin yönlendirileceği ağ arayüzü (ethernet)",
|
||||
"mtuDesc": "WireGuard arayüz MTU'su",
|
||||
"portDesc": "WireGuard dinleme portu",
|
||||
"changeCidr": "CIDR Değiştir",
|
||||
"cidrSuccess": "CIDR değiştirildi",
|
||||
"device": "Cihaz",
|
||||
"deviceDesc": "WireGuard trafiğinin yönlendirileceği Ethernet cihazı",
|
||||
"mtuDesc": "WireGuard'ın kullanacağı MTU",
|
||||
"portDesc": "WireGuard'ın dinleyeceği UDP Portu (muhtemelen Yapılandırma Portunu da değiştirmek isteyeceksiniz)",
|
||||
"changeCidr": "CIDR'ı Değiştir",
|
||||
"restart": "Arayüzü Yeniden Başlat",
|
||||
"restartDesc": "WireGuard arayüzünü resetler",
|
||||
"restartWarn": "Arayüzü yeniden başlatmak tüm istemci bağlantılarını koparacaktır. Emin misiniz?",
|
||||
"restartSuccess": "Arayüz yeniden başlatıldı",
|
||||
"firewall": "Trafik Filtreleme",
|
||||
"firewallEnabled": "İstemci Bazlı Firewall",
|
||||
"firewallEnabledDesc": "iptables kullanarak istemci trafiğini kısıtlayın."
|
||||
"restartDesc": "WireGuard arayüzünü yeniden başlat",
|
||||
"restartWarn": "Arayüzü yeniden başlatmak istediğinizden emin misiniz? Bu tüm istemcilerin bağlantısını kesecektir.",
|
||||
"restartSuccess": "Arayüz yeniden başlatıldı"
|
||||
},
|
||||
"introText": "Yönetici paneline hoş geldiniz.\n\nBuradan sistem ayarlarını, WireGuard yapılandırmasını ve Hooks ayarlarını yönetebilirsiniz."
|
||||
"introText": "Yönetici paneline hoş geldiniz.\n\nBurada genel ayarları, yapılandırmayı, arayüz ayarlarını ve hook'ları yönetebilirsiniz.\n\nKenar çubuğundaki bölümlerden birini seçerek başlayın."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} alanı zorunludur",
|
||||
"validNumber": "{0} geçerli bir sayı olmalıdır",
|
||||
"validNumberRange": "{0} geçerli bir sayı veya aralık olmalıdır",
|
||||
"validString": "{0} geçerli bir metin olmalıdır",
|
||||
"validBoolean": "{0} geçerli bir boolean olmalıdır",
|
||||
"validArray": "{0} geçerli bir dizi olmalıdır",
|
||||
"stringMin": "{0} en az {1} karakter olmalıdır",
|
||||
"numberMin": "{0} en az {1} olmalıdır"
|
||||
"required": "{0} gerekli",
|
||||
"validNumber": "{0} geçerli bir sayı olmalı",
|
||||
"validString": "{0} geçerli bir dize olmalı",
|
||||
"validBoolean": "{0} geçerli bir boolean olmalı",
|
||||
"validArray": "{0} geçerli bir dizi olmalı",
|
||||
"stringMin": "{0} en az {1} karakter olmalı",
|
||||
"numberMin": "{0} en az {1} olmalı"
|
||||
},
|
||||
"client": {
|
||||
"id": "Client ID",
|
||||
"name": "İsim",
|
||||
"expiresAt": "Son Kullanma",
|
||||
"id": "İstemci ID",
|
||||
"name": "Ad",
|
||||
"expiresAt": "Son Kullanma Tarihi",
|
||||
"address4": "IPv4 Adresi",
|
||||
"address6": "IPv6 Adresi",
|
||||
"serverAllowedIps": "Server Allowed IPs",
|
||||
"firewallIps": "Firewall Allowed IPs",
|
||||
"firewallIpsInvalid": "Geçersiz Firewall IP formatı. Desteklenen söz dizimi için dokümantasyona bakın. See docs for supported syntax."
|
||||
"serverAllowedIps": "Sunucu İzin Verilen IP'ler"
|
||||
},
|
||||
"user": {
|
||||
"username": "Kullanıcı Adı",
|
||||
"password": "Şifre",
|
||||
"remember": "Hatırla",
|
||||
"name": "İsim",
|
||||
"name": "Ad",
|
||||
"email": "E-posta",
|
||||
"emailInvalid": "Geçersiz e-posta formatı",
|
||||
"passwordMatch": "Şifreler eşleşmiyor",
|
||||
"totpEnable": "2FA Aktif",
|
||||
"totpEnableTrue": "2FA Aktif edilmelidir",
|
||||
"totpCode": "2FA Kodu"
|
||||
"emailInvalid": "E-posta geçerli bir e-posta olmalı",
|
||||
"passwordMatch": "Şifreler eşleşmeli",
|
||||
"totpEnable": "TOTP Etkinleştir",
|
||||
"totpEnableTrue": "TOTP Etkinleştir doğru olmalı",
|
||||
"totpCode": "TOTP Kodu"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "Host"
|
||||
"host": "Ana Bilgisayar"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "Zaman Aşımı",
|
||||
"sessionTimeout": "Oturum Zaman Aşımı",
|
||||
"metricsEnabled": "Metrikler",
|
||||
"metricsPassword": "Metrik Şifresi"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Aygıt",
|
||||
"cidrValid": "Geçersiz CIDR"
|
||||
"device": "Cihaz",
|
||||
"cidrValid": "CIDR geçerli olmalı"
|
||||
},
|
||||
"otl": "OTL (One Time Link)",
|
||||
"stringMalformed": "Hatalı format",
|
||||
"body": "Body geçerli bir obje olmalıdır",
|
||||
"otl": "Tek seferlik bağlantı",
|
||||
"stringMalformed": "Dize hatalı biçimlendirilmiş",
|
||||
"body": "Gövde geçerli bir nesne olmalı",
|
||||
"hook": "Hook",
|
||||
"enabled": "Aktif",
|
||||
"enabled": "Etkin",
|
||||
"mtu": "MTU",
|
||||
"port": "Port",
|
||||
"persistentKeepalive": "Keepalive",
|
||||
"persistentKeepalive": "Kalıcı Keepalive",
|
||||
"address": "IP Adresi",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "Allowed IPs",
|
||||
"allowedIps": "İzin Verilen IP'ler",
|
||||
"file": "Dosya"
|
||||
},
|
||||
"hooks": {
|
||||
@@ -251,47 +236,5 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Kopyalama desteklenmiyor",
|
||||
"copied": "Kopyalandı!",
|
||||
"failed": "Kopyalama başarısız",
|
||||
"copy": "Kopyala"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Junk paket sayısı (Jc)",
|
||||
"jCDescription": "Gönderilecek sahte paket sayısı (1-128)",
|
||||
"jMinLabel": "Junk min boyutu (Jmin)",
|
||||
"jMinDescription": "Sahte paketlerin minimum boyutu (Jmin < Jmax, MTU ile sınırlı)",
|
||||
"jMaxLabel": "Junk maks boyutu (Jmax)",
|
||||
"jMaxDescription": "Sahte paketlerin maksimum boyutu (Jmax > Jmin, MTU ile sınırlı)",
|
||||
"s1Label": "Init junk boyutu (S1)",
|
||||
"s1Description": "Başlangıç paketi junk boyutu",
|
||||
"s2Label": "Response junk boyutu (S2)",
|
||||
"s2Description": "Yanıt paketi junk boyutu",
|
||||
"s3Label": "Cookie junk boyutu (S3)",
|
||||
"s3Description": "Cookie reply junk boyutu",
|
||||
"s4Label": "Transport junk boyutu (S4)",
|
||||
"s4Description": "Transport junk boyutu",
|
||||
"h1Label": "Init magic header (H1)",
|
||||
"h1Description": "Init paket başlık değeri",
|
||||
"h2Label": "Response magic header (H2)",
|
||||
"h2Description": "Response paket başlık değeri",
|
||||
"h3Label": "Cookie magic header (H3)",
|
||||
"h3Description": "Cookie reply başlık değeri",
|
||||
"h4Label": "Transport magic header (H4)",
|
||||
"h4Description": "Transport paket başlık değeri",
|
||||
"i1Label": "Özel junk 1 (I1)",
|
||||
"i1Description": "Hex formatında protocol mimic paketi",
|
||||
"i2Label": "Özel junk 2 (I2)",
|
||||
"i2Description": "Hex formatında protocol mimic paketi",
|
||||
"i3Label": "Özel junk 3 (I3)",
|
||||
"i3Description": "Hex formatında protocol mimic paketi",
|
||||
"i4Label": "Özel junk 4 (I4)",
|
||||
"i4Description": "Hex formatında protocol mimic paketi",
|
||||
"i5Label": "Özel junk 5 (I5)",
|
||||
"i5Description": "Hex formatında protocol mimic paketi",
|
||||
"mtuNote": "Değerler MTU'ya bağlıdır",
|
||||
"obfuscationParameters": "AmneziaWG Obfuscation Ayarları"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
"name": "Ім'я",
|
||||
"expireDate": "Термін дії",
|
||||
"expireDateDesc": "Дата, коли клієнт буде відключений. Порожнє для постійного користування",
|
||||
"delete": "Видалити",
|
||||
"deleteClient": "Видалити клієнта",
|
||||
"deleteDialog1": "Ви впевнені, що бажаєте видалити",
|
||||
"deleteDialog2": "Цю дію неможливо скасувати.",
|
||||
@@ -117,10 +116,7 @@
|
||||
"dnsDesc": "DNS сервер, який використовуватимуть клієнти (перевизначає глобальну конфігурацію)",
|
||||
"notConnected": "Клієнт не підключений",
|
||||
"endpoint": "Кінцева точка",
|
||||
"endpointDesc": "IP-адреса клієнта, з якої встановлюється з’єднання WireGuard",
|
||||
"search": "Пошук клієнтів...",
|
||||
"config": "Конфігурація",
|
||||
"viewConfig": "Переглянути конфігурацію"
|
||||
"endpointDesc": "IP-адреса клієнта, з якої встановлюється з’єднання WireGuard"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Змінити",
|
||||
@@ -240,47 +236,5 @@
|
||||
"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–150, S1+56 ≠ S2)",
|
||||
"s2Label": "Розмір сміттєвих даних у пакеті відповіді (S2)",
|
||||
"s2Description": "Розмір сміттєвих даних у пакеті відповіді (0–1188 [1280* - 92 = 1188], рекомендовано: 15–150)",
|
||||
"s3Label": "Розмір сміттєвих даних у пакеті «cookie reply» (S3)",
|
||||
"s3Description": "Розмір сміттєвих даних у пакеті «cookie reply»",
|
||||
"s4Label": "Розмір сміттєвих даних у транспортному пакеті (S4)",
|
||||
"s4Description": "Розмір сміттєвих даних у транспортному пакеті",
|
||||
"h1Label": "Початковий магічний заголовок (H1)",
|
||||
"h1Description": "Значення заголовка початкового пакета (5–2147483647, має бути унікальним від H2–H4)",
|
||||
"h2Label": "Магічний заголовок відповіді (H2)",
|
||||
"h2Description": "Значення заголовка пакета відповіді (5–2147483647, має бути унікальним від H1, H3, H4)",
|
||||
"h3Label": "Магічний заголовок «cookie reply» (H3)",
|
||||
"h3Description": "Значення заголовка пакета «cookie reply» (5–2147483647, має бути унікальним від H1, H2, H4)",
|
||||
"h4Label": "Магічний заголовок транспортного пакета (H4)",
|
||||
"h4Description": "Значення заголовка транспортного пакета (5–2147483647, має бути унікальним від H1–H3)",
|
||||
"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...>",
|
||||
"mtuNote": "Значення залежать від MTU",
|
||||
"obfuscationParameters": "Параметри обфускації AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +88,8 @@
|
||||
"name": "客户端名称",
|
||||
"expireDate": "过期日期",
|
||||
"expireDateDesc": "客户端将被自动禁用的日期。留空表示永久有效",
|
||||
"delete": "删除客户端",
|
||||
"deleteClient": "删除客户端",
|
||||
"deleteDialog1": "您确定要删除客户端",
|
||||
"deleteDialog1": "您确定要删除此客户端吗?",
|
||||
"deleteDialog2": "此操作无法撤销。",
|
||||
"enabled": "已启用",
|
||||
"address": "IP地址",
|
||||
@@ -114,13 +113,7 @@
|
||||
"hooks": "钩子脚本",
|
||||
"hooksDescription": "钩子脚本仅在使用wg-quick时有效",
|
||||
"hooksLeaveEmpty": "如果不使用wg-quick,请留空此字段",
|
||||
"dnsDesc": "客户端将使用的 DNS 服务器(将覆盖全局配置)",
|
||||
"notConnected": "客户端未连接",
|
||||
"endpoint": "端点",
|
||||
"endpointDesc": "建立 WireGuard 连接时客户端的 IP 地址",
|
||||
"search": "搜索客户端...",
|
||||
"config": "配置",
|
||||
"viewConfig": "查看配置文本"
|
||||
"search": "搜索客户端..."
|
||||
},
|
||||
"dialog": {
|
||||
"change": "确认修改",
|
||||
@@ -240,47 +233,5 @@
|
||||
"postUp": "启动后脚本",
|
||||
"preDown": "停止前脚本",
|
||||
"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-150,S1+56 ≠ S2)",
|
||||
"s2Label": "响应数据包垃圾数据大小(S2)",
|
||||
"s2Description": "响应数据包中垃圾数据的大小(范围:0-1188[1280* - 92 = 1188],推荐值:15-150)",
|
||||
"s3Label": "Cookie 回复数据包垃圾数据大小(S3)",
|
||||
"s3Description": "Cookie 回复数据包中垃圾数据的大小",
|
||||
"s4Label": "传输数据包垃圾数据大小(S4)",
|
||||
"s4Description": "传输数据包中垃圾数据的大小",
|
||||
"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 不同)",
|
||||
"i1Label": "特殊垃圾数据包 1(I1)",
|
||||
"i1Description": "协议模拟数据包(十六进制格式):<b 0x...>",
|
||||
"i2Label": "特殊垃圾数据包 2(I2)",
|
||||
"i2Description": "协议模拟数据包(十六进制格式):<b 0x...>",
|
||||
"i3Label": "特殊垃圾数据包 3(I3)",
|
||||
"i3Description": "协议模拟数据包(十六进制格式):<b 0x...>",
|
||||
"i4Label": "特殊垃圾数据包 4(I4)",
|
||||
"i4Description": "协议模拟数据包(十六进制格式):<b 0x...>",
|
||||
"i5Label": "特殊垃圾数据包 5(I5)",
|
||||
"i5Description": "协议模拟数据包(十六进制格式):<b 0x...>",
|
||||
"mtuNote": "具体数值取决于 MTU(最大传输单元)",
|
||||
"obfuscationParameters": "AmneziaWG 混淆参数"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
{
|
||||
"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-150,S1+56 ≠ S2)",
|
||||
"s2Label": "回應封包填充大小 (S2)",
|
||||
"s2Description": "回應封包填充大小 (0-1188 [1280* - 92 = 1188],建議: 15-150)",
|
||||
"s3Label": "Cookie 回覆封包填充大小 (S3)",
|
||||
"s3Description": "Cookie 回覆封包填充大小",
|
||||
"s4Label": "傳輸封包填充大小 (S4)",
|
||||
"s4Description": "傳輸封包填充大小",
|
||||
"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 不同)",
|
||||
"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...>",
|
||||
"mtuNote": "數值取決於 MTU",
|
||||
"obfuscationParameters": "AmneziaWG 混淆參數"
|
||||
}
|
||||
}
|
||||
+1
-33
@@ -5,7 +5,7 @@ export default defineNuxtConfig({
|
||||
future: {
|
||||
compatibilityVersion: 4,
|
||||
},
|
||||
compatibilityDate: '2026-02-06',
|
||||
compatibilityDate: '2025-02-04',
|
||||
devtools: { enabled: true },
|
||||
modules: [
|
||||
'@nuxtjs/i18n',
|
||||
@@ -15,7 +15,6 @@ export default defineNuxtConfig({
|
||||
'radix-vue/nuxt',
|
||||
'@vueuse/nuxt',
|
||||
'@nuxt/eslint',
|
||||
'@nuxt/test-utils/module',
|
||||
],
|
||||
colorMode: {
|
||||
preference: 'system',
|
||||
@@ -23,7 +22,6 @@ export default defineNuxtConfig({
|
||||
classSuffix: '',
|
||||
cookieName: 'theme',
|
||||
},
|
||||
css: ['~/app.css'],
|
||||
i18n: {
|
||||
// https://i18n.nuxtjs.org/docs/guide/server-side-translations
|
||||
experimental: {
|
||||
@@ -81,21 +79,11 @@ export default defineNuxtConfig({
|
||||
language: 'zh-HK',
|
||||
name: '繁體中文(香港)',
|
||||
},
|
||||
{
|
||||
code: 'zh-TW',
|
||||
language: 'zh-TW',
|
||||
name: '正體中文 (台灣)',
|
||||
},
|
||||
{
|
||||
code: 'pl',
|
||||
language: 'pl-PL',
|
||||
name: 'Polski',
|
||||
},
|
||||
{
|
||||
code: 'cs',
|
||||
language: 'cs-CZ',
|
||||
name: 'Čeština',
|
||||
},
|
||||
{
|
||||
code: 'pt-BR',
|
||||
language: 'pt-BR',
|
||||
@@ -116,26 +104,6 @@ export default defineNuxtConfig({
|
||||
language: 'id-ID',
|
||||
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',
|
||||
vueI18n: './i18n.config.ts',
|
||||
|
||||
+29
-34
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wg-easy",
|
||||
"version": "15.3.0-beta.1",
|
||||
"version": "15.2.0-beta.1",
|
||||
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -17,62 +17,57 @@
|
||||
"check:all": "pnpm typecheck && pnpm lint && pnpm format:check && pnpm build",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"cli:build": "node cli/build.js",
|
||||
"cli:dev": "tsx cli/index.ts",
|
||||
"test:unit": "vitest run --project unit"
|
||||
"cli:dev": "tsx cli/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eschricht/nuxt-color-mode": "^1.2.0",
|
||||
"@heroicons/vue": "^2.2.0",
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@nuxtjs/i18n": "^10.2.3",
|
||||
"@libsql/client": "^0.15.15",
|
||||
"@nuxtjs/i18n": "^10.2.0",
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@phc/format": "^1.0.0",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"@vueuse/nuxt": "^14.2.1",
|
||||
"apexcharts": "^5.10.3",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@vueuse/core": "^14.0.0",
|
||||
"@vueuse/nuxt": "^14.0.0",
|
||||
"apexcharts": "^5.3.6",
|
||||
"argon2": "^0.44.0",
|
||||
"cidr-tools": "^11.2.0",
|
||||
"citty": "^0.2.1",
|
||||
"cidr-tools": "^11.0.3",
|
||||
"citty": "^0.1.6",
|
||||
"consola": "^3.4.2",
|
||||
"crc-32": "^1.2.2",
|
||||
"debug": "^4.4.3",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"ip-bigint": "^8.2.10",
|
||||
"is-cidr": "^6.0.3",
|
||||
"drizzle-orm": "^0.44.7",
|
||||
"ip-bigint": "^8.2.2",
|
||||
"is-cidr": "^6.0.1",
|
||||
"is-ip": "^5.0.1",
|
||||
"js-sha256": "^0.11.1",
|
||||
"nuxt": "^3.21.1",
|
||||
"otpauth": "^9.5.0",
|
||||
"nuxt": "^3.20.1",
|
||||
"otpauth": "^9.4.1",
|
||||
"pinia": "^3.0.4",
|
||||
"qr": "^0.5.5",
|
||||
"qr": "^0.5.2",
|
||||
"radix-vue": "^1.9.17",
|
||||
"semver": "^7.7.4",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"semver": "^7.7.3",
|
||||
"tailwindcss": "^3.4.18",
|
||||
"timeago.js": "^4.0.2",
|
||||
"vue": "latest",
|
||||
"vue3-apexcharts": "^1.11.1",
|
||||
"zod": "^4.3.6"
|
||||
"vue3-apexcharts": "^1.10.0",
|
||||
"zod": "^4.1.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "^1.15.2",
|
||||
"@nuxt/test-utils": "^4.0.0",
|
||||
"@nuxt/eslint": "^1.10.0",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/phc__format": "^1.0.1",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vitest/ui": "4.0.18",
|
||||
"drizzle-kit": "^0.31.9",
|
||||
"esbuild": "^0.27.3",
|
||||
"eslint": "^9.39.4",
|
||||
"drizzle-kit": "^0.31.6",
|
||||
"esbuild": "^0.27.0",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tsx": "^4.21.0",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-tailwindcss": "^0.7.1",
|
||||
"tsx": "^4.20.6",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18",
|
||||
"vue-tsc": "^3.2.5"
|
||||
"vue-tsc": "^3.1.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.31.0"
|
||||
"packageManager": "pnpm@10.21.0"
|
||||
}
|
||||
|
||||
Generated
+2601
-3385
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@ export default definePermissionEventHandler(
|
||||
event,
|
||||
validateZod(InterfaceCidrUpdateSchema, event)
|
||||
);
|
||||
|
||||
await Database.interfaces.updateCidr(data);
|
||||
await WireGuard.saveConfig();
|
||||
return { success: true };
|
||||
|
||||
@@ -8,26 +8,6 @@ export default definePermissionEventHandler(
|
||||
event,
|
||||
validateZod(InterfaceUpdateSchema, event)
|
||||
);
|
||||
|
||||
// If enabling firewall, check if iptables is available
|
||||
if (data.firewallEnabled) {
|
||||
// Clear cache to force fresh check
|
||||
firewall.clearAvailabilityCache();
|
||||
|
||||
const iptablesAvailable = await firewall.isAvailable(
|
||||
!WG_ENV.DISABLE_IPV6
|
||||
);
|
||||
if (!iptablesAvailable) {
|
||||
const requiredTools = WG_ENV.DISABLE_IPV6
|
||||
? 'iptables'
|
||||
: 'iptables and ip6tables';
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: `Per-Client Firewall requires ${requiredTools} to be installed on the host system. Please install ${requiredTools} before enabling this feature.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await Database.interfaces.update(data);
|
||||
await WireGuard.saveConfig();
|
||||
return { success: true };
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
export default definePermissionEventHandler('admin', 'any', async () => {
|
||||
return {
|
||||
interface: {
|
||||
port: WG_OVERRIDE_ENV.PORT !== undefined,
|
||||
device: WG_OVERRIDE_ENV.DEVICE !== undefined,
|
||||
mtu: WG_OVERRIDE_ENV.MTU !== undefined,
|
||||
ipv4Cidr: WG_OVERRIDE_ENV.IPV4_CIDR !== undefined,
|
||||
ipv6Cidr: WG_OVERRIDE_ENV.IPV6_CIDR !== undefined,
|
||||
},
|
||||
userConfig: {
|
||||
host: WG_CLIENT_OVERRIDE_ENV.HOST !== undefined,
|
||||
port: WG_CLIENT_OVERRIDE_ENV.CLIENT_PORT !== undefined,
|
||||
defaultDns: WG_CLIENT_OVERRIDE_ENV.DEFAULT_DNS !== undefined,
|
||||
defaultAllowedIps:
|
||||
WG_CLIENT_OVERRIDE_ENV.DEFAULT_ALLOWED_IPS !== undefined,
|
||||
defaultMtu: WG_CLIENT_OVERRIDE_ENV.DEFAULT_MTU !== undefined,
|
||||
defaultPersistentKeepalive:
|
||||
WG_CLIENT_OVERRIDE_ENV.DEFAULT_PERSISTENT_KEEPALIVE !== undefined,
|
||||
},
|
||||
general: {
|
||||
sessionTimeout: WG_GENERAL_OVERRIDE_ENV.SESSION_TIMEOUT !== undefined,
|
||||
metricsPassword: WG_GENERAL_OVERRIDE_ENV.METRICS_PASSWORD !== undefined,
|
||||
metricsPrometheus:
|
||||
WG_GENERAL_OVERRIDE_ENV.METRICS_PROMETHEUS !== undefined,
|
||||
metricsJson: WG_GENERAL_OVERRIDE_ENV.METRICS_JSON !== undefined,
|
||||
},
|
||||
hooks: {
|
||||
preUp: WG_HOOKS_OVERRIDE_ENV.PRE_UP !== undefined,
|
||||
postUp: WG_HOOKS_OVERRIDE_ENV.POST_UP !== undefined,
|
||||
preDown: WG_HOOKS_OVERRIDE_ENV.PRE_DOWN !== undefined,
|
||||
postDown: WG_HOOKS_OVERRIDE_ENV.POST_DOWN !== undefined,
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -5,7 +5,6 @@ export default defineEventHandler(async () => {
|
||||
const updateAvailable = gt(latestRelease.version, RELEASE);
|
||||
const insecure = WG_ENV.INSECURE;
|
||||
const isAwg = WG_ENV.WG_EXECUTABLE === 'awg';
|
||||
const wgInterface = await Database.interfaces.get();
|
||||
|
||||
return {
|
||||
currentRelease: RELEASE,
|
||||
@@ -13,6 +12,5 @@ export default defineEventHandler(async () => {
|
||||
updateAvailable,
|
||||
insecure,
|
||||
isAwg,
|
||||
firewallEnabled: wgInterface.firewallEnabled,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import type { SharedPublicUser } from '~~/shared/utils/permissions';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await useWGSession(event);
|
||||
|
||||
if (!session.data.userId) {
|
||||
// not logged in
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Not authenticated',
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await Database.users.get(session.data.userId);
|
||||
@@ -26,5 +21,5 @@ export default defineEventHandler(async (event) => {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
totpVerified: user.totpVerified,
|
||||
} satisfies SharedPublicUser;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -8,6 +8,19 @@ export default defineSetupEventHandler(2, async ({ event }) => {
|
||||
|
||||
await Database.users.create(username, password);
|
||||
|
||||
await Database.general.setSetupStep(3);
|
||||
return { success: true };
|
||||
// If host and port are already set by environment variables, skip step 4
|
||||
const host = WG_INITIAL_ENV.HOST ?? WG_CLIENT_OVERRIDE_ENV.HOST;
|
||||
const port = WG_INITIAL_ENV.PORT ?? WG_INTERFACE_OVERRIDE_ENV.PORT;
|
||||
|
||||
const setupDone = host && port;
|
||||
|
||||
if (setupDone) {
|
||||
// Skip to done
|
||||
await Database.general.setSetupStep(0);
|
||||
} else {
|
||||
// Proceed to step 3 (which leads to step 4)
|
||||
await Database.general.setSetupStep(3);
|
||||
}
|
||||
|
||||
return { success: true, setupDone: setupDone };
|
||||
});
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||
CREATE TABLE `__new_interfaces_table` (
|
||||
`name` text PRIMARY KEY NOT NULL,
|
||||
`device` text NOT NULL,
|
||||
`port` integer NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`ipv4_cidr` text NOT NULL,
|
||||
`ipv6_cidr` text NOT NULL,
|
||||
`mtu` integer NOT NULL,
|
||||
`j_c` integer DEFAULT 7,
|
||||
`j_min` integer DEFAULT 10,
|
||||
`j_max` integer DEFAULT 1000,
|
||||
`s1` integer DEFAULT 128,
|
||||
`s2` integer DEFAULT 56,
|
||||
`s3` integer,
|
||||
`s4` integer,
|
||||
`h1` text,
|
||||
`h2` text,
|
||||
`h3` text,
|
||||
`h4` text,
|
||||
`i1` text,
|
||||
`i2` text,
|
||||
`i3` text,
|
||||
`i4` text,
|
||||
`i5` text,
|
||||
`enabled` integer NOT NULL,
|
||||
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
|
||||
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `__new_interfaces_table`("name", "device", "port", "private_key", "public_key", "ipv4_cidr", "ipv6_cidr", "mtu", "j_c", "j_min", "j_max", "s1", "s2", "s3", "s4", "h1", "h2", "h3", "h4", "i1", "i2", "i3", "i4", "i5", "enabled", "created_at", "updated_at") SELECT "name", "device", "port", "private_key", "public_key", "ipv4_cidr", "ipv6_cidr", "mtu", "j_c", "j_min", "j_max", "s1", "s2", "s3", "s4", "h1", "h2", "h3", "h4", "i1", "i2", "i3", "i4", "i5", "enabled", "created_at", "updated_at" FROM `interfaces_table`;--> statement-breakpoint
|
||||
DROP TABLE `interfaces_table`;--> statement-breakpoint
|
||||
ALTER TABLE `__new_interfaces_table` RENAME TO `interfaces_table`;--> statement-breakpoint
|
||||
PRAGMA foreign_keys=ON;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE `clients_table` ADD `firewall_ips` text;--> statement-breakpoint
|
||||
ALTER TABLE `interfaces_table` ADD `firewall_enabled` integer DEFAULT false NOT NULL;
|
||||
@@ -1,972 +0,0 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "68c43b7a-772d-4c34-8278-e9fce5b53df1",
|
||||
"prevId": "e09bc17a-dab6-45a3-a09c-57af222b08fb",
|
||||
"tables": {
|
||||
"clients_table": {
|
||||
"name": "clients_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"interface_id": {
|
||||
"name": "interface_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv4_address": {
|
||||
"name": "ipv4_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv6_address": {
|
||||
"name": "ipv6_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_up": {
|
||||
"name": "pre_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"post_up": {
|
||||
"name": "post_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"pre_down": {
|
||||
"name": "pre_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"post_down": {
|
||||
"name": "post_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"private_key": {
|
||||
"name": "private_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"public_key": {
|
||||
"name": "public_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_shared_key": {
|
||||
"name": "pre_shared_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"allowed_ips": {
|
||||
"name": "allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"server_allowed_ips": {
|
||||
"name": "server_allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"persistent_keepalive": {
|
||||
"name": "persistent_keepalive",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"mtu": {
|
||||
"name": "mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_c": {
|
||||
"name": "j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_min": {
|
||||
"name": "j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_max": {
|
||||
"name": "j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i1": {
|
||||
"name": "i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i2": {
|
||||
"name": "i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i3": {
|
||||
"name": "i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i4": {
|
||||
"name": "i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i5": {
|
||||
"name": "i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"dns": {
|
||||
"name": "dns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"server_endpoint": {
|
||||
"name": "server_endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"clients_table_ipv4_address_unique": {
|
||||
"name": "clients_table_ipv4_address_unique",
|
||||
"columns": [
|
||||
"ipv4_address"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"clients_table_ipv6_address_unique": {
|
||||
"name": "clients_table_ipv6_address_unique",
|
||||
"columns": [
|
||||
"ipv6_address"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"clients_table_user_id_users_table_id_fk": {
|
||||
"name": "clients_table_user_id_users_table_id_fk",
|
||||
"tableFrom": "clients_table",
|
||||
"tableTo": "users_table",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "restrict",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
"clients_table_interface_id_interfaces_table_name_fk": {
|
||||
"name": "clients_table_interface_id_interfaces_table_name_fk",
|
||||
"tableFrom": "clients_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"interface_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"general_table": {
|
||||
"name": "general_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"setup_step": {
|
||||
"name": "setup_step",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"session_password": {
|
||||
"name": "session_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"session_timeout": {
|
||||
"name": "session_timeout",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_prometheus": {
|
||||
"name": "metrics_prometheus",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_json": {
|
||||
"name": "metrics_json",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_password": {
|
||||
"name": "metrics_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"hooks_table": {
|
||||
"name": "hooks_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_up": {
|
||||
"name": "pre_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"post_up": {
|
||||
"name": "post_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_down": {
|
||||
"name": "pre_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"post_down": {
|
||||
"name": "post_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"hooks_table_id_interfaces_table_name_fk": {
|
||||
"name": "hooks_table_id_interfaces_table_name_fk",
|
||||
"tableFrom": "hooks_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"interfaces_table": {
|
||||
"name": "interfaces_table",
|
||||
"columns": {
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"device": {
|
||||
"name": "device",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"private_key": {
|
||||
"name": "private_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"public_key": {
|
||||
"name": "public_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv4_cidr": {
|
||||
"name": "ipv4_cidr",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv6_cidr": {
|
||||
"name": "ipv6_cidr",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"mtu": {
|
||||
"name": "mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_c": {
|
||||
"name": "j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 7
|
||||
},
|
||||
"j_min": {
|
||||
"name": "j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 10
|
||||
},
|
||||
"j_max": {
|
||||
"name": "j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 1000
|
||||
},
|
||||
"s1": {
|
||||
"name": "s1",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 128
|
||||
},
|
||||
"s2": {
|
||||
"name": "s2",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 56
|
||||
},
|
||||
"s3": {
|
||||
"name": "s3",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"s4": {
|
||||
"name": "s4",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h1": {
|
||||
"name": "h1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h2": {
|
||||
"name": "h2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h3": {
|
||||
"name": "h3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h4": {
|
||||
"name": "h4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i1": {
|
||||
"name": "i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i2": {
|
||||
"name": "i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i3": {
|
||||
"name": "i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i4": {
|
||||
"name": "i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i5": {
|
||||
"name": "i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"interfaces_table_port_unique": {
|
||||
"name": "interfaces_table_port_unique",
|
||||
"columns": [
|
||||
"port"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"one_time_links_table": {
|
||||
"name": "one_time_links_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"one_time_link": {
|
||||
"name": "one_time_link",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"one_time_links_table_one_time_link_unique": {
|
||||
"name": "one_time_links_table_one_time_link_unique",
|
||||
"columns": [
|
||||
"one_time_link"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"one_time_links_table_id_clients_table_id_fk": {
|
||||
"name": "one_time_links_table_id_clients_table_id_fk",
|
||||
"tableFrom": "one_time_links_table",
|
||||
"tableTo": "clients_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users_table": {
|
||||
"name": "users_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"totp_key": {
|
||||
"name": "totp_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"totp_verified": {
|
||||
"name": "totp_verified",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_table_username_unique": {
|
||||
"name": "users_table_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_configs_table": {
|
||||
"name": "user_configs_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_mtu": {
|
||||
"name": "default_mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_persistent_keepalive": {
|
||||
"name": "default_persistent_keepalive",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_dns": {
|
||||
"name": "default_dns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_allowed_ips": {
|
||||
"name": "default_allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_j_c": {
|
||||
"name": "default_j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 7
|
||||
},
|
||||
"default_j_min": {
|
||||
"name": "default_j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 10
|
||||
},
|
||||
"default_j_max": {
|
||||
"name": "default_j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 1000
|
||||
},
|
||||
"default_i1": {
|
||||
"name": "default_i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i2": {
|
||||
"name": "default_i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i3": {
|
||||
"name": "default_i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i4": {
|
||||
"name": "default_i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i5": {
|
||||
"name": "default_i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"host": {
|
||||
"name": "host",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_configs_table_id_interfaces_table_name_fk": {
|
||||
"name": "user_configs_table_id_interfaces_table_name_fk",
|
||||
"tableFrom": "user_configs_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
@@ -1,987 +0,0 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "0f072f91-cd10-4702-ae7b-245255d69d1e",
|
||||
"prevId": "68c43b7a-772d-4c34-8278-e9fce5b53df1",
|
||||
"tables": {
|
||||
"clients_table": {
|
||||
"name": "clients_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"interface_id": {
|
||||
"name": "interface_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv4_address": {
|
||||
"name": "ipv4_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv6_address": {
|
||||
"name": "ipv6_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_up": {
|
||||
"name": "pre_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"post_up": {
|
||||
"name": "post_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"pre_down": {
|
||||
"name": "pre_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"post_down": {
|
||||
"name": "post_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"private_key": {
|
||||
"name": "private_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"public_key": {
|
||||
"name": "public_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_shared_key": {
|
||||
"name": "pre_shared_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"allowed_ips": {
|
||||
"name": "allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"server_allowed_ips": {
|
||||
"name": "server_allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"firewall_ips": {
|
||||
"name": "firewall_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"persistent_keepalive": {
|
||||
"name": "persistent_keepalive",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"mtu": {
|
||||
"name": "mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_c": {
|
||||
"name": "j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_min": {
|
||||
"name": "j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_max": {
|
||||
"name": "j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i1": {
|
||||
"name": "i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i2": {
|
||||
"name": "i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i3": {
|
||||
"name": "i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i4": {
|
||||
"name": "i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i5": {
|
||||
"name": "i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"dns": {
|
||||
"name": "dns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"server_endpoint": {
|
||||
"name": "server_endpoint",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"clients_table_ipv4_address_unique": {
|
||||
"name": "clients_table_ipv4_address_unique",
|
||||
"columns": [
|
||||
"ipv4_address"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"clients_table_ipv6_address_unique": {
|
||||
"name": "clients_table_ipv6_address_unique",
|
||||
"columns": [
|
||||
"ipv6_address"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"clients_table_user_id_users_table_id_fk": {
|
||||
"name": "clients_table_user_id_users_table_id_fk",
|
||||
"tableFrom": "clients_table",
|
||||
"tableTo": "users_table",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "restrict",
|
||||
"onUpdate": "cascade"
|
||||
},
|
||||
"clients_table_interface_id_interfaces_table_name_fk": {
|
||||
"name": "clients_table_interface_id_interfaces_table_name_fk",
|
||||
"tableFrom": "clients_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"interface_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"general_table": {
|
||||
"name": "general_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"setup_step": {
|
||||
"name": "setup_step",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"session_password": {
|
||||
"name": "session_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"session_timeout": {
|
||||
"name": "session_timeout",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_prometheus": {
|
||||
"name": "metrics_prometheus",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_json": {
|
||||
"name": "metrics_json",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"metrics_password": {
|
||||
"name": "metrics_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"hooks_table": {
|
||||
"name": "hooks_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_up": {
|
||||
"name": "pre_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"post_up": {
|
||||
"name": "post_up",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"pre_down": {
|
||||
"name": "pre_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"post_down": {
|
||||
"name": "post_down",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"hooks_table_id_interfaces_table_name_fk": {
|
||||
"name": "hooks_table_id_interfaces_table_name_fk",
|
||||
"tableFrom": "hooks_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"interfaces_table": {
|
||||
"name": "interfaces_table",
|
||||
"columns": {
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"device": {
|
||||
"name": "device",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"private_key": {
|
||||
"name": "private_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"public_key": {
|
||||
"name": "public_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv4_cidr": {
|
||||
"name": "ipv4_cidr",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ipv6_cidr": {
|
||||
"name": "ipv6_cidr",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"mtu": {
|
||||
"name": "mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"j_c": {
|
||||
"name": "j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 7
|
||||
},
|
||||
"j_min": {
|
||||
"name": "j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 10
|
||||
},
|
||||
"j_max": {
|
||||
"name": "j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 1000
|
||||
},
|
||||
"s1": {
|
||||
"name": "s1",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 128
|
||||
},
|
||||
"s2": {
|
||||
"name": "s2",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 56
|
||||
},
|
||||
"s3": {
|
||||
"name": "s3",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"s4": {
|
||||
"name": "s4",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h1": {
|
||||
"name": "h1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h2": {
|
||||
"name": "h2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h3": {
|
||||
"name": "h3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"h4": {
|
||||
"name": "h4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i1": {
|
||||
"name": "i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i2": {
|
||||
"name": "i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i3": {
|
||||
"name": "i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i4": {
|
||||
"name": "i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"i5": {
|
||||
"name": "i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"firewall_enabled": {
|
||||
"name": "firewall_enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"interfaces_table_port_unique": {
|
||||
"name": "interfaces_table_port_unique",
|
||||
"columns": [
|
||||
"port"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"one_time_links_table": {
|
||||
"name": "one_time_links_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"one_time_link": {
|
||||
"name": "one_time_link",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"one_time_links_table_one_time_link_unique": {
|
||||
"name": "one_time_links_table_one_time_link_unique",
|
||||
"columns": [
|
||||
"one_time_link"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"one_time_links_table_id_clients_table_id_fk": {
|
||||
"name": "one_time_links_table_id_clients_table_id_fk",
|
||||
"tableFrom": "one_time_links_table",
|
||||
"tableTo": "clients_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users_table": {
|
||||
"name": "users_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"totp_key": {
|
||||
"name": "totp_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"totp_verified": {
|
||||
"name": "totp_verified",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_table_username_unique": {
|
||||
"name": "users_table_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_configs_table": {
|
||||
"name": "user_configs_table",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_mtu": {
|
||||
"name": "default_mtu",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_persistent_keepalive": {
|
||||
"name": "default_persistent_keepalive",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_dns": {
|
||||
"name": "default_dns",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_allowed_ips": {
|
||||
"name": "default_allowed_ips",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_j_c": {
|
||||
"name": "default_j_c",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 7
|
||||
},
|
||||
"default_j_min": {
|
||||
"name": "default_j_min",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 10
|
||||
},
|
||||
"default_j_max": {
|
||||
"name": "default_j_max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 1000
|
||||
},
|
||||
"default_i1": {
|
||||
"name": "default_i1",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i2": {
|
||||
"name": "default_i2",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i3": {
|
||||
"name": "default_i3",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i4": {
|
||||
"name": "default_i4",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"default_i5": {
|
||||
"name": "default_i5",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"host": {
|
||||
"name": "host",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "(CURRENT_TIMESTAMP)"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_configs_table_id_interfaces_table_name_fk": {
|
||||
"name": "user_configs_table_id_interfaces_table_name_fk",
|
||||
"tableFrom": "user_configs_table",
|
||||
"tableTo": "interfaces_table",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"name"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,6 @@
|
||||
"when": 1761298328460,
|
||||
"tag": "0002_keen_sleepwalker",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "6",
|
||||
"when": 1770902426367,
|
||||
"tag": "0003_breezy_colossus",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "6",
|
||||
"when": 1771352889394,
|
||||
"tag": "0004_optimal_mandrill",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -34,8 +34,6 @@ export const client = sqliteTable('clients_table', {
|
||||
serverAllowedIps: text('server_allowed_ips', { mode: 'json' })
|
||||
.$type<string[]>()
|
||||
.notNull(),
|
||||
// Firewall-enforced allowed IPs (null = use allowedIps)
|
||||
firewallIps: text('firewall_ips', { mode: 'json' }).$type<string[] | null>(),
|
||||
persistentKeepalive: int('persistent_keepalive').notNull(),
|
||||
mtu: int().notNull(),
|
||||
jC: int('j_c'),
|
||||
|
||||
@@ -175,26 +175,30 @@ export class ClientService {
|
||||
|
||||
return this.#db.transaction(async (tx) => {
|
||||
const clients = await tx.query.client.findMany().execute();
|
||||
const clientInterface = await tx.query.wgInterface
|
||||
const _clientInterface = await tx.query.wgInterface
|
||||
.findFirst({
|
||||
where: eq(wgInterface.name, 'wg0'),
|
||||
})
|
||||
.execute();
|
||||
|
||||
if (!clientInterface) {
|
||||
if (!_clientInterface) {
|
||||
throw new Error('WireGuard interface not found');
|
||||
}
|
||||
|
||||
const clientConfig = await tx.query.userConfig
|
||||
const clientInterface = applyInterfaceOverrides(_clientInterface);
|
||||
|
||||
const _clientConfig = await tx.query.userConfig
|
||||
.findFirst({
|
||||
where: eq(userConfig.id, clientInterface.name),
|
||||
})
|
||||
.execute();
|
||||
|
||||
if (!clientConfig) {
|
||||
if (!_clientConfig) {
|
||||
throw new Error('WireGuard interface configuration not found');
|
||||
}
|
||||
|
||||
const clientConfig = applyUserConfigOverrides(_clientConfig);
|
||||
|
||||
const ipv4Cidr = parseCidr(clientInterface.ipv4Cidr);
|
||||
const ipv4Address = nextIP(4, ipv4Cidr, clients);
|
||||
const ipv6Cidr = parseCidr(clientInterface.ipv6Cidr);
|
||||
@@ -241,16 +245,18 @@ export class ClientService {
|
||||
|
||||
update(id: ID, data: UpdateClientType) {
|
||||
return this.#db.transaction(async (tx) => {
|
||||
const clientInterface = await tx.query.wgInterface
|
||||
const _clientInterface = await tx.query.wgInterface
|
||||
.findFirst({
|
||||
where: eq(wgInterface.name, 'wg0'),
|
||||
})
|
||||
.execute();
|
||||
|
||||
if (!clientInterface) {
|
||||
if (!_clientInterface) {
|
||||
throw new Error('WireGuard interface not found');
|
||||
}
|
||||
|
||||
const clientInterface = applyInterfaceOverrides(_clientInterface);
|
||||
|
||||
if (!containsCidr(clientInterface.ipv4Cidr, data.ipv4Address)) {
|
||||
throw new Error('IPv4 address is not within the CIDR range');
|
||||
}
|
||||
@@ -272,7 +278,8 @@ export class ClientService {
|
||||
privateKey,
|
||||
publicKey,
|
||||
}: ClientCreateFromExistingType) {
|
||||
const clientConfig = await Database.userConfigs.get();
|
||||
const _clientConfig = await Database.userConfigs.get();
|
||||
const clientConfig = applyUserConfigOverrides(_clientConfig);
|
||||
|
||||
return this.#db
|
||||
.insert(client)
|
||||
|
||||
@@ -71,7 +71,6 @@ export const ClientUpdateSchema = schemaForType<UpdateClientType>()(
|
||||
postDown: HookSchema,
|
||||
allowedIps: AllowedIpsSchema.nullable(),
|
||||
serverAllowedIps: serverAllowedIps,
|
||||
firewallIps: FirewallIpsSchema.nullable(),
|
||||
mtu: MtuSchema,
|
||||
jC: JcSchema,
|
||||
jMin: JminSchema,
|
||||
|
||||
@@ -20,21 +20,17 @@ export const wgInterface = sqliteTable('interfaces_table', {
|
||||
s2: int().default(56),
|
||||
s3: int(),
|
||||
s4: int(),
|
||||
h1: text(),
|
||||
h2: text(),
|
||||
h3: text(),
|
||||
h4: text(),
|
||||
i1: text(),
|
||||
i2: text(),
|
||||
i3: text(),
|
||||
i4: text(),
|
||||
i5: text(),
|
||||
h1: int().default(0),
|
||||
h2: int().default(0),
|
||||
h3: int().default(0),
|
||||
h4: int().default(0),
|
||||
// does nothing yet
|
||||
enabled: int({ mode: 'boolean' }).notNull(),
|
||||
// Enable per-client firewall filtering via iptables
|
||||
firewallEnabled: int('firewall_enabled', { mode: 'boolean' })
|
||||
.notNull()
|
||||
.default(false),
|
||||
createdAt: text('created_at')
|
||||
.notNull()
|
||||
.default(sql`(CURRENT_TIMESTAMP)`),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user