mirror of
https://github.com/WGDashboard/WGDashboard.git
synced 2026-08-03 22:42:59 +00:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a749db1b45 | |||
| 56ac97b15c | |||
| 21570cb27f | |||
| 0cf3ec2965 | |||
| 3c493be351 | |||
| 1128c332ae | |||
| 65645d6775 | |||
| 46d15959b1 | |||
| 8e9ab60ce7 | |||
| ca8f47b73e | |||
| c098aea151 | |||
| 68be16bf81 | |||
| 9d88a602cd | |||
| 9e8ca0e630 | |||
| 0343e8f915 | |||
| 2a5043424e | |||
| 7df99a12d0 | |||
| 59c88853de | |||
| 6574b216fb | |||
| 6da668616b | |||
| 9a1ac86ee6 | |||
| dae13faf25 | |||
| cdd7901b7d | |||
| be2ac265bb | |||
| 3cdeb4c5b5 | |||
| 4d15555e7d | |||
| 769f96fdc7 | |||
| 4f99096d80 | |||
| 3bc88a3006 | |||
| 9982841993 | |||
| 4bff8e1d4d | |||
| d837012d86 | |||
| 96dd08e6c7 | |||
| b524fcd88b | |||
| 1658b73724 | |||
| 1f28539bff | |||
| e9fb32d9a8 | |||
| bd91b3c97a | |||
| dfcd80de5b | |||
| 85cbf498c0 | |||
| ee6586e50d | |||
| 4c59f81c85 | |||
| 1db476e1b9 | |||
| 7cb845a65d | |||
| 3da0039004 | |||
| 3d966b928f | |||
| 58fa826862 | |||
| 2be7e08b7c | |||
| aa8bfe179a | |||
| 8207c1209c | |||
| 20a6cfdec3 | |||
| 71077880ad | |||
| d51889a222 | |||
| ece7cd1896 | |||
| 4d20d00631 | |||
| 6ec8d2f201 | |||
| 195ef37928 | |||
| b16f0aa3c2 | |||
| dc26b13ea6 | |||
| b66a619e81 | |||
| dd93cbcb42 | |||
| a5be721f39 | |||
| 40c0a91afa | |||
| 35e1a3af25 | |||
| 91de807557 | |||
| 9d5478e3e3 | |||
| b07be518fb | |||
| 35be7ca3db | |||
| 36521a7d70 | |||
| 3520087dce | |||
| d354e8ad38 | |||
| 4be7cd4073 | |||
| b04be970e6 | |||
| de81384f88 | |||
| 071a4765b9 | |||
| fbaa15cb8d | |||
| c9abfa5f61 | |||
| d3d7c7e678 | |||
| 930c4169c5 | |||
| 90614a6360 | |||
| ef8459415b | |||
| 365f07da0b | |||
| 8d00cca321 | |||
| 1fffa33dd5 | |||
| ff34e4f8c8 | |||
| af385a4537 | |||
| e2ff34ce1d | |||
| 2ac9fea881 | |||
| 9e59ad0ebc | |||
| 18c2568c22 | |||
| d58e082336 | |||
| fedf7db8a4 | |||
| 523fee7b42 | |||
| 624206d5a7 | |||
| fa9d9f24b5 | |||
| c42bc47761 | |||
| 24e0f514d7 | |||
| 1744570086 | |||
| 9669782b0c | |||
| 03eddd2846 | |||
| 26b82745fc | |||
| abc82369d9 | |||
| f1764d3822 | |||
| 8fd15b9ca6 | |||
| 5f62e9ac69 | |||
| 8eb7e97d6e | |||
| 3b03099700 | |||
| 8d6eb4bb41 | |||
| 387adfee8c | |||
| a33d6bfc9a | |||
| 5726627058 | |||
| cdd85b659c | |||
| 42f9460369 | |||
| ba11a7a355 | |||
| 71f4449741 | |||
| 14b5885814 | |||
| 3d8cdcaf84 | |||
| f1448b0e52 | |||
| 6e92b2b6a2 | |||
| 18ee8822d9 | |||
| 081c63cd43 | |||
| 326628d258 | |||
| 566dda93f3 | |||
| 5c28e639ae | |||
| 3dfe740780 | |||
| ebd538e2d8 | |||
| b36b0469e1 | |||
| 2b9a39f124 | |||
| cd709c2807 | |||
| 6bc54e5d65 | |||
| 65c2e69ac6 | |||
| 96acc10153 | |||
| 1a667a60c1 | |||
| bbc85d6a2d | |||
| 3995a5db47 | |||
| b8750860a8 | |||
| 4711c750cc | |||
| 51bee91c32 | |||
| 5fcfe97fab | |||
| 74bee75df3 | |||
| 1aa1b8a51b | |||
| 833ee88340 | |||
| 6cb4bac673 | |||
| e87c52b6f2 | |||
| f53da6eacb | |||
| 8d35887950 | |||
| ebf37c879d |
@@ -5,3 +5,5 @@ tests/
|
||||
docs/
|
||||
src/db
|
||||
src/wg-dashboard.ini
|
||||
src/static/app
|
||||
src/static/client
|
||||
|
||||
@@ -7,25 +7,36 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/src"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/src/static/app"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/src/static/client"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/docker"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "docker-compose"
|
||||
directory: "/docker"
|
||||
target-branch: "development"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
name: Clone of Docker Build and Push
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOCKERHUB_PREFIX: docker.io
|
||||
GITHUB_CONTAINER_PREFIX: ghcr.io
|
||||
DOCKER_IMAGE: WGDashboard
|
||||
|
||||
jobs:
|
||||
docker_build_debug:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_PREFIX }}
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.GITHUB_CONTAINER_PREFIX }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: linux/amd64
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Extract Docker metadata from environment
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_PREFIX }}/donaldzou/${{ env.DOCKER_IMAGE }}
|
||||
${{ env.GITHUB_CONTAINER_PREFIX }}/${{ github.repository_owner }}/${{ env.DOCKER_IMAGE }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=sha,format=short,prefix=
|
||||
|
||||
- name: Build and export Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64
|
||||
|
||||
docker_scan_debug:
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_build_debug
|
||||
steps:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_PREFIX }}
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.GITHUB_CONTAINER_PREFIX }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker Scout CVEs
|
||||
uses: docker/scout-action@v1
|
||||
with:
|
||||
command: cves
|
||||
image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ github.repository_owner }}/${{ env.DOCKER_IMAGE }}:main
|
||||
only-severities: critical,high
|
||||
only-fixed: true
|
||||
write-comment: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
exit-code: true
|
||||
|
||||
- name: Docker Scout Compare
|
||||
uses: docker/scout-action@v1
|
||||
with:
|
||||
command: compare
|
||||
# Set to Github for maximum compat
|
||||
image: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ github.repository_owner }}/${{ env.DOCKER_IMAGE }}:main
|
||||
to: ${{ env.GITHUB_CONTAINER_PREFIX }}/${{ github.repository_owner }}/${{ env.DOCKER_IMAGE }}:latest
|
||||
only-severities: critical,high
|
||||
ignore-unchanged: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
- 'development'
|
||||
- '**dev'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
# Pull the current golang-alpine image.
|
||||
FROM golang:1.25-alpine3.23 AS awg-go
|
||||
FROM golang:1.26-alpine3.23 AS awg-go
|
||||
|
||||
# Install build-dependencies.
|
||||
RUN apk add --no-cache \
|
||||
@@ -30,7 +30,7 @@ RUN go version && \
|
||||
# AWG TOOLS BUILDING STAGE
|
||||
# Base: Alpine
|
||||
#
|
||||
FROM alpine:3.23 AS awg-tools
|
||||
FROM alpine:3.24 AS awg-tools
|
||||
|
||||
# Install needed dependencies.
|
||||
RUN apk add --no-cache \
|
||||
|
||||
+70
-1
@@ -105,7 +105,7 @@ Updating the WGDashboard container should be through 'The Docker Way' - by pulli
|
||||
| `username` | Any non‐empty string | `-` | `admin` | Username for the WGDashboard web interface account. |
|
||||
| `password` | Any non‐empty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). |
|
||||
| `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTP‐based two‐factor authentication for the account. |
|
||||
| `wg_autostart` | Wireguard interface name | `false` | `true` | Auto‐start the WireGuard client when the container launches. |
|
||||
| `wg_autostart` | Wireguard interface name | `- ` | `wg0` | Automatically start the specified WireGuard interface when the container starts |
|
||||
| `email_server` | SMTP server address | `-` | `smtp.gmail.com` | SMTP server for sending email notifications. |
|
||||
| `email_port` | SMTP port number | `-` | `587` | Port for connecting to the SMTP server. |
|
||||
| `email_encryption` | `TLS`, `SSL`, etc. | `-` | `TLS` | Encryption method for email communication. |
|
||||
@@ -213,6 +213,75 @@ ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
- Access the web interface via `http://your-ip:10086` (or whichever port you specified in the compose).
|
||||
- The first time run will auto-generate WireGuard keys and configs (configs are generated from the template).
|
||||
|
||||
## 🧑💻 Local Development with Docker
|
||||
|
||||
You can develop against WGDashboard locally by mounting the `src/` directory into the container. This lets you edit Python and frontend code on your host and see changes reflected immediately (with a service restart for Python).
|
||||
|
||||
Create a `docker/compose-local.yaml` alongside the existing `compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
wgdashboard:
|
||||
image: ghcr.io/wgdashboard/wgdashboard:latest
|
||||
restart: unless-stopped
|
||||
container_name: wgdashboard
|
||||
|
||||
ports:
|
||||
- 10086:10086/tcp
|
||||
- 51820:51820/udp
|
||||
|
||||
volumes:
|
||||
- aconf:/etc/amnezia/amneziawg
|
||||
- conf:/etc/wireguard
|
||||
- data:/data
|
||||
# Mount local src for live editing
|
||||
- ../src:/opt/wgdashboard/src
|
||||
# Keep venv in a named volume so it isn't overwritten by the mount
|
||||
- venv:/opt/wgdashboard/src/venv
|
||||
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
|
||||
volumes:
|
||||
aconf:
|
||||
conf:
|
||||
data:
|
||||
venv:
|
||||
```
|
||||
|
||||
The key additions compared to the production compose file:
|
||||
- `../src:/opt/wgdashboard/src` — mounts your local `src/` directory into the container so code changes are reflected without rebuilding the image.
|
||||
- `venv:/opt/wgdashboard/src/venv` — keeps the Python virtual environment in a named Docker volume. Without this, the host mount would overwrite the venv created during image build.
|
||||
|
||||
To start the development container:
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
docker compose -f compose-local.yaml up -d
|
||||
```
|
||||
|
||||
After editing Python files (e.g. `src/dashboard.py`), restart the container to pick up changes:
|
||||
|
||||
```bash
|
||||
docker restart wgdashboard
|
||||
```
|
||||
|
||||
For frontend changes, install dependencies and rebuild the Vue app on your host:
|
||||
|
||||
```bash
|
||||
cd src/static/app
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
Then restart the container so it serves the updated dist files:
|
||||
|
||||
```bash
|
||||
docker restart wgdashboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Closing remarks:
|
||||
|
||||
For feedback please submit an issue to the repository. Or message dselen@nerthus.nl.
|
||||
|
||||
@@ -278,6 +278,10 @@ start_and_monitor() {
|
||||
|
||||
${WGDASH}/src/venv/bin/gunicorn --config ${WGDASH}/src/gunicorn.conf.py
|
||||
|
||||
cp /etc/resolv.conf /etc/resolv.conf.docker
|
||||
/usr/sbin/resolvconf -u
|
||||
cat /etc/resolv.conf.docker | resolvconf -a docker.inet
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Loading WGDashboard failed... Look above for details."
|
||||
fi
|
||||
|
||||
+2
-2
@@ -100,7 +100,7 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
|
||||
date = datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
|
||||
|
||||
emailSender = EmailSender(dashboardConfig)
|
||||
if not emailSender.ready():
|
||||
if not emailSender.is_ready():
|
||||
return ResponseObject(False, "We can't send you an email due to your Administrator has not setup email service. Please contact your administrator.")
|
||||
|
||||
data = request.get_json()
|
||||
@@ -244,4 +244,4 @@ def createClientBlueprint(wireguardConfigurations: dict[WireguardConfiguration],
|
||||
|
||||
return ResponseObject(status, message)
|
||||
|
||||
return client
|
||||
return client
|
||||
|
||||
+144
-49
@@ -2,13 +2,15 @@ import logging
|
||||
import random, shutil, sqlite3, configparser, hashlib, ipaddress, json, os, secrets, subprocess
|
||||
import time, re, uuid, bcrypt, psutil, pyotp, threading
|
||||
import traceback
|
||||
from functools import wraps
|
||||
from urllib.parse import unquote
|
||||
from uuid import uuid4
|
||||
from zipfile import ZipFile
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import sqlalchemy
|
||||
from jinja2 import Template
|
||||
from flask import Flask, request, render_template, session, send_file, current_app
|
||||
from flask import Flask, request, render_template, session, send_file, current_app, redirect, url_for
|
||||
from flask_cors import CORS
|
||||
from icmplib import ping, traceroute
|
||||
from flask.json.provider import DefaultJSONProvider
|
||||
@@ -30,6 +32,7 @@ from modules.PeerJobs import PeerJobs
|
||||
from modules.DashboardConfig import DashboardConfig
|
||||
from modules.WireguardConfiguration import WireguardConfiguration
|
||||
from modules.AmneziaConfiguration import AmneziaConfiguration
|
||||
from modules.DashboardOIDC import DashboardOIDC
|
||||
|
||||
from client import createClientBlueprint
|
||||
|
||||
@@ -68,6 +71,21 @@ def ResponseObject(status=True, message=None, data=None, status_code = 200) -> F
|
||||
response.content_type = "application/json"
|
||||
return response
|
||||
|
||||
def require_fields(*fields):
|
||||
"""Decorator that validates required fields in request.json."""
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
data = request.json
|
||||
if data is None:
|
||||
return ResponseObject(False, "Request body must be JSON", status_code=400)
|
||||
missing = [field for field in fields if field not in data]
|
||||
if missing:
|
||||
return ResponseObject(False, f"Missing required fields: {', '.join(missing)}", status_code=400)
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
return decorator
|
||||
|
||||
'''
|
||||
Flask App
|
||||
'''
|
||||
@@ -208,6 +226,7 @@ with app.app_context():
|
||||
NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates()
|
||||
InitWireguardConfigurationsList(startup=True)
|
||||
DashboardClients: DashboardClients = DashboardClients(WireguardConfigurations)
|
||||
AdminOIDC = DashboardOIDC("Admin")
|
||||
app.register_blueprint(createClientBlueprint(WireguardConfigurations, DashboardConfig, DashboardClients))
|
||||
|
||||
_, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix")
|
||||
@@ -262,6 +281,8 @@ def auth_req():
|
||||
f'{appPrefix}/api/sharePeer/get',
|
||||
f'{appPrefix}/api/isTotpEnabled',
|
||||
f'{appPrefix}/api/locale',
|
||||
f'{appPrefix}/api/oidc/providers',
|
||||
f'{appPrefix}/api/oidc/authenticate',
|
||||
]
|
||||
|
||||
|
||||
@@ -269,7 +290,9 @@ def auth_req():
|
||||
("username" not in session or session.get("role") != "admin")
|
||||
and (f"{appPrefix}/" != request.path and f"{appPrefix}" != request.path)
|
||||
and not request.path.startswith(f'{appPrefix}/client')
|
||||
and not request.path.startswith(f'{appPrefix}/static')
|
||||
and not request.path.startswith(f'{appPrefix}/img')
|
||||
and not request.path.startswith(f'{appPrefix}/json')
|
||||
and not request.path.startswith(f'{appPrefix}/assets')
|
||||
and request.path not in whiteList
|
||||
):
|
||||
response = Flask.make_response(app, {
|
||||
@@ -297,6 +320,38 @@ def API_ValidateAuthentication():
|
||||
def API_RequireAuthentication():
|
||||
return ResponseObject(data=DashboardConfig.GetConfig("Server", "auth_req")[1])
|
||||
|
||||
# OIDC for Admin
|
||||
@app.get(f'{APP_PREFIX}/api/oidc/providers')
|
||||
def API_OIDC_GetProviders():
|
||||
_, oidc = DashboardConfig.GetConfig("OIDC", "admin_enable")
|
||||
if not oidc:
|
||||
return ResponseObject(status=False, message="OIDC is disabled")
|
||||
|
||||
return ResponseObject(data=AdminOIDC.GetProviders())
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/oidc/authenticate')
|
||||
def API_OIDC_Authenticate():
|
||||
_, oidc = DashboardConfig.GetConfig("OIDC", "admin_enable")
|
||||
if not oidc:
|
||||
return ResponseObject(False, "OIDC is disabled")
|
||||
|
||||
requestData = request.get_json()
|
||||
status, data = AdminOIDC.VerifyToken(**requestData)
|
||||
if not status:
|
||||
return ResponseObject(False, "OIDC Authentication Failed. Reason: " + data)
|
||||
session['role'] = 'admin'
|
||||
authToken = hashlib.sha256(f'${data['sid']}{datetime.now()}{app.secret_key}'.encode()).hexdigest()
|
||||
session['username'] = authToken
|
||||
session['signInMethod'] = 'OIDC'
|
||||
session['signInPayload'] = {
|
||||
"Provider": requestData.get('provider'),
|
||||
"Payload": data
|
||||
}
|
||||
resp = ResponseObject()
|
||||
resp.set_cookie('authToken', authToken)
|
||||
return resp
|
||||
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/authenticate')
|
||||
def API_AuthenticateLogin():
|
||||
data = request.get_json()
|
||||
@@ -316,7 +371,10 @@ def API_AuthenticateLogin():
|
||||
totpEnabled = DashboardConfig.GetConfig("Account", "enable_totp")[1]
|
||||
totpValid = False
|
||||
if totpEnabled:
|
||||
totpValid = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now() == data['totp']
|
||||
totp_code = str(data.get("totp", "")).strip()
|
||||
totpValid = pyotp.TOTP(
|
||||
DashboardConfig.GetConfig("Account", "totp_key")[1]
|
||||
).verify(totp_code, valid_window=1)
|
||||
|
||||
if (valid
|
||||
and data['username'] == DashboardConfig.GetConfig("Account", "username")[1]
|
||||
@@ -325,6 +383,7 @@ def API_AuthenticateLogin():
|
||||
authToken = hashlib.sha256(f"{data['username']}{datetime.now()}".encode()).hexdigest()
|
||||
session['role'] = 'admin'
|
||||
session['username'] = authToken
|
||||
session['signInMethod'] = 'local'
|
||||
resp = ResponseObject(True, DashboardConfig.GetConfig("Other", "welcome_session")[1])
|
||||
resp.set_cookie("authToken", authToken)
|
||||
session.permanent = True
|
||||
@@ -340,6 +399,14 @@ def API_AuthenticateLogin():
|
||||
def API_SignOut():
|
||||
resp = ResponseObject(True, "")
|
||||
resp.delete_cookie("authToken")
|
||||
if session.get('signInMethod') == "OIDC":
|
||||
status, oidc_config = AdminOIDC.GetProviderConfiguration(session.get('signInPayload').get("Provider"))
|
||||
signOut = requests.get(
|
||||
oidc_config.get("end_session_endpoint"),
|
||||
params={
|
||||
'id_token_hint': session.get('signInPayload').get("Payload").get('sid')
|
||||
}
|
||||
)
|
||||
session.clear()
|
||||
return resp
|
||||
|
||||
@@ -1202,52 +1269,75 @@ def API_getDashboardTheme():
|
||||
def API_getDashboardVersion():
|
||||
return ResponseObject(data=DashboardConfig.GetConfig("Server", "version")[1])
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/savePeerScheduleJob')
|
||||
@app.post(f'{APP_PREFIX}/api/PeerScheduleJob')
|
||||
@require_fields('Configuration', 'Peer', 'Field', 'Operator', 'Value', 'Action')
|
||||
def API_savePeerScheduleJob():
|
||||
data = request.json
|
||||
if "Job" not in data.keys():
|
||||
return ResponseObject(False, "Please specify job")
|
||||
job: dict = data['Job']
|
||||
if "Peer" not in job.keys() or "Configuration" not in job.keys():
|
||||
return ResponseObject(False, "Please specify peer and configuration")
|
||||
configuration = WireguardConfigurations.get(job['Configuration'])
|
||||
if configuration is None:
|
||||
return ResponseObject(False, "Configuration does not exist")
|
||||
f, fp = configuration.searchPeer(job['Peer'])
|
||||
if not f:
|
||||
return ResponseObject(False, "Peer does not exist")
|
||||
|
||||
|
||||
s, p = AllPeerJobs.saveJob(PeerJob(
|
||||
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
|
||||
job['CreationDate'], job['ExpireDate'], job['Action']))
|
||||
if s:
|
||||
return ResponseObject(s, data=p)
|
||||
return ResponseObject(s, message=p)
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/deletePeerScheduleJob')
|
||||
configuration = WireguardConfigurations.get(data['Configuration'])
|
||||
if configuration is None:
|
||||
return ResponseObject(False, "Configuration does not exist", status_code=404)
|
||||
|
||||
peerKey = unquote(data['Peer'])
|
||||
found, _ = configuration.searchPeer(peerKey)
|
||||
if not found:
|
||||
return ResponseObject(False, "Peer does not exist", status_code=404)
|
||||
|
||||
jobID = data.get('JobID', str(uuid4()))
|
||||
if len(AllPeerJobs.searchJobById(jobID)) > 0:
|
||||
return ResponseObject(False, "Job already exists", status_code=409)
|
||||
|
||||
success, result = AllPeerJobs.saveJob(PeerJob(
|
||||
jobID, data['Configuration'], peerKey, data['Field'], data['Operator'], data['Value'],
|
||||
datetime.now(), data.get('ExpireDate'), data['Action']))
|
||||
if success:
|
||||
return ResponseObject(success, data=result)
|
||||
return ResponseObject(success, message=result)
|
||||
|
||||
@app.put(f'{APP_PREFIX}/api/PeerScheduleJob')
|
||||
@require_fields('JobID', 'Configuration', 'Peer', 'Field', 'Operator', 'Value', 'Action')
|
||||
def API_updatePeerScheduleJob():
|
||||
data = request.json
|
||||
|
||||
configuration = WireguardConfigurations.get(data['Configuration'])
|
||||
if configuration is None:
|
||||
return ResponseObject(False, "Configuration does not exist", status_code=404)
|
||||
|
||||
peerKey = unquote(data['Peer'])
|
||||
found, _ = configuration.searchPeer(peerKey)
|
||||
if not found:
|
||||
return ResponseObject(False, "Peer does not exist", status_code=404)
|
||||
|
||||
existing = AllPeerJobs.searchJobById(data['JobID'])
|
||||
if len(existing) == 0:
|
||||
return ResponseObject(False, "Job does not exist", status_code=404)
|
||||
|
||||
success, result = AllPeerJobs.saveJob(PeerJob(
|
||||
data['JobID'], data['Configuration'], peerKey, data['Field'], data['Operator'], data['Value'],
|
||||
datetime.now(), data.get('ExpireDate'), data['Action']))
|
||||
if success:
|
||||
return ResponseObject(success, data=result)
|
||||
return ResponseObject(success, message=result)
|
||||
|
||||
@app.delete(f'{APP_PREFIX}/api/PeerScheduleJob')
|
||||
@require_fields('JobID', 'Configuration', 'Peer')
|
||||
def API_deletePeerScheduleJob():
|
||||
data = request.json
|
||||
if "Job" not in data.keys():
|
||||
return ResponseObject(False, "Please specify job")
|
||||
job: dict = data['Job']
|
||||
if "Peer" not in job.keys() or "Configuration" not in job.keys():
|
||||
return ResponseObject(False, "Please specify peer and configuration")
|
||||
configuration = WireguardConfigurations.get(job['Configuration'])
|
||||
|
||||
configuration = WireguardConfigurations.get(data['Configuration'])
|
||||
if configuration is None:
|
||||
return ResponseObject(False, "Configuration does not exist")
|
||||
# f, fp = configuration.searchPeer(job['Peer'])
|
||||
# if not f:
|
||||
# return ResponseObject(False, "Peer does not exist")
|
||||
return ResponseObject(False, "Configuration does not exist", status_code=404)
|
||||
|
||||
s, p = AllPeerJobs.deleteJob(PeerJob(
|
||||
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
|
||||
job['CreationDate'], job['ExpireDate'], job['Action']))
|
||||
if s:
|
||||
return ResponseObject(s)
|
||||
return ResponseObject(s, message=p)
|
||||
peerKey = unquote(data['Peer'])
|
||||
success, result = AllPeerJobs.deleteJob(PeerJob(
|
||||
data['JobID'], data['Configuration'], peerKey, data.get('Field', ''),
|
||||
data.get('Operator', ''), data.get('Value', ''),
|
||||
datetime.now(), data.get('ExpireDate'), data.get('Action', '')))
|
||||
if success:
|
||||
return ResponseObject(success, message="Job deleted successfully")
|
||||
return ResponseObject(success, message=result)
|
||||
|
||||
@app.get(f'{APP_PREFIX}/api/getPeerScheduleJobLogs/<configName>')
|
||||
@app.get(f'{APP_PREFIX}/api/PeerScheduleJobLogs/<configName>')
|
||||
def API_getPeerScheduleJobLogs(configName):
|
||||
if configName not in WireguardConfigurations.keys():
|
||||
return ResponseObject(False, "Configuration does not exist")
|
||||
@@ -1272,11 +1362,11 @@ def API_ping_getAllPeersIpAddress():
|
||||
for x in allowed_ip:
|
||||
try:
|
||||
ip = ipaddress.ip_network(x, strict=False)
|
||||
if ip.num_addresses == 1:
|
||||
parsed.append(str(ip.network_address))
|
||||
except ValueError as e:
|
||||
app.logger.error(f"Failed to parse IP address of {p.id} - {c.Name}")
|
||||
host = list(ip.hosts())
|
||||
if len(host) == 1:
|
||||
parsed.append(str(host[0]))
|
||||
|
||||
endpoint = p.endpoint.replace(" ", "").replace("(none)", "")
|
||||
if len(p.name) > 0:
|
||||
cips[f"{p.name} - {p.id}"] = {
|
||||
@@ -1413,11 +1503,15 @@ def API_Welcome_GetTotpLink():
|
||||
@app.post(f'{APP_PREFIX}/api/Welcome_VerifyTotpLink')
|
||||
def API_Welcome_VerifyTotpLink():
|
||||
data = request.get_json()
|
||||
totp = pyotp.TOTP(DashboardConfig.GetConfig("Account", "totp_key")[1]).now()
|
||||
if totp == data['totp']:
|
||||
totp_code = str(data.get("totp", "")).strip()
|
||||
totpValid = pyotp.TOTP(
|
||||
DashboardConfig.GetConfig("Account", "totp_key")[1]
|
||||
).verify(totp_code, valid_window=1)
|
||||
|
||||
if totpValid:
|
||||
DashboardConfig.SetConfig("Account", "totp_verified", "true")
|
||||
DashboardConfig.SetConfig("Account", "enable_totp", "true")
|
||||
return ResponseObject(totp == data['totp'])
|
||||
return ResponseObject(totpValid)
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/Welcome_Finish')
|
||||
def API_Welcome_Finish():
|
||||
@@ -1485,7 +1579,7 @@ def API_Locale_Update():
|
||||
|
||||
@app.get(f'{APP_PREFIX}/api/email/ready')
|
||||
def API_Email_Ready():
|
||||
return ResponseObject(EmailSender.ready())
|
||||
return ResponseObject(EmailSender.is_ready())
|
||||
|
||||
@app.post(f'{APP_PREFIX}/api/email/send')
|
||||
def API_Email_Send():
|
||||
@@ -1509,7 +1603,8 @@ def API_Email_Send():
|
||||
subject = Template(data.get('Subject', '')).render(peer=p.toJson(), configurationFile=download)
|
||||
if data.get('IncludeAttachment', False):
|
||||
u = str(uuid4())
|
||||
attachmentName = f'{u}.conf'
|
||||
peerName = p.toJson().get('name', '').strip()
|
||||
attachmentName = f'{peerName if peerName else u}.conf'
|
||||
with open(os.path.join('./attachments', attachmentName,), 'w+') as f:
|
||||
f.write(download['file'])
|
||||
|
||||
|
||||
@@ -32,11 +32,15 @@ class AmneziaConfiguration(WireguardConfiguration):
|
||||
self.H2 = 2
|
||||
self.H3 = 3
|
||||
self.H4 = 4
|
||||
self.I1 = "0"
|
||||
self.I2 = "0"
|
||||
self.I3 = "0"
|
||||
self.I4 = "0"
|
||||
self.I5 = "0"
|
||||
self.I1 = ""
|
||||
self.I2 = ""
|
||||
self.I3 = ""
|
||||
self.I4 = ""
|
||||
self.I5 = ""
|
||||
self.J1 = ""
|
||||
self.J2 = ""
|
||||
self.J3 = ""
|
||||
self.Itime = ""
|
||||
|
||||
super().__init__(DashboardConfig, AllPeerJobs, AllPeerShareLinks, DashboardWebHooks, name, data, backup, startup, wg=False)
|
||||
|
||||
@@ -79,7 +83,11 @@ class AmneziaConfiguration(WireguardConfiguration):
|
||||
"I2": self.I2,
|
||||
"I3": self.I3,
|
||||
"I4": self.I4,
|
||||
"I5": self.I5
|
||||
"I5": self.I5,
|
||||
"J1": self.J1,
|
||||
"J2": self.J2,
|
||||
"J3": self.J3,
|
||||
"Itime": self.Itime
|
||||
}
|
||||
|
||||
def createDatabase(self, dbName = None):
|
||||
|
||||
@@ -87,8 +87,9 @@ class AmneziaPeer(Peer):
|
||||
|
||||
if psk_exist: os.remove(uid)
|
||||
|
||||
if len(updateAllowedIp.decode().strip("\n")) != 0:
|
||||
current_app.logger.error(f"Update peer failed when updating Allowed IPs.\nInput: {newAllowedIPs}\nOutput: {updateAllowedIp.decode().strip('\n')}")
|
||||
output = updateAllowedIp.decode().strip("\n")
|
||||
if len(output) != 0:
|
||||
current_app.logger.error(f"Update peer failed when updating Allowed IPs.\nInput: {newAllowedIPs}\nOutput: {output}")
|
||||
return False, "Internal server error"
|
||||
|
||||
command = [f"{self.configuration.Protocol}-quick", "save", self.configuration.Name]
|
||||
@@ -116,5 +117,5 @@ class AmneziaPeer(Peer):
|
||||
self.configuration.getPeers()
|
||||
return True, None
|
||||
except subprocess.CalledProcessError as exc:
|
||||
current_app.logger.error(f"Subprocess call failed:\n{exc.output.decode("UTF-8")}")
|
||||
current_app.logger.error(f"Subprocess call failed:\n{exc.output.decode('UTF-8')}")
|
||||
return False, "Internal server error"
|
||||
|
||||
@@ -12,10 +12,10 @@ from .Utilities import (GetRemoteEndpoint, ValidateDNSAddress)
|
||||
from .DashboardAPIKey import DashboardAPIKey
|
||||
|
||||
class DashboardConfig:
|
||||
DashboardVersion = 'v4.3.2'
|
||||
DashboardVersion = 'v4.3.4'
|
||||
ConfigurationPath = os.getenv('CONFIGURATION_PATH', '.')
|
||||
ConfigurationFilePath = os.path.join(ConfigurationPath, 'wg-dashboard.ini')
|
||||
|
||||
|
||||
def __init__(self):
|
||||
if not os.path.exists(DashboardConfig.ConfigurationFilePath):
|
||||
open(DashboardConfig.ConfigurationFilePath, "x")
|
||||
@@ -51,7 +51,8 @@ class DashboardConfig:
|
||||
"peer_display_mode": "grid",
|
||||
"remote_endpoint": GetRemoteEndpoint(),
|
||||
"peer_MTU": "1420",
|
||||
"peer_keep_alive": "21"
|
||||
"peer_keep_alive": "21",
|
||||
"peer_preshared_key_default": "false"
|
||||
},
|
||||
"Other": {
|
||||
"welcome_session": "true"
|
||||
@@ -146,14 +147,17 @@ class DashboardConfig:
|
||||
if col_name not in existing_columns:
|
||||
type_str = col_type().compile(dialect=self.engine.dialect)
|
||||
current_app.logger.info(f"Adding missing column '{col_name}' to table '{table_name}'")
|
||||
conn.execute(db.text(f'ALTER TABLE "{table_name}" ADD COLUMN "{col_name}" {type_str}'))
|
||||
preparer = self.engine.dialect.identifier_preparer
|
||||
quoted_table = preparer.quote_identifier(table_name)
|
||||
quoted_column = preparer.quote_identifier(col_name)
|
||||
conn.execute(db.text(f"ALTER TABLE {quoted_table} ADD COLUMN {quoted_column} {type_str}"))
|
||||
|
||||
def getConnectionString(self, database) -> str or None:
|
||||
sqlitePath = os.path.join(DashboardConfig.ConfigurationPath, "db")
|
||||
|
||||
|
||||
if not os.path.isdir(sqlitePath):
|
||||
os.mkdir(sqlitePath)
|
||||
|
||||
|
||||
if self.GetConfig("Database", "type")[1] == "postgresql":
|
||||
cn = f'postgresql+psycopg2://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
|
||||
elif self.GetConfig("Database", "type")[1] == "mysql":
|
||||
|
||||
@@ -82,13 +82,18 @@ class DashboardOIDC:
|
||||
|
||||
headers = jwt.get_unverified_header(id_token)
|
||||
kid = headers["kid"]
|
||||
|
||||
|
||||
key = next(k for k in jwks["keys"] if k["kid"] == kid)
|
||||
|
||||
|
||||
alg = key.get("alg") or headers.get("alg")
|
||||
supported_algs = oidc_config.get("id_token_signing_alg_values_supported")
|
||||
if supported_algs and alg not in supported_algs:
|
||||
return False, f"Unsupported token signing algorithm: {alg}"
|
||||
|
||||
payload = jwt.decode(
|
||||
id_token,
|
||||
key,
|
||||
algorithms=[key["alg"]],
|
||||
algorithms=[alg],
|
||||
audience=provider_info.get('client_id'),
|
||||
issuer=issuer,
|
||||
access_token=access_token
|
||||
@@ -134,7 +139,7 @@ class DashboardOIDC:
|
||||
'openid_configuration': oidc_config
|
||||
}
|
||||
self.provider_secret[k] = providers[k]['client_secret']
|
||||
current_app.logger.info(f"Registered OIDC Provider: {k}")
|
||||
current_app.logger.info(f"Registered OIDC Provider[{self.mode}]: {k}")
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Failed to register OIDC config for {k}", exc_info=e)
|
||||
except Exception as e:
|
||||
|
||||
+17
-13
@@ -72,7 +72,7 @@ class Peer:
|
||||
peers = []
|
||||
for peer in self.configuration.getPeersList():
|
||||
# Make sure to exclude your own data when updating since its not really relevant
|
||||
if peer.id != self.id:
|
||||
if peer.id == self.id:
|
||||
continue
|
||||
peers.append(peer)
|
||||
|
||||
@@ -84,19 +84,19 @@ class Peer:
|
||||
|
||||
if allowed_ip in used_allowed_ips:
|
||||
return False, "Allowed IP already taken by another peer"
|
||||
|
||||
|
||||
if not ValidateDNSAddress(dns_addresses):
|
||||
return False, f"DNS IP-Address or FQDN is incorrect"
|
||||
|
||||
|
||||
if isinstance(mtu, str):
|
||||
mtu = 0
|
||||
|
||||
if isinstance(keepalive, str):
|
||||
keepalive = 0
|
||||
|
||||
|
||||
if mtu not in range(0, 1461):
|
||||
return False, "MTU format is not correct"
|
||||
|
||||
|
||||
if keepalive < 0:
|
||||
return False, "Persistent Keepalive format is not correct"
|
||||
|
||||
@@ -117,7 +117,7 @@ class Peer:
|
||||
newAllowedIPs = allowed_ip.replace(" ", "")
|
||||
if not CheckAddress(newAllowedIPs):
|
||||
return False, "Allowed IPs entry format is incorrect"
|
||||
|
||||
|
||||
command = [self.configuration.Protocol, "set", self.configuration.Name, "peer", self.id, "allowed-ips", newAllowedIPs, "preshared-key", uid if psk_exist else "/dev/null"]
|
||||
updateAllowedIp = subprocess.check_output(command, stderr=subprocess.STDOUT)
|
||||
|
||||
@@ -151,7 +151,7 @@ class Peer:
|
||||
)
|
||||
return True, None
|
||||
except subprocess.CalledProcessError as exc:
|
||||
current_app.logger.error(f"Subprocess call failed:\n{exc.output.decode("UTF-8")}")
|
||||
current_app.logger.error(f"Subprocess call failed:\n{exc.output.decode('UTF-8')}")
|
||||
return False, "Internal server error"
|
||||
|
||||
def downloadPeer(self) -> dict[str, str]:
|
||||
@@ -168,14 +168,14 @@ class Peer:
|
||||
filename = re.sub(r'[.,/?<>\\:*|"]', '', filename).rstrip(". ") # remove special characters
|
||||
|
||||
reserved_pattern = r"^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\..*)?$" # match com1-9, lpt1-9, con, nul, prn, aux, nul
|
||||
|
||||
|
||||
if re.match(reserved_pattern, filename, re.IGNORECASE):
|
||||
filename = f"file_{filename}" # prepend "file_" if it matches
|
||||
|
||||
for i in filename:
|
||||
if re.match("^[a-zA-Z0-9_=+.-]$", i):
|
||||
final["fileName"] += i
|
||||
|
||||
|
||||
interfaceSection = {
|
||||
"PrivateKey": self.private_key,
|
||||
"Address": self.allowed_ip,
|
||||
@@ -188,7 +188,7 @@ class Peer:
|
||||
if self.configuration.configurationInfo.OverridePeerSettings.DNS else self.DNS
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if self.configuration.Protocol == "awg":
|
||||
interfaceSection.update({
|
||||
"Jc": self.configuration.Jc,
|
||||
@@ -206,9 +206,13 @@ class Peer:
|
||||
"I2": self.configuration.I2,
|
||||
"I3": self.configuration.I3,
|
||||
"I4": self.configuration.I4,
|
||||
"I5": self.configuration.I5
|
||||
"I5": self.configuration.I5,
|
||||
"J1": self.configuration.J1,
|
||||
"J2": self.configuration.J2,
|
||||
"J3": self.configuration.J3,
|
||||
"Itime": self.configuration.Itime
|
||||
})
|
||||
|
||||
|
||||
peerSection = {
|
||||
"PublicKey": self.configuration.PublicKey,
|
||||
"AllowedIPs": (
|
||||
@@ -232,7 +236,7 @@ class Peer:
|
||||
for (key, val) in combine[s]:
|
||||
if val is not None and ((type(val) is str and len(val) > 0) or (type(val) is int and val > 0)):
|
||||
final["file"] += f"{key} = {val}\n"
|
||||
|
||||
|
||||
final["file"] = jinja2.Template(final["file"]).render(configuration=self.configuration)
|
||||
|
||||
|
||||
|
||||
@@ -109,23 +109,31 @@ class WireguardConfiguration:
|
||||
}
|
||||
|
||||
if self.Protocol == 'awg':
|
||||
self.__parser["Interface"]["Jc"] = self.Jc
|
||||
self.__parser["Interface"]["Jc"] = self.Jc
|
||||
self.__parser["Interface"]["Jmin"] = self.Jmin
|
||||
self.__parser["Interface"]["Jmax"] = self.Jmax
|
||||
self.__parser["Interface"]["S1"] = self.S1
|
||||
self.__parser["Interface"]["S2"] = self.S2
|
||||
self.__parser["Interface"]["S3"] = self.S3
|
||||
self.__parser["Interface"]["S4"] = self.S4
|
||||
self.__parser["Interface"]["H1"] = self.H1
|
||||
self.__parser["Interface"]["H2"] = self.H2
|
||||
self.__parser["Interface"]["H3"] = self.H3
|
||||
self.__parser["Interface"]["H4"] = self.H4
|
||||
self.__parser["Interface"]["I1"] = self.I1
|
||||
self.__parser["Interface"]["I2"] = self.I2
|
||||
self.__parser["Interface"]["I3"] = self.I3
|
||||
self.__parser["Interface"]["I4"] = self.I4
|
||||
self.__parser["Interface"]["I5"] = self.I5
|
||||
values = {
|
||||
"Jc": self.Jc,
|
||||
"Jmin": self.Jmin,
|
||||
"Jmax": self.Jmax,
|
||||
"S1": self.S1,
|
||||
"S2": self.S2,
|
||||
"S3": self.S3,
|
||||
"S4": self.S4,
|
||||
"H1": self.H1,
|
||||
"H2": self.H2,
|
||||
"H3": self.H3,
|
||||
"H4": self.H4,
|
||||
"I1": self.I1,
|
||||
"I2": self.I2,
|
||||
"I3": self.I3,
|
||||
"I4": self.I4,
|
||||
"I5": self.I5,
|
||||
"J1": self.J1,
|
||||
"J2": self.J2,
|
||||
"J3": self.J3,
|
||||
"Itime": self.Itime
|
||||
}
|
||||
for key, value in values.items():
|
||||
if value != None and str(value).strip():
|
||||
self.__parser["Interface"][key] = str(value)
|
||||
|
||||
if "Backup" not in data.keys():
|
||||
self.createDatabase()
|
||||
@@ -1007,8 +1015,10 @@ class WireguardConfiguration:
|
||||
with open(self.configPath, 'r') as f:
|
||||
original = [l.rstrip("\n") for l in f.readlines()]
|
||||
allowEdit = ["Address", "PreUp", "PostUp", "PreDown", "PostDown", "ListenPort", "Table"]
|
||||
awgKeys = []
|
||||
if self.Protocol == 'awg':
|
||||
allowEdit += ["Jc", "Jmin", "Jmax", "S1", "S2", "S3", "S4", "H1", "H2", "H3", "H4", "I1", "I2", "I3", "I4", "I5"]
|
||||
awgKeys = ["Jc", "Jmin", "Jmax", "S1", "S2", "S3", "S4", "H1", "H2", "H3", "H4", "I1", "I2", "I3", "I4", "I5", "J1", "J2", "J3", "Itime"]
|
||||
allowEdit += awgKeys
|
||||
start = original.index("[Interface]")
|
||||
try:
|
||||
end = original.index("[Peer]")
|
||||
@@ -1022,7 +1032,10 @@ class WireguardConfiguration:
|
||||
if split[0] not in allowEdit:
|
||||
new.append(original[line])
|
||||
for key in allowEdit:
|
||||
new.insert(1, f"{key} = {str(newData[key]).strip()}")
|
||||
val = str(newData.get(key, "")).strip()
|
||||
if key in awgKeys and val == "":
|
||||
continue
|
||||
new.insert(1, f"{key} = {val}")
|
||||
new.append("")
|
||||
for line in range(end, len(original)):
|
||||
new.append(original[line])
|
||||
@@ -1072,6 +1085,11 @@ class WireguardConfiguration:
|
||||
doRenameStatement("_restrict_access")
|
||||
doRenameStatement("_deleted")
|
||||
doRenameStatement("_transfer")
|
||||
conn.execute(
|
||||
self.infoTable.update()
|
||||
.where(self.infoTable.c.ID == self.Name)
|
||||
.values(ID=newConfigurationName)
|
||||
)
|
||||
|
||||
self.AllPeerJobs.updateJobConfigurationName(self.Name, newConfigurationName)
|
||||
shutil.copy(
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
bcrypt==5.0.0
|
||||
ifcfg==0.24
|
||||
psutil==7.2.2
|
||||
pyotp==2.9.0
|
||||
pyotp==2.10.0
|
||||
Flask==3.1.2
|
||||
flask-cors==6.0.2
|
||||
flask-cors==6.0.5
|
||||
icmplib==3.0.4
|
||||
gunicorn==25.0.3
|
||||
requests==2.32.5
|
||||
gunicorn==26.0.0
|
||||
requests==2.34.2
|
||||
tcconfig==0.30.1
|
||||
sqlalchemy==2.0.46
|
||||
sqlalchemy==2.0.51
|
||||
sqlalchemy_utils==0.42.1
|
||||
psycopg[binary]==3.3.2
|
||||
PyMySQL==1.1.2
|
||||
psycopg[binary]==3.3.4
|
||||
PyMySQL==1.2.0
|
||||
tzlocal==5.3.1
|
||||
python-jose==3.5.0
|
||||
pydantic==2.12.5
|
||||
pydantic==2.13.4
|
||||
|
||||
@@ -11,6 +11,26 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WGDashboard</title>
|
||||
<base href="./">
|
||||
<style>
|
||||
#preloader{
|
||||
width: 100vw; height: 100vh; display: flex
|
||||
}
|
||||
#preloader_placeholder{
|
||||
width: 50px; height: 50px; background-color: #000; margin: auto;
|
||||
animation: 3s ease-in-out fadeInPreloader infinite;
|
||||
}
|
||||
@keyframes fadeInPreloader {
|
||||
0%{
|
||||
opacity: 0;
|
||||
}
|
||||
50%{
|
||||
opacity: 1;
|
||||
}
|
||||
100%{
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const isViteDevMode = document.querySelector('script[src*="@vite/client"]') !== null;
|
||||
const base = document.querySelector('base');
|
||||
@@ -20,7 +40,13 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="app">
|
||||
<div id="preloader">
|
||||
<div id="preloader_placeholder">
|
||||
<img style="width: 100%" src="./img/Logo-2-128x128.png" alt="WGDashboard Admin" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="./src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
+1054
-1415
File diff suppressed because it is too large
Load Diff
+15
-15
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "4.3.2",
|
||||
"version": "4.3.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"module": "es2022",
|
||||
@@ -13,35 +13,35 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@volar/language-server": "2.4.28",
|
||||
"@vue/language-server": "3.2.4",
|
||||
"@vuepic/vue-datepicker": "^12.1.0",
|
||||
"@vueuse/core": "^14.2.0",
|
||||
"@vueuse/shared": "^14.1.0",
|
||||
"@vue/language-server": "3.2.7",
|
||||
"@vuepic/vue-datepicker": "^14.0.0",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"@vueuse/shared": "^14.3.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"bootstrap-icons": "^1.11.3",
|
||||
"cidr-tools": "^11.0.8",
|
||||
"cidr-tools": "^12.0.2",
|
||||
"css-color-converter": "^2.0.0",
|
||||
"dayjs": "^1.11.19",
|
||||
"electron-builder": "^26.7.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"fuse.js": "^7.3.0",
|
||||
"i": "^0.3.7",
|
||||
"is-cidr": "^6.0.3",
|
||||
"npm": "^11.8.0",
|
||||
"ol": "^10.7.0",
|
||||
"is-cidr": "^7.0.0",
|
||||
"npm": "^11.13.0",
|
||||
"ol": "^10.9.0",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"qrcodejs": "^1.0.0",
|
||||
"simple-code-editor": "^2.0.9",
|
||||
"uuid": "^13.0.0",
|
||||
"vue": "^3.5.28",
|
||||
"uuid": "^14.0.0",
|
||||
"vue": "^3.5.32",
|
||||
"vue-chartjs": "^5.3.3",
|
||||
"vue-router": "^5.0.2"
|
||||
"vue-router": "^5.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.4",
|
||||
"vite": "^7.3.1"
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"vite": "^8.0.16"
|
||||
},
|
||||
"overrides": {
|
||||
"tar": "^7.5.6"
|
||||
|
||||
+14
-5
@@ -6,18 +6,27 @@ export default {
|
||||
components: {LocaleText},
|
||||
props: {
|
||||
data: Object,
|
||||
saving: Boolean
|
||||
saving: Boolean,
|
||||
defaultEnabled: Boolean
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
enable: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const hasKey = !!(this.data && this.data.preshared_key && this.data.preshared_key.length > 0)
|
||||
if (hasKey || this.defaultEnabled){
|
||||
this.enable = true
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
enable(){
|
||||
if (this.enable){
|
||||
this.data.preshared_key = window.wireguard.generateKeypair().presharedKey
|
||||
}else {
|
||||
if (this.enable) {
|
||||
if (!this.data.preshared_key){
|
||||
this.data.preshared_key = window.wireguard.generateKeypair().presharedKey
|
||||
}
|
||||
} else {
|
||||
this.data.preshared_key = ""
|
||||
}
|
||||
}
|
||||
@@ -48,4 +57,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -32,7 +32,7 @@ const peerData = ref({
|
||||
keepalive: parseInt(dashboardStore.Configuration.Peers.peer_keep_alive),
|
||||
mtu: parseInt(dashboardStore.Configuration.Peers.peer_mtu),
|
||||
preshared_key: "",
|
||||
preshared_key_bulkAdd: false,
|
||||
preshared_key_bulkAdd: Boolean(dashboardStore.Configuration.Peers.peer_preshared_key_default),
|
||||
allowed_ips_validation: true,
|
||||
})
|
||||
const availableIp = ref([])
|
||||
@@ -128,7 +128,7 @@ watch(() => {
|
||||
<EndpointAllowedIps :saving="saving" :data="peerData"></EndpointAllowedIps>
|
||||
<div class="row gy-3">
|
||||
<div class="col-sm" v-if="!peerData.bulkAdd">
|
||||
<PresharedKeyInput :saving="saving" :data="peerData" :bulk="peerData.bulkAdd"></PresharedKeyInput>
|
||||
<PresharedKeyInput :saving="saving" :data="peerData" :bulk="peerData.bulkAdd" :defaultEnabled="Boolean(dashboardStore.Configuration.Peers.peer_preshared_key_default)"></PresharedKeyInput>
|
||||
</div>
|
||||
|
||||
<div class="col-sm">
|
||||
@@ -177,4 +177,4 @@ watch(() => {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default {
|
||||
keepalive: parseInt(this.dashboardStore.Configuration.Peers.peer_keep_alive),
|
||||
mtu: parseInt(this.dashboardStore.Configuration.Peers.peer_mtu),
|
||||
preshared_key: "",
|
||||
preshared_key_bulkAdd: false,
|
||||
preshared_key_bulkAdd: Boolean(this.dashboardStore.Configuration.Peers.peer_preshared_key_default),
|
||||
},
|
||||
availableIp: undefined,
|
||||
availableIpSearchString: "",
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
<hr class="mb-0 mt-2">
|
||||
<div class="row gy-3">
|
||||
<div class="col-sm" v-if="!this.data.bulkAdd">
|
||||
<PresharedKeyInput :saving="saving" :data="data" :bulk="this.data.bulkAdd"></PresharedKeyInput>
|
||||
<PresharedKeyInput :saving="saving" :data="data" :bulk="this.data.bulkAdd" :defaultEnabled="Boolean(this.dashboardStore.Configuration.Peers.peer_preshared_key_default)"></PresharedKeyInput>
|
||||
</div>
|
||||
|
||||
<div class="col-sm">
|
||||
@@ -187,4 +187,4 @@ div{
|
||||
.card{
|
||||
max-height: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -32,6 +32,7 @@ Chart.register(
|
||||
import PeerSessions from "@/components/peerDetailsModalComponents/peerSessions.vue";
|
||||
import PeerTraffics from "@/components/peerDetailsModalComponents/peerTraffics.vue";
|
||||
import PeerEndpoints from "@/components/peerDetailsModalComponents/peerEndpoints.vue";
|
||||
import { GetLocale } from "@/utilities/locale"
|
||||
const props = defineProps(['selectedPeer'])
|
||||
const selectedDate = ref(undefined)
|
||||
defineEmits(['close'])
|
||||
@@ -49,13 +50,15 @@ defineEmits(['close'])
|
||||
<button type="button" class="btn-close ms-auto" @click="$emit('close')"></button>
|
||||
</div>
|
||||
<div class="card-body px-4">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2 flex-column flex-md-row">
|
||||
<div>
|
||||
<p class="mb-0 text-muted"><small><LocaleText t="Peer" /></small></p>
|
||||
<h2 class="mb-0">{{ selectedPeer.name }}</h2>
|
||||
<h2 :class="{'text-muted': selectedPeer.name.length === 0 }">
|
||||
{{ selectedPeer.name.length > 0 ? selectedPeer.name : GetLocale("Untitled Peer") }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedPeer.notes" class="text-end">
|
||||
<div v-if="selectedPeer.notes" class="text-start text-md-end">
|
||||
<p class="mb-0 text-muted"><small><LocaleText t="Notes" /></small></p>
|
||||
<p class="mb-0" style="white-space: pre-wrap">{{ selectedPeer.notes }}</p>
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
methods: {
|
||||
async fetchLog(){
|
||||
this.dataLoading = true;
|
||||
await fetchGet(`/api/getPeerScheduleJobLogs/${this.configurationInfo.Name}`, {}, (res) => {
|
||||
await fetchGet(`/api/PeerScheduleJobLogs/${this.configurationInfo.Name}`, {}, (res) => {
|
||||
this.data = res.data;
|
||||
this.logFetchTime = dayjs().format("YYYY-MM-DD HH:mm:ss")
|
||||
this.dataLoading = false;
|
||||
|
||||
+4
-7
@@ -2,7 +2,7 @@
|
||||
import ScheduleDropdown from "@/components/configurationComponents/peerScheduleJobsComponents/scheduleDropdown.vue";
|
||||
import {ref} from "vue";
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
import {fetchPost} from "@/utilities/fetch.js";
|
||||
import {fetchPost, fetchPut, fetchDelete} from "@/utilities/fetch.js";
|
||||
import { VueDatePicker } from "@vuepic/vue-datepicker";
|
||||
import dayjs from "dayjs";
|
||||
import LocaleText from "@/components/text/localeText.vue";
|
||||
@@ -46,9 +46,8 @@ export default {
|
||||
methods: {
|
||||
save(){
|
||||
if (this.job.Field && this.job.Operator && this.job.Action && this.job.Value){
|
||||
fetchPost(`/api/savePeerScheduleJob`, {
|
||||
Job: this.job
|
||||
}, (res) => {
|
||||
const fn = this.newJob ? fetchPost : fetchPut;
|
||||
fn(`/api/PeerScheduleJob`, this.job, (res) => {
|
||||
if (res.status){
|
||||
this.edit = false;
|
||||
this.store.newMessage("Server", "Peer job saved", "success")
|
||||
@@ -84,9 +83,7 @@ export default {
|
||||
},
|
||||
delete(){
|
||||
if(this.job.CreationDate){
|
||||
fetchPost(`/api/deletePeerScheduleJob`, {
|
||||
Job: this.job
|
||||
}, (res) => {
|
||||
fetchDelete(`/api/PeerScheduleJob`, this.job, (res) => {
|
||||
if (!res.status){
|
||||
this.store.newMessage("Server", res.message, "danger")
|
||||
this.$emit('delete')
|
||||
|
||||
@@ -22,6 +22,8 @@ import PeersDefaultSettingsInput from "@/components/settingsComponent/peersDefau
|
||||
targetData="peer_mtu" title="MTU"></PeersDefaultSettingsInput>
|
||||
<PeersDefaultSettingsInput
|
||||
targetData="peer_keep_alive" title="Persistent Keepalive"></PeersDefaultSettingsInput>
|
||||
<PeersDefaultSettingsInput
|
||||
targetData="peer_preshared_key_default" title="Pre-Shared Key Default"></PeersDefaultSettingsInput>
|
||||
<PeersDefaultSettingsInput
|
||||
targetData="remote_endpoint" title="Peer Remote Endpoint"
|
||||
:warning="true" warningText="This will be changed globally, and will be apply to all peer's QR code and configuration file."
|
||||
@@ -34,4 +36,4 @@ import PeersDefaultSettingsInput from "@/components/settingsComponent/peersDefau
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -31,6 +31,11 @@ export default {
|
||||
mounted() {
|
||||
this.value = this.store.Configuration.Peers[this.targetData];
|
||||
},
|
||||
computed: {
|
||||
isBoolean(){
|
||||
return typeof this.value === "boolean"
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
async useValidation(){
|
||||
if(this.changed){
|
||||
@@ -67,7 +72,14 @@ export default {
|
||||
<LocaleText :t="this.title"></LocaleText>
|
||||
</small></strong>
|
||||
</label>
|
||||
<input type="text" class="form-control"
|
||||
<div v-if="isBoolean" class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
v-model="this.value"
|
||||
:id="this.uuid"
|
||||
@change="this.changed = true; useValidation()"
|
||||
:disabled="this.updating">
|
||||
</div>
|
||||
<input v-else type="text" class="form-control"
|
||||
:class="{'is-invalid': showInvalidFeedback, 'is-valid': isValid}"
|
||||
:id="this.uuid"
|
||||
v-model="this.value"
|
||||
@@ -88,4 +100,4 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<script setup async>
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {fetchGet} from "@/utilities/fetch.js";
|
||||
import LocaleText from "@/components/text/localeText.vue";
|
||||
const providers = ref([])
|
||||
const oidcEnabled = ref(false)
|
||||
|
||||
await fetchGet("/api/oidc/providers", {}, async (res) => {
|
||||
if (res.status){
|
||||
await Promise.all(Object.entries(res.data).map(([key, value]) => {
|
||||
return fetch(`${value.issuer}/.well-known/openid-configuration`).then((res) => {
|
||||
providers.value.push({
|
||||
Provider: key,
|
||||
ProviderInfo: value
|
||||
})
|
||||
}).catch(() => {
|
||||
console.log("Failed to request " + key)
|
||||
})
|
||||
}))
|
||||
oidcEnabled.value = providers.value.length > 0
|
||||
}
|
||||
})
|
||||
console.log(providers.value)
|
||||
const oidcUrl = (provider) => {
|
||||
const params = new URLSearchParams({
|
||||
client_id: provider.ProviderInfo.client_id,
|
||||
redirect_uri: window.location.protocol + '//' + window.location.host + window.location.pathname,
|
||||
response_type: 'code',
|
||||
state: provider.Provider,
|
||||
scope: 'openid email profile'
|
||||
})
|
||||
console.log(params.entries())
|
||||
const url = new URL(provider.ProviderInfo.openid_configuration.authorization_endpoint)
|
||||
url.search = params.toString()
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="oidcEnabled">
|
||||
<hr class="mb-4"/>
|
||||
<div class="d-flex gap-2">
|
||||
<a class="btn bg-body border w-100 rounded-3"
|
||||
:href="oidcUrl(provider)"
|
||||
v-for="provider in providers" style="flex: 1 1 0;">
|
||||
<LocaleText :t="'Sign In With ' + provider.Provider"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
+57
-10
@@ -7,18 +7,65 @@ import '@vuepic/vue-datepicker/dist/main.css'
|
||||
import {createApp, markRaw} from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import router from './router/router.js'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import {DashboardConfigurationStore} from "@/stores/DashboardConfigurationStore.js";
|
||||
|
||||
const app = createApp(App)
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const state = params.get('state')
|
||||
const code = params.get('code')
|
||||
|
||||
app.use(router)
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
pinia.use(({ store }) => {
|
||||
store.$router = markRaw(router)
|
||||
})
|
||||
if (state && code) {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
console.log('After replaceState:', window.location.href);
|
||||
}
|
||||
|
||||
|
||||
app.use(pinia)
|
||||
app.mount('#app')
|
||||
|
||||
|
||||
const initApp = async () => {
|
||||
const { default: router } = await import('./router/router.js')
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
pinia.use(({ store }) => {
|
||||
store.$router = markRaw(router)
|
||||
})
|
||||
|
||||
|
||||
app.use(pinia)
|
||||
app.mount('#app')
|
||||
console.log('After router import:', window.location.href)
|
||||
}
|
||||
|
||||
export const getUrl = (url) => {
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
return url;
|
||||
}
|
||||
return `./.${url}`;
|
||||
}
|
||||
|
||||
if (state && code){
|
||||
await fetch(getUrl('/api/oidc/authenticate'), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
provider: state,
|
||||
code: code,
|
||||
redirect_uri: window.location.protocol + '//' + window.location.host + window.location.pathname
|
||||
})
|
||||
}).then(res => res.json()).then( async (res) => {
|
||||
if (res.status){
|
||||
window.location.replace(window.location.protocol + '//' + window.location.host + window.location.pathname)
|
||||
}else{
|
||||
await initApp()
|
||||
const store = DashboardConfigurationStore()
|
||||
store.newMessage('Server OIDC', res.message, 'danger')
|
||||
}
|
||||
})
|
||||
}else{
|
||||
await initApp()
|
||||
}
|
||||
|
||||
@@ -4,17 +4,21 @@ const getHeaders = () => {
|
||||
let headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
const store = DashboardConfigurationStore();
|
||||
const crossServer = store.getActiveCrossServer();
|
||||
if (crossServer){
|
||||
headers['wg-dashboard-apikey'] = crossServer.apiKey
|
||||
if (crossServer.headers){
|
||||
for (let header of Object.values(crossServer.headers)){
|
||||
if (header.key && header.value && !Object.keys(headers).includes(header.key)){
|
||||
headers[header.key] = header.value
|
||||
}
|
||||
}
|
||||
}
|
||||
try{
|
||||
const store = DashboardConfigurationStore();
|
||||
const crossServer = store.getActiveCrossServer();
|
||||
if (crossServer){
|
||||
headers['wg-dashboard-apikey'] = crossServer.apiKey
|
||||
if (crossServer.headers){
|
||||
for (let header of Object.values(crossServer.headers)){
|
||||
if (header.key && header.value && !Object.keys(headers).includes(header.key)){
|
||||
headers[header.key] = header.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (e) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +26,13 @@ const getHeaders = () => {
|
||||
}
|
||||
|
||||
export const getUrl = (url) => {
|
||||
const store = DashboardConfigurationStore();
|
||||
const apiKey = store.getActiveCrossServer();
|
||||
if (apiKey){
|
||||
return `${apiKey.host}${url}`
|
||||
}
|
||||
try{
|
||||
const store = DashboardConfigurationStore();
|
||||
const apiKey = store.getActiveCrossServer();
|
||||
if (apiKey){
|
||||
return `${apiKey.host}${url}`
|
||||
}
|
||||
}catch (e){}
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
return url;
|
||||
}
|
||||
@@ -79,4 +85,50 @@ export const fetchPost = async (url, body, callback) => {
|
||||
console.log("Error:", x)
|
||||
router.push({path: '/signin'})
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchPut = async (url, body, callback) => {
|
||||
await fetch(`${getUrl(url)}`, {
|
||||
headers: getHeaders(),
|
||||
method: "PUT",
|
||||
body: JSON.stringify(body)
|
||||
}).then((x) => {
|
||||
const store = DashboardConfigurationStore();
|
||||
if (!x.ok){
|
||||
if (x.status !== 200){
|
||||
if (x.status === 401){
|
||||
store.newMessage("WGDashboard", "Sign in session ended, please sign in again", "warning")
|
||||
}
|
||||
throw new Error(x.statusText)
|
||||
}
|
||||
}else{
|
||||
return x.json()
|
||||
}
|
||||
}).then(x => callback ? callback(x) : undefined).catch(x => {
|
||||
console.log("Error:", x)
|
||||
router.push({path: '/signin'})
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchDelete = async (url, body, callback) => {
|
||||
await fetch(`${getUrl(url)}`, {
|
||||
headers: getHeaders(),
|
||||
method: "DELETE",
|
||||
body: JSON.stringify(body)
|
||||
}).then((x) => {
|
||||
const store = DashboardConfigurationStore();
|
||||
if (!x.ok){
|
||||
if (x.status !== 200){
|
||||
if (x.status === 401){
|
||||
store.newMessage("WGDashboard", "Sign in session ended, please sign in again", "warning")
|
||||
}
|
||||
throw new Error(x.statusText)
|
||||
}
|
||||
}else{
|
||||
return x.json()
|
||||
}
|
||||
}).then(x => callback ? callback(x) : undefined).catch(x => {
|
||||
console.log("Error:", x)
|
||||
router.push({path: '/signin'})
|
||||
})
|
||||
}
|
||||
@@ -7,10 +7,11 @@ import {GetLocale} from "@/utilities/locale.js";
|
||||
import LocaleText from "@/components/text/localeText.vue";
|
||||
import SignInInput from "@/components/signIn/signInInput.vue";
|
||||
import SignInTOTP from "@/components/signIn/signInTOTP.vue";
|
||||
import SignInOIDC from "@/components/signIn/signInOIDC.vue";
|
||||
|
||||
export default {
|
||||
name: "signin",
|
||||
components: {SignInTOTP, SignInInput, LocaleText, RemoteServerList, Message},
|
||||
components: {SignInOIDC, SignInTOTP, SignInInput, LocaleText, RemoteServerList, Message},
|
||||
async setup(){
|
||||
const store = DashboardConfigurationStore()
|
||||
let theme = "dark"
|
||||
@@ -171,7 +172,7 @@ export default {
|
||||
</form>
|
||||
<RemoteServerList v-else></RemoteServerList>
|
||||
|
||||
<div class="d-flex mt-3" v-if="!this.store.IsElectronApp">
|
||||
<div class="d-flex mt-3 flex-column" v-if="!this.store.IsElectronApp">
|
||||
<div class="form-check form-switch ms-auto">
|
||||
<input
|
||||
v-model="this.store.CrossServerConfiguration.Enable"
|
||||
@@ -184,6 +185,8 @@ export default {
|
||||
<LocaleText t="Access Remote Server"></LocaleText>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<SignInOIDC />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Generated
+1676
-1727
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "client",
|
||||
"version": "v1.0",
|
||||
"version": "v1.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -9,20 +9,20 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.9.0",
|
||||
"bootstrap": "^5.3.6",
|
||||
"axios": "^1.18.0",
|
||||
"bootstrap": "^5.3.8",
|
||||
"bootstrap-icons": "^1.13.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"oidc-client-ts": "^3.2.1",
|
||||
"pinia": "^3.0.2",
|
||||
"dayjs": "^1.11.21",
|
||||
"oidc-client-ts": "^3.5.0",
|
||||
"pinia": "^3.0.4",
|
||||
"qrcode": "^1.5.4",
|
||||
"uuid": "^11.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.1"
|
||||
"uuid": "^14.0.0",
|
||||
"vue": "^3.5.35",
|
||||
"vue-router": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"vite": "^6.2.4",
|
||||
"vite-plugin-vue-devtools": "^7.7.2"
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"vite": "^8.0.16",
|
||||
"vite-plugin-vue-devtools": "^8.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {computed, ref} from "vue";
|
||||
import ConfigurationQRCode from "@/components/Configuration/configurationQRCode.vue";
|
||||
import dayjs from "dayjs";
|
||||
import Duration from 'dayjs/plugin/Duration'
|
||||
import Duration from 'dayjs/plugin/duration'
|
||||
dayjs.extend(Duration);
|
||||
const props = defineProps([
|
||||
'config'
|
||||
@@ -113,4 +113,4 @@ const emits = defineEmits(['select'])
|
||||
background-color: #28a745 !important;
|
||||
box-shadow: 0 0 0 .2rem #28a74545;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,6 @@ import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from "@/router/router.js";
|
||||
import {createPinia} from "pinia";
|
||||
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.js'
|
||||
@@ -13,7 +12,13 @@ const params = new URLSearchParams(window.location.search)
|
||||
const state = params.get('state')
|
||||
const code = params.get('code')
|
||||
|
||||
if (state && code) {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
|
||||
const initApp = async () => {
|
||||
debugger
|
||||
const { default: router } = await import('./router/router.js')
|
||||
const app = createApp(App)
|
||||
const serverInformation = await axiosGet("/api/serverInformation", {})
|
||||
app.use(createPinia())
|
||||
@@ -31,12 +36,10 @@ if (state && code){
|
||||
code: code,
|
||||
redirect_uri: window.location.protocol + '//' + window.location.host + window.location.pathname
|
||||
}).then(async (data) => {
|
||||
let url = new URL(window.location.href);
|
||||
url.search = '';
|
||||
history.replaceState({}, document.title, url.toString());
|
||||
|
||||
await initApp()
|
||||
if (!data.status){
|
||||
if (data.status){
|
||||
window.location.replace(window.location.protocol + '//' + window.location.host + window.location.pathname)
|
||||
}else {
|
||||
await initApp()
|
||||
const store = clientStore()
|
||||
store.newNotification(data.message, 'danger')
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{a5 as A,D as S,r as n,g as l,z as v}from"./index-BCgxBvDt.js";const b=A("DashboardClientAssignmentStore",()=>{const f=n({}),d=n([]),o=n({}),c=n([]),g=n(!1),r=n(""),i=S(),w=async()=>{await l("/api/clients/allClients",{},s=>{o.value=s.data})},y=async()=>{await l("/api/clients/allClientsRaw",{},s=>{c.value=s.data,console.log(c.value)})},m=s=>Object.values(o.value).flat().find(e=>e.ClientID===s),u=async(s,e)=>{await l("/api/clients/assignedClients",{ConfigurationName:s,Peer:e},a=>{d.value=a.data})};return{assignments:d,getAssignedClients:u,getClients:w,getClientsRaw:y,clients:o,unassignClient:async(s,e,a)=>{g.value=!0,await v("/api/clients/unassignClient",{AssignmentID:a},async t=>{t.status?(i.newMessage("Server","Unassign successfully!","success"),s&&e&&await u(s,e)):(i.newMessage("Server","Unassign Failed. Reason: "+t.message,"success"),console.error("Unassign Failed. Reason: "+t.message)),g.value=!1})},assignClient:async(s,e,a,t=!0)=>{r.value=a,await v("/api/clients/assignClient",{ConfigurationName:s,Peer:e,ClientID:a},async C=>{C.status?(i.newMessage("Server","Assign successfully!","success"),t&&await u(s,e)):(i.newMessage("Server","Assign Failed. Reason: "+C.message,"success"),console.error("Assign Failed. Reason: "+C.message)),r.value=""})},getClientById:m,unassigning:g,assigning:r,clientsRaw:c,allConfigurationsPeers:f,getAllConfigurationsPeers:async()=>{await l("/api/clients/allConfigurationsPeers",{},s=>{f.value=s.data})}}});export{b as D};
|
||||
import{a5 as A,r as n,D as S,g as l,z as v}from"./index-DM7YJCOo.js";const b=A("DashboardClientAssignmentStore",()=>{const f=n({}),d=n([]),o=n({}),c=n([]),g=n(!1),r=n(""),i=S(),w=async()=>{await l("/api/clients/allClients",{},s=>{o.value=s.data})},y=async()=>{await l("/api/clients/allClientsRaw",{},s=>{c.value=s.data,console.log(c.value)})},m=s=>Object.values(o.value).flat().find(e=>e.ClientID===s),u=async(s,e)=>{await l("/api/clients/assignedClients",{ConfigurationName:s,Peer:e},a=>{d.value=a.data})};return{assignments:d,getAssignedClients:u,getClients:w,getClientsRaw:y,clients:o,unassignClient:async(s,e,a)=>{g.value=!0,await v("/api/clients/unassignClient",{AssignmentID:a},async t=>{t.status?(i.newMessage("Server","Unassign successfully!","success"),s&&e&&await u(s,e)):(i.newMessage("Server","Unassign Failed. Reason: "+t.message,"success"),console.error("Unassign Failed. Reason: "+t.message)),g.value=!1})},assignClient:async(s,e,a,t=!0)=>{r.value=a,await v("/api/clients/assignClient",{ConfigurationName:s,Peer:e,ClientID:a},async C=>{C.status?(i.newMessage("Server","Assign successfully!","success"),t&&await u(s,e)):(i.newMessage("Server","Assign Failed. Reason: "+C.message,"success"),console.error("Assign Failed. Reason: "+C.message)),r.value=""})},getClientById:m,unassigning:g,assigning:r,clientsRaw:c,allConfigurationsPeers:f,getAllConfigurationsPeers:async()=>{await l("/api/clients/allConfigurationsPeers",{},s=>{f.value=s.data})}}});export{b as D};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
@media screen and (min-width:576px){.backLink[data-v-f874264d]{display:none}}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
@media screen and (min-width: 576px){.backLink[data-v-f874264d]{display:none}}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
@media screen and (max-width: 576px){.clientListContainer.hide[data-v-a8650ee3],.clientViewerContainer.hide[data-v-a8650ee3]{display:none!important}.clientListContainer[data-v-a8650ee3]{border-right:none!important;animation:blurIn-a8650ee3 .2s ease-in-out forwards}.clientViewerContainer[data-v-a8650ee3]{animation:blurIn-a8650ee3 .2s ease-in-out forwards}}@keyframes blurIn-a8650ee3{0%{filter:blur(8px)}to{filter:blur(0px)}}
|
||||
@@ -1 +0,0 @@
|
||||
@media screen and (max-width:576px){.clientListContainer.hide[data-v-a8650ee3],.clientViewerContainer.hide[data-v-a8650ee3]{display:none!important}.clientListContainer[data-v-a8650ee3]{border-right:none!important;animation:blurIn-a8650ee3 .2s ease-in-out forwards}.clientViewerContainer[data-v-a8650ee3]{animation:blurIn-a8650ee3 .2s ease-in-out forwards}}@keyframes blurIn-a8650ee3{0%{filter:blur(8px)}to{filter:blur(0px)}}
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{_ as r,c as i,b as o,w as e,k as l,j as a,l as _,S as u,h as d,f as t}from"./index-BCgxBvDt.js";const m={name:"configuration"},f={class:"mt-md-5 mt-3 text-body"};function p(h,k,x,w,$,v){const n=d("RouterView");return t(),i("div",f,[o(n,null,{default:e(({Component:s,route:c})=>[o(l,{name:"fade2",mode:"out-in"},{default:e(()=>[(t(),a(u,null,{default:e(()=>[(t(),a(_(s),{key:c.path,class:"z-1"}))]),_:2},1024))]),_:2},1024)]),_:1})])}const B=r(m,[["render",p]]);export{B as default};
|
||||
import{_ as r,c as i,b as o,w as e,k as l,j as a,l as _,S as u,h as d,f as t}from"./index-DM7YJCOo.js";const m={name:"configuration"},f={class:"mt-md-5 mt-3 text-body"};function p(h,k,x,w,$,v){const n=d("RouterView");return t(),i("div",f,[o(n,null,{default:e(({Component:s,route:c})=>[o(l,{name:"fade2",mode:"out-in"},{default:e(()=>[(t(),a(u,null,{default:e(()=>[(t(),a(_(s),{key:c.path,class:"z-1"}))]),_:2},1024))]),_:2},1024)]),_:1})])}const B=r(m,[["render",p]]);export{B as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
@media screen and (max-width: 992px){.apiKey-card-body{&[data-v-a76253c8]{flex-direction:column!important;align-items:start!important}div.ms-auto[data-v-a76253c8]{margin-left:0!important}div[data-v-a76253c8]{width:100%;align-items:start!important}small[data-v-a76253c8]{margin-right:auto}}}.apiKey-move[data-v-f7e62927],.apiKey-enter-active[data-v-f7e62927],.apiKey-leave-active[data-v-f7e62927]{transition:all .5s ease}.apiKey-enter-from[data-v-f7e62927],.apiKey-leave-to[data-v-f7e62927]{opacity:0;transform:translateY(30px) scale(.9)}.apiKey-leave-active[data-v-f7e62927]{position:absolute;width:100%}.dropdown-menu[data-v-4e34593e]{width:100%}
|
||||
@@ -1 +0,0 @@
|
||||
@media screen and (max-width:992px){.apiKey-card-body{&[data-v-a76253c8]{flex-direction:column!important;align-items:start!important}div.ms-auto[data-v-a76253c8]{margin-left:0!important}div[data-v-a76253c8]{width:100%;align-items:start!important}small[data-v-a76253c8]{margin-right:auto}}}.apiKey-move[data-v-f7e62927],.apiKey-enter-active[data-v-f7e62927],.apiKey-leave-active[data-v-f7e62927]{transition:all .5s ease}.apiKey-enter-from[data-v-f7e62927],.apiKey-leave-to[data-v-f7e62927]{opacity:0;transform:translateY(30px) scale(.9)}.apiKey-leave-active[data-v-f7e62927]{position:absolute;width:100%}.dropdown-menu[data-v-4e34593e]{width:100%}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{_ as f,c as i,a as t,b as u,h as w,d as k,m as x,y,n as p,t as v,z as _,D as m,W as b,A as S,f as n,r as D,F as $,i as W,q as V}from"./index-BCgxBvDt.js";import{L as C}from"./localeText-ZTaDi7ZY.js";const F={name:"dashboardSettingsInputWireguardConfigurationPath",components:{LocaleText:C},props:{targetData:String,title:String,warning:!1,warningText:""},setup(){const o=m(),s=b(),r=`input_${S()}`;return{store:o,uuid:r,WireguardConfigurationStore:s}},data(){return{value:"",invalidFeedback:"",showInvalidFeedback:!1,isValid:!1,timeout:void 0,changed:!1,updating:!1}},mounted(){this.value=this.store.Configuration.Server[this.targetData]},methods:{async useValidation(){this.changed&&(this.updating=!0,await _("/api/updateDashboardConfigurationItem",{section:"Server",key:this.targetData,value:this.value},o=>{o.status?(this.isValid=!0,this.showInvalidFeedback=!1,this.store.Configuration.Account[this.targetData]=this.value,clearTimeout(this.timeout),this.timeout=setTimeout(()=>this.isValid=!1,5e3),this.WireguardConfigurationStore.getConfigurations(),this.store.newMessage("Server","WireGuard configuration path saved","success")):(this.isValid=!1,this.showInvalidFeedback=!0,this.invalidFeedback=o.message),this.changed=!1,this.updating=!1}))}}},I={class:"card"},T={class:"card-header"},A={class:"my-2"},L={class:"card-body"},M={class:"form-group"},N=["for"],P={class:"d-flex gap-2 align-items-start"},B={class:"flex-grow-1"},G=["id","disabled"],z={class:"invalid-feedback fw-bold"},U=["disabled"],q={key:0,class:"bi bi-save2-fill"},E={key:1,class:"spinner-border spinner-border-sm"},K={key:0,class:"px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1 mb-2"};function j(o,s,r,a,c,g){const d=w("LocaleText");return n(),i("div",I,[t("div",T,[t("h6",A,[u(d,{t:"Path"})])]),t("div",L,[t("div",M,[t("label",{for:this.uuid,class:"text-muted mb-1"},[t("strong",null,[t("small",null,[u(d,{t:this.title},null,8,["t"])])])],8,N),t("div",P,[t("div",B,[x(t("input",{type:"text",class:p(["form-control rounded-3",{"is-invalid":this.showInvalidFeedback,"is-valid":this.isValid}]),id:this.uuid,"onUpdate:modelValue":s[0]||(s[0]=e=>this.value=e),onKeydown:s[1]||(s[1]=e=>this.changed=!0),disabled:this.updating},null,42,G),[[y,this.value]]),t("div",z,v(this.invalidFeedback),1)]),t("button",{onClick:s[2]||(s[2]=e=>this.useValidation()),disabled:!this.changed,class:"ms-auto btn rounded-3 border-success-subtle bg-success-subtle text-success-emphasis"},[this.updating?(n(),i("span",E)):(n(),i("i",q))],8,U)]),r.warning?(n(),i("div",K,[t("small",null,[s[3]||(s[3]=t("i",{class:"bi bi-exclamation-triangle-fill me-2"},null,-1)),u(d,{t:r.warningText},null,8,["t"])])])):k("",!0)])])])}const et=f(F,[["render",j]]),H={class:"card rounded-3"},J={class:"card-header"},O={class:"my-2"},Q={class:"card-body d-flex gap-2"},R={class:"list-group w-100"},X=["onClick"],Y={__name:"dashboardSettingsWireguardConfigurationAutostart",setup(o){const s=m(),r=b(),a=D(s.Configuration.WireGuardConfiguration.autostart),c=V(()=>r.Configurations.map(e=>e.Name)),g=async()=>{await _("/api/updateDashboardConfigurationItem",{section:"WireGuardConfiguration",key:"autostart",value:a.value},async e=>{e.status?(s.newMessage("Server","Start up configurations saved","success"),a.value=e.data):s.newMessage("Server","Start up configurations failed to save","danger")})},d=e=>{a.value.includes(e)?a.value=a.value.filter(h=>h!==e):a.value.push(e),g()};return(e,h)=>(n(),i("div",H,[t("div",J,[t("h6",O,[u(C,{t:"Toggle When Start Up"})])]),t("div",Q,[t("div",R,[(n(!0),i($,null,W(c.value,l=>(n(),i("button",{type:"button",key:l,onClick:Z=>d(l),class:"list-group-item list-group-item-action py-2 w-100 d-flex align-items-center"},[t("samp",null,v(l),1),t("i",{class:p(["ms-auto",[a.value.includes(l)?"bi-check-circle-fill":"bi-circle"]])},null,2)],8,X))),128))])])]))}},at=f(Y,[["__scopeId","data-v-4aa2aed9"]]);export{et as D,at as a};
|
||||
import{_ as f,c as i,a as t,b as u,h as w,d as k,m as x,y,n as p,t as v,z as _,D as m,W as b,A as S,f as n,r as D,q as $,F as W,i as V}from"./index-DM7YJCOo.js";import{L as C}from"./localeText-BJvnc1lF.js";const F={name:"dashboardSettingsInputWireguardConfigurationPath",components:{LocaleText:C},props:{targetData:String,title:String,warning:!1,warningText:""},setup(){const o=m(),s=b(),r=`input_${S()}`;return{store:o,uuid:r,WireguardConfigurationStore:s}},data(){return{value:"",invalidFeedback:"",showInvalidFeedback:!1,isValid:!1,timeout:void 0,changed:!1,updating:!1}},mounted(){this.value=this.store.Configuration.Server[this.targetData]},methods:{async useValidation(){this.changed&&(this.updating=!0,await _("/api/updateDashboardConfigurationItem",{section:"Server",key:this.targetData,value:this.value},o=>{o.status?(this.isValid=!0,this.showInvalidFeedback=!1,this.store.Configuration.Account[this.targetData]=this.value,clearTimeout(this.timeout),this.timeout=setTimeout(()=>this.isValid=!1,5e3),this.WireguardConfigurationStore.getConfigurations(),this.store.newMessage("Server","WireGuard configuration path saved","success")):(this.isValid=!1,this.showInvalidFeedback=!0,this.invalidFeedback=o.message),this.changed=!1,this.updating=!1}))}}},I={class:"card"},T={class:"card-header"},A={class:"my-2"},L={class:"card-body"},M={class:"form-group"},N=["for"],P={class:"d-flex gap-2 align-items-start"},B={class:"flex-grow-1"},G=["id","disabled"],z={class:"invalid-feedback fw-bold"},U=["disabled"],q={key:0,class:"bi bi-save2-fill"},E={key:1,class:"spinner-border spinner-border-sm"},K={key:0,class:"px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1 mb-2"};function j(o,s,r,a,c,g){const d=w("LocaleText");return n(),i("div",I,[t("div",T,[t("h6",A,[u(d,{t:"Path"})])]),t("div",L,[t("div",M,[t("label",{for:this.uuid,class:"text-muted mb-1"},[t("strong",null,[t("small",null,[u(d,{t:this.title},null,8,["t"])])])],8,N),t("div",P,[t("div",B,[x(t("input",{type:"text",class:p(["form-control rounded-3",{"is-invalid":this.showInvalidFeedback,"is-valid":this.isValid}]),id:this.uuid,"onUpdate:modelValue":s[0]||(s[0]=e=>this.value=e),onKeydown:s[1]||(s[1]=e=>this.changed=!0),disabled:this.updating},null,42,G),[[y,this.value]]),t("div",z,v(this.invalidFeedback),1)]),t("button",{onClick:s[2]||(s[2]=e=>this.useValidation()),disabled:!this.changed,class:"ms-auto btn rounded-3 border-success-subtle bg-success-subtle text-success-emphasis"},[this.updating?(n(),i("span",E)):(n(),i("i",q))],8,U)]),r.warning?(n(),i("div",K,[t("small",null,[s[3]||(s[3]=t("i",{class:"bi bi-exclamation-triangle-fill me-2"},null,-1)),u(d,{t:r.warningText},null,8,["t"])])])):k("",!0)])])])}const et=f(F,[["render",j]]),H={class:"card rounded-3"},J={class:"card-header"},O={class:"my-2"},Q={class:"card-body d-flex gap-2"},R={class:"list-group w-100"},X=["onClick"],Y={__name:"dashboardSettingsWireguardConfigurationAutostart",setup(o){const s=m(),r=b(),a=D(s.Configuration.WireGuardConfiguration.autostart),c=$(()=>r.Configurations.map(e=>e.Name)),g=async()=>{await _("/api/updateDashboardConfigurationItem",{section:"WireGuardConfiguration",key:"autostart",value:a.value},async e=>{e.status?(s.newMessage("Server","Start up configurations saved","success"),a.value=e.data):s.newMessage("Server","Start up configurations failed to save","danger")})},d=e=>{a.value.includes(e)?a.value=a.value.filter(h=>h!==e):a.value.push(e),g()};return(e,h)=>(n(),i("div",H,[t("div",J,[t("h6",O,[u(C,{t:"Toggle When Start Up"})])]),t("div",Q,[t("div",R,[(n(!0),i(W,null,V(c.value,l=>(n(),i("button",{type:"button",key:l,onClick:Z=>d(l),class:"list-group-item list-group-item-action py-2 w-100 d-flex align-items-center"},[t("samp",null,v(l),1),t("i",{class:p(["ms-auto",[a.value.includes(l)?"bi-check-circle-fill":"bi-circle"]])},null,2)],8,X))),128))])])]))}},at=f(Y,[["__scopeId","data-v-4aa2aed9"]]);export{et as D,at as a};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
.agentContainer[data-v-f37f608d]{--agentHeight: 100vh;position:absolute;z-index:9999;top:0;left:100%;width:450px;box-shadow:0 10px 30px #0000004d;backdrop-filter:blur(8px);background:linear-gradient(var(--degree),#009dff52 var(--distance2),#F9464752 100%)}.agentContainer.enabled[data-v-f37f608d]{height:calc(var(--agentHeight) - 1rem)}@media screen and (max-width:768px){.agentContainer[data-v-f37f608d]{--agentHeight: 100vh !important;top:0;left:0;max-height:calc(var(--agentHeight) - 58px - 1rem);width:calc(100% - 1rem)}}.agentChatroomBody[data-v-f37f608d]{flex:1 1 auto;overflow-y:auto;max-height:calc(var(--agentHeight) - 70px - 244px)}@media screen and (max-width:768px){.navbar-container[data-v-982f1a52]{position:absolute!important;z-index:1000;animation-duration:.4s;animation-fill-mode:both;display:none;animation-timing-function:cubic-bezier(.82,.58,.17,.9)}.navbar-container.active[data-v-982f1a52]{animation-direction:normal;display:block!important;animation-name:zoomInFade-982f1a52}}.navbar-container[data-v-982f1a52]{height:100vh;position:relative}@supports (height: 100dvh){@media screen and (max-width:768px){.navbar-container[data-v-982f1a52]{height:calc(100dvh - 58px)}}}@keyframes zoomInFade-982f1a52{0%{opacity:0;transform:translateY(60px);filter:blur(3px)}to{opacity:1;transform:translateY(0);filter:blur(0px)}}.slideIn-enter-active[data-v-982f1a52],.slideIn-leave-active[data-v-982f1a52]{transition:all .3s cubic-bezier(.82,.58,.17,1)}.slideIn-enter-from[data-v-982f1a52],.slideIn-leave-to[data-v-982f1a52]{transform:translateY(30px);filter:blur(3px);opacity:0}main[data-v-0c6a5068]{height:100vh}@supports (height: 100dvh){@media screen and (max-width:768px){main[data-v-0c6a5068]{height:calc(100dvh - 58px)}}}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.agentContainer[data-v-f37f608d]{--agentHeight: 100vh;position:absolute;z-index:9999;top:0;left:100%;width:450px;box-shadow:0 10px 30px #0000004d;backdrop-filter:blur(8px);background:linear-gradient(var(--degree),#009dff52 var(--distance2),#F9464752 100%)}.agentContainer.enabled[data-v-f37f608d]{height:calc(var(--agentHeight) - 1rem)}@media screen and (max-width: 768px){.agentContainer[data-v-f37f608d]{--agentHeight: 100vh !important;top:0;left:0;max-height:calc(var(--agentHeight) - 58px - 1rem);width:calc(100% - 1rem)}}.agentChatroomBody[data-v-f37f608d]{flex:1 1 auto;overflow-y:auto;max-height:calc(var(--agentHeight) - 70px - 244px)}@media screen and (max-width: 768px){.navbar-container[data-v-982f1a52]{position:absolute!important;z-index:1000;animation-duration:.4s;animation-fill-mode:both;display:none;animation-timing-function:cubic-bezier(.82,.58,.17,.9)}.navbar-container.active[data-v-982f1a52]{animation-direction:normal;display:block!important;animation-name:zoomInFade-982f1a52}}.navbar-container[data-v-982f1a52]{height:100vh;position:relative}@supports (height: 100dvh){@media screen and (max-width: 768px){.navbar-container[data-v-982f1a52]{height:calc(100dvh - 58px)}}}@keyframes zoomInFade-982f1a52{0%{opacity:0;transform:translateY(60px);filter:blur(3px)}to{opacity:1;transform:translateY(0);filter:blur(0px)}}.slideIn-enter-active[data-v-982f1a52],.slideIn-leave-active[data-v-982f1a52]{transition:all .3s cubic-bezier(.82,.58,.17,1)}.slideIn-enter-from[data-v-982f1a52],.slideIn-leave-to[data-v-982f1a52]{transform:translateY(30px);filter:blur(3px);opacity:0}main[data-v-0c6a5068]{height:100vh}@supports (height: 100dvh){@media screen and (max-width: 768px){main[data-v-0c6a5068]{height:calc(100dvh - 58px)}}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{H as I,P as S,q as w,u as L,Q as R,J as k}from"./index-BCgxBvDt.js";const W=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const X=Object.prototype.toString,Y=t=>X.call(t)==="[object Object]",$=()=>{};function C(t){return Array.isArray(t)?t:[t]}function q(t,a,r){return I(t,a,{...r,immediate:!0})}const O=W?window:void 0;function P(t){var a;const r=S(t);return(a=r?.$el)!==null&&a!==void 0?a:r}function T(...t){const a=(o,u,s,d)=>(o.addEventListener(u,s,d),()=>o.removeEventListener(u,s,d)),r=w(()=>{const o=C(S(t[0])).filter(u=>u!=null);return o.every(u=>typeof u!="string")?o:void 0});return q(()=>{var o,u;return[(o=(u=r.value)===null||u===void 0?void 0:u.map(s=>P(s)))!==null&&o!==void 0?o:[O].filter(s=>s!=null),C(S(r.value?t[1]:t[0])),C(L(r.value?t[2]:t[1])),S(r.value?t[3]:t[2])]},([o,u,s,d],p,c)=>{if(!o?.length||!u?.length||!s?.length)return;const f=Y(d)?{...d}:d,v=o.flatMap(b=>u.flatMap(h=>s.map(y=>a(b,h,y,f))));c(()=>{v.forEach(b=>b())})},{flush:"post"})}function B(t,a,r={}){const{window:o=O,ignore:u=[],capture:s=!0,detectIframe:d=!1,controls:p=!1}=r;if(!o)return p?{stop:$,cancel:$,trigger:$}:$;let c=!0;const f=e=>S(u).some(n=>{if(typeof n=="string")return Array.from(o.document.querySelectorAll(n)).some(i=>i===e.target||e.composedPath().includes(i));{const i=P(n);return i&&(e.target===i||e.composedPath().includes(i))}});function v(e){const n=S(e);return n&&n.$.subTree.shapeFlag===16}function b(e,n){const i=S(e),m=i.$.subTree&&i.$.subTree.children;return m==null||!Array.isArray(m)?!1:m.some(A=>A.el===n.target||n.composedPath().includes(A.el))}const h=e=>{const n=P(t);if(e.target!=null&&!(!(n instanceof Element)&&v(t)&&b(t,e))&&!(!n||n===e.target||e.composedPath().includes(n))){if("detail"in e&&e.detail===0&&(c=!f(e)),!c){c=!0;return}a(e)}};let y=!1;const E=[T(o,"click",e=>{y||(y=!0,setTimeout(()=>{y=!1},0),h(e))},{passive:!0,capture:s}),T(o,"pointerdown",e=>{const n=P(t);c=!f(e)&&!!(n&&!e.composedPath().includes(n))},{passive:!0}),d&&T(o,"blur",e=>{setTimeout(()=>{var n;const i=P(t);((n=o.document.activeElement)===null||n===void 0?void 0:n.tagName)==="IFRAME"&&!i?.contains(o.document.activeElement)&&a(e)},0)},{passive:!0})].filter(Boolean),x=()=>E.forEach(e=>e());return p?{stop:x,cancel:()=>{c=!1},trigger:e=>{c=!0,h(e),c=!1}}:x}function D(t,a={}){const{threshold:r=50,onSwipe:o,onSwipeEnd:u,onSwipeStart:s,passive:d=!0}=a,p=k({x:0,y:0}),c=k({x:0,y:0}),f=w(()=>p.x-c.x),v=w(()=>p.y-c.y),{max:b,abs:h}=Math,y=w(()=>b(h(f.value),h(v.value))>=r),E=R(!1),x=w(()=>y.value?h(f.value)>h(v.value)?f.value>0?"left":"right":v.value>0?"up":"down":"none"),e=l=>[l.touches[0].clientX,l.touches[0].clientY],n=(l,g)=>{p.x=l,p.y=g},i=(l,g)=>{c.x=l,c.y=g},m={passive:d,capture:!d},A=l=>{E.value&&u?.(l,x.value),E.value=!1},j=[T(t,"touchstart",l=>{if(l.touches.length!==1)return;const[g,M]=e(l);n(g,M),i(g,M),s?.(l)},m),T(t,"touchmove",l=>{if(l.touches.length!==1)return;const[g,M]=e(l);i(g,M),m.capture&&!m.passive&&Math.abs(f.value)>Math.abs(v.value)&&l.preventDefault(),!E.value&&y.value&&(E.value=!0),E.value&&o?.(l)},m),T(t,["touchend","touchcancel"],A,m)];return{isSwiping:E,direction:x,coordsStart:p,coordsEnd:c,lengthX:f,lengthY:v,stop:()=>j.forEach(l=>l())}}export{D as a,B as o,P as u};
|
||||
import{H as I,q as w,P as S,J as k,Q as L,u as R}from"./index-DM7YJCOo.js";const W=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const X=Object.prototype.toString,Y=t=>X.call(t)==="[object Object]",$=()=>{};function C(t){return Array.isArray(t)?t:[t]}function q(t,a,r){return I(t,a,{...r,immediate:!0})}const O=W?window:void 0;function P(t){var a;const r=S(t);return(a=r?.$el)!==null&&a!==void 0?a:r}function T(...t){const a=(o,u,s,d)=>(o.addEventListener(u,s,d),()=>o.removeEventListener(u,s,d)),r=w(()=>{const o=C(S(t[0])).filter(u=>u!=null);return o.every(u=>typeof u!="string")?o:void 0});return q(()=>{var o,u;return[(o=(u=r.value)===null||u===void 0?void 0:u.map(s=>P(s)))!==null&&o!==void 0?o:[O].filter(s=>s!=null),C(S(r.value?t[1]:t[0])),C(R(r.value?t[2]:t[1])),S(r.value?t[3]:t[2])]},([o,u,s,d],p,c)=>{if(!o?.length||!u?.length||!s?.length)return;const f=Y(d)?{...d}:d,v=o.flatMap(b=>u.flatMap(h=>s.map(y=>a(b,h,y,f))));c(()=>{v.forEach(b=>b())})},{flush:"post"})}function B(t,a,r={}){const{window:o=O,ignore:u=[],capture:s=!0,detectIframe:d=!1,controls:p=!1}=r;if(!o)return p?{stop:$,cancel:$,trigger:$}:$;let c=!0;const f=e=>S(u).some(n=>{if(typeof n=="string")return Array.from(o.document.querySelectorAll(n)).some(i=>i===e.target||e.composedPath().includes(i));{const i=P(n);return i&&(e.target===i||e.composedPath().includes(i))}});function v(e){const n=S(e);return n&&n.$.subTree.shapeFlag===16}function b(e,n){const i=S(e),m=i.$.subTree&&i.$.subTree.children;return m==null||!Array.isArray(m)?!1:m.some(A=>A.el===n.target||n.composedPath().includes(A.el))}const h=e=>{const n=P(t);if(e.target!=null&&!(!(n instanceof Element)&&v(t)&&b(t,e))&&!(!n||n===e.target||e.composedPath().includes(n))){if("detail"in e&&e.detail===0&&(c=!f(e)),!c){c=!0;return}a(e)}};let y=!1;const E=[T(o,"click",e=>{y||(y=!0,setTimeout(()=>{y=!1},0),h(e))},{passive:!0,capture:s}),T(o,"pointerdown",e=>{const n=P(t);c=!f(e)&&!!(n&&!e.composedPath().includes(n))},{passive:!0}),d&&T(o,"blur",e=>{setTimeout(()=>{var n;const i=P(t);((n=o.document.activeElement)===null||n===void 0?void 0:n.tagName)==="IFRAME"&&!i?.contains(o.document.activeElement)&&a(e)},0)},{passive:!0})].filter(Boolean),x=()=>E.forEach(e=>e());return p?{stop:x,cancel:()=>{c=!1},trigger:e=>{c=!0,h(e),c=!1}}:x}function D(t,a={}){const{threshold:r=50,onSwipe:o,onSwipeEnd:u,onSwipeStart:s,passive:d=!0}=a,p=k({x:0,y:0}),c=k({x:0,y:0}),f=w(()=>p.x-c.x),v=w(()=>p.y-c.y),{max:b,abs:h}=Math,y=w(()=>b(h(f.value),h(v.value))>=r),E=L(!1),x=w(()=>y.value?h(f.value)>h(v.value)?f.value>0?"left":"right":v.value>0?"up":"down":"none"),e=l=>[l.touches[0].clientX,l.touches[0].clientY],n=(l,g)=>{p.x=l,p.y=g},i=(l,g)=>{c.x=l,c.y=g},m={passive:d,capture:!d},A=l=>{E.value&&u?.(l,x.value),E.value=!1},j=[T(t,"touchstart",l=>{if(l.touches.length!==1)return;const[g,M]=e(l);n(g,M),i(g,M),s?.(l)},m),T(t,"touchmove",l=>{if(l.touches.length!==1)return;const[g,M]=e(l);i(g,M),m.capture&&!m.passive&&Math.abs(f.value)>Math.abs(v.value)&&l.preventDefault(),!E.value&&y.value&&(E.value=!0),E.value&&o?.(l)},m),T(t,["touchend","touchcancel"],A,m)];return{isSwiping:E,direction:x,coordsStart:p,coordsEnd:c,lengthX:f,lengthY:v,stop:()=>j.forEach(l=>l())}}export{D as a,B as o,P as u};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{_ as e,G as t,c as o,t as a,f as c}from"./index-BCgxBvDt.js";const s={name:"localeText",props:{t:""},computed:{getLocaleText(){return t(this.t)}}};function n(r,p,l,_,i,x){return c(),o("span",null,a(this.getLocaleText),1)}const m=e(s,[["render",n]]);export{m as L};
|
||||
import{_ as e,G as t,c as o,t as a,f as c}from"./index-DM7YJCOo.js";const s={name:"localeText",props:{t:""},computed:{getLocaleText(){return t(this.t)}}};function n(r,p,l,_,i,x){return c(),o("span",null,a(this.getLocaleText),1)}const m=e(s,[["render",n]]);export{m as L};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{L as l}from"./localeText-ZTaDi7ZY.js";import{d as c}from"./dayjs.min-By2W00ek.js";import{_ as h,c as o,a as e,b as a,w as u,e as p,h as g,t as i,k as f,n as _,f as n}from"./index-BCgxBvDt.js";const x={name:"message",methods:{dayjs:c,hide(){this.ct(),this.message.show=!1},show(){this.timeout=setTimeout(()=>{this.message.show=!1},5e3)},ct(){clearTimeout(this.timeout)}},components:{LocaleText:l},props:{message:Object},mounted(){this.show()},data(){return{dismiss:!1,timeout:null}}},v=["id"],b={key:0,class:"d-flex"},w={class:"fw-bold d-block",style:{"text-transform":"uppercase"}},y={class:"ms-auto"},k={key:1},T={class:"card-body d-flex align-items-center gap-3"};function M(C,s,L,j,t,m){const d=g("LocaleText");return n(),o("div",{onMouseenter:s[1]||(s[1]=r=>{t.dismiss=!0,this.ct()}),onMouseleave:s[2]||(s[2]=r=>{t.dismiss=!1,this.show()}),class:"card shadow rounded-3 position-relative message ms-auto",id:this.message.id},[e("div",{class:_([{"text-bg-danger":this.message.type==="danger","text-bg-success":this.message.type==="success","text-bg-warning":this.message.type==="warning"},"card-header pos"])},[a(f,{name:"zoom",mode:"out-in"},{default:u(()=>[t.dismiss?(n(),o("div",k,[e("small",{onClick:s[0]||(s[0]=r=>m.hide()),class:"d-block mx-auto w-100 text-center",style:{cursor:"pointer"}},[s[3]||(s[3]=e("i",{class:"bi bi-x-lg me-2"},null,-1)),a(d,{t:"Dismiss"})])])):(n(),o("div",b,[e("small",w,[a(d,{t:"FROM "}),p(" "+i(this.message.from),1)]),e("small",y,i(m.dayjs().format("hh:mm A")),1)]))]),_:1})],2),e("div",T,[e("div",null,i(this.message.content),1)])],40,v)}const z=h(x,[["render",M],["__scopeId","data-v-94c76b54"]]);export{z as M};
|
||||
import{L as l}from"./localeText-BJvnc1lF.js";import{d as c}from"./dayjs.min-DZl6XMNW.js";import{_ as h,c as o,a as e,b as a,w as u,e as p,h as g,t as i,k as f,n as _,f as n}from"./index-DM7YJCOo.js";const x={name:"message",methods:{dayjs:c,hide(){this.ct(),this.message.show=!1},show(){this.timeout=setTimeout(()=>{this.message.show=!1},5e3)},ct(){clearTimeout(this.timeout)}},components:{LocaleText:l},props:{message:Object},mounted(){this.show()},data(){return{dismiss:!1,timeout:null}}},v=["id"],b={key:0,class:"d-flex"},w={class:"fw-bold d-block",style:{"text-transform":"uppercase"}},y={class:"ms-auto"},k={key:1},T={class:"card-body d-flex align-items-center gap-3"};function M(C,s,L,j,t,m){const d=g("LocaleText");return n(),o("div",{onMouseenter:s[1]||(s[1]=r=>{t.dismiss=!0,this.ct()}),onMouseleave:s[2]||(s[2]=r=>{t.dismiss=!1,this.show()}),class:"card shadow rounded-3 position-relative message ms-auto",id:this.message.id},[e("div",{class:_([{"text-bg-danger":this.message.type==="danger","text-bg-success":this.message.type==="success","text-bg-warning":this.message.type==="warning"},"card-header pos"])},[a(f,{name:"zoom",mode:"out-in"},{default:u(()=>[t.dismiss?(n(),o("div",k,[e("small",{onClick:s[0]||(s[0]=r=>m.hide()),class:"d-block mx-auto w-100 text-center",style:{cursor:"pointer"}},[s[3]||(s[3]=e("i",{class:"bi bi-x-lg me-2"},null,-1)),a(d,{t:"Dismiss"})])])):(n(),o("div",b,[e("small",w,[a(d,{t:"FROM "}),p(" "+i(this.message.from),1)]),e("small",y,i(m.dayjs().format("hh:mm A")),1)]))]),_:1})],2),e("div",T,[e("div",null,i(this.message.content),1)])],40,v)}const z=h(x,[["render",M],["__scopeId","data-v-94c76b54"]]);export{z as M};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
.message[data-v-94c76b54]{width:100%}@media screen and (min-width:576px){.message[data-v-94c76b54]{width:400px}}
|
||||
.message[data-v-94c76b54]{width:100%}@media screen and (min-width: 576px){.message[data-v-94c76b54]{width:400px}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{S as C,e as y,c as w,m as _,a as L,f as S,l as v,i as M,b as k,d as x,g as A,h as F,j as R,M as D,V as P,T as b,k as l,O as E,n as O,F as h,P as f,o as T,p as c,C as V,q as u,r as X}from"./Vector-5IlHN0Py.js";import{_ as Y,D as G,c as $,d as j,f as q}from"./index-BCgxBvDt.js";class r extends C{constructor(t,e){super(),this.flatMidpoint_=null,this.flatMidpointRevision_=-1,this.maxDelta_=-1,this.maxDeltaRevision_=-1,e!==void 0&&!Array.isArray(t[0])?this.setFlatCoordinates(e,t):this.setCoordinates(t,e)}appendCoordinate(t){y(this.flatCoordinates,t),this.changed()}clone(){const t=new r(this.flatCoordinates.slice(),this.layout);return t.applyProperties(this),t}closestPointXY(t,e,o,n){return n<w(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(_(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),L(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,this.maxDelta_,!1,t,e,o,n))}forEachSegment(t){return S(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t)}getCoordinateAtM(t,e){return this.layout!="XYM"&&this.layout!="XYZM"?null:(e=e!==void 0?e:!1,v(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e))}getCoordinates(){return M(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)}getCoordinateAt(t,e){return k(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e,this.stride)}getLength(){return x(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)}getFlatMidpoint(){return this.flatMidpointRevision_!=this.getRevision()&&(this.flatMidpoint_=this.getCoordinateAt(.5,this.flatMidpoint_??void 0),this.flatMidpointRevision_=this.getRevision()),this.flatMidpoint_}getSimplifiedGeometryInternal(t){const e=[];return e.length=A(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e,0),new r(e,"XY")}getType(){return"LineString"}intersectsExtent(t){return F(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,this.getExtent())}setCoordinates(t,e){this.setLayout(e,t,1),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=R(this.flatCoordinates,0,t,this.stride),this.changed()}}const B={name:"osmap",props:{type:"",d:Object||Array},data(){return{osmAvailable:!0}},setup(){return{store:G()}},methods:{getLastLonLat(){if(this.type==="traceroute"){const i=this.d.findLast(t=>t.geo&&t.geo.lat&&t.geo.lon);return i?[i.geo.lon,i.geo.lat]:[0,0]}return[this.d.geo.lon,this.d.geo.lat]}},async mounted(){await fetch("https://tile.openstreetmap.org/",{signal:AbortSignal.timeout(1500)}).then(i=>{const t=new D({target:"map",layers:[new b({source:new E})],view:new P({center:l(this.getLastLonLat()),zoom:this.type==="traceroute"?3:10})}),e=[],o=new O;if(this.type==="traceroute")this.d.forEach(s=>{if(s.geo&&s.geo.lat&&s.geo.lon){const a=l([s.geo.lon,s.geo.lat]);e.push(a);const g=this.getLastLonLat(),m=new h({geometry:new f(a),last:s.geo.lon===g[0]&&s.geo.lat===g[1]});o.addFeature(m)}});else{const s=l([this.d.geo.lon,this.d.geo.lat]);e.push(s);const a=new h({geometry:new f(s)});o.addFeature(a)}const n=new r(e),d=new h({geometry:n});o.addFeature(d);const p=new T({source:o,style:function(s){if(s.getGeometry().getType()==="Point")return new c({image:new V({radius:10,fill:new X({color:s.get("last")?"#dc3545":"#0d6efd"}),stroke:new u({color:"white",width:5})})});if(s.getGeometry().getType()==="LineString")return new c({stroke:new u({color:"#0d6efd",width:2})})}});t.addLayer(p)}).catch(i=>{this.osmAvailable=!1})}},z={key:0,id:"map",class:"w-100 rounded-3"};function I(i,t,e,o,n,d){return this.osmAvailable?(q(),$("div",z)):j("",!0)}const H=Y(B,[["render",I]]);export{H as O};
|
||||
import{S as C,e as y,c as w,m as _,a as L,f as S,l as v,i as M,b as k,d as x,g as A,h as F,j as R,M as D,V as P,T as b,k as l,O as E,n as O,F as h,P as f,o as T,p as c,C as V,q as u,r as X}from"./Vector-CuSZivra.js";import{_ as Y,D as G,c as $,d as j,f as q}from"./index-DM7YJCOo.js";class r extends C{constructor(t,e){super(),this.flatMidpoint_=null,this.flatMidpointRevision_=-1,this.maxDelta_=-1,this.maxDeltaRevision_=-1,e!==void 0&&!Array.isArray(t[0])?this.setFlatCoordinates(e,t):this.setCoordinates(t,e)}appendCoordinate(t){y(this.flatCoordinates,t),this.changed()}clone(){const t=new r(this.flatCoordinates.slice(),this.layout);return t.applyProperties(this),t}closestPointXY(t,e,o,n){return n<w(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(_(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),L(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,this.maxDelta_,!1,t,e,o,n))}forEachSegment(t){return S(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t)}getCoordinateAtM(t,e){return this.layout!="XYM"&&this.layout!="XYZM"?null:(e=e!==void 0?e:!1,v(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e))}getCoordinates(){return M(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)}getCoordinateAt(t,e){return k(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e,this.stride)}getLength(){return x(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)}getFlatMidpoint(){return this.flatMidpointRevision_!=this.getRevision()&&(this.flatMidpoint_=this.getCoordinateAt(.5,this.flatMidpoint_??void 0),this.flatMidpointRevision_=this.getRevision()),this.flatMidpoint_}getSimplifiedGeometryInternal(t){const e=[];return e.length=A(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e,0),new r(e,"XY")}getType(){return"LineString"}intersectsExtent(t){return F(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,this.getExtent())}setCoordinates(t,e){this.setLayout(e,t,1),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=R(this.flatCoordinates,0,t,this.stride),this.changed()}}const B={name:"osmap",props:{type:"",d:Object||Array},data(){return{osmAvailable:!0}},setup(){return{store:G()}},methods:{getLastLonLat(){if(this.type==="traceroute"){const i=this.d.findLast(t=>t.geo&&t.geo.lat&&t.geo.lon);return i?[i.geo.lon,i.geo.lat]:[0,0]}return[this.d.geo.lon,this.d.geo.lat]}},async mounted(){await fetch("https://tile.openstreetmap.org/",{signal:AbortSignal.timeout(1500)}).then(i=>{const t=new D({target:"map",layers:[new b({source:new E})],view:new P({center:l(this.getLastLonLat()),zoom:this.type==="traceroute"?3:10})}),e=[],o=new O;if(this.type==="traceroute")this.d.forEach(s=>{if(s.geo&&s.geo.lat&&s.geo.lon){const a=l([s.geo.lon,s.geo.lat]);e.push(a);const g=this.getLastLonLat(),m=new h({geometry:new f(a),last:s.geo.lon===g[0]&&s.geo.lat===g[1]});o.addFeature(m)}});else{const s=l([this.d.geo.lon,this.d.geo.lat]);e.push(s);const a=new h({geometry:new f(s)});o.addFeature(a)}const n=new r(e),d=new h({geometry:n});o.addFeature(d);const p=new T({source:o,style:function(s){if(s.getGeometry().getType()==="Point")return new c({image:new V({radius:10,fill:new X({color:s.get("last")?"#dc3545":"#0d6efd"}),stroke:new u({color:"white",width:5})})});if(s.getGeometry().getType()==="LineString")return new c({stroke:new u({color:"#0d6efd",width:2})})}});t.addLayer(p)}).catch(i=>{this.osmAvailable=!1})}},z={key:0,id:"map",class:"w-100 rounded-3"};function I(i,t,e,o,n,d){return this.osmAvailable?(q(),$("div",z)):j("",!0)}const H=Y(B,[["render",I]]);export{H as O};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
import{_ as v,D as g,r as o,o as h,L as x,g as y,c as i,f as n,a as s,b as c,d as w,n as C,w as k,k as F}from"./index-DM7YJCOo.js";import{L as T}from"./localeText-BJvnc1lF.js";import"./browser-CUYUHo3j.js";import"./galois-field-I2lBzzs-.js";const M={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0"},S={class:"container d-flex h-100 w-100"},D={class:"m-auto modal-dialog-centered dashboardModal justify-content-center"},L={class:"card rounded-3 shadow w-100"},P={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0"},B={class:"mb-0"},G={class:"card-body p-4 d-flex flex-column gap-3"},N={style:{height:"300px"},class:"d-flex"},V=["value"],j={key:0,class:"spinner-border m-auto",role:"status"},I={class:"d-flex"},W=["disabled"],$={key:0,class:"d-block"},q={key:1,class:"d-block",id:"check"},z={__name:"peerConfigurationFile",props:{selectedPeer:Object},emits:["close"],setup(u,{emit:p}){const m=p,f=u,r=g(),t=o(!1),l=o(""),a=o(!0);o({error:!1,message:void 0}),h(()=>{const d=x();y("/api/downloadPeer/"+d.params.id,{id:f.selectedPeer.id},e=>{e.status?(l.value=e.data.file,a.value=!1):this.dashboardStore.newMessage("Server",e.message,"danger")})});const b=async()=>{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(l.value).then(()=>{t.value=!0,setTimeout(()=>{t.value=!1},3e3)}).catch(()=>{r.newMessage("WGDashboard","Failed to copy","danger")}):(document.querySelector("#peerConfigurationFile").select(),document.execCommand("copy")?(t.value=!0,setTimeout(()=>{t.value=!1},3e3)):r.newMessage("WGDashboard","Failed to copy","danger"))};return(d,e)=>(n(),i("div",M,[s("div",S,[s("div",D,[s("div",L,[s("div",P,[s("h4",B,[c(T,{t:"Peer Configuration File"})]),s("button",{type:"button",class:"btn-close ms-auto",onClick:e[0]||(e[0]=_=>m("close"))})]),s("div",G,[s("div",N,[s("textarea",{style:{height:"300px"},class:C(["form-control w-100 rounded-3 animate__fadeIn animate__faster animate__animated",{"d-none":a.value}]),id:"peerConfigurationFile",value:l.value},null,10,V),a.value?(n(),i("div",j,[...e[2]||(e[2]=[s("span",{class:"visually-hidden"},"Loading...",-1)])])):w("",!0)]),s("div",I,[s("button",{onClick:e[1]||(e[1]=_=>b()),disabled:t.value||a.value,class:"ms-auto btn bg-primary-subtle border-primary-subtle text-primary-emphasis rounded-3 position-relative"},[c(F,{name:"slide-up",mode:"out-in"},{default:k(()=>[t.value?(n(),i("span",q,[...e[4]||(e[4]=[s("i",{class:"bi bi-check-circle-fill"},null,-1)])])):(n(),i("span",$,[...e[3]||(e[3]=[s("i",{class:"bi bi-clipboard-fill"},null,-1)])]))]),_:1})],8,W)])])])])])]))}},H=v(z,[["__scopeId","data-v-b0ea2d46"]]);export{H as default};
|
||||
@@ -1 +0,0 @@
|
||||
import{_ as v,D as g,o as h,L as x,g as y,r as d,c as o,f as i,a as s,b as c,d as w,n as C,w as k,k as F}from"./index-BCgxBvDt.js";import{L as T}from"./localeText-ZTaDi7ZY.js";import"./browser-ZR_b4Y9v.js";import"./galois-field-I2lBzzs-.js";const M={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0"},S={class:"container d-flex h-100 w-100"},D={class:"m-auto modal-dialog-centered dashboardModal justify-content-center"},L={class:"card rounded-3 shadow w-100"},P={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0"},B={class:"mb-0"},G={class:"card-body p-4 d-flex flex-column gap-3"},N={style:{height:"300px"},class:"d-flex"},V=["value"],j={key:0,class:"spinner-border m-auto",role:"status"},I={class:"d-flex"},W=["disabled"],$={key:0,class:"d-block"},q={key:1,class:"d-block",id:"check"},z={__name:"peerConfigurationFile",props:{selectedPeer:Object},emits:["close"],setup(u,{emit:p}){const m=p,f=u,r=g(),t=d(!1),n=d(""),a=d(!0);h(()=>{const l=x();y("/api/downloadPeer/"+l.params.id,{id:f.selectedPeer.id},e=>{e.status?(n.value=e.data.file,a.value=!1):this.dashboardStore.newMessage("Server",e.message,"danger")})});const b=async()=>{navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(n.value).then(()=>{t.value=!0,setTimeout(()=>{t.value=!1},3e3)}).catch(()=>{r.newMessage("WGDashboard","Failed to copy","danger")}):(document.querySelector("#peerConfigurationFile").select(),document.execCommand("copy")?(t.value=!0,setTimeout(()=>{t.value=!1},3e3)):r.newMessage("WGDashboard","Failed to copy","danger"))};return(l,e)=>(i(),o("div",M,[s("div",S,[s("div",D,[s("div",L,[s("div",P,[s("h4",B,[c(T,{t:"Peer Configuration File"})]),s("button",{type:"button",class:"btn-close ms-auto",onClick:e[0]||(e[0]=_=>m("close"))})]),s("div",G,[s("div",N,[s("textarea",{style:{height:"300px"},class:C(["form-control w-100 rounded-3 animate__fadeIn animate__faster animate__animated",{"d-none":a.value}]),id:"peerConfigurationFile",value:n.value},null,10,V),a.value?(i(),o("div",j,[...e[2]||(e[2]=[s("span",{class:"visually-hidden"},"Loading...",-1)])])):w("",!0)]),s("div",I,[s("button",{onClick:e[1]||(e[1]=_=>b()),disabled:t.value||a.value,class:"ms-auto btn bg-primary-subtle border-primary-subtle text-primary-emphasis rounded-3 position-relative"},[c(F,{name:"slide-up",mode:"out-in"},{default:k(()=>[t.value?(i(),o("span",q,[...e[4]||(e[4]=[s("i",{class:"bi bi-check-circle-fill"},null,-1)])])):(i(),o("span",$,[...e[3]||(e[3]=[s("i",{class:"bi bi-clipboard-fill"},null,-1)])]))]),_:1})],8,W)])])])])])]))}},H=v(z,[["__scopeId","data-v-b0ea2d46"]]);export{H as default};
|
||||
@@ -1 +0,0 @@
|
||||
import{L as o}from"./localeText-ZTaDi7ZY.js";import{P as t}from"./peersDefaultSettingsInput-DSctHfye.js";import{B as s,c as l,a,b as e,f as n}from"./index-BCgxBvDt.js";const r={class:"d-flex gap-3 flex-column"},i={class:"card rounded-3"},d={class:"card-header"},c={class:"my-2"},_={class:"card-body"},D=s({__name:"peerDefaultSettings",setup(p){return(g,m)=>(n(),l("div",r,[a("div",i,[a("div",d,[a("h6",c,[e(o,{t:"Peer Default Settings"})])]),a("div",_,[a("div",null,[e(t,{targetData:"peer_global_dns",title:"DNS"}),e(t,{targetData:"peer_endpoint_allowed_ip",title:"Endpoint Allowed IPs"}),e(t,{targetData:"peer_mtu",title:"MTU"}),e(t,{targetData:"peer_keep_alive",title:"Persistent Keepalive"}),e(t,{targetData:"remote_endpoint",title:"Peer Remote Endpoint",warning:!0,warningText:"This will be changed globally, and will be apply to all peer's QR code and configuration file."})])])])]))}});export{D as default};
|
||||
@@ -0,0 +1 @@
|
||||
import{L as r}from"./localeText-BJvnc1lF.js";import{P as t}from"./peersDefaultSettingsInput-n69y01QP.js";import{B as l,c as o,a,b as e,f as s}from"./index-DM7YJCOo.js";const n={class:"d-flex gap-3 flex-column"},i={class:"card rounded-3"},d={class:"card-header"},_={class:"my-2"},c={class:"card-body"},D=l({__name:"peerDefaultSettings",setup(p){return(f,g)=>(s(),o("div",n,[a("div",i,[a("div",d,[a("h6",_,[e(r,{t:"Peer Default Settings"})])]),a("div",c,[a("div",null,[e(t,{targetData:"peer_global_dns",title:"DNS"}),e(t,{targetData:"peer_endpoint_allowed_ip",title:"Endpoint Allowed IPs"}),e(t,{targetData:"peer_mtu",title:"MTU"}),e(t,{targetData:"peer_keep_alive",title:"Persistent Keepalive"}),e(t,{targetData:"peer_preshared_key_default",title:"Pre-Shared Key Default"}),e(t,{targetData:"remote_endpoint",title:"Peer Remote Endpoint",warning:!0,warningText:"This will be changed globally, and will be apply to all peer's QR code and configuration file."})])])])]))}});export{D as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{a as p,S as b}from"./schedulePeerJob-Bkf8s8xv.js";import{_ as h,h as i,c as a,f as s,a as e,b as r,w as u,d as m,F as _,i as f,j as v,T as J,A as x,W as g}from"./index-BCgxBvDt.js";import{L as w}from"./localeText-ZTaDi7ZY.js";import"./vue-datepicker-B-Few8JH.js";import"./index-D9MDCdu-.js";import"./dayjs.min-By2W00ek.js";const P={name:"peerJobs",setup(){return{store:g()}},props:{selectedPeer:Object},components:{LocaleText:w,SchedulePeerJob:b,ScheduleDropdown:p},data(){return{}},methods:{deleteJob(d){this.selectedPeer.jobs=this.selectedPeer.jobs.filter(t=>t.JobID!==d.JobID)},addJob(){this.selectedPeer.jobs.unshift(JSON.parse(JSON.stringify({JobID:x().toString(),Configuration:this.selectedPeer.configuration.Name,Peer:this.selectedPeer.id,Field:this.store.PeerScheduleJobs.dropdowns.Field[0].value,Operator:this.store.PeerScheduleJobs.dropdowns.Operator[0].value,Value:"",CreationDate:"",ExpireDate:"",Action:this.store.PeerScheduleJobs.dropdowns.Action[0].value})))}}},S={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll"},y={class:"container d-flex h-100 w-100"},$={class:"m-auto modal-dialog-centered dashboardModal"},C={class:"card rounded-3 shadow",style:{width:"700px"}},D={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2"},j={class:"mb-0 fw-normal"},k={class:"card-body px-4 pb-4 pt-2 position-relative"},T={class:"d-flex align-items-center mb-3"},N={class:"card shadow-sm",key:"none",style:{height:"153px"}},I={class:"card-body text-muted text-center d-flex"},L={class:"m-auto"};function O(d,t,B,F,V,A){const n=i("LocaleText"),l=i("SchedulePeerJob");return s(),a("div",S,[e("div",y,[e("div",$,[e("div",C,[e("div",D,[e("h4",j,[r(n,{t:"Schedule Jobs"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:t[0]||(t[0]=o=>this.$emit("close"))})]),e("div",k,[e("div",T,[e("button",{class:"btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow",onClick:t[1]||(t[1]=o=>this.addJob())},[t[3]||(t[3]=e("i",{class:"bi bi-plus-lg me-2"},null,-1)),r(n,{t:"Job"})])]),r(J,{name:"schedulePeerJobTransition",tag:"div",class:"position-relative"},{default:u(()=>[(s(!0),a(_,null,f(this.selectedPeer.jobs,(o,E)=>(s(),v(l,{onRefresh:t[2]||(t[2]=c=>this.$emit("refresh")),onDelete:c=>this.deleteJob(o),dropdowns:this.store.PeerScheduleJobs.dropdowns,key:o.JobID,pjob:o},null,8,["onDelete","dropdowns","pjob"]))),128)),this.selectedPeer.jobs.length===0?(s(),a("div",N,[e("div",I,[e("h6",L,[r(n,{t:"This peer does not have any job yet."})])])])):m("",!0)]),_:1})])])])])])}const H=h(P,[["render",O],["__scopeId","data-v-5bbdd42b"]]);export{H as default};
|
||||
import{a as p,S as b}from"./schedulePeerJob-jjF9HAtj.js";import{_ as h,h as i,c as a,f as s,a as e,b as r,w as u,d as m,F as _,i as f,j as v,T as J,A as x,W as g}from"./index-DM7YJCOo.js";import{L as w}from"./localeText-BJvnc1lF.js";import"./vue-datepicker-9N8DgATH.js";import"./index-i3npkoSo.js";import"./dayjs.min-DZl6XMNW.js";const P={name:"peerJobs",setup(){return{store:g()}},props:{selectedPeer:Object},components:{LocaleText:w,SchedulePeerJob:b,ScheduleDropdown:p},data(){return{}},methods:{deleteJob(d){this.selectedPeer.jobs=this.selectedPeer.jobs.filter(t=>t.JobID!==d.JobID)},addJob(){this.selectedPeer.jobs.unshift(JSON.parse(JSON.stringify({JobID:x().toString(),Configuration:this.selectedPeer.configuration.Name,Peer:this.selectedPeer.id,Field:this.store.PeerScheduleJobs.dropdowns.Field[0].value,Operator:this.store.PeerScheduleJobs.dropdowns.Operator[0].value,Value:"",CreationDate:"",ExpireDate:"",Action:this.store.PeerScheduleJobs.dropdowns.Action[0].value})))}}},S={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll"},y={class:"container d-flex h-100 w-100"},$={class:"m-auto modal-dialog-centered dashboardModal"},C={class:"card rounded-3 shadow",style:{width:"700px"}},D={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2"},j={class:"mb-0 fw-normal"},k={class:"card-body px-4 pb-4 pt-2 position-relative"},T={class:"d-flex align-items-center mb-3"},N={class:"card shadow-sm",key:"none",style:{height:"153px"}},I={class:"card-body text-muted text-center d-flex"},L={class:"m-auto"};function O(d,t,B,F,V,A){const n=i("LocaleText"),l=i("SchedulePeerJob");return s(),a("div",S,[e("div",y,[e("div",$,[e("div",C,[e("div",D,[e("h4",j,[r(n,{t:"Schedule Jobs"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:t[0]||(t[0]=o=>this.$emit("close"))})]),e("div",k,[e("div",T,[e("button",{class:"btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow",onClick:t[1]||(t[1]=o=>this.addJob())},[t[3]||(t[3]=e("i",{class:"bi bi-plus-lg me-2"},null,-1)),r(n,{t:"Job"})])]),r(J,{name:"schedulePeerJobTransition",tag:"div",class:"position-relative"},{default:u(()=>[(s(!0),a(_,null,f(this.selectedPeer.jobs,(o,E)=>(s(),v(l,{onRefresh:t[2]||(t[2]=c=>this.$emit("refresh")),onDelete:c=>this.deleteJob(o),dropdowns:this.store.PeerScheduleJobs.dropdowns,key:o.JobID,pjob:o},null,8,["onDelete","dropdowns","pjob"]))),128)),this.selectedPeer.jobs.length===0?(s(),a("div",N,[e("div",I,[e("h6",L,[r(n,{t:"This peer does not have any job yet."})])])])):m("",!0)]),_:1})])])])])])}const H=h(P,[["render",O],["__scopeId","data-v-5bbdd42b"]]);export{H as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{S as _}from"./schedulePeerJob-Bkf8s8xv.js";import{_ as g,h as c,c as r,f as t,a as e,b as l,F as p,i as b,d as f,t as m,j as v,W as y}from"./index-BCgxBvDt.js";import{L as x}from"./localeText-ZTaDi7ZY.js";import"./vue-datepicker-B-Few8JH.js";import"./index-D9MDCdu-.js";import"./dayjs.min-By2W00ek.js";const J={name:"peerJobsAllModal",setup(){return{store:y()}},components:{LocaleText:x,SchedulePeerJob:_},props:{configurationPeers:Array[Object]},computed:{getAllJobs(){return this.configurationPeers.filter(a=>a.jobs.length>0)}}},w={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll"},$={class:"container d-flex h-100 w-100"},k={class:"m-auto modal-dialog-centered dashboardModal"},A={class:"card rounded-3 shadow",style:{width:"900px"}},L={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2"},S={class:"mb-0 fw-normal"},j={class:"card-body px-4 pb-4 pt-2"},C={key:0,class:"accordion",id:"peerJobsLogsModalAccordion"},P={class:"accordion-header"},M=["data-bs-target"],B={key:0},N={class:"text-muted"},D=["id"],T={class:"accordion-body"},V={key:1,class:"card shadow-sm",style:{height:"153px"}},F={class:"card-body text-muted text-center d-flex"},O={class:"m-auto"};function W(a,o,E,I,R,q){const n=c("LocaleText"),u=c("SchedulePeerJob");return t(),r("div",w,[e("div",$,[e("div",k,[e("div",A,[e("div",L,[e("h4",S,[l(n,{t:"All Active Jobs"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:o[0]||(o[0]=s=>this.$emit("close"))})]),e("div",j,[e("button",{class:"btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow mb-2",onClick:o[1]||(o[1]=s=>this.$emit("allLogs"))},[o[4]||(o[4]=e("i",{class:"bi bi-clock me-2"},null,-1)),l(n,{t:"Logs"})]),this.getAllJobs.length>0?(t(),r("div",C,[(t(!0),r(p,null,b(this.getAllJobs,(s,d)=>(t(),r("div",{class:"accordion-item",key:s.id},[e("h2",P,[e("button",{class:"accordion-button collapsed",type:"button","data-bs-toggle":"collapse","data-bs-target":"#collapse_"+d},[e("small",null,[e("strong",null,[s.name?(t(),r("span",B,m(s.name)+" • ",1)):f("",!0),e("samp",N,m(s.id),1)])])],8,M)]),e("div",{id:"collapse_"+d,class:"accordion-collapse collapse","data-bs-parent":"#peerJobsLogsModalAccordion"},[e("div",T,[(t(!0),r(p,null,b(s.jobs,i=>(t(),v(u,{onDelete:o[2]||(o[2]=h=>this.$emit("refresh")),onRefresh:o[3]||(o[3]=h=>this.$emit("refresh")),dropdowns:this.store.PeerScheduleJobs.dropdowns,viewOnly:!0,key:i.JobID,pjob:i},null,8,["dropdowns","pjob"]))),128))])],8,D)]))),128))])):(t(),r("div",V,[e("div",F,[e("span",O,[l(n,{t:"No active job at the moment."})])])]))])])])])])}const X=g(J,[["render",W]]);export{X as default};
|
||||
import{S as _}from"./schedulePeerJob-jjF9HAtj.js";import{_ as g,h as c,c as r,f as t,a as e,b as l,F as p,i as b,d as f,t as m,j as v,W as y}from"./index-DM7YJCOo.js";import{L as x}from"./localeText-BJvnc1lF.js";import"./vue-datepicker-9N8DgATH.js";import"./index-i3npkoSo.js";import"./dayjs.min-DZl6XMNW.js";const J={name:"peerJobsAllModal",setup(){return{store:y()}},components:{LocaleText:x,SchedulePeerJob:_},props:{configurationPeers:Array[Object]},computed:{getAllJobs(){return this.configurationPeers.filter(a=>a.jobs.length>0)}}},w={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll"},$={class:"container d-flex h-100 w-100"},k={class:"m-auto modal-dialog-centered dashboardModal"},A={class:"card rounded-3 shadow",style:{width:"900px"}},L={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2"},S={class:"mb-0 fw-normal"},j={class:"card-body px-4 pb-4 pt-2"},C={key:0,class:"accordion",id:"peerJobsLogsModalAccordion"},P={class:"accordion-header"},M=["data-bs-target"],B={key:0},N={class:"text-muted"},D=["id"],T={class:"accordion-body"},V={key:1,class:"card shadow-sm",style:{height:"153px"}},F={class:"card-body text-muted text-center d-flex"},O={class:"m-auto"};function W(a,o,E,I,R,q){const n=c("LocaleText"),u=c("SchedulePeerJob");return t(),r("div",w,[e("div",$,[e("div",k,[e("div",A,[e("div",L,[e("h4",S,[l(n,{t:"All Active Jobs"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:o[0]||(o[0]=s=>this.$emit("close"))})]),e("div",j,[e("button",{class:"btn bg-primary-subtle border-1 border-primary-subtle text-primary-emphasis rounded-3 shadow mb-2",onClick:o[1]||(o[1]=s=>this.$emit("allLogs"))},[o[4]||(o[4]=e("i",{class:"bi bi-clock me-2"},null,-1)),l(n,{t:"Logs"})]),this.getAllJobs.length>0?(t(),r("div",C,[(t(!0),r(p,null,b(this.getAllJobs,(s,d)=>(t(),r("div",{class:"accordion-item",key:s.id},[e("h2",P,[e("button",{class:"accordion-button collapsed",type:"button","data-bs-toggle":"collapse","data-bs-target":"#collapse_"+d},[e("small",null,[e("strong",null,[s.name?(t(),r("span",B,m(s.name)+" • ",1)):f("",!0),e("samp",N,m(s.id),1)])])],8,M)]),e("div",{id:"collapse_"+d,class:"accordion-collapse collapse","data-bs-parent":"#peerJobsLogsModalAccordion"},[e("div",T,[(t(!0),r(p,null,b(s.jobs,i=>(t(),v(u,{onDelete:o[2]||(o[2]=h=>this.$emit("refresh")),onRefresh:o[3]||(o[3]=h=>this.$emit("refresh")),dropdowns:this.store.PeerScheduleJobs.dropdowns,viewOnly:!0,key:i.JobID,pjob:i},null,8,["dropdowns","pjob"]))),128))])],8,D)]))),128))])):(t(),r("div",V,[e("div",F,[e("span",O,[l(n,{t:"No active job at the moment."})])])]))])])])])])}const X=g(J,[["render",W]]);export{X as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.icon[data-v-3c48f50e]{flex:1;min-width:30px;max-width:30px;width:30px;aspect-ratio:1 / 1}.icon[data-v-accdf15e]{flex:1;aspect-ratio:1 / 1}#peerTag[data-v-ab3e5c4e]{width:300px;position:absolute;right:0;z-index:9999;margin-top:2px}.animation__fadeInDropdown[data-v-71502547]{animation-name:fadeInDropdown-71502547;animation-duration:.2s;animation-timing-function:cubic-bezier(.82,.58,.17,.9)}@keyframes fadeInDropdown-71502547{0%{opacity:0;filter:blur(3px);transform:translateY(-60px)}to{opacity:1;filter:blur(0px);transform:translateY(-40px)}}.displayModal .dashboardModal[data-v-71502547]{width:400px!important}@media screen and (max-width: 992px){.peerSearchContainer[data-v-71502547]{flex-direction:column}.peerSettingContainer .dashboardModal[data-v-71502547]{width:100%!important}}.peerSearchContainer>button[data-v-71502547],.peerSearchContainer .dropdown>button[data-v-71502547]{text-align:left;display:flex;align-items:center}span[data-v-d4e41a56]{top:-34px;left:0}.dropdown-menu[data-v-18549c26]{right:0;min-width:200px}.dropdown-menu.dropup[data-v-18549c26]{bottom:100%}.dropdown-item.disabled[data-v-18549c26],.dropdown-item[data-v-18549c26]:disabled{opacity:.7}.confirmDelete[data-v-18549c26]{padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x)}.subMenuBtn.active[data-v-f38d3291]{background-color:#ffffff20}.peerCard[data-v-f38d3291]{transition:box-shadow .1s cubic-bezier(.82,.58,.17,.9)}.peerCard[data-v-f38d3291]:hover{box-shadow:var(--bs-box-shadow)!important}@media screen and (max-width: 992px){.calendar-day .session-badge-list[data-v-5178a57b],.sessions-label[data-v-5178a57b]{display:none}}.session-list[data-v-5178a57b]{aspect-ratio:1 / 1}@media screen and (min-width: 992px){.session-dot[data-v-5178a57b]{display:none!important}.session-list[data-v-5178a57b]{height:12.5vh;overflow:scroll;aspect-ratio:auto!important}}.calendar-grid[data-v-3b03c7a5]{display:grid;grid-template-areas:"sun mon tue wed thu fri sat";grid-template-columns:repeat(7,1fr)}.calendar-day.day-6[data-v-3b03c7a5]{border-right:none!important}.calendar-day[data-v-3b03c7a5]{min-height:150px}@media screen and (max-width: 992px){.calendar-day[data-v-3b03c7a5]{min-height:100px!important}}@media screen and (min-width: 992px){.dayDetail[data-v-3b03c7a5]{display:none}}.extra-day .day-label[data-v-3b03c7a5]{opacity:.5}.peerNav .nav-link{&.active[data-v-b4fba9bc]{background-color:#efefef}}th[data-v-b4fba9bc],td[data-v-b4fba9bc]{background-color:transparent!important}@media screen and (max-width: 576px){.titleBtn[data-v-b4fba9bc]{flex-basis:100%}}
|
||||
@@ -1 +0,0 @@
|
||||
.icon[data-v-3c48f50e]{flex:1;min-width:30px;max-width:30px;width:30px;aspect-ratio:1 / 1}.icon[data-v-accdf15e]{flex:1;aspect-ratio:1 / 1}#peerTag[data-v-ab3e5c4e]{width:300px;position:absolute;right:0;z-index:9999;margin-top:2px}.animation__fadeInDropdown[data-v-71502547]{animation-name:fadeInDropdown-71502547;animation-duration:.2s;animation-timing-function:cubic-bezier(.82,.58,.17,.9)}@keyframes fadeInDropdown-71502547{0%{opacity:0;filter:blur(3px);transform:translateY(-60px)}to{opacity:1;filter:blur(0px);transform:translateY(-40px)}}.displayModal .dashboardModal[data-v-71502547]{width:400px!important}@media screen and (max-width:992px){.peerSearchContainer[data-v-71502547]{flex-direction:column}.peerSettingContainer .dashboardModal[data-v-71502547]{width:100%!important}}.peerSearchContainer>button[data-v-71502547],.peerSearchContainer .dropdown>button[data-v-71502547]{text-align:left;display:flex;align-items:center}span[data-v-d4e41a56]{top:-34px;left:0}.dropdown-menu[data-v-18549c26]{right:0;min-width:200px}.dropdown-menu.dropup[data-v-18549c26]{bottom:100%}.dropdown-item.disabled[data-v-18549c26],.dropdown-item[data-v-18549c26]:disabled{opacity:.7}.confirmDelete[data-v-18549c26]{padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x)}.subMenuBtn.active[data-v-f38d3291]{background-color:#ffffff20}.peerCard[data-v-f38d3291]{transition:box-shadow .1s cubic-bezier(.82,.58,.17,.9)}.peerCard[data-v-f38d3291]:hover{box-shadow:var(--bs-box-shadow)!important}@media screen and (max-width:992px){.calendar-day .session-badge-list[data-v-5178a57b],.sessions-label[data-v-5178a57b]{display:none}}.session-list[data-v-5178a57b]{aspect-ratio:1 / 1}@media screen and (min-width:992px){.session-dot[data-v-5178a57b]{display:none!important}.session-list[data-v-5178a57b]{height:12.5vh;overflow:scroll;aspect-ratio:auto!important}}.calendar-grid[data-v-3b03c7a5]{display:grid;grid-template-areas:"sun mon tue wed thu fri sat";grid-template-columns:repeat(7,1fr)}.calendar-day.day-6[data-v-3b03c7a5]{border-right:none!important}.calendar-day[data-v-3b03c7a5]{min-height:150px}@media screen and (max-width:992px){.calendar-day[data-v-3b03c7a5]{min-height:100px!important}}@media screen and (min-width:992px){.dayDetail[data-v-3b03c7a5]{display:none}}.extra-day .day-label[data-v-3b03c7a5]{opacity:.5}.peerNav .nav-link{&.active[data-v-b4fba9bc]{background-color:#efefef}}th[data-v-b4fba9bc],td[data-v-b4fba9bc]{background-color:transparent!important}@media screen and (max-width:576px){.titleBtn[data-v-b4fba9bc]{flex-basis:100%}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
@media screen and (max-width: 768px){.qrcode[data-v-02f2240d]{width:100%!important;height:auto!important;aspect-ratio:1/1}}.qrcode[data-v-02f2240d]{width:200px!important;height:200px!important}
|
||||
@@ -1 +0,0 @@
|
||||
@media screen and (max-width:768px){.qrcode[data-v-02f2240d]{width:100%!important;height:auto!important;aspect-ratio:1/1}}.qrcode[data-v-02f2240d]{width:200px!important;height:200px!important}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{Q as l}from"./browser-ZR_b4Y9v.js";import{L as _}from"./localeText-ZTaDi7ZY.js";import{_ as h,h as f,c,f as s,a as e,b as p,d as i,j as m,n as u,g,D as v}from"./index-BCgxBvDt.js";import"./galois-field-I2lBzzs-.js";const w={name:"peerQRCode",components:{LocaleText:_},props:{selectedPeer:Object},setup(){return{dashboardStore:v()}},data(){return{loading:!0}},mounted(){g("/api/downloadPeer/"+this.$route.params.id,{id:this.selectedPeer.id},o=>{if(this.loading=!1,o.status){let t="";if(this.selectedPeer.configuration.Protocol==="awg"){let a={containers:[{awg:{isThirdPartyConfig:!0,last_config:o.data.file,port:this.selectedPeer.configuration.ListenPort,transport_proto:"udp"},container:"amnezia-awg"}],defaultContainer:"amnezia-awg",description:this.selectedPeer.name,hostName:this.dashboardStore.Configuration.Peers.remote_endpoint};l.toCanvas(document.querySelector("#awg_vpn_qrcode"),btoa(JSON.stringify(a)),d=>{d&&console.error(d)})}t=o.data.file,l.toCanvas(document.querySelector("#qrcode"),t,a=>{a&&console.error(a)})}else this.dashboardStore.newMessage("Server",o.message,"danger")})}},b={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0"},x={class:"container d-flex h-100 w-100"},P={class:"m-auto modal-dialog-centered dashboardModal justify-content-center"},C={class:"card rounded-3 shadow"},y={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0"},S={class:"mb-0"},k={class:"card-body p-4"},q={class:"d-flex gap-2 flex-column"},L={class:"d-flex flex-column gap-2 align-items-center"},N={key:0,class:"d-flex flex-column gap-2 align-items-center"},Q={key:1,class:"spinner-border m-auto",role:"status"};function z(o,t,a,d,r,A){const n=f("LocaleText");return s(),c("div",b,[e("div",x,[e("div",P,[e("div",C,[e("div",y,[e("h4",S,[p(n,{t:"QR Code"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:t[0]||(t[0]=R=>this.$emit("close"))})]),e("div",k,[e("div",q,[e("div",L,[e("canvas",{id:"qrcode",style:{width:"200px !important",height:"200px !important"},class:u(["rounded-3 shadow animate__animated animate__fadeIn animate__faster qrcode",{"d-none":r.loading}])},null,2),this.selectedPeer.configuration.Protocol==="wg"?(s(),m(n,{key:0,t:"Scan with WireGuard App",class:"text-muted"})):i("",!0),this.selectedPeer.configuration.Protocol==="awg"?(s(),m(n,{key:1,t:"Scan with AmneziaWG App",class:"text-muted"})):i("",!0)]),this.selectedPeer.configuration.Protocol==="awg"?(s(),c("div",N,[e("canvas",{id:"awg_vpn_qrcode",class:u(["rounded-3 shadow animate__animated animate__fadeIn animate__faster qrcode",{"d-none":r.loading}])},null,2),p(n,{t:"Scan with AmneziaVPN App",class:"text-muted"})])):i("",!0),r.loading?(s(),c("div",Q,[...t[1]||(t[1]=[e("span",{class:"visually-hidden"},"Loading...",-1)])])):i("",!0)])])])])])])}const $=h(w,[["render",z],["__scopeId","data-v-02f2240d"]]);export{$ as default};
|
||||
import{Q as l}from"./browser-CUYUHo3j.js";import{L as _}from"./localeText-BJvnc1lF.js";import{_ as h,h as f,c,f as s,a as e,b as p,d as i,j as m,n as u,g,D as v}from"./index-DM7YJCOo.js";import"./galois-field-I2lBzzs-.js";const w={name:"peerQRCode",components:{LocaleText:_},props:{selectedPeer:Object},setup(){return{dashboardStore:v()}},data(){return{loading:!0}},mounted(){g("/api/downloadPeer/"+this.$route.params.id,{id:this.selectedPeer.id},o=>{if(this.loading=!1,o.status){let t="";if(this.selectedPeer.configuration.Protocol==="awg"){let a={containers:[{awg:{isThirdPartyConfig:!0,last_config:o.data.file,port:this.selectedPeer.configuration.ListenPort,transport_proto:"udp"},container:"amnezia-awg"}],defaultContainer:"amnezia-awg",description:this.selectedPeer.name,hostName:this.dashboardStore.Configuration.Peers.remote_endpoint};l.toCanvas(document.querySelector("#awg_vpn_qrcode"),btoa(JSON.stringify(a)),d=>{d&&console.error(d)})}t=o.data.file,l.toCanvas(document.querySelector("#qrcode"),t,a=>{a&&console.error(a)})}else this.dashboardStore.newMessage("Server",o.message,"danger")})}},b={class:"peerSettingContainer w-100 h-100 position-absolute top-0 start-0"},x={class:"container d-flex h-100 w-100"},P={class:"m-auto modal-dialog-centered dashboardModal justify-content-center"},C={class:"card rounded-3 shadow"},y={class:"card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-0"},S={class:"mb-0"},k={class:"card-body p-4"},q={class:"d-flex gap-2 flex-column"},L={class:"d-flex flex-column gap-2 align-items-center"},N={key:0,class:"d-flex flex-column gap-2 align-items-center"},Q={key:1,class:"spinner-border m-auto",role:"status"};function z(o,t,a,d,r,A){const n=f("LocaleText");return s(),c("div",b,[e("div",x,[e("div",P,[e("div",C,[e("div",y,[e("h4",S,[p(n,{t:"QR Code"})]),e("button",{type:"button",class:"btn-close ms-auto",onClick:t[0]||(t[0]=R=>this.$emit("close"))})]),e("div",k,[e("div",q,[e("div",L,[e("canvas",{id:"qrcode",style:{width:"200px !important",height:"200px !important"},class:u(["rounded-3 shadow animate__animated animate__fadeIn animate__faster qrcode",{"d-none":r.loading}])},null,2),this.selectedPeer.configuration.Protocol==="wg"?(s(),m(n,{key:0,t:"Scan with WireGuard App",class:"text-muted"})):i("",!0),this.selectedPeer.configuration.Protocol==="awg"?(s(),m(n,{key:1,t:"Scan with AmneziaWG App",class:"text-muted"})):i("",!0)]),this.selectedPeer.configuration.Protocol==="awg"?(s(),c("div",N,[e("canvas",{id:"awg_vpn_qrcode",class:u(["rounded-3 shadow animate__animated animate__fadeIn animate__faster qrcode",{"d-none":r.loading}])},null,2),p(n,{t:"Scan with AmneziaVPN App",class:"text-muted"})])):i("",!0),r.loading?(s(),c("div",Q,[...t[1]||(t[1]=[e("span",{class:"visually-hidden"},"Loading...",-1)])])):i("",!0)])])])])])])}const $=h(w,[["render",z],["__scopeId","data-v-02f2240d"]]);export{$ as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{_ as p,W as m,r as u,a0 as f,L as h,K as _,o as v,a1 as g,c as x,d as S,f as y,a as s,m as b,y as B,q as w,G as T}from"./index-BCgxBvDt.js";const q={key:0,class:"fixed-bottom w-100 bottom-0 z-2 p-3",style:{"z-index":"1"}},C={class:"d-flex flex-column searchPeersContainer ms-auto p-2 rounded-5",style:{width:"300px"}},P={class:"rounded-5 border border-white p-2 d-flex align-items-center gap-1 w-100"},R=["placeholder"],k={__name:"peerSearchBar",props:["ConfigurationInfo"],emits:["close"],setup(V,{emit:z}){const l=w(()=>T("Search Peers..."));let r;const t=m(),e=u(t.searchString),d=()=>{r?(clearTimeout(r),r=setTimeout(()=>{t.searchString=e.value},300)):r=setTimeout(()=>{t.searchString=e.value},300)};f("searchBar");const a=h(),i=_();a.query.peer&&(e.value=a.query.peer,i.replace({query:null}));const n=u(!0);return v(()=>{document.querySelector("#searchPeers").focus()}),g(()=>{n.value=!1}),(G,o)=>n.value?(y(),x("div",q,[s("div",C,[s("div",P,[b(s("input",{ref:"searchBar",class:"flex-grow-1 form-control form-control-sm rounded-5 bg-transparent border-0 border-secondary-subtle",placeholder:l.value,id:"searchPeers",onKeyup:o[0]||(o[0]=c=>d()),"onUpdate:modelValue":o[1]||(o[1]=c=>e.value=c)},null,40,R),[[B,e.value]])])])])):S("",!0)}},K=p(k,[["__scopeId","data-v-576347d8"]]);export{K as default};
|
||||
import{_ as p,q as m,G as f,W as h,r as u,a0 as _,L as v,K as g,o as x,a1 as S,c as y,d as b,f as B,a as s,m as w,y as T}from"./index-DM7YJCOo.js";const q={key:0,class:"fixed-bottom w-100 bottom-0 z-2 p-3",style:{"z-index":"1"}},C={class:"d-flex flex-column searchPeersContainer ms-auto p-2 rounded-5",style:{width:"300px"}},P={class:"rounded-5 border border-white p-2 d-flex align-items-center gap-1 w-100"},R=["placeholder"],k={__name:"peerSearchBar",props:["ConfigurationInfo"],emits:["close"],setup(V,{emit:z}){const l=m(()=>f("Search Peers..."));let r;const t=h(),e=u(t.searchString),d=()=>{r?(clearTimeout(r),r=setTimeout(()=>{t.searchString=e.value},300)):r=setTimeout(()=>{t.searchString=e.value},300)};_("searchBar");const a=v(),i=g();a.query.peer&&(e.value=a.query.peer,i.replace({query:null}));const n=u(!0);return x(()=>{document.querySelector("#searchPeers").focus()}),S(()=>{n.value=!1}),(G,o)=>n.value?(B(),y("div",q,[s("div",C,[s("div",P,[w(s("input",{ref:"searchBar",class:"flex-grow-1 form-control form-control-sm rounded-5 bg-transparent border-0 border-secondary-subtle",placeholder:l.value,id:"searchPeers",onKeyup:o[0]||(o[0]=c=>d()),"onUpdate:modelValue":o[1]||(o[1]=c=>e.value=c)},null,40,R),[[T,e.value]])])])])):b("",!0)}},K=p(k,[["__scopeId","data-v-576347d8"]]);export{K as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
import{_ as h,c as o,a as e,m as c,d as m,b as d,h as f,y as g,n as v,t as p,z as b,D as w,A as x,f as r}from"./index-BCgxBvDt.js";import{L as _}from"./localeText-ZTaDi7ZY.js";const k={components:{LocaleText:_},props:{targetData:String,title:String,warning:!1,warningText:""},setup(){const s=w(),t=`input_${x()}`;return{store:s,uuid:t}},data(){return{value:"",invalidFeedback:"",showInvalidFeedback:!1,isValid:!1,timeout:void 0,changed:!1,updating:!1}},mounted(){this.value=this.store.Configuration.Peers[this.targetData]},methods:{async useValidation(){this.changed&&await b("/api/updateDashboardConfigurationItem",{section:"Peers",key:this.targetData,value:this.value},s=>{s.status?(this.isValid=!0,this.showInvalidFeedback=!1,this.store.Configuration.Peers[this.targetData]=this.value,clearTimeout(this.timeout),this.timeout=setTimeout(()=>this.isValid=!1,5e3)):(this.isValid=!1,this.showInvalidFeedback=!0,this.invalidFeedback=s.message),this.changed=!1,this.updating=!1})}}},V={class:"form-group mb-2"},D=["for"],y=["id","disabled"],T={class:"invalid-feedback"},C={key:0,class:"px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1"};function F(s,t,a,I,n,u){const l=f("LocaleText");return r(),o("div",V,[e("label",{for:this.uuid,class:"text-muted mb-1"},[e("strong",null,[e("small",null,[d(l,{t:this.title},null,8,["t"])])])],8,D),c(e("input",{type:"text",class:v(["form-control",{"is-invalid":n.showInvalidFeedback,"is-valid":n.isValid}]),id:this.uuid,"onUpdate:modelValue":t[0]||(t[0]=i=>this.value=i),onKeydown:t[1]||(t[1]=i=>this.changed=!0),onBlur:t[2]||(t[2]=i=>u.useValidation()),disabled:this.updating},null,42,y),[[g,this.value]]),e("div",T,p(this.invalidFeedback),1),a.warning?(r(),o("div",C,[e("small",null,[t[3]||(t[3]=e("i",{class:"bi bi-exclamation-triangle-fill me-2"},null,-1)),d(l,{t:a.warningText},null,8,["t"])])])):m("",!0)])}const B=h(k,[["render",F]]);export{B as P};
|
||||
@@ -0,0 +1 @@
|
||||
import{_ as c,c as a,a as t,m as u,d as m,b as h,h as f,v as g,y as v,n as p,t as b,z as k,D as w,A as x,f as n}from"./index-DM7YJCOo.js";import{L as _}from"./localeText-BJvnc1lF.js";const V={components:{LocaleText:_},props:{targetData:String,title:String,warning:!1,warningText:""},setup(){const i=w(),e=`input_${x()}`;return{store:i,uuid:e}},data(){return{value:"",invalidFeedback:"",showInvalidFeedback:!1,isValid:!1,timeout:void 0,changed:!1,updating:!1}},mounted(){this.value=this.store.Configuration.Peers[this.targetData]},computed:{isBoolean(){return typeof this.value=="boolean"}},methods:{async useValidation(){this.changed&&await k("/api/updateDashboardConfigurationItem",{section:"Peers",key:this.targetData,value:this.value},i=>{i.status?(this.isValid=!0,this.showInvalidFeedback=!1,this.store.Configuration.Peers[this.targetData]=this.value,clearTimeout(this.timeout),this.timeout=setTimeout(()=>this.isValid=!1,5e3)):(this.isValid=!1,this.showInvalidFeedback=!0,this.invalidFeedback=i.message),this.changed=!1,this.updating=!1})}}},y={class:"form-group mb-2"},D=["for"],C={key:0,class:"form-check form-switch"},T=["id","disabled"],F=["id","disabled"],B={class:"invalid-feedback"},I={key:2,class:"px-2 py-1 text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2 d-inline-block mt-1"};function P(i,e,l,S,d,o){const r=f("LocaleText");return n(),a("div",y,[t("label",{for:this.uuid,class:"text-muted mb-1"},[t("strong",null,[t("small",null,[h(r,{t:this.title},null,8,["t"])])])],8,D),o.isBoolean?(n(),a("div",C,[u(t("input",{class:"form-check-input",type:"checkbox",role:"switch","onUpdate:modelValue":e[0]||(e[0]=s=>this.value=s),id:this.uuid,onChange:e[1]||(e[1]=s=>{this.changed=!0,o.useValidation()}),disabled:this.updating},null,40,T),[[g,this.value]])])):u((n(),a("input",{key:1,type:"text",class:p(["form-control",{"is-invalid":d.showInvalidFeedback,"is-valid":d.isValid}]),id:this.uuid,"onUpdate:modelValue":e[2]||(e[2]=s=>this.value=s),onKeydown:e[3]||(e[3]=s=>this.changed=!0),onBlur:e[4]||(e[4]=s=>o.useValidation()),disabled:this.updating},null,42,F)),[[v,this.value]]),t("div",B,b(this.invalidFeedback),1),l.warning?(n(),a("div",I,[t("small",null,[e[5]||(e[5]=t("i",{class:"bi bi-exclamation-triangle-fill me-2"},null,-1)),h(r,{t:l.warningText},null,8,["t"])])])):m("",!0)])}const z=c(V,[["render",P]]);export{z as P};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{L as n}from"./localeText-ZTaDi7ZY.js";import{c as a,d as r,e as s,j as i,f as e}from"./index-BCgxBvDt.js";const d={class:"position-relative"},c={key:0,class:"badge wireguardBg rounded-3 shadow z-1"},l={key:1,class:"badge amneziawgBg rounded-3 shadow"},p={__name:"protocolBadge",props:{protocol:String,mini:!1},setup(o){return(m,t)=>(e(),a("div",d,[o.protocol==="wg"?(e(),a("span",c,[t[0]||(t[0]=s(" WireGuard ",-1)),o.mini?r("",!0):(e(),i(n,{key:0,t:"Configuration"}))])):o.protocol==="awg"?(e(),a("span",l,[t[1]||(t[1]=s(" AmneziaWG ",-1)),o.mini?r("",!0):(e(),i(n,{key:0,t:"Configuration"}))])):r("",!0)]))}};export{p as _};
|
||||
import{L as n}from"./localeText-BJvnc1lF.js";import{c as a,d as r,e as s,j as i,f as e}from"./index-DM7YJCOo.js";const d={class:"position-relative"},c={key:0,class:"badge wireguardBg rounded-3 shadow z-1"},l={key:1,class:"badge amneziawgBg rounded-3 shadow"},p={__name:"protocolBadge",props:{protocol:String,mini:!1},setup(o){return(m,t)=>(e(),a("div",d,[o.protocol==="wg"?(e(),a("span",c,[t[0]||(t[0]=s(" WireGuard ",-1)),o.mini?r("",!0):(e(),i(n,{key:0,t:"Configuration"}))])):o.protocol==="awg"?(e(),a("span",l,[t[1]||(t[1]=s(" AmneziaWG ",-1)),o.mini?r("",!0):(e(),i(n,{key:0,t:"Configuration"}))])):r("",!0)]))}};export{p as _};
|
||||
+4
-4
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.btn.disabled[data-v-abe2acbc]{opacity:1;background-color:#0d6efd17;border-color:transparent}[data-v-b94dda6b]{font-size:.875rem}input[data-v-b94dda6b]{padding:.1rem .4rem}input[data-v-b94dda6b]:disabled{border-color:transparent;background-color:#0d6efd17;color:#0d6efd}.dp__main[data-v-b94dda6b]{width:auto;flex-grow:1;--dp-input-padding: 2.5px 30px 2.5px 12px;--dp-border-radius: .5rem}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user